| Insn | Syntax | Semantics | Code |
| HALT | HALT | HALT; | 0000 0XXX XXXX XXXX |
| RETN | RETN | PC = r7; | 0000 1XXX XXXX XXXX |
| JUMP | JUMP imm11 (label) | PC = ZEXT(imm11); | 0001 0iii iiii iiii |
| CALL | CALL imm11 (label) | r7 = PC + 1; PC = ZEXT(imm11); | 0001 1iii iiii iiii |
| SLED | SLED rs | LEDS[rs] = rd; | 0010 0ddd sssX XXXX |
| LSWI | LSWI rd | rd = SWITCHES[rs]; | 0010 1ddd sssX XXXX |
| LCTR | LCTR rd imm1 | rd = COUNTERS[imm1]; | 0011 0ddd XXXX XXXi |
| CCTR | CCTR rd imm1 | COUNTERS[imm1] = 0; | 0011 1XXX XXXX XXXi |
| BEQZ | BEQZ rd imm8 (label) | if (rd == 0) PC = PC + SEXT(imm8); | 0100 0ddd iiii iiii |
| BNEZ | BNEZ rd imm8 (label) | if (rd != 0) PC = PC + SEXT(imm8); | 0100 1ddd iiii iiii |
| BLTZ | BLTZ rd imm8 (label) | if (rd < 0) PC = PC + SEXT(imm8); | 0101 0ddd iiii iiii |
| BGEZ | BGEZ rd imm8 (label) | if (rd >= 0) PC = PC + SEXT(imm8); | 0101 1ddd iiii iiii |
| BGTZ | BGTZ rd imm8 (label) | if (rd > 0) PC = PC + SEXT(imm8); | 0110 0ddd iiii iiii |
| BLEZ | BLEZ rd imm8 (label) | if (rd <= 0) PC = 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 |
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". The -x flag
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 -[x|b] -[s|t]
<filename>. 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, with the -x option, all files are in 16-bit space-delimited
hexadecimal. With the -b option, they
are all binary. The -[s|t] option is
quite useful as well. With -s, the
simulator runs silently. With -t, it
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.
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 sequence: SUBR R1, R1, R1; ORHI R1, -1; ORLO R1, -1. The first instruction sets R1 to 0. The second ors the bits FF into the upper half of R1 (the 8 bit binary representation of -1 is FF). After the second instruction, the contents of R1 are FF00. The final instruction ors the bits FF into the lower half of R1. You can set a register to the value of the first heap address in a similar manner.