Nolimips

Nolimips is a MIPS simulator designed to execute simple register based MIPS assembly code. It is a minimalist MIPS virtual machine that, contrary to other simulators (SPIM), supports unlimited registers. The lack of a simulator featuring this prompted the development of Nolimips.

Its features are:
  • sufficient support of MIPS instruction set

  • infinitely many registers

It was written by Benoît Perrot as an LRDE member, so that EPITA students could exercise their compiler projects after instruction selection but before register allocation. It is implemented in C++ and Python.

Resources:

Documentation:

Here is a brief summary of the documentation for Nolimips.

Table of Contents

Invoking Nolimips

To invoke nolimips run:
  • -h --help: Display a help message and exit successfully.

  • -V --version: Display the version number and exit successfully.

  • --usage: Give a short usage message

  • --tasks-selection:

    Each task of NOLIMIPS (parsing, execution, etc.) comes with a set of prerequisites: for example the pretty printing of an input program implies the parsing of its source file. This option asks NOLIMIPS to display the tasks that must be run before to run the ones explicitly specified on command line.

  • --parse: Parse a file.

  • --trace-scan: Trace the scanning.

  • --trace-parse: Trace the parse.

  • -N --nop-after-branch:

    To avoid a bubble in their pipeline, MIPS processors execute the instruction immediately following a branch; this instruction is said to be in the delay slot (FIXME: see further). This option fills the delay slot of branch instructions with a NOP, disabling the delay slot, simplifying the task of assembly programmers how do not care about writing optimized code.

  • -u --unlimited-regs:

    During last stages of a compiler, the intermediate representation of a source file (which mainly consists in a generic, architecture independent assembly code) is progressively translated into an architecture dependent assembly code. Low level (but still intermediate) representations are designed to be as near as possible of target assembly code, but generaly consider an extended target machine with an unlimited amount of registers. This option gives NOLIMIPS the ability to handle an arbitrary number of registers, allowing compiler developpers to test their low level output before implementing register allocation. These new registers may be used as any other MIPS registers through the symbols $x0, $x1, and so on. They have a general purpose and are not considered as caller save nor callee save registers.

  • --prg-display: Display the read program.

  • --prg-solve: Resolve jump offsets and check bounds of immediates.

  • --callee-save=num --caller-save=num --argument-registers=num: Respectively set the maximum number of callee-save, caller-save and argument registers to num, a positive number.

  • --check-callee-save: Warn if a callee save register is not preserved across a call.

  • --profile: Enable program profiling

  • -l library --system-library=library:

    Specify the builtin system library to use. Accepted library values are ‘spim’ (selected by default and implementing SPIM’s behavior), ‘nolimips’ (NOLIMIPS’ own library), and ‘none’ (no builtin library).

  • -e --execute: Execute the program on virtual machine.

  • -E --trace-exec: Trace the execution.

  • -i --shell: Launch interactive shell.

Steps of Nolimips

NOLIMIPS works in three steps:
  • it scans and parses the file (lexical and syntaxical analysis),

producing an abstract representation of a program; - it resolves the program, checking the existence of labels used and computing branch offsets (assembly); - it loads the resolved program in the virtual machine, search for an entry point labeled main and start execution (execution).

Nolimips Language

NOLIMIPS supports a minimal MIPS instruction set and unlimited registers.

Basic main in Nolimips:
.data
.text

# Routine main
main:
        # Your Code
        # Trigger exit syscall (mandatory to use nolimips)
        li      $v0, 0x06
        syscall                 ; exit

For more example of Mips program you can see tests in Nolimips.

The Nolimips supported instruction set

Here is a list of categories for which you would like a description of each instruction:

Arithmetic instructions

ADD

Add src1 and src2 and store the result in dest (32-bit integers). If an overflow occurs, then trap.

add dest, src1, src2
ADDU

Add src1 and src2 and store the result in dest (32-bit integers).

addu dest, src1, src2
ADDI

Add a constant imm and src and store the result in dest (32-bit integers). If overflow occurs, then trap.

addi dest, src1, immediate
ADDIU

Add a constant imm and src and store the result in dest (32-bit integer).

