The instruction set used is a simplifyed subset of the MIPS32 instruction set abbreviated sMIPS which excludes floating point types, unsigned types, interaction with coprocessors as well as the syscall,break and jump and link instructions. Further many of the "immediate" instructions has been made into pseudo-instructions typically requireing more instruction cycles to execute.
The remaining ISA is greatly inspired by the MIPS32 ISA and likewise makes use of 32 registers $0 - $31 where $0 is defined as having the constant value 0. the LO and HI registers are here implemented as regular GP-registers $26 - $27 respectively that would otherwise be used for OS kernel in MIPS32. All in all this ISA is compatible with the MIPS32 ISA and vice versa (if resolving the psedou-instructions).
Integers' MSB are regarded as a sign-extension, but the signs are otherwise not pertained in e.g. shifts, so it is the programmers responsibility to ensure the signs are pertained by e.g. flipping the MSB after a left-shift back to it's previous value.
sMIPS instruction formatsEdit
Instructions are divided into three types: R, I and J. Every instruction starts with a 6-bit opcode. In addition to the opcode, R-type instructions specify three registers, a shift amount field, and a function field; I-type instructions specify two registers and a 16-bit immediate value; J-type instructions follow the opcode with a 26-bit jump target.
The following are the three formats used for the core instruction set:
|Type||-31- format (bits) -0-|
|R||opcode (6)||rs (5)||rt (5)||rd (5)||shamt (5)||funct (6)|
|I||opcode (6)||rs (5)||rt (5)||immediate (16)|
|J||opcode (6)||address (26)|
The J-type has been preserved to allow for specifying addresses using 26 bit. Otherwise ANDI could have been used, but would only give us a 16bit address space.
With the following instruction-set where $26 = LO and $27 = HI :
sMIPS instruction setEdit
|Arithmetic||Add||add $d,$s,$t||$d = $s + $t||R||0||2116||adds two registers|
000000ss sssttttt ddddd--- --100001
|Subtract||sub $d,$s,$t||$d = $s - $t||R||0||2316||subtracts two registers|
000000ss sssttttt ddddd000 00100011
|Add immediate||addi $t,$s,C||$t = $s + C||I||916||-||Used to add constants (and also to copy one register to another: addi $1, $2, 0)|
001001ss sssttttt CCCCCCCC CCCCCCCC
|Multiply||mult $s,$t||LO = (($s * $t) << 32) >> 32;
HI = ($s * $t) >> 32;
|R||0||1916||Multiplies two registers and puts the 64-bit result in two special memory spots - LO and HI. Alternatively, one could say the result of this operation is: (int HI,int LO) = (64-bit) $s * $t . See mfhi and mflo for accessing LO and HI regs.|
|Divide||div $s, $t||LO = $s / $t HI = $s % $t||R||0||1B16||Divides two registers and puts the 32-bit integer result in LO and the remainder in HI.|
|Data Transfer||Load word||lw $t,C($s)||$t = Memory[$s + C]||I||2316||-||loads the word stored from: MEM[$s+C] and the following 3 bytes.|
|Store word||sw $t,C($s)||Memory[$s + C] = $t||I||2B16||-||stores a word into: MEM[$s+C] and the following 3 bytes. The order of the operands is a large source of confusion.|
|Logical||And||and $d,$s,$t||$d = $s & $t||R||0||2416||Bitwise and|
000000ss sssttttt ddddd--- --100100
|Or||or $d,$s,$t||$d = $s | $t||R||0||2516||Bitwise or|
|Exclusive or||xor $d,$s,$t||$d = $s ^ $t||R||0||2616|
|Nor||nor $d,$s,$t||$d = ~ ($s | $t)||R||0||2716||Bitwise nor|
|Set on less than||slt $d,$s,$t||$d = ($s < $t)||R||0||2A16||Tests if one register is less than another.|
|Bitwise Shift||Shift left logical||sll $d,$t,shamt||$d = $t << shamt||R||0||0||shifts shamt number of bits to the left (multiplies by )|
|Shift right logical||srl $d,$t,shamt||$d = $t >> shamt||R||0||216||shifts shamt number of bits to the right - zeros are shifted in (divides by ). Note that this instruction only works as division of a two's complement number if the value is positive.|
|Conditional branch||Branch on equal||beq $s,$t,C||if ($s == $t) go to PC+4+4*C||I||416||-||Goes to the instruction at the specified address if two registers are equal.|
000100ss sssttttt CCCCCCCC CCCCCCCC
|Branch on not equal||bne $s,$t,C||if ($s != $t) go to PC+4+4*C||I||516||-||Goes to the instruction at the specified address if two registers are not equal.|
|Unconditional jump||Jump||j C||PC = PC+4[31:28] . C*4||J||216||-||Unconditionally jumps to the instruction at the specified address.|
|Jump register||jr $s||goto address $s||R||0||816||Jumps to the address contained in the specified register|
These instructions are accepted by the MIPS assembler, although they are not real instructions within the MIPS instruction set. Instead, the assembler translates them into sequences of real instructions.
|Name||instruction syntax||Real instruction translation||meaning|
|And immediate||andi $t,$s,C||addi $1,$0,C; and $t,$1,$s||$t = $s & C|
|or immediate||ori $t,$s,C||addi $1,$0,C; or $t,$1,$s||C|
|Set on less than immediate||slti $t,$s,C||addi $1,$0,C; slt $t,$1,$s||$t = ($s < C)|
|Move||move $t,$s||addi $t,$s,0||R[t]=R[s]|
|Move from low||mflo $d||move $d,$26||R[t]="LO"|
|Move from high||mflh $d||move $d,$27||R[t]="HI"|
|Clear||clear $rt||add $rt,$zero,$zero||R[rt]=0|
|Not||not $rt, $rs||nor $rt, $rs, $zero||R[rt]=~R[rs]|
|Load Address||la $rd, LabelAddr||lui $rd, LabelAddr[31:16]; ori $rd,$rd, LabelAddr[15:0]||$rd = Label Address|
|Load Immediate||li $rd, IMMED[31:0]||lui $rd, IMMED[31:16]; ori $rd,$rd, IMMED[15:0]||$rd = 32 bit Immediate value|
|Branch unconditionally||b Label||beq $zero,$zero,Label||PC=Label|
|Branch and link||bal Label||bgezal $zero,Label||R=PC+8; PC=Label|
|Branch if greater than||bgt $rs,$rt,Label||slt $at,$rt,$rs; bne $at,$zero,Label||if(R[rs]>R[rt]) PC=Label|
|Branch if less than||blt $rs,$rt,Label||slt $at,$rs,$rt; bne $at,$zero,Label||if(R[rs]<R[rt]) PC=Label|
|Branch if greater than or equal||bge $rs,$rt,Label||slt $at,$rs,$rt; beq $at,$zero,Label||if(R[rs]>=R[rt]) PC=Label|
|Branch if less than or equal||ble $rs,$rt,Label||slt $at,$rt,$rs; beq $at,$zero,Label||if(R[rs]<=R[rt]) PC=Label|
|Branch if greater than unsigned||bgtu $rs,$rt,Label||if(R[rs]>R[rt]) PC=Label|
|Branch if greater than zero||bgtz $rs,Label||if(R[rs]>0) PC=Label|
|Branch if equal to zero||beqz $rs,Label||if(R[rs]==0) PC=Label|
|Multiplies and returns only first 32 bits||mul $d, $s, $t||mult $s, $t; mflo $d||$d = $s * $t|
|Divides and returns quotient||div $d, $s, $t||div $s, $t; mflo $d||$d = $s / $t|
|Divides and returns remainder||rem $d, $s, $t||div $s, $t; mfhi $d||$d = $s % $t|
|No operation||nop||sll $0,$0,0 (0x00000000)||NOP|
A very simple single-file assembler supporting the described instructions has been developed and can be downloaded HERE.
The assembler is a simple two pass assembler, first resolving all labels into addresses and pseduo-instuctions into real instructions then translating the instructions into machine code. There are some limitations regarding labels, namely that they should be prefixed "lab_" and that they have to be declared on a seperate line.
The assembler is made in Java and can be run with the following commands :
Java -jar sMIPSAssembler.jar <infile> <outfile> [mode = "B"]
Where type can have the values B (binary), H (hex), S (sMIPS instructions) or I (integer) depending on the outfile representation. If S is selected the output is the conversion from MIPS32 to sMIPS. Default mode is B.
Not much effort has been put into reporting detailed error messages, so the programmer should carefully (syntactically) type the correct instructions.