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.

Loading Mint..

Description
The instruction set
Examples
    Small examples
    Compiler generated examples
Download



 

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:

I have made no restrictions on the use/structure of memory (max byte address is 2^20-1 => 1048575). Adresses 65520 and 65524 are reserved for IO - see SW and LW below. Also, the program has no connection to memory - i.e. you cannot execute random memory areas ( e.g. by setting a register to a memory address and then call JR on this register - the interpreter will execute the line in the code, not load an instruction from memory and execute this). The right way to jump to an instruction is by using the JAL, J, BNE or BEQ instructions. You should only use the JR instruction with $ra, and only after setting $ra with the JAL instruction (or set $ra with JAL, store $ra on stack and load $ra from stack).

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.

    STOP: STOP
        Stop execution

    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



All programming by Ulrik Magnusson