addiu dest, src1, imm
SUB

Subtract src2 from src1 and store the result in dest (32-bit integers). If an overflow occurs (FIXME), then trap.

sub dest, src1, src2
SUBU

Subtract src2 from src1 and store the result in dest (32-bit integers).

subu dest, src1, src2
NEG

Negate (logical 2-complement) src and store the result in dest. If an overflow occurs (FIXME), then trap.

neg dest, src
NEGU

Negate src (logical 2-complement) and store the result in dest.

negu dest, src
ABS

Compute the absolute value of src (32-bit integer) and write it to dest.

abs dest, src
MUL

Multiply two words src1 and src2 and write the result to dest.

mul dest, src1, src2
DIV

Divide src1 by src2 (32-bit signed integers), write the quotient in LO and the remainder in HI (32-bit integer).

div dest, src1, src2
DIVU

Divide src1 by src2 (32-bit unsigned integers), write the quotient in LO and the remainder in HI (32-bit integer).

divu dest, src1, src2
REM

Compute the remainder from dividing src1 by src2 (32-bit signed integers) and write it to dest.

rem dest, src1, src2
REMU

Compute the remainder from dividing src1 by src2 (32-bit unsigned integers) and write it to dest.

remu dest, src1, src2

Bitwise instructions

SLL

Left-shift (logical) the word src by the fixed number imm of bits and store the result in dest.

sll dest, src1, imm
SLLV

Left-shift (logical) the word src1 by the variable number src2 of bits and store the result in dest.

sllv dest, src1, src2
SRA

Right-shift (arithmetic) the word src by the fixed number imm of bits and store the result in dest.

sra dest, src1, imm
SRAV

Right-shift (arithmetic) the word src1 by the variable number src2 of bits and store the result in dest.

srav dest, src1, src2
SRL

Right-shift (logical) the word src1 by the fixed number imm of bits and store the result in dest.

srl dest, src1, imm
SRLV

Right-shift (logical) the word src1 by the variable number src2 of bits and store the result in dest.

srl dest, src1, src2
ROL

Left-rotate the word src by a number of bits (imm or src2) and store the result in dest.

rol dest, src1, imm|src2
ROR

Right-rotate the word src by a number (imm or src2) of bits and store the result in dest.

ror dest, src1, imm|src2
AND

Compute the bitwise logical AND between src1 and src2 and store the result to dest.

and dest, src1, src2
ANDI

Compute the bitwise logical AND between src and a constant imm and store the result to dest.

andi dest, src1, imm
OR

Compute the bitwise logical OR between src1 and src2 and store the result to dest.

or dest, src1, src2
ORI

Compute the bitwise logical OR between src and a constant imm and store the result to dest.

ori dest, src1, imm
XOR

Compute the bitwise logical XOR between src1 and src2 and store the result to dest.

xor dest, src1, src2
XORI

Compute the bitwise logical XOR between src and a constant imm and store the result to dest.

xori dest, src1, imm
NOR

Compute the bitwise logical NOR between src1 and src2 and store the result to dest.

nor dest, src1, src2
NOT

Negate (logical 1-complement) src and store the result in dest.

not dest, src

Comparison instructions

SEQ

Set dest to 1 if src1 equals src2, else clear it.

seq dest, src1, src2
SNE

Set dest to 1 if src1 does not equal src2, else clear it.

sne dest, src1, src2
SGE

Set dest to 1 if src1 is greater or equal to src2 (signed comparison), else clear it.

sge dest, src1, src2
SGEU

Set dest to 1 if src1 is greater or equal to src2 (unsigned comparison), else clear it.

sgeu dest, src1, src2
SGT

Set dest to 1 if src1 is greater than src2 (signed comparison), else clear it.

sgt dest, src1, src2
SGTU

Set dest to 1 if src1 is greater than src2 (unsigned comparison), else clear it.

sgtu dest, src1, src2
SLE

Set dest to 1 if src1 is lower or equal to src2 (signed comparison), else clear it.

sle dest, src1, src2
SLEU

Set dest to 1 if src1 is lower or equal to src2 (unsigned comparison), else clear it.

sleu dest, src1, src2
SLT

Set dest to 1 if src1 is lower than src2 (signed comparison), else clear it.

slt dest, src1, src2
SLTU

Set dest to 1 if src1 is lower than src2 (unsigned comparison), else clear it.

sltu dest, src1, src2
SLTI

Set dest to 1 if src1 is lower than a constant imm (signed comparison), else clear it.

slti dest, src1, imm
SLTIU

Set dest to 1 if src1 is lower than a constant imm (unsigned comparison), else clear it.

sltiu dest, src1, imm

Branch instructions

BEQ

Branch to label if src1 equals src2.

beq src1, src2, label
BEQZ

Branch to label if src equals zero.

beqz src, label
BNE

Branch to label if src1 does not equal src2.

bne src1, src2, label
BNEZ

Branch to label if src does not equal zero.

bnez src, label
BGE

Branch to label if src1 is greater or equal to src2 (signed comparison).

bge src1, src2, label
BGEU

Branch to label if src1 is greater or equal to src2 (unsigned comparison).

bgeu src1, src2, label
BGEZ

Branch to label if src is greater or equal to zero (signed comparison).

bgez src, label
BGEZAL

Call label if src is greater or equal to zero (signed comparison)

bgezal src, label
BGT

Branch to label if src1 is greater than src2 (signed comparison).

bgt src1, src2, label
BGTU

Branch to label if src1 is greater than src2 (unsigned comparison).

bgtu src1, src2, label
BGTZ

Branch to label if src is greater than zero (signed comparison).

bgtz src, label
BLE

Branch to label if src1 is lower or equal to src2 (signed comparison).

ble src1, src2, label
BLEU

Branch to label if src1 is lower or equal to src2 (unsigned comparison).

bleu src1, src2, label
BLEZ

Branch to label if src is lower or equal to zero (signed comparison).

blez src, label
BLT

Branch to label if src1 is lower than src2 (signed comparison).

blt src1, src2, label
BLTU

Branch to label if src1 is lower than src2 (unsigned comparison).

bltu src1, src2, label
BLTZ

Branch to label if src1 is lower than zero (signed comparison).

bltz src, label
BLTZAL

Call label if src1 is lower than zero (signed comparison).

bltzal src, label
J
Jump to label unconditionaly.
j label
JAL

Call label unconditionaly.

jal label
JR

Jump to address contained in dest unconditionaly.

jr dest
JALR

Call address contained in dest unconditionaly.

jalr dest

Load instructions

LB

Load the 8-bit quantity at address (offset + base) into dest as a signed value.

lb dest, address
LBU

Load the 8-bit quantity at address (offset + base) into dest as an unsigned value.

lbu dest, address
LW

Load the 32-bit quantity at address (offset + base) into dest as a signed value.

lw dest, address
LUI
Move the constant imm into the upper half word of dest.
lui dest, imm
LI

Move the constant imm into dest.

li dest, imm
LA

Move the computed address into dest.

la dest, address

Store instructions

SB

Store the low byte from src at address (offset + base).

sb src, address
SW

Store the low word from src at address (offset + base).

sw src, address

Movement instructions

MOVE

Move the contents of src to dest.

move dest, src
MFHI

Move the contents of HI to dest.

mfhi dest
MFLO

Move the contents of LO to dest.

mflo dest
MTHI

Move the contents of dest to HI.

mthi dest
MTLO

Move the contents of dest to LO.

mtlo dest
MFC0

Move the contents of control coprocessor src register to CPU dest register.

mfc0 dest, src
MTC0

Move the contents of CPU src register to control coprocessor dest register.

mtc0 dest, src

Syscall instructions

SYSCALL
Raise a system call exception.
  • 0x02: read(fd: $a0, buf: $a1, count: $a2): $v0

  • 0x03: write(fd: $a0, buf: $a1, count: $a2): $v0

  • 0x06: exit(status: $a0)

  • 0x33: malloc(size: $a0)

List of syscall for Nolimips

syscall ; syscall_name

Nop instructions

NOP

To do nothing.

nop