24小时全年无休客服
本公司旗下写手皆为公司直聘 网络写手勿扰
案例中心
CIT 5930 | Assignment
Assignment
CIT 5930 | Assignment: C - File I/O – Making the LC4 Assembler | 1
Setting up Codio and Makefile for this HW:
1) Open the Codio assignment via Canvas
2) From the Codio File-Tree click on: assembler.c
3) Makefile must implement these 3 targets – all, clean, clobber
NOTE:
If your program is crashing, before you can be helped via TA office hours, you must run GDB on
your program. A small amount of detective work with GDB will save hours! Be prepared for TAs
to tell you to run GDB before they will help you in office hours. Watch the tutorial and run it on
your program if it is crashing!
Assignment Overview:
From lecture you’ve learned that C is file-oriented and that working with files represents I/O
devices in C. C places files into two categories: “text” and “binary.” In this assignment you’ll work
with both types by reading in a text file and writing out a binary file. The text file that you will
read in this assignment will be a .ASM file (a text file intended for PennSim) and the type of
output file you’ll generate will be a .OBJ file ( the same type of binary file that PennSim would
write out). Aside from reading and writing out the files, your task will be make a mini-LC4-
Assembler! A program that reads in assembly language and generates its machine equivalent.
This assignment will require a bit more programming rigor than we’ve had thus far, but now that
you’ve gained a good amount of programming skill in this class and in others, it is the perfect
time to tackle a large programming assignment.
CIT 5930 | Assignment: C - File I/O – Making the LC4 Assembler | 2
Problem #1: Reading in a text file (the .ASM file)
Open “assembler.c” from the helper files; it contains the main() function for the program.
Carefully examine the variables at the top:
char* filename = NULL ;
char program [ROWS][COLS] ;
char program_bin_str [ROWS][17] ;
unsigned short int program_bin [ROWS] ;
The first pointer variable “filename” will be a pointer to a string that contains the text file you’ll
be reading. Your program must take in as an argument the name of a .ASM file. As an example,
once you compile your main() program, you would execute it as follows:
./assembler test1.asm
In your last HW you learned how to use the arguments passed into main(). So the first thing to
implement is to check if argc has arguments, and if it does, point “filename” to the argument
that contains the passed in string that is the file’s name. You should return from main()
immediately (with an error message) if the caller doesn’t provide an input file name as follows:
error1: usage: ./assembler
Start by updating “assembler.c” to read in the arguments. Compile your changes and test them
before continuing. You should take this moment to setup your Makefile as well, it should contain
two basic directives: assembler and asm_parser.o
After you’ve successfully gotten the filename from the caller, the first function you must call will
be:
int read_asm_file (char* filename, char program [ROWS][COLS] ) ;
The purpose of read_asm_file() is to open the ASM file, and place its contents into the 2D array:
program[][]. You must complete the implementation of this function in the provided helper file:
“asm_parser.c”. Notice, it takes in the pointer to the “filename” that you’ll open in this function.
It also takes in the two dimensional array, program, that was defined back in main(). You’ll see
that “ROWS” and “COLS” are two #define’ed constants in the file: asm_parser.h. Rows is set to
100 and COLS is set to 255. This means that you can only read in a program that is up to 100 lines
long and each line of this program can be no longer than 255.
You’ll want to look at the class notes (or a C-reference textbook) to use fopen() to open the
filename that has been passed in. Then you’ll want to use a function like: fgets() to read each
CIT 5930 | Assignment: C - File I/O – Making the LC4 Assembler | 3
line of the .ASM file into the program[][] 2D array. Be aware that “fgets()” will keep carriage
returns (aka – the newline character) and you’ll need to strip these from the input.
Take a look at test1.asm file that was included in the helper file. It contains the following
program:
ADD R1, R0, R1
MUL R2, R1, R1
SUB R3, R2, R1
DIV R1, R3, R2
AND R1, R2, R3
OR R1, R3, R2
XOR R1, R3, R2
After you complete read_asm_file() and if you were to run it on test1.asm, your 2D array:
program[][]should contain the contents of the ASM file in this order:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
0 A D D R 1 , R 0 , R 1 ‘\0’
1 M U L R 2 , R 1 , R 1 ‘\0’
2 S U B R 3 , R 2 , R 1 ‘\0’
3 D I V R 1 , R 3 , R 2 ‘\0’
4 A N D R 1 , R 2 , R 3 ‘\0’
5 O R R 1 , R 3 , R 2 ‘\0’ X
6 X O R R 1 , R 3 , R 2 ‘\0’
7 ‘\0’ X X X X X X X X X X X X X X
Notice, there are no “newline” characters at the end of the lines.
If reading in the file is a success, return 0 from the function, if not, return 2 from the function
and print an error to the screen: error2: read_asm_file() failed
Implement and test this function carefully before continuing on with the assignment.
CIT 5930 | Assignment: C - File I/O – Making the LC4 Assembler | 4
Problem #2: Parsing an Instruction
Once read_asm_file() is working properly, back in main(), you’ll call the function:
parse_instruction(), which is also located in asm_file.c:
int parse_instruction (char* instr, char* instr_bin_str) ;
NOTE:
You are required to implement the following instructions: ADD, MUL, SUB, DIV, AND, OR, XOR
(ADD IMM and AND IMM are not required, but will be EC, as detailed on page 10)
purpose, arguments & return value
The purpose of this function is to take in a single row of your program[][] array and convert to
its binary equivalent – in text form. The argument: instr must point to a row in main()’s 2D array:
program[][]. The argument: instr_bin_str must point to the corresponding row in main()’s 2D
array: program_bin_str[][]. If there no errors are encountered the function will return a 0 and if
any error occurs (in this function) it should return the number 3 and an error message should be
printed: error3: parse_instruction() failed.
Let’s assume you’ve called parse_instruction() and “instr” points to the first row in your
program[][] array:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
*instr -> A D D R 1 , R 0 , R 1 ‘\0’
Parse_instruction() needs to examine this string and convert it into a binary equivalent. You’ll
need to use the LC4 ISA to determine the binary equivalent of an instruction. When your function
returns, the memory pointed to by: instr_bin_str, should look like this:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
*instr_bin_str -> 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 ‘\0’
Notice, this isn’t actually binary, but it is the “ADD” instruction’s binary equivalent in TEXT form.
We will convert this string form of the binary instruction to HEX later in the function:
convert_instrunction().
CIT 5930 | Assignment: C - File I/O – Making the LC4 Assembler | 5
How to implement this function
STRTOK() allows you to parse a string that is separated by “tokens”. In this function you’ll be
parsing the string pointed to be “instr” and you’ll be building up the string pointed to by
“instr_bin_str”. “instr” will contain spaces and commas (those will be your tokens). Your first call
to strtok() on the “instr” string should return back the OPCODE: ADD, SUB, MUL, DIV, XOR, etc.
The only thing common to all 26 instructions in the ISA is that the very first part of them is the
opcode. Once you determine the OPCODE, you’ll call the appropriate helper function to parse
the remainder of the instruction.
As an example, let’s say the OPCODE is ADD. For this problem, you do not need to worry about
the “immediate” variants of the ADD instruction (or AND immediate) – when we test your code,
we won’t use ADD – immediate or AND immediate instructions. Once you’ve determined the
OPCODE is ADD, you would call the parse_add() helper function. It will take the instruction (instr)
as an argument, but also the instr_bin_str string because parse_add will be responsible for
determining the binary equivalent for the ADD instruction you are currently working on and it
will update instr_bin_str.
int parse_add (char* instr, char* instr_bin_str ) ;
When parse_add() returns, if no errors occurred during parsing the ADD instrunction, instr_bin
should now be complete. At this time, you can return a 0 from parse_instrunction().
CIT 5930 | Assignment: C - File I/O – Making the LC4 Assembler | 6
Problem #3: Parsing an ADD instruction
int parse_add (char* instr, char* instr_bin_str ) ;
The helper function: parse_add(), should be called only by the parse_instruction() function. It
has two char* arguments: instr and instr_bin_str. Because this function will only be called when
an ADD OPCODE is encountered by parse_instruction(), instr will contain an ADD instruction and
instr_bin_str should be empty. [][]. If there no errors are encountered the function will return a
0 and if any error occurs (in this function) it should return the number 4 and an error message
should be printed: error4: parse_add() failed.
The purpose of this function is to populate the instr_bin_str. Upon the function’s start, the binary
OPCODE can be immediately copied into the instr_bin_str[0:3]. Afterwards, the strtok() function
can be used again to separate the registers: RD, RS, RT, from the “instr” string.
For each register: RD, RS, RT, the parse_reg() helper function should be called:
int parse_reg (char reg_num, char* instr_bin_str) ;
This function must take as input a number in character form and populate instr_bin_str with the
appropriate corresponding binary number. For example, if RD = R0 for the ADD instruction, the
‘0’ character would be passed in the argument: reg_num. parse_reg() would then copy into
instr_bin_str[4:6] the characters ‘000’. A 5 should be returned if any errors occur and the
standard error message should be printed; otherwise a 0 should be returned upon success.
This helper function: parse_reg() should only parse one register at a time. Also, because it is not
specific to the ADD instruction (nearly all instructions contain registers), it can be called from
other functions that need their register’s converted to binary. Example: prase_mul() should also
call parse_reg().
Note that parse_add() must also populate the SUB-OPCODE field in instr_bin_str[10:12]. When
parse_add() returns, instr_bin_str should be complete. parse_instrunction() should then return
to main(). You will need to create a helper function for each instruction type, use parse_add()
as a model. As an example, you’ll need to create: parse_mul(), parse_xor(), etc – they will all be
very similar functions, so perfect parse_add() before you attempt those other functions.
CIT 5930 | Assignment: C - File I/O – Making the LC4 Assembler | 7
Problem #4: Converting the binary string to hex
After parse_instruction() returns successfully to main, the function:
unsigned short int str_to_bin (char* instr_bin_str) ;
Should be called from main(), passing the recently parsed binary string from the array:
program_bin_str[X], where “X” represents the binary instruction that was just populated by the
last call to parse_instruction().