PA1
Transcription
PA1
Programming Assignment One: PA1 (displayX) Milestone: Wednesday night, April 15 @ 11:59pm Final: Tuesday night, April 21 @ 11:59pm Overview: The purpose of this assignment is to build your knowledge of the SPARC assembly language, especially branching and looping logic, calling assembly routines from within a C program, calling C functions from within assembly routines, passing parameters and returning values, using Unix command line arguments, and learning some useful Standard C Library routines. You will be writing a program that takes 4 inputs from the command line: [cs30xyz@ieng9]:pa1$ ./pa1 X_size X_char filler_char border_char These inputs are parameters for displaying a X pattern which will be printed to stdout. 'size' specifies the size of the X pattern. 'x_char' specifies the ASCII character value used to display the X pattern. 'filler_char' and 'border_char' are the ASCII values for the characters which will make up the area around the X pattern and the border around the entire pattern, respectively. See man ascii for a map of the ASCII character set. Appropriate error checking and reporting is required. Note that in most cases, we will display all the related errors instead of stopping after we encounter the first error. Start early! Remember that you can and should use man in order to lookup information on specific C functions. For example, if you would like to know what type of parameters strtol() takes, or what strtol() does to errno, type man strtol. Also, take advantage of the tutors in the lab. They are there to help you learn more on your own and help you get through the course! Grading: README: 10 points Compiling: 10 points Using our Makefile; no warnings, more details below Style: 20 points Correctness: 60 points -10 points for each unimplemented module or module written in the wrong language (C vs Assembly and vice versa). Includes both abnormal and normal output, both to the correct destination (stderr vs stdout). Make sure you have all files tracked in Git - we will be checking for multiple commits of each file and that they were meaningful commits. Wrong Language: -10 points -10 for each module in the wrong language, C vs. Assembly or vice versa. Extra Credit: 5 points NOTE: If what you turn in does not compile with given Makefile, you will receive 0 points for this assignment. Starter Files To get you started, follow the steps below to copy required files (the Makefile template, the unit test for checkRange(), and pa1_strings.h) to your pa1 directory: $ $ $ $ $ $ $ cd mkdir pa1 cp ~/../public/Makefile-PA1 ~/pa1/Makefile cp ~/../public/test.h ~/pa1/test.h cp ~/../public/testcheckRange.c ~/pa1/testcheckRange.c cp ~/../public/pa1.h ~/pa1/pa1.h cp ~/../public/pa1_strings.h ~/pa1/pa1_strings.h Setup and Git: You are required to use Git with this and all future programming assignments. Look at the PA0 writeup for additional information on Git. Setting up a local repository Navigate to your pa1 directory and initialize a local git repository: [cs30xyz@ieng9]:pa1$ git init If you haven't already set your global git user info, go ahead and do that now: [cs30xyz@ieng9]:pa1$ git config --global user.name "John Doe" [cs30xyz@ieng9]:pa1$ git config --global user.email "johndoe@ucsd.edu" Adding and committing files As you're developing, you can see the status of the files in your directory with the following command: [cs30xyz@ieng9]:pa1$ git status After you edit a file with meaningful changes*, you should add and commit it to the repository: [cs30xyz@ieng9]:pa1$ git add filename [cs30xyz@ieng9]:pa1$ git commit -m "Some message describing the changes" Note: You can commit multiple files at the same time by git adding several files before calling commit: [cs30xyz@ieng9]:pa1$ [cs30xyz@ieng9]:pa1$ [cs30xyz@ieng9]:pa1$ [cs30xyz@ieng9]:pa1$ git git git git add file1 add file2 add file3 commit -m "Changed things in three files" NOTE: You must do a git add on each file you wish to commit before every git commit! It is not enough to do a git add once at the beginning. git commit will only collect files that have been git add’ed since the last commit. * "Meaningful change" is a subjective term. Essentially, whenever you make a code change that results in a stable version that you want to keep track of, you should commit those changes. Ignoring files with .gitignore You may notice as you're developing your program that Git really wants to keep track of .o files, .ln files, and .swp files, which you don't really need to track. You can get it to stop bugging you about them by creating a .gitignore file. Simply open .gitignore in vim/gvim: [cs30xyz@ieng9]:pa1$ vim .gitignore And add the following lines to it: .gitignore *.o *.ln *.sw* *~ a.out core Now when you do git status, those pesky files won't show up in the list of untracked files. Example Output A sample stripped executable for you to try, and compare your output against, is available at: ~/../public/pa1test When there is a discrepancy between the sample output in this document and the pa1test output, follow the pa1test output. Below are some example outputs of this program. Bolded text is example of what you type in the terminal. 1.1. Valid Input [cs30x3@ieng9]:pa1-displayX:591$ ./pa1 8 33 34 35 ########## #!""""""!# #"!""""!"# #""!""!""# #"""!!"""# #"""!!"""# #""!""!""# #"!""""!"# #!""""""!# ########## 1.2. Valid Input [cs30x3@ieng9]:pa1-displayX:617$ ./pa1 12 45 52 67 CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC CC-4444444444-CC CC4-44444444-4CC CC44-444444-44CC CC444-4444-444CC CC4444-44-4444CC CC44444--44444CC CC44444--44444CC CC4444-44-4444CC CC444-4444-444CC CC44-444444-44CC CC4-44444444-4CC CC-4444444444-CC CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC 2. Wrong Number of arguments [cs30x3@ieng9]:pa1-displayX:618$ ./pa1 12 45 52 67 55 Usage: ./pa1 X_size X_char filler_char border_char X_size (must be within the range of [4 - 5000]) (must be even) X_char (must be an ASCII value within the range [32 - 126]) filler_char (must be an ASCII value within the range [32 - 126]) (must be different than X_char) border_char (must be an ASCII value within the range [32 - 126]) (must be different than X_char) 3. Non-integer input [cs30x3@ieng9]:pa1-displayX:620$ ./pa1 12 45a gh52 67.1 "45a" is not an integer "gh52" is not an integer "67.1" is not an integer 4. Size is not even [cs30x3@ieng9]:pa1-displayX:621$ ./pa1 11 32 33 34 X_size(11) must be even 5. Arguments are out of range [cs30x3@ieng9]:pa1-displayX:622$ ./pa1 4 31 127 34 X_char(31) must be an ASCII code in the range [32 - 126] filler_char(127) must be an ASCII code in the range [32 - 126] 6. Input chars are not unique [cs30x3@ieng9]:pa1-displayX:629$ ./pa1 4 32 32 32 X_char(32) and filler_char(32) must be different X_char(32) and border_char(32) must be different Overview You will write a C main() driver to read in the command line arguments representing the size of the X pattern, the ASCII value (as an integer) of the character to use to display the X pattern, ASCII code for the character to use to fill in around the X pattern, and ASCII code for the character to use for the border [see man ascii] and convert them to long ints utilizing the Standard C Library routine strtol(). In main() you will also check that each of the command line arguments are within their required ranges by calling checkRange(). By calling isEven() you will check that the X pattern size is an even value. Finally, make sure that neither the filler nor border characters are the same as the X character (the filler and border characters can be the same). See Example Output for the specific order of validity checking. Then if everything is fine display the X pattern (displayX() with the user-supplied values) by outputting a single character at a time with printChar(). To determine the depth of the border, use numOfDigits() from within displayX(). Function Prototypes of the C functions you will write: int main( int argc, char *argv[] ); Function Prototypes of the SPARC Assembly functions you will write: int checkRange( long minRange, long maxRange, long value ); void displayX( long size, long xChar, long fillerChar, long borderChar ); int numOfDigits( long num, int base ); int isEven( long value ); void printChar( char ch ); C Modules 1. main.c Function Prototype: int main( int argc, char *argv[] ); This function will drive the rest of the program. It will perform input checking and if all input is valid it will call displayX(). If any of the input checks fail use the corresponding string in the pa1_strings.h file to print. First, it will check if the correct number of arguments is given, if not it will print the usage and exit. Second, it will convert the size variable. It will check if it is an integer, if it fails it will print the error and move onto the next input variable. If it succeeds, it will check the range, then if it is even. Third, it will convert the xChar variable. It will check if it is an integer, if it fails it will print the error and move onto the next input variable. If it succeeds, it will check the range. Fourth, it will convert the filler variable. It will check if it is an integer, if it fails it will print the error and move onto the next input variable. If it succeeds, it will check the range, then if it is the same as the xChar. Fifth, it will convert the border variable. It will check if it is an integer, if it fails it will print the error and move onto the next input variable. If it succeeds, it will check the range, then if it is the same as the xChar. If the inputs pass all of the above checks, then main will call displayX() with the inputs that have been converted to longs and then return 0 to indicate successful execution. Assembly Modules 1. isEven.s Function Prototype: int isEven( long num ); This assembly module will implement the logic for checking if the long int argument value is even or not. Return 0 if not even to indicate false; return a non-zero value if it is even to indicate true. 2. printChar.s Function Prototype: void printChar( char ch ); This assembly module will print the character argument to stdout. This is very similar to the assembly module printWelcome.s given as part of PA0 -- use printf(). But printChar() just prints a single character. 3. checkRange.s Function Prototype: int checkRange( long minRange, long maxRange, long value ); This assembly module will check to make sure the value of the first argument is within the range of minRange and maxRange, exclusive. Return 0 for false; return non-zero for true. 4. displayX.s Function Prototype: void displayX( long size, long xChar, long fillerChar, long borderChar ); This assembly module will perform the actual outputting of individual characters (via calls to printChar()) such that an X pattern is displayed with the user-supplied values. **You are given an equivalent C version HERE: http://ieng9.ucsd.edu/~cs30x/pa1/displayX_template** You may hand translate this code into assembly. Just a bunch of nested for loops and an if conditional. Chapter 2 in the textbook covers just about everything you need to code these assembly modules. We will be covering all these assembly constructs in class. There are probably many ways to code displayX(). You are not limited to using the above algorithm, but one of the purposes of this programming assignment is to have you write looping/conditional constructs (branches), use the simple .mul/.div/.rem subroutines with parameter passing and return values, and perform simple arithmetic instructions (inc, add/sub) in assembly. You may output only a single character at time in the fashion of the algorithm above. We would prefer you use the above algorithm for these reasons, but we also do not want to suppress creative thinking that may lead to alternative solutions. You must use the "preferred" style of coding loops as detailed in the class Notes #4 -- set up an opposite logic branch to jump over the loop body and a positive logic branch to jump backwards to the loop body. To define an assembler constant, do something (you could call it something other than NL) like this towards the top of an assembly file: NL = '\n' 5. numOfDigits.s Function prototype: int numOfDigits( long num, int base); This assembly module will count the number of base digits in its argument. The base argument can be in the range [2-36]. Use checkRange() to ensure the base argument is within this range. If it is out of range, return -1. As a special case, if num is the value 0, return with the value 1. For the general case, you can simply set up a loop: while num is not equal to 0, increment a counter and set num equal to num divided by base (this gets rid of the right-most base digit). Then return the counter value. You can use the following assembler constants: MIN_BASE = 2 MAX_BASE = 36 Do not hardcode anything like checking if the argument is less than base, else less than base2, else less than base3, etc. Note: This module must handle positive and negative values. If you code it correctly you should not have to add any additional code to account for negative values. Unit Testing Provided in the Makefile for PA1 are rules for compiling and running tests on individual functions that are part of this assignment. You are given the source for testcheckRange.c used to test your checkRange() function. Use testcheckRange.c as a template for you to write modules to test your isEven() and numOfDigits() functions. These kinds of test programs are called Unit Tests because they test a function independently as a single unit of code separate from the whole program. This allows you to develop and more importantly test individual functions more or less in any order, and allows you to have a high level of confidence each function is correct when you put them together to form the whole program. Unit tests you need to write: testisEven.c testnumOfDigits.c Think of how to test each of these functions -- boundary cases, special cases, general cases, extreme limits, error cases, etc. as appropriate for each function. As part of the grading, we will run all the unit test targets in the Makefile and manually grade your unit test programs. For example: make runtestisEven README File Along with your source code, you will be turning in a README (use all caps and no file extension for example, the file is README and not README.txt) file with every assignment. Use vi/vim to edit this file! Your README file for this and all assignments should contain: - Header with your name, cs30x login - High level description of what your program does - How to compile it (usually just typing "make") - How to run it (give an example) - An example of normal output and where that normal output goes (stdout or a file or ???) - An example of abnormal/error output and where that error output goes (stderr usually) - How you tested your program - Anything else that you would want/need to communicate with someone who has not read the writeup - Answers to questions (if there are any) Questions to Answer for the README Start gdb with your pa1 executable, then set a breakpoint at strtol Run the program (in gdb) with the following command line args: run 9InchNails 999999999999999 55 66 You should be at the entry point of the Std C Lib routine strtol called from main. 1. How do you print the value of the string that is the 1st arg in strtol? (The value should be "9InchNails") 2. How do you print the decimal value of the base that is the 3rd arg in strtol? (The value should be 10) 3. How do you print the hex value of &endptr that is the 2nd arg in strtol? The value should be something like 0xffbe---- (a high stack address - will vary) Go to the next high level source instruction in main. This should be the next C instruction in main after the function call to strtol. Type next 4. How do you print the value returned by strtol? Show two ways: a) Using the name of the local variable you use to hold the return value b) Displaying the value in the register used to return the value The value should be 9 5. How do you print the character endptr is pointing to? (Should be the character 'I') 6. How do you print the entire null-terminated string endptr is pointing to? (Should be "InchNails") 7. How do you print the decimal value of the global variable errno at this point? (The value should be 0). Continue the execution of your pa1 in gdb Type continue You should see the error message "9InchNails" is not an integer displayed by your program. You should be back at the strtol breakpoint. Go to the next source instruction in main. Type next It should be the source-level instruction after the call to strtol passing in 999999999999999 to convert to an int. Print the decimal value of errno at this point. The value of errno should be 34 now which is the value of ERANGE. See the man page for errno and section 2 intro. You can continue or quit. The remaining questions pertain to Git. 8. What is the Git command to show the current state of your working tree? 9. What is the Git command to discard any changes made to a file since its last commit? 10. What is the Git command to display the differences between the local version of a file and the version last committed? Extra Credit There are 5 points total for extra credit on this assignment. [2 Points] Early turnin, 48 hours before regular due date and time. (1 point if you get it 24 hours early) [3 Points] Eliminating nops in the sample assembly file. Copy over EC_main.c and nops.s from the public directory: [cs30xyz@ieng9]:pa1$ cp ~/../public/EC_main.c ~/pa1 [cs30xyz@ieng9]:pa1$ cp ~/../public/nops.s ~/pa1 You will be modifying nops.s to perform assembly optimization. NOTE: Only nops.s should have assembly optimization for extra credit. Do not modify any other assembly functions for PA1 assignment. Make sure you do not make any changes to EC_main.c . All the optimization changes you need to make should be in nops.s . In order to do this extra credit, you need a working version of isEven.s Once you have the working versions, you can compile the example program for this extra credit: [cs30xyz@ieng9]:pa1$ gcc -o EC_main EC_main.c nops.s isEven.s This program takes in a single positive integer as input, and prints a secret number based on the input. Sample Outputs: [cs30xyz@ieng9]:pa1$ ./EC_main Usage: ./EC_main num num - integer to calculate secret number for [cs30xyz@ieng9]:pa1$ ./EC_main 5 0: 0 1: 0 2: 2 3: 3 4: 7 The secret number for 5 is 7 [cs30xyz@ieng9]:pa1$ ./EC_main 0 The secret number for 0 is 0 Notice that there are a total of 7 nops in the assembly code (nops.s). Your task is to eliminate as many of the nops as you can by replacing the nops with an existing instruction from somewhere else in the file. There may be a nop that is not optimizable with a correct and useful instruction - watch out for this. Every two nops eliminated will be worth half a point, so to get all 3 points you will have to eliminate 6 nops with useful instructions from somewhere else in the file. NOTE: If the optimized version does not have the same output as the unoptimized version, no points will be awarded. Milestone and Turnin Instructions Milestone Check - due Wednesday night, April 15 @ 11:59 pm [15 points (25%) of Correctness Section] Before final and complete turnin of your assignment, you are required to turnin several modules to your local for Milestone check. Files required for Milestone: isEven.s checkRange.s numOfDigits.s pa1.h pa1_strings.h Makefile Each assembly module (isEven.s, checkRange.s, and numOfDigits.s) is worth 5 points for a total of 15 points. Each module must pass all of our unit tests in order to receive full credit. A working Makefile with all the appropriate targets created must be turned in as well. See the examples in the Makefile for checkRange. Any required header files must also be committed as well. In order for your files to be graded for the Milestone Check, you must use the milestone specific turnin script. cd ~/pa1 cse30_pa1milestone_turnin All three Makefile test cases must compile successfully via the commands make testcheckRange, make testisEven, and make testnumOfDigits. Complete Turnin - due Tuesday night, April 21 @ 11:59 pm Once you have checked your output, compiled, executed your code, and finished your README file (see below), you are ready to turn it in. Before you turn in your assignment, you should do make clean in order to remove all the object files, lint files, core dumps, and executables. Note: The turnin facility will be used for all your future programming assignments too. So get familiar with it now. How to Turn in an Assignment First, you need to have all the relevant files in a subdirectory of your home directory. The subdirectory should be named: pa#, where # is the number of the homework assignment. Besides your source/header files, you may also have one or more of the following files. Note the capitalization and case of each letter of each file. Makefile: To compile your program with make -- usually provided or you will be instructed to modify an existing Makefile. README: Information regarding your program. Again, we emphasize the importance of using the above names *exactly* otherwise our Makefiles won't find your files. When you are ready to submit your pa1, type: Cd ~/pa1 cse30turnin pa1 Follow the instructions. You should see a message about archiving the following files for turnin: checkRange.s displayX.s isEven.s main.c Makefile numOfDigits.s pa1.h printChar.s pa1_strings.h README If you did the extra credit, the following two files should also be included EC_main.c nops.s Additionally, you can type the following to verify that everything was submitted properly. cse30verify pa1 Failure to follow the procedures outlined here will result in your assignment not being collected properly and will result in a loss of points. Late assignments WILL NOT are accepted. If, at a later point you wish to make another submittal BEFORE the deadline: cd cse30turnin pa1 Or whatever the current pa# is, the new archive will replace/overwrite the old one. To verify the time on your submission file: cse30verify pa1 It will show you the time and date of your most recent submission. The governing time will be the one which appears on that file, (the system time). The system time may be obtained by typing "date". Your files must be located in a subdirectory of your home directory, named paX (where X is the assignment number, without capitalizations). If the files aren't located there, they cannot be properly collected. Remember to cd to your home directory first before running turnin. If there is anything in these procedures which needs clarifying, please feel free to ask any tutor, the instructor, or post on the Piazza Discussion Board. Style Requirements You will be graded for the style of programming on all the assignments. A few suggestions/requirements for style are given below. Read carefully, and if any of them need clarification do not hesitate to ask. - Use reasonable comments to make your code clear and readable. - Use file headers and function header blocks to describe the purpose of your programs and functions. Sample file/function headers are provided with PA0. - Explicitly comment all the various registers that you use in your assembly code. - In the assembly routines, you will have to give high level comments for the synthetic instructions, specifying what the instruction does. - You should test your program to take care of invalid inputs like nonintegers, strings, no inputs, etc. This is very important. Points will be taken off if your code doesn't handle exceptional cases of inputs. - Use reasonable variable names. - Error output goes to stderr. Normal output goes to stdout. - Use #defines and assembly constants to make your code as general as possible. - Use a local header file to hold common #defines, function prototypes, type definitions, etc., but not variable definitions. - Judicious use of blank spaces around logical chunks of code makes your code much easier to read and debug. - Keep all lines less than 80 characters, split long lines if necessary. - Use 2-4 spaces for each level of indenting in your C source code (do not use tab). Be consistent. Make sure all levels of indenting line up with the other lines at that level of indenting. - Do use tabs in your Assembly source code. - Always recompile and execute your program right before turning it in just in case you commented out some code by mistake. - Before running turnin please do a make clean in your project directory. - Do #include only the header files that you need and nothing more. - Always macro guard your header files (#ifndef … #endif). - Never have hardcoded magic numbers. This means we shouldn't see magic constants sitting in your code. Use a #define if you must instead.