Computer Laboratory > Teaching > Course material 2007–08 > ECAD Labs > Tiger "MIPS"

  The Tiger "MIPS" Processor

The "MIPS" like processor is a 32-bit embedded soft core processor with a five stage pipeline and a RISC instruction set. The architecture is software interlocked. The initial version, Rhino, was designed by Robin Message and David Simner during their internship in the Summer 2006. Tiger is an upgraded version of Rhino, designed by Simon Moore and Gregory Chadwick. It is designed to be used with Altera's Avalon bus.

  Download Source

The source is available for download as a Quartus Archive file:
or simply as a zip of the source:
both available for use under the following license:
Creative Commons License Tiger "MIPS" processor by Simon Moore and Gregory Chadwick is licensed under a Creative Commons Attribution-Non-Commercial-Share Alike 2.0 UK: England & Wales License.

For use on the PWF in Cambridge: when you open the Quartus archive file in Quartus you will be asked where you'd like to place the project, so select a suitable directory (e.g. U:\game_of_life on the PWF). Note that this project has incremental compilation enabled which works just fine on the PWF, but is not licensed on the web edition of the tools. If you turn off incremental compilation, then it should compile just find on the web edition.

The contains the project without the SOPC component or incremental compilation set up. To set these up you will have to follow the respective tutorials. This will take slightly more time, but would serve as a good introduction to some of the tools available. Ensure you complete the SOPC tutorial first, followed by incremental compilation.

Warning: SOPC Builder will not work on the PWF machines. See the tutorial for details.

  Example code

The code below calculates the 1000th prime number and leaves it in register $t0

  # assembler directives
        .globl main

        # start of the program
        add  $t2, $0, 1                 # Initialise $t2 to 1
        addi $t0, $0, 2                 # Initialise $t0 to 2
        addi $t3, $0, 1000              # Initialise $t3 to 1000

        addi $t1, $0, 2                 # Reset $t1 to 2

        div  $t0, $t1                   # Compute $t0 / $t1
        mfhi $t4                        # Move the remainder into $t4

        beq  $t4, $0, main.loop         # If the remainder is zero then $t0 has a non-trivial factor
        addi $t0, $t0, 1                # Increment $t0 in the branch delay slot

        addi $t0, $t0, -1               # After the delay slot, we need to decrement $t0

        sub  $t4, $t1, $t2              # $t4 = $t1 - $t2
        bltz $t4, main.innerloop        # If $t4 < 0 (i.e. $t1 < $t2) then loop
        addi $t1, $t1, 1                # Increment $t1 in the branch delay slot

        addi $t2, $t2, 1                # Increment $t2

        sub  $t4, $t2, $t3              # $t4 = $t2 - $t3
        bltz $t4, main.loop             # If $t4 < 0 (i.e. $t2 < $t3) then loop
        addi $t0, $t0, 1                # Increment $t0 in the branch delay slot

        addi $t0, $t0, -1               # Decrement $t0 after final iteration
                                        # to leave the result in $t0

        # Another assembler directive
        .end main 

  Higher-level code

The equivalent code in a higher-level language is shown below

  // The following are mappings from variables to registers in the above program
  // a    => $t0
  // b    => $t1
  // c    => $t2
  // 1000 => $t3

  int getPrime() {
      int c = 1;
      for (a = 2;c < 1000; a++) {
          for (int b = 2; b < a; b++) {
	      if (a % b == 0)
	          goto label;

      return a;


The table below gives a list of some of the more commonly used instructions.
For a complete reference, see the Programmers Reference Guide

addi $t0, $zero, 5Load the value 5 into $t0
add $t0, $t3, $t5$t0 = $t3 + $t5
or $t0, $t2, $t3Bitwise-or the contents of $t2 and $t3 and store the result in $t0
nopNo-operation; equivalent to or $zero, $zero, $zero
jal lblSave the program counter in $ra, and jump to lbl
jr $raReturn from a sub-routine
beq $t0, $t1, lblIf $t0 == $t1 then jump to lbl
lw $t0, 84($zero)Load the contents at address 84 into $t0
lw $t0, 44($t1)Load the contents at the address stored in $t1 offset by 44

  DIV instruction - IMPORTANT

The MIPS architecture supports a 2-operand DIV instruction as detailed in the Programmers Reference Guide, however, the GNU Assembler handles DIV instructions in a slightly different way. The assembler supports a 3-operand DIV instruction, with the first operand being the destination address. To achieve the same semantics as the standard MIPS DIV instruction, set the destination register to $zero.

I.e. if in MIPS assembler you wish to execute div $t0, $t1 you would have to write div $zero, $t0, $t1 instead.

  Pseudo instructions

Pseudo instructions are instructions that do not have their own binary representation, but are rather assembled into a sequence of real instructions. The pseudo instructions are there to help make the programmers life easier. The 2 most useful pseudo instructions are li and la.

Load immediateli $rd immLoad the constant imm into register $rd
Load addressla $rd lblLoad the address of lbl into register $rd

  Memory access

The MIPS provides several instructions for accessing memory, the most common ones being lw, lh, lb these being load word; load halfword; and load byte respectively. For an in-depth description of the entire MIPS instruction set, see the Programmers Reference Guide. Accesses using lw must use word-aligned addresses. Since the MIPS is a 32-bit architecture, this means the 2 least-significant-bits of the address must be zero. Similarly, lh requires the address to be half-word aligned, i.e. the LSB of the address must be zero. lb can load an arbitrary byte from memory. Similar restrictions are placed on the corresponding store instructions; sw, sh, sb.

  GNU Tool Chain

You can download the toolset here. For documentation, see the Lab 2 getting started on MIPS assember and lecture 4 of Computer Design.