home | Java main Page | Search this site | Back to Java main page |
Mint - a MIPS Interpreter
A simple interpreter for a subset of the
MIPS instruction set.
Description:
The applet above is an interpreter for a subset of the MIPS instruction set (http://www.mips.com) and NOT a simulator of MIPS hardware. The interpreter does not execute instructions efficiently, and is not supposed to work for larger programs. It is just my very first try at writing an interpreter, but it could be useful if you are dabbling with machine code for the first time You can download it and run it as an application. Beware of strange or missing error messages.
Especially, Mint does NOT support:
You can also get away with loading 32 bit integers into registers with
32 bit instructions
i.e.
ORI $1,$2, 2147483647
is accepted, even though the ORI instruction only has 16 bits for the
immediate.
The interpreter should be able to execute valid MIPS instructions, provided they do not use memory adresses above 2^20-1. Just beware that invalid instructions are not necessarily discarded.
Please contact me at ulrikm@yahoo.com if you discover any bugs or want to request a feature (since the program was designed to be easily extendable, it should not take too much effort to add e.g. floating point instructions, if you really need them). Do not hesistate to request additional regular instructions (e.g. xor or sgt).
The instruction set
The MIPS architecture has 32 registers with 32 bits
each. Two have special purposes:
$0 must always be zero
$31 stores the return address
(from procedure call)
It might be a good idea to follow the conventions
for the registers as listed below, but only 0 and 31 have special meaning
to the interpreter - you can either refer to registers
by their number (e.g. $0) or by their name (e.g. $zero):
Register | Name | use |
0 | $zero | always zero |
1 | reserved for assembler | |
2-3 | $v0-$v1 | results and expression evaluation |
4-7 | $a0-$a3 | arguments |
8-15 | $t0-$t7 | temporaries |
16-23 | $s0-$s7 | saved |
24-25 | $t8-$t9 | temporaries |
26-27 | reserved for operating system | |
28 | $gp | global pointer |
29 | $sp | stack pointer |
30 | $fp | frame pointer |
31 | $ra | return address |
The interpreter has 2^20 bytes memory (byte addressed
big endian). You do not get ualigned access errors, but strange
things will happen if you access memory addresses
that are not multiples of 4. I have not imposed any structure on the
memory (except adresses 65520 and 65524 - see SW
and LW below). The program is not connected
to the
memory structure - this is not a simulator.
These are the valid instructions / language constructs:
LUI, ADD,
ADDI,
SUB,
SUBI,
AND,
ANDI,
OR,
ORI,
SLL,
SRL
SLT, SLTI,
BEQ, BNE,
J,
JAL,
JR,
LW, SW,
STOP, EQU,
EQUR,
labels, comments
LUI: Load
Upper Immediate
Load a 16 bit integer('number')
into the upper part (bits 31-16) of a register ('reg')
reg = number << 16
Syntax: LUI reg, number
Example: LUI $t0, 0
ADD: ADD
Put the result of adding
the values in two registers (reg2 and reg3) in a third register (reg1)
reg1 = reg2 + reg3;
Syntax: ADD reg1, reg2,
reg3
Example: ADD $t0, $t1, $3
ADDI: ADD Immediate
Put the result of adding
the values in a register(reg2) and a 16 bit integer(number) in a third
register (reg1)
reg1 = reg2 + number;
Syntax: ADDI reg1, reg2,
number
Example: ADDI $t0, $0, 42
SUB: SUBtract
Put the result of subtracting
the value in one register(reg3) from another register(reg2) in a third
register (reg1)
reg1 = reg2 - reg3;
Syntax: SUB reg1, reg2,
reg3
Example: SUB $t0, $0, 42
SUBI: SUBtract
Immediate
Put the result of subtracting
a 16 bit integer(number) from the value in a register(reg2) and in
a third register (reg1)
reg1 = reg2 - number;
Syntax: SUBI reg1, reg2,
number
Example: SUBI $t0, $0, 42
AND: AND
Put the result of anding
the value in one register(reg3) with another register(reg2) in a third
register (reg1)
reg1 = reg2 & reg3;
Syntax: AND reg1, reg2,
reg3
Example: AND $t0, $t1, $3
ANDI: AND Immediate
Put the result of anding
a 16 bit integer(number) with the value in a register(reg2) and in
a third register (reg1)
reg1 = reg2 & number;
Syntax: ANDI reg1, reg2,
number
Example: ANDI $t0, $0, 42
OR: OR
Put the result of or'ing
the value in one register(reg3) with another register(reg2) in a third
register (reg1)
reg1 = reg2 | reg3;
Syntax: OR reg1, reg2, reg3
Example: OR $t0, $t1, $3
ORI: OR Immediate
Put the result of or'ing
a 16 bit integer(number) with the value in a register(reg2) and in
a third register (reg1)
reg1 = reg2 | number;
Syntax: ORI reg1, reg2,
number
Example: ORI $t0, $0, 42
SLL: Shift
Left Logical
Put the result of shifting
the value in reg2 number places to the left in a third register (reg1)
reg1 = reg2 << number;
Syntax: SLL reg1, reg2,
number
Example: SLL $t0, $0, 1
SRL: Shift
Right Logical
Put the result of shifting
the value in reg2 number places to the right in a third register
(reg1)
reg1 = reg2 >> number;
Syntax: SRL reg1, reg2,
number
Example: SRL $t0, $t0, 1
SLT: Set on Less
Than
If reg2 is less than reg3
then reg1 gets the value 1, else 0
reg1 = reg2 < reg3? 1:
0;
Syntax: SLT reg1, reg2,
reg3
Example: SLT $t0, $t1, $0
SLTI:
Set on Less Than Immediate
If reg2 is less than number(16
bit) then reg1 gets the value 1, else 0
reg1 = reg2 < number?
1: 0;
Syntax: SLT reg1, reg2,
number
Example: SLT $t0, $t1, 42
BEQ: Branch on
EQual
If reg1 equals reg2 then
goto label name
Syntax: BEQ reg1, reg2,
name
Example: BEQ $t0, $t1, end
BNE: Branch
on Not Equal
If reg1 does not equal reg2
then jump to label name
Syntax: BNE reg1, reg2,
name
Example: BNE $t0, $t1, end
J: Jump
Unconditionally jump to
label name
Syntax: J name
Example: J end
JAL: Jump And Link
Set the "return address
register" (register 31) to the following instruction and jump to label
name
Syntax: JAL name
Example: JAL compute_next_fibonnaci
JR: Jump Register
Jump to the instruction
number in reg
Syntax: J reg
Example: J $31
LW: Load Word
Move the contents of a memory
location (32 bit) into a register. reg1 gets the value that is at the memory
position
number + reg2
Syntax: LW reg1, number(reg2)
Example: LW $t0, 0($t1)
Note: If the value in reg2
is 65520, the value is read from the terminal.
The prompt will print: "Enter
number: ".
SW: Store Word
Move the contents of a register
to memory. The memory at position number+reg2 gets the value of reg1.
Syntax: SW reg, number(reg2)
Example: SW $t0, 0($t1)
Note: If the value in reg2
is 65524, the value is printed to the terminal.
EQU: EQUals
Define a constant: To use
'name' as a symbolic name for 'number'
Syntax: name EQU number
Example:
the_answer EQU 42
EQUR: EQUals
Register
Define a register: To use
'name' as a symbolic name for 'reg'
Syntax: name EQUR reg
Example:
zero_reg EQUR $0
LABELS:
Label an instruction:
Syntax: name:
Example: end:
COMMENT:
Syntax: ;str
Example: ; This is a comment
Examples
To copy and paste into the applet
Small examples:
Example 1: Simple
print out numbers from 0
to 9:
ORI $t0, $zero, 0
ORI $t1, $zero, 65524
ORI $t2, $zero, 10
loop:
SW $t0, 0($t1)
ADDI $t0, $t0, 1
BNE $t0, $t2, loop
Example 2: Memory
Set memory at 0 to 12 to
the numbers 42 to 30 and print out these numbers in reverse (30 to 42)
ORI $t0, $zero, 52
ORI $t1, $zero, 30
ORI $t2, $zero, 65524
set:
SUBI $t0, $t0, 4
SW $t1, 0($t0)
ADDI $t1, $t1, 1
BNE $t0, $zero, set
ORI $t0, $zero, 48
print:
LW $t1, 0($t0)
SW $t1, 0($t2)
SUBI $t0, $t0, 4
SLT $t3, $t0, $zero
BEQ $t3, $zero, print
Example 3: Simple procedure call (leaf procedure
with arguments passed on stack)
void main()
{
int i = 10;
while(true)
{
if( i == 0 )
{
return;
}
print( i );
i--;
}
}
;initializing stack pointer to size of memory (2^20)
ORI $sp, $zero, 1048576
; int i = 10;
ORI $t0, $zero, 10
loop:
; if(i == 0) return;
BEQ $t0, $zero, end
;decrement stackpointer for argument to print
SUBI $sp, $sp, 4
;store argument on stack and jump to print (print(i))
SW $t0, 0($sp)
JAL print
; i--
SUBI $t0, $t0, 1
J loop
print:
;pop argument from stack
LW $t1, 0($sp)
ADDI $sp, $sp, 4
;printing argument
ORI $t2, $zero, 65524
SW $t1, 0($t2)
JR $ra
end:
Example 4: Recursive procedure call
int
times( int a, int b )
{
if( b == 1 )
{
return a;
}
return a + times( a, b-1 );
}
void main()
{
int a = read(); // input
int b = read(); // input
int c = times( a, b );
print( c );
}
main:
ORI $sp, $zero, 1048576 ; initializing stack pointer
JAL read
; read()
OR $a0, $zero, $v0 ; a = read()
JAL read
; read()
OR $a1, $zero, $v0 ; b = read()
JAL times
; times(a,b)
OR $a0, $zero, $v0 ; c = times(a,b)
JAL print
J end
read:
ORI $t0, $zero, 65520
LW $v0, 0($t0)
JR $ra
print:
ORI $t0, $zero, 65524
SW $a0, 0($t0)
JR $ra
times:
SUBI $sp, $sp, 4
SW $ra, 0($sp)
; saving return address
SUBI $sp, $sp, 4
SW $a0, 0($sp)
; saving argument a
SUBI $sp, $sp, 4
SW $a1, 0($sp)
; saving argument b
ORI $t0, $zero, 1
BNE $a1, $t0, times_L1 ; if(b != 1) then goto times_L1
OR $v0, $zero, $a0 ; return
a
ADDI $sp, $sp, 12 ; pop
arguments and return address off stack
JR $ra
times_L1:
SUBI $a1, $a1, 1
; b - 1
JAL times
LW $a1, 0($sp)
; restore argument b
ADDI $sp, $sp, 4
LW $a0, 0($sp)
; restore argument a
ADDI $sp, $sp, 4
LW $ra, 0($sp)
; restore return address
ADDI $sp, $sp, 4
ADD $v0, $a0, $v0 ; return
a + times(a, b-1)
JR $ra
end:
Compiler generated examples:
They all ask for at least 2 inputs - the number
of inputs followed by the actual input
Fib.asm : computes the nth fibonnaci number
Sample run - compute the 7th fibonnaci number:
Running interpreter..
Enter number:> 1
Enter number:> 7
13
Done.
Primes.asm : computes all primes smaller than
n
Sample run - compute all primes smaller than 30:
Running interpreter..
Enter number:> 1
Enter number:> 30
2
3
5
7
11
13
17
19
23
29
Done.
Fac.asm: computes n!
Sample run - compute 7!:
Running interpreter..
Enter number:> 1
Enter number:> 7
5040
Done.
Download:
If you have a Java Virtual Machine installed on your system, you can
run the application with
java Mint <filename>
Download the compiled class files here (source included): mint.zip