CSE141L Lab 3, Part 2: Creating an Assembler


CSE 141L Homepage | Lab Overview | Lab Description


Deadline: May 6 at Noon
Changes:
  1. None.

Lab Overview:

Now that we have an ISA designed, it is time to start creating some programmer tools that will allow us (and eventually our customers) use it. We have a separate division working on a C-to-assembly compiler so we can focus on a single task: creating an assembler. As you should remember from previous classes, an assembler takes assembly code and automatically translates it to machine code. For this part, you should continue working with your partner to help things go as smoothly as possible. As we mentioned in
Part 1, we are working on a tight timeline so lets get started. Good luck!

Lab Deliverables:

For part 2 of this lab, you will be creating an assembler which takes some source code (written in assembly language of your ISA) and translates it to machine code. You may use any high-level programming language you choose (e.g. Java, C/C++, etc) to do so. You will need to submit both the source code and a compiled executable for your assembler. This part of the lab is the first that you will have an interview with Sat. You will need to sign up for a 15-minute time slot during which you will need to discuss your ISA design and also demonstrate your working assembler. There is no formal progress report for this part of the lab.


Lab Description:

Jump to: Assembler Requirements | Assembler Inputs/Outputs | Code Stub

Assembler Requirements:

First, examine the following sample assembly code.

.text
	la  $1, table0    // load the address of a label table0 (pseudo instruction)
	lw  $2, $1        // $2 <= 0x000C0FFEE 
	lw  $3, table0    // load the value at label table0 (pseudo instruction), $3 <= 0x000C0FFEE
	lw  $4, 3(table0) // $4 <= table1
	lw  $5, 1($4)     // $5 <= 0x1DEADBEEF
	sw  $5, 1($1)     // 0x001COFFEE is overwritten to 0x1DEADBEEF 
	li  $6, 0xC0FFEE  // load immediate (pseudo instruction), $6 <= 0xC0FFEE
														         
.data
	table0:
		.word 0x000C0FFEE
		.word 0x001C0FFEE
		.word 0x002C0FFEE
		.word table1
	table1:
		.word 0x0DEADBEEF
		.word 0x1DEADBEEF
		.word 0x2DEADBEEF
		.word 0x3DEADBEEF
		.word 0x4DEADBEEF, 0x5DEADBEEF, 0x6DEADBEEF
		.fill 10 0x0

Your assembler must support the following keywords and reserved words used in the example code above. The following list is the minimal required set; you may extend it with other keywords.

Keyword Description
.text Indicates the start of the text section, consisting of instructions. .text can appear many times in an assembly file, but they must be merged into a single section in the output of the assembler. The input to the assembler (-text_addr) will specify the address that the assembler will assume the resulting text section is loaded at.
.data Indicates the start of the data section. Similar to .text, there can be multiple .data in an assembly file. The input to the assembler (-data_addr) will specify the address that the assembler will assume the resulting data section is loaded at.
.word Specifies the word data at a memory location. It can be followed by multiple one or more words to describe data for multiple words.
.fill Duplicates a data many times. For example, .fill 10 0x0 duplicates 0x0 ten times.
label: Represents an instruction or data memory address, similar to labels in other languages, can be used in instructions to specify a specific address (e.g. la $0, table0). When you use labels, you can minimize the amount of manual modifications in your assembly code upon insertions or deletions of instructions and/or data. For example, suppose that .word 0x003COFFEE is insterted after .word 0x002C0FFEE in the previous sample code; the only needed change is the fourth instruction from lw $4, 3(table0) to lw $4, 4(table). In other words, labels make the code maintenance cost more manageable by keeping the effect of a code modification be local to a label.

In addition to the keywords listed above, the assembler must support at least four pseudo instructions equivalent to the following MIPS pseudo instructions appeared in the previous example code.

Instruction Description
la $rd, offset(label) Loads the address of (label + offset) into $rd.
lw $rd, offset(label) Loads the data located at (label + offset) into $rd.
li $rd, immediate Loads the immediate value into $rd.
sw $rs, offset(label) Stores the value of $rs to the address (label + offset).

These pseudo instructions will make programmers' life easier by allowing programmers not to concern absolute addresses; instead, they can describe most addresses with label and offset. Note that pseudo instructions might be equivalent to multiple instructions in your ISA. Also note that the addresses used in pseudo instructions can be either an instruction memory address or a data memory address depending on the location of the label. You may change pseudo instruction names if needed, but the semantics of instructions should be the same.

Code Stub:

To execute a benchmark in your processor, you will need to create a small code stub that sets up the environment, including:

When all the environmental settings are properly done, the code stub should call a benchmark function. Since code stub should be the first code executed upon power-on, the text section of the code stub should be placed at 0x0 of the instruction memory in the output file of the assembler. (Assume that your processor starts by fetching an instruction from 0x0 upon reset.) Before you implement a general program loader, you have to use code stub; in this lab, always assemble with a code stub.

Inputs and Outputs of the Assembler:

Your assembler should accept the following input parameters.

Instruction Description
-stub [stub_name] A single .s (assembly code stub) file, optionally used when the output files are intended for simulation purposes.
-src [$name] A single .s (assembly test bench) file.
-text_addr [addr] The start address of the text section in the instruction memory. This option is ignored when -stub option is set.
-data_addr [addr] The start address of the data section in the data memory.

Your assembler have two outputs: $name_i.coe and $name_d.coe. $name_i.coe corresponds to a 17-bit instruction memory while $name_d.coe corresponds to a 34-bit data memory. They must have the following forms:

The first line in each output file specifies the numerical format used in the file. We use hexadecimal notation. Note that each entry of the 'MEMORY_INITIALIZATION_VECTOR' is data for each word, starting from address 0x0. Thus an entry of the instruction memory is 17-bit, while that of the data memory is 34-bit. These output files will be used as inputs to your simulator as well as coregen utility which generates SRAM modules in Xilinx ISE.

Since a *.coe file always start out at 0x0, you must fill out unused memory area from 0x0 to -text_addr or -data_addr with arbitrary values (typically 0x0). However, for other unused memory locations, you do not need to specify values; unspecified memory locations will have arbitrary values.

Assembler example usages:

  1. prompt> asm -stub start.s -src test.s -data_addr 0x200

    The assembler will generate two files - test_i.coe and test_d.coe. Since -stub option is used, the text section will be loaded at 0x0 of the instruction memory, while the data section will be located at 0x200 of the data memory. The test section starts with instructions in the code stub start.s, then it calls the benchmark function in test.s which is located after start.s in the instruction memory .

  2. prompt> asm -src garbage.s -text_addr 0x100 -data_addr 0x200

    The assembler will generate two files - garbage_i.coe and garbage_d.coe, which will be loaded at 0x100 of the instruction memory and 0x200 of the data memory, respectively. Since no code stub is used, the function in garbage.s will be directly located at 0x100 of the instruction memory and 0x200 of the instruction memory, respectively.


This lab created by Donghwan Jeon, 2007. Modified by Sat Garcia, 2008.