R372 ISA

The ISA will will implement is CSE 372 is called R372. It is a simple RISC ISA that resembles MIPS. However, it has the following differences and simplifications.

R372 Definition

The following table contains the R372 definition.
Insn Syntax Semantics Code
NOOP  NOOP  undefined  0000 0XXX XXXX XXXX
HALT  HALT  HALT  0000 1XXX XXXX XXXX
LCTR  LCTR rd imm1  rd = COUNTERS[imm1];  0001 0ddd XXXX XXXi
CCTR  CCTR rd imm1  COUNTERS[imm1] = 0;  0001 1XXX XXXX XXXi
JMPI  JMPI imm11 (label)  PC = ZEXT(imm11);  0010 0iii iiii iiii
JMPR  JMPR rd  PC = rd;  0010 1ddd XXXX XXXX
BEQZ  BEQZ rd imm8 (label)  if (rd == 0) PC = PC + SEXT(imm8);  0011 0ddd iiii iiii
BNEZ  BNEZ rd imm8 (label)  if (rd != 0) PC = PC + SEXT(imm8);  0011 1ddd iiii iiii
SEQR  SEQR rd rs rt  rd = (rs == rt);  0100 0ddd ssst ttXX
SLTR  SLTR rd rs rt  rd = (rs < rt);  0100 1ddd ssst ttXX
SLER  SLER rd rs rt  rd = (rs <= rt);  0101 0ddd ssst ttXX
unused  unused  undefined  0101 1XXX XXXX XXXX
CNST  CNST rd imm8  rd = SEXT(imm8)  0110 0ddd iiii iiii
APCI  APCI rd imm8  rd = PC + SEXT(imm8)  0110 1ddd iiii iiii
ORHI  ORHI rd imm8  rd = rd | (imm8 << 8);  0111 0ddd iiii iiii
ORLO  ORLO rd imm8  rd = rd | ZEXT(imm8);  0111 1ddd iiii iiii
LOAD  LOAD rd rs imm5  rd = mem[rs + SEXT(imm5)];  1000 0ddd sssi iiii
STOR  STOR rd rs imm5  mem[rs + SEXT(imm5)] = rd;  1000 1ddd sssi iiii
ANDI  ANDI rd rs imm5  rd = rs & ZEXT(imm5);  1001 0ddd sssi iiii
IORI  IORI rd rs imm5  rd = rs | ZEXT(imm5);  1001 1ddd sssi iiii
ADDI  ADDI rd rs imm  rd = rs + SEXT(imm5);  1010 0ddd sssi iiii
SLLI  SLLI rd rs imm  rd = rs << (imm & 15);  1010 1ddd sssX iiii
SRLI  SRLI rd rs imm  rd = ZEXT(rs >> (imm & 15));  1011 0ddd sssX iiii
SRAI  SRAI rd rs imm  rd = SEXT(rs >> (imm & 15));  1011 1ddd sssX iiii
ADDR  ADDR rd rs rt  rd = rs + rt;  1100 0ddd ssst ttXX
SUBR  SUBR rd rs rt  rd = rs - rt;  1100 1ddd ssst ttXX
MULR  MULR rd rs rt  rd = rs * rt;  1101 0ddd ssst ttXX
unused  unused  undefined  1101 1XXX XXXX XXXX
XORR  XORR rd rs rt  rd = rs ^ rt;  1110 0ddd ssst ttXX
NOTR  NOTR rd rt  rd = ~rt;  1110 1ddd XXXt ttXX
ANDR  ANDR rd rs rt  rd = rs & rt;  1111 0ddd ssst ttXX
IORR  IORR rd rs rt  rd = rs | rt;  1111 1ddd ssst ttXX

R372 Tools

I have written some tools to help you write and debug programs in this ISA. The tools are in the ENIAC directory ~amir/cse371/r372/bin/ (the directory ~amir is on the mount /mnt/eniac/home8/a/) and are compiled for Linux. In other words, you cannot run these tools from Red or Blue. If you must, or if you want to run the tools on your machines at home, the sources are in ~amir/cse371/r372/src/. You can compile them for whatever platform you choose. However, be forewarned that I will not provide compilation help or tech support for any platform other than Linux.

There are two primary tools.

assembler: assembler -[x|b] <filename>. Given a file <filename>.a containing R372 assembly code will generate a file <filename>.imem.in which is an R372 "executable". By default, the assembler formats the executable in 16-bit space-delimited hexadecimal. The -b option formats the executable in binary. When initially developing programs, it helps to do everything in hexadecimal mode. In this mode, it is easy to create sample input files. Use binary mode only when you are ready to run your programs on the simulated hardware in the lab. In addition to the instruction mnemonics in the table above, the assembler also accepts comments (which it recognizes as lines starting with //) and labels (which it recognizes as lines starting with :). The assembler is not industrial strength, and will get confused by blank lines, extra spaces, missing commas, etc. Watch out for this and send mail to the newsgroup if you are having problems.

simulator: simulator <filename> [-t] [-x] [-<input>]. Given input files <filename>.imem.in containing R372 machine code and <filename>.dmem.in containing an input data memory image, will run the executable and generate a file <filename>.dmem.out which is the output data memory image of the program. Again, all files are in 16-bit space-delimited hexadecimal. If a program has multiple input data files <filename>.dmem.in1, <filename>.dmem.in2, you can choose them using the option -1 or -2, respectively.

The [-t] option is quite useful as well. With -t, the simulator prints out an annotated instruction level trace of your program, including the data inputs and outputs to each dynamic instruction. This should make it easier to debug your programs. The simulator prints out values in integer format. If you would rather debug values in hexadecimal format (which is easier for certain things) add the [-x] option.

Here are a few more notes you should understand about the structure of the simulator and its input and output files.

R372 is a 16-bit ISA which means it can address 64K 16-bit memory words. These memory words are divided into two regions: instructions and data. Instruction memory is the lower 32K words starting at address 0 and ending at address (1<<15)-1. In 16-bit hex, these addresses are 0000 and 7FFF. The start PC (i.e., the address of the instruction that executes when the processor first boots is 0000. Data memory is the upper 32K words and goes from address (1<<15) to (1<<16)-1, or from 8000 to FFFF. When the simulator boots, it loads the file <filename>.imem.in into the instruction memory region, starting at address 0000. It also loads the file <filename>.dmem.in into the data memory region starting at address 8000. The <filename>.imem.in file is created by the assembler. The <filename>.dmem.in file is created by you. Hexadecimal files (the ones expected by the simulator when run in -x mode) can be easily created in emacs or any other text editor. For instance to create an initial data memory image with the number 11 in the first memory word and the number 3 in the second memory word, simply create a file called <filename>.dmem.in and make the contents of that file be "000B 0003".

As far as data memory, programs typically need both a "stack" area and a "heap" area, and the convention is that the heap area starts at the lower end of memory (8000) and grows up while the stack starts at the upper end (FFFF) of memory and grows down. The reason for this is that arrays are typically placed in the heap and it is easier to have a stack that grows down than to have a compiler that reverses all array access calculations. Anyway, you are free to use whatever convention you want, but this is probably easiest. The first thing your program should do when it boots is set up pointers to the stack and heap. R372 has 8 registers. You basically have to reserve one of them to be the stack pointer. You can initialize register R1 to FFFF using the following instruction: CNST R1, -1. To set a register to the first heap address, however, you need a sequence of multiple instructions: CNST R1, 0; ORHI R1, -128.