Description
Purpose In this project, you’ll be getting some basic experience with how to write assembly language. You will write a simple function (which we’ll name studentMain()), and in it you will perform some simple tasks. 1.1 Required Filenames to Turn in Name your assembly language file asm1.s. You will also turn in a short report about the code that you wrote. The purpose of this is primarily to make sure you actually start using MARS for development (in addition to using the grading script). Using MARS will help you understand things better – even if it takes a little bit of time to get to know it. To make sure we can read it, your report must be a PDF. 1.2 Resources I have posted some resources in a piazza post for ASM1. Please have a look there. There are videos/documents that you need to review before starting ASM1. For instance, Russ (a previous instructor) made a video showing you how to get started with the MARS simulator. I have also explained in brief the process of starting ASM1. I am happy to review whatever parts of it did not make sense in class. 2 The Report NOTE: You will need to compose your code before you can write the report. So read the section on the task requirements first, and also read up on how to run using the MARS gui. But after your code is ready, come back and write this report. For this project, in addition to writing some assembly, you also need to write a short report, detailing some features of your code. To find out the required information, load up your solution (asm1.s), and also the first testcase (test 01.s). The easiest way to do this is to put both of these files in the same directory (with no other .s files), and then turn on the “Compile all files in directory” option of MARS. 1 Assemble these two files, and do a quick test run to make sure that your code works (check to see if the output produced looks right; for this part of the project, you don’t have to confirm that it’s perfect). For the first part of your report, you need to find some place where you used an LA instruction to get the address of the median variable. In MARS, you can do this as follows: • If it’s not already active, click on the “Execute” tab, near the top left of the window. • Inside Execute, you should see the “Text Segment” at the top. This is your code. Scroll up and down that window until you see your LA instruction. (Use the line numbers to help you find it.) • You will find that the LA instruction is actually a pseudoinstruction – it actually is implemented as 2 instructions in hardware. • Set a breakpoint at your LA instruction. (Breakpoints are the check-boxes on the left edge of the Text Segment window.) Then re-run the program again from the beginning. Your program will automatically pause when your LA instruction is just about to run. • Look for the “Run one step at a time” button on the toolbar; use it to run exactly two instructions. You will see that the first one modifies the register $at (MARS will highlight that register in the “Registers” pane on the right). The second instruction is the one that actually will modify the register that you mentioned in your LA instruction. • First item for your report – The address of median Now, look more closely at what LA did. It put the address of median into the register you chose. Give the address in hexadecimal. If all of the registers are in decimal instead of hexadecimal, look at the Settings menu to change them to hexadecimal. • Second item for your report – The two instructions that make up LA Next, look at the two instructions which make up the LA pseudoinstruction (the first is LUI). Write down, for your report, exactly what MARS shows in the Basic column of the Text Segment for these two instructions. The register names won’t look familiar – this column uses register numbers instead of names – but the second instruction should have a name that you’ve seen before. • Third item for your report – Hex encodings Finally, write down the actual 32-bit hex encodings of these two instructions (which you can find in the Code column). Do you see the constants used by these instructions stored inside those encodings somewhere? Thus, the first part of your report should include: 2 • The full 32-bit address of median, in hex. • The full text of the assembly instructions which make up the LA pseudoinstruction. • The encodings of both instructions, also as 32-bit hex numbers. 2.1 Strings and Data The second part of your report will observe how strings are loaded into memory. (Choose any one of the string constants that you used in your code.) Look at the first four characters of that string. Compare these four to an ASCII table. What are the ASCII codes (in hex) for these four characters? Now, find the LA instruction in your code which reads this string. Run the program to that point, and use it to figure out the address of this string in memory. (It probably starts with 0x1001….) Now, look at the Data Segment window (just below the Text Segment). Each row of this table represents 32 (0x20) bytes of data; on the left, you can see the addresses that the rows represent. Scroll until you can see the region of memory where your string is. (If you are completely in the wrong section of memory, use the drop-down at the bottom of the Data Segment window to choose what region you’re looking at. You want the .data section.) Once you’ve found the right row, look across the columns to find the cell that represents where your string is. (Each cell is 4 bytes of data.) Look for hex values that match the ASCII codes you’re expecting. If your string address is a multiple of 4, then they should all be inside the same word of memory; if your address is not aligned (which is just fine for strings), then they will be spread across two words. What do you notice? Probably, you’ll see that the characters appear to be in reverse order! For the second part of your report, write down: • The entire string constant from your code that you chose to use. • The ASCII codes (in hex) for the first 4 characters in that string. • The address where the string ended up. • The word (or maybe 2 words) in memory which contained the ASCII codes you were expecting. Finally, write at least one paragraph about your investigation. You can discuss any one (or more) of the following questions: • What was something new that you learned from this exercise, and how might you use it in the future? • What questions do you have that were inspired by this exercise? 3 • Explain your process for finding the information required by this exercise. Include screenshots to show what you saw, and discuss a bit of what you did. • I mentioned that the constant loaded by the LA instruction is present in the two instructions that LA becomes. Looking at the instruction encodings, what can you conclude about where the constants are stored? 3 Allowable Instructions When writing MIPS assembly, the only instructions that you are allowed to use (so far) are: • add, addi, sub, addu, addiu • and, andi, or, ori, xor, xori, nor • beq, bne, j • slt, slti • sll, sra, srl • lw, lh, lb, sw, sh, sb • la • syscall While MIPS has many other useful instructions (and the assembler recognizes many pseudo-instructions), do not use them! We want you to learn the fundamentals of how assembly language works – you can use fancy tricks after this class is over. WARNING: If you use instructions outside of this set – or, if you don’t give them the right types of parameters, our “MIPS checker” script will discover this, and you will lose half of your testcase points. 4 Standard Wrapper Your code will need to define a single function, named studentMain(). Later, when you learn how to write functions, things will get more interesting; for now, you should just copy-paste the code below. The following lines of code should be placed before your first instruction. This declares the function studentMain(), makes it available to the testcase, and then also gives the function “prologue” – that is, the basic code to start a function. 4 .globl studentMain studentMain: addiu $sp, $sp, -24 # allocate stack space — default of 24 here sw $fp, 0($sp) # save caller’s frame pointer sw $ra, 4($sp) # save return address addiu $fp, $sp, 20 # setup main’s frame pointer The following lines of code should be placed after your last instruction; this implements the “epilogue”, which basically is the return statement at the end of your function. lw $ra, 4($sp) # get return address from stack lw $fp, 0($sp) # restore the caller’s frame pointer addiu $sp, $sp, 24 # restore the caller’s stack pointer jr $ra # return to caller’s code (Both of these pieces should be inside a .text section.) 5 Task Overview Your code (inside the studentMain() function) will read five variables, named median, absVal, sum, rotate and dump. Each is a word, and will be either 1 or 0. Each represents a single operation you might perform; load each one, and if the variable is 1, then perform that task. Note that some testcases will have you perform no tasks; others may have you perform several, or even all of them. Perform the tasks in the order listed in the spec; if you change the order, you will not pass the testcase. In addition, you will be given three variables to read: one, two, three. All are words. These will be used as the inputs to the tasks below. You may either read them all at the begining of your function, and save them in registers – or read them as-needed in each task below. 5.1 Matching the Output You must match the expected output exactly, byte for byte. Every task (besides rotate) ends with a blank line (if it does anything at all); do not print the blank line if you do not perform the task. (Thus, if a testcase asks you to perform no tasks, your code will print nothing at all.) To find exactly the correct spelling, spacing, and other details, always look at the .out file for each example testcase I’ve provided. Any text in this spec is approximate; if it doesn’t match the .out file, then trust the .out file. 5 5.2 Implementation Hint One possible way to implement this project, which saves on code duplication, is to load all of the variables into registers first, before you do any checking. (Note: If you do this, you still ought to store into memory in the “copy” task, even if you also have a copy in a register.) If you do this, then document which registers are used for each variable, with a block comment at the head of your function. Be careful not to modify any of these registers – otherwise, actions taken during one task might affect another. 5.3 Task 1: median If median==1, then you will find the median value of the values. Implement the following code: if (median == 1) { if (one == two || one == three) print(“median: %d\n”, one); else if (two == three) print(“median: %d\n”, two); else { int cmp12 = (one < two); int cmp13 = (one < three); int cmp23 = (two < three); printf(“Comparisons: %d %d %d\n”, cmp12,cmp13,cmp23); if (cmp12 == cmp23) // a<bb>c printf(“median: %d\n”, two); if (cmp12 != cmp13) // b<aa>c printf(“median: %d\n”, one); if (cmp13 != cmp23) // a<cc>b printf(“median: %d\n”, three); } printf(“\n”); } (Take a look at the code above. Can you figure out why it works? What would happen if you took out the equality checks, would it still find the correct median value?) 5.4 Task 2: absVal If absVal==1, then check all three of the values. If any one of them is negative, then print out a message about it, and then reverse the value. (See the testcases to see the proper message to print.) 6 You must update the values in memory. In addition, if you decided to cache those variables in registers (this is allowed, but not required), then make sure that you update the values in the registers as well. If you perform this task, then print out a blank line at the end – even if you don’t find any values that you need to change. 5.5 Task 3: sum If sum==1, then sum up the three values, and print out the sum. See the testcases to see the proper message to print. You will also print out a blank line after this task if you perform it. 5.6 Task 4: rotate If rotate==1, then “rotate” the values – that is, move one into two, two into three, three into one. You must update the values in memory. In addition, if you decided to cache those variables in registers (this is allowed, but not required), then make sure that you update the values in the registers as well. Note there is no blank line after the rotate task. 5.7 Task 5: dump If dump==1, then print out the values, as follows: one: 789 two: 123 three: 456 As with most of the other operations, print out a blank line after the output. (Compare your output to the testscases to confirm that your format is correct.) 5.8 Requirement: Don’t Assume Memory Layout! It may be tempting to assume that the variables are all laid out in a particular order. Do not assume that! Your code should check the variables in the order that we state in this spec – but you must not assume that they will actually be in that order in the testcase. Instead, you must use the la instruction for every variable that you load from memory. To make sure that you don’t make this mistake, we will include testcases that have the variables in many different orders. 7 6 Running Your Code You should always run your code using the grading script before you turn it in. However, while you are writing (or debugging) your code, it is often handy to run the code yourself. 6.1 Running With Mars (GUI) To launch the Mars application (as a GUI), open the JAR file that you downloaded from Piazza. You may be able to just double-click it in your operating system; if not, then you can run it by typing the following command into a terminal: java -jar This will open a GUI, where you can edit and then run your code. Put your code, plus one1 testcase, in some directory. Open your code in the Mars editor; you can edit it there. When it’s ready to run, assemble it (F3), run it (F5), or step through it one instruction at a time (F7). You can even step backwards in time (F8)! 6.1.1 Running the Mars GUI the First Time The first time that you run the Mars GUI, you will need to go into the Settings menu, and set two options: • Assemble all files in directory – so your code will find, and link with, the testcase • Initialize Program Counter to ’main’ if defined – so that the program will begin with main() (in the testcase) instead of the first line of code in your file. 6.2 Running Mars at the Command Line You can also run Mars without a GUI. This will only print out the things that you explicitly print inside your program (and errors, of course).2 However, it’s an easy way to test simple fixes. (And of course, it’s how the grading script works.) Perhaps the nicest part of it is that (unlike the GUI, as far as I can tell), you can tell Mars exactly what files you want to run – so multiple testcases in the directory is OK. To run Mars at the command line, type the following command: 1 Why can’t you put multiple testcases in the directory at the same time? As far as I can tell (though I’m just learning Mars myself), the Mars GUI only runs in two modes: either (a) it runs only one file, or (b) it runs all of the files in the same directory. If you put multiple testcases in the directory, it will get duplicate-symbol errors. 2 Mars has lots of additional options that allow you to dump more information, but I haven’t investigated them. If you find something useful, be sure to share it with the class! 8 java -jar sm .s .s 7 A Note About Grading Your code will be tested automatically. Therefore, your code must: • Use exactly the filenames that we specify (remember that names are case sensitive). • Not use any other files (unless allowed by the project spec) – since our grading script won’t know to use them. • Follow the spec precisely (don’t change any names, or edit the files I give you, unless the spec says to do so). • (In projects that require output) match the required output exactly! Any extra spaces, blank lines misspelled words, etc. will cause the testcase to fail. To make it easy to check, I have provided the grading script. I strongly recommend that you download the grading script and all of the testcases, and use them to test your code from the beginning. You want to detect any problems early on! 7.1 mips checker.pl In addition to downloading grade asm1, you should also download mips checker.pl, and put it in the same directory. The grading script will call the checker script. 7.2 Testcases For assembly language programs, the testcases will be named test *.s . For C programs, the testcases will be named test *.c . For Java programs, the testcases will be named Test *.java . (You will only have testcases for the languages that you have to actually write for each project, of course.) Each testcase has a matching output file, which ends in .out; our grading script needs to have both files available in order to test your code. For many projects, we will have “secret testcases,” which are additional testcases that we do not publish until after the solutions have been posted. These may cover corner cases not covered by the basic testcase, or may simply provide additional testing. You are encouraged to write testcases of your own, in order to better test your code. 9 7.3 Automatic Testing We have provided a testing script (in the same directory), named grade asm1, along with a helper script, mips checker.pl. Place both scripts, all of the testcase files (including their .out files), and your program files in the same directory. (I recommend that you do this on Lectura, or a similar department machine. It might also work on your Mac or Linux box, but no promises!) 7.4 Writing Your Own Testcases The grading script will grade your code based on the testcases it finds in the current directory. Start with the testcases I provide – however, I encourage you to write your own as well. If you write your own, simply name your testcases using the same pattern as mine, and the grading script will pick them up. While you normally cannot share code with friends and classmates, testcases are the exception. We encourage you to share you testcases – ideally by posting them on Piazza. Sometimes, I may even pick your testcase up to be part of the official set, when I do the grading! 8 Turning in Your Solution You must turn in your code using the same turnin command that you used for sim1. For this assignment, you will navigate to the folder that contains the folder asm1. Then run the command: turnin cs252f21-asm1 asm1. Please turn in only your program; do not turn in any testcases. In addition, you must turn in your report (see details above). Part of your score for Project 1 will come from this report. So please ensure that you include your report in your asm1 folder that you submit. 10