| 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 |
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.