CSE 378 Homework 1 - Part 3

Assembler Programming

Problem Overview

You're going to write a MIPS simulator, that is, a program that can simulate the execution of MIPS instructions. More precisely, your simulator handles exactly six instructions: add, sub, or, xor, addi, and halt. (The last is not an actual MIPS instruction, but is useful for obvious reasons. It's part of the Cebollita instruction set.)

Your program takes as input a program written using only those six instructions. You execute each of the instructions, in order, halting when you encounter a halt instruction. As you execute each instruction, you update values stored in the simulator's registers. That's pretty much all there is to it.

Your simulator happens to be written in MIPS assembler as well (or, actually, the subset of MIPS assembler that Cebollita implements).

Program Input

Input to your program is a list of instructions, encoded as decimal integer representations of the 32-bit machine instructions. For example:
5
537395212
554237972
554303505
19552293
1073741848
The first integer indicates how many instructions follow. The integers that come next are instructions, written in decimal (because the only routine available to read an integer from assembler requires decimal input). They correspond to the assembler program, and the hex encoded machine instructions, shown in the following cebdumpm output:
 00000000 0x2008000c: addi    $t0, $0, 12
 00000004 0x21090014: addi    $t1, $t0, 20
 00000008 0x210a0011: addi    $t2, $t0, 17
 0000000c 0x012a5825: or      $t3, $t1, $t2
 00000010 0x40000018: halt

Program Output

None. We'll run your program in Cebollita and examine the contents of the simulated registers when it halts.

Skeleton Code

Having a look at skeleton code will probably make things somewhat less confusing. At the top, it allocates space to hold the program to be simulated and to keep the values in the simulated registers. In the .text section, the code begins by reading in the input: first the number of instructions in the input and then the instructions themselves. It then initializes the simulated PC, as a pointer into the memory holding the program to be simulated, and goes into a loop fetching instructions and updating the simulated PC to mimic sequential flow control. The skeleton doesn't actually simulate the effect of each instruction it fetches, though - that's what you'll implement. Instead, it simply checks whether or not the instruction just fetched is a halt. If not, it fetches the next instruction. Otherwise, the skeleton program itself halts.

Building Your Application

There are two steps:
  1. Assemble:
    $ java asm.parser mipsSim.s
    
    That produces file mipsSim.o.

  2. Link:
    $ java asm.Linker prologue-standalone.o mipsSim.o
    
    (The order of the operands is significant.) That produces a.exe.
You can now execute a.exe in the Cebollita simulator:
$ java dbg.UI a.exe

Preparing Test Input

It's a bit clunky to prepare the input to your simulator. The basic process is
  1. Create a small assembler program (testProgram.s) that uses only the instructions your simulator supports.
  2. Assemble it to produce a .o file.
  3. Use java asm.Module to dump the instructions in hex.
  4. Convert the hex to decimal.
  5. Run your simulator and type in the input.

That's so painful that we're providing some automation to help. The distribution (see below) comes with a simple makefile - it should be intelligible from what you've seen in CSE 303. The makefile has four useful targets:

  1. $ make a.exe
    will assemble and link your simulator (mipsSim.s).
  2. $ make inputFile
    will assemble testProgram.s, run java asm.Module on it to get the hex coding of the instructions, then run a perl program (instToDec.pl) to extract the hex instructions and turn them into decimal, and finally create a file (inputFile) that is suitable for feeding as input to your simulator.
  3. $ make run
    will build your simulator, build the input file, and then invoke the Cebollita simulator to run your simulator, providing it with input from inputFile. (The --distFile switch to java dbg.UI causes it to read input from the named file, rather than from the keyboard.)
  4. $ make clean
    deletes all intermediate files.
You can (and should) use the makefile even if you're not currently 100% comfortable with make - it's easy, just try it. Your system must have perl installed, though, to use all the facilities provided.

Caveat

The Cebollita assembler doesn't implement everything described in the text. In particular, it doesn't implement pseudo-instructions - instructions that are not actually supported by the hardware, but for which the assembler inserts one or two instructions that achieve the same effect. Examples are things like li, la, and b. It also doesn't implement the full MIPS instructio set. It's very unlikely, though, that you'll want to use an instruction that isn't available.

I would guess that the vast majority of you won't come across any distinctions between what the book describes and what Cebollita implements. If something won't assemble, though, the Cebollita documentation is the place to look for exactly what it supports.

Un-Caveat

You can (and should!) assume in your code that the input is always error free - there are 10 or fewer instructions, and each is one of the six your simulator supports.

This is terrible programming practice, but makes life a lot easier, especially when hand coding assembler. (Never, ever, make this assumption again, though. I hang my head in shame that we need it to make this assignment reasonable.)

Downloading Starter Files

Download hw1programming.tar.gz, and save it in the directory you want to work in. Expand it like this:
$ tar xzf hw1programming.tar.gz
That will produce files instToDec.pl, makefile, mipsSim.s, prologue-standalone.o, and testProgram.s.

How To Turn In

TBA