WeMIPS is an instruction-level emulator for the assembly language of the MIPS32 architecture. It is implemented in client-side JavaScript and HTML, and can thus be run in your own (JavaScript-capable and -enabled) webbrowser.
While WeMIPS can be provided on-line (for example here), it is also possible to simply install it locally on your own computer and use it there.
The WeMIPS Emulator was originally created by Eric Wooley and Ortal Yahdav, with additions and updates by Ralf Gerlich.
- View Online for the version hosted by Ralf Gerlich, or wemips.dev.plumbing for the version hosted on github pages or clone WeMIPS somewhere on your computer.
- Open the top-most WeMips.html in your browser.
- You can now use WeMIPS!
There are 2 ways to process your code: Stepping, and Running.
- The first way is to "step" through 1 line at a time. This can be accomplished by clicking the step button. When you step through your code, you will see that the editor will highlight specific lines. These lines indicate which lines the emulator is processing. The last line the emulator successfully ran will be highlighted in green. The next line to be run will be highlighted in grey. If the emulator runs into a MIPS error, it will be highlighted in red. You will notice as you step through your program that the last register, or stack or heap address changed, is also highlighted in green. See the Auto Switch feature for more details.
- The second way to process your code is to "run" it. This can be accomplished by clicking the run button. When you run your code, each line is successively run until your program is interrupted. Your program can be interrupted by errors, requests for input, or the completion of your code.
Wherever an immediate value is required, you can use expressions with operands such as addition, subtraction, etc., as long as the result is a constant value.
For example, it is possible to use
addi $t0, $zero, (15+3*32)
Operators are evaluated according to their precedence, i.e., addition and subtraction have lower precedence than multiplication and the former are thus evaluated after the latter. In the following, operands are listed in decreasing order of precedence (i.e., operators further down in the list are evaluated after operators further up):
- Unary Plus ("+"), Unary Minus ("-"), Bitwise NOT ("~"), Logical NOT ("!")
- Multiplication ("*"), Division ("/"), Remainder ("%")
- Addition ("+"), Subtraction ("-")
- Shift Left ("<<"), Arithmetic Shift Right (">>"), Logical Shift Right (">>>")
- Less Than ("<"), Less Than or Equal ("<="), Greater Than or Equal (">="), Greater Than (">")
- Equals ("=="), Not Equals ("!=")
- Bitwise AND ("&")
- Bitwise XOR ("^")
- Bitwise OR ("|")
- Logical AND ("&&")
- Logical OR ("||")
- Ternary Conditional Operator ("cond?trueValue:falseValue")
It is also possible to extract the lower and higher 16 bits of a constants, respectively, by using the lo16
and hi16
functions:
lui $t0, hi16(123456)
addiu $t0, $t0, lo16(123456)
Numerical constants can be provided in decimal, hexadecimal, octal and binary:
- Hexadecimal numbers are specified with a
0x
or0X
prefix, e.g.,0xabcd
. Case does not matter, i.e.0XABcd
is the same as0xabCD
. - Octal numbers are prefixed by a
0
, e.g.0775
. - Binary numbers are specified with a
0b
or0B
prefix, e.g.0b101001010
. - Decimal numbers are specified without any prefix. That also means that they may not start with a zero (
0
), otherwise they will be interepreted as octal (which will lead to errors if using non-octal digits).
It is possible to introduce named constants for use in expressions.
Simply add a line of the form symbol = expression
.
You will be able to use the name symbol
in other expressions after that assignment.
x = 312
y = x*x
lui $t0, hi16(y)
addiu $t0, $t0, lo16(y)
You can type a line number and press Go to jump to a specific line of code. This will become the next line the mips engine will run.
Tap the Show/Hide Demos button to reveal the list of built-in demos. Tap a demo (e.g. Hello World) to replace the existing MIPS code with the predefined MIPS code for that demo. Then press run (or step) to watch it execute. Most of them are self explanatory, or have comments that explain how they work.
With this feature enabled, whenever a register (or heap/stack) is modified, the tab will automatically switch the corresponding tab so that you can see the relevant change. In the case where multiple things are modified at once, the last change will take precedence.
By default, support for pseudo-instructions is active and pipeline emulation is inactive. To change that, use the emulation options below the text editor.
Note that when pipeline emulation is activated, branch and jump instructions will be delayed by one instruction slot, and the instruction immediately following them will be executed before the first instruction at the target location.
Sometimes it is useful to see the actual bits that compose a byte, or to see the corresponding ASCII character that is stored in the stack/heap. You can toggle between seeing any of these three values for a corresponding address in the stack/heap.
Up top we can toggle which registers are currently visible (S, T, A, or V registers). Underneath that, we can see a register's current value. Registers are initially populated with junk data until an instruction modifies them. In this screenshot, we can see that the $s0 register currently has the value 170. A register is composed of 32 bits, and can therefore hold 232 different values.
You can click a register's value and overwrite its contents with whatever you want.
Category | Instructions |
---|---|
Arithmetic Operations (signed) | ADD, ADDI, SUB, MULT, DIV |
Arithmetic Operations (unsigned) | ADDU, ADDIU, SUBU, MULTU, DIVU |
Comparison Instructions | SLT, SLTI, SLTU, SLTIU |
Logical Operations | AND, ANDI, OR, ORI, XOR, XORI, NOR |
Shift Operations | SLL, SLLV, SRL, SRLV, SRA, SRAV |
Jump Instructions | B, J, JAL, JR, JALR |
Branch Instructions | BEQ, BNE, BGT, BGE, BLT, BLE |
Branch Instructions (unsigned) | BGTU, BGEU, BLTU, BLEU |
Branch Instructions (zero comp.) | BEQZ, BNEZ, BGTZ, BGEZ, BLTZ, BLEZ |
Branch and Link Instructions | BGEZAL, BLTZAL |
Register Transfer Instructions | MFHI, MFLO, MTHI, MTLO |
Load Instructions | LB, LBU, LH, LHW, LW, LWL, LWR, LUI |
Store Instructions | SB, SH, SW, SWL, SWR |
Instructions shown in bold are hardware instructions, all others are pseudo-instructions.
Note that the floating point unit (FPU) is not implemented!
The syscalls supported are similar to the syscalls used by the MARS emulator:
Description | $v0 code | Arguments | Return Value |
---|---|---|---|
Print Integer | 1 | $a0 = integer to print | |
Print String | 4 | $a0 = stack address of null-terminated string to print to console | |
Read Integer | 5 | $v0 = contains integer read | |
Read String | 8 | $a0 = address of input buffer $a1 = maximum number of characters to read (this will be one less than the allowed string since it needs space for the null terminator) |
$v0 = contains the length of the input string |
Allocate Heap Memory | 9 | $a0 = number of bytes to allocate | $v0 = contains address of allocated memory |
Confirm Dialog | 50 | $a0 = address of null-terminated string that is the message to user | $a0 contains value of user-chosen option 0: OK 1: Cancel |
Input Dialog Int | 51 | $a0 = address of null-terminated string that is the message to user | $a0 contains int read $a1 contains status value 0: OK status -1: input data cannot be correctly parsed -2: Cancel was chosen -3: OK was chosen but no data had been input into field |
Input Dialog String | 54 | $a0 = address of null-terminated string that is the message to user $a1 = address of input buffer $a2 = maximum number of characters to read |
$a1 contains status value 0: OK status. Buffer contains the input string. -2: Cancel was chosen. No change to buffer. -3: OK was chosen but no data had been input into field. No change to buffer. -4: length of the input string exceeded the specified maximum. Buffer contains the maximum allowable input string plus a terminating null. |
Alert | 55 | $a0 = address of null-terminated string that is the message to user | |
Alert Int | 56 | $a0 = address of null-terminated string that is an information-type message to user $a1 = int value to display in string form after the first string |
|
Alert String | 59 | $a0 = address of null-terminated string that is an information-type message to user $a1 = address of null-terminated string to display after the first string |
|
Generate Save String Code | 60 | $a0 = stack address of null-terminated string to generate code for | |
Binary -> Decimal | 61 | $a0 = stack address of binary string | |
Decimal -> Binary | 62 | $a0 = decimal number to convert $a1 = number of chars to output $a2 = size of each block to output |
The stack is byte-addressable. Each time you start the emulator, the frame pointer will be initialized to a random address less than 232, in order to simulate the fact that when you first run your program, the frame pointer may be at any given value.
The black arrow is used to show where $sp is currently pointing to.
You can click show relative address, in order to show relative addresses from the frame pointer rather than having to look at large numbers.
You can change a value in the stack by clicking it to edit it. You can also view it in several modes, as an integer, in binary, and it’s ascii representation (‘None’ if no ascii character is available). Viewing the stack in a different mode doesn’t mean you can’t edit it. You can edit it in binary mode to save a binary representation, as you could with integers and ascii.
The heap is byte-addressable. It can be extended using the syscall 9 (see the table above).
Contents of the heap can be changed as for the stack, and representation (decimal/ascii/binary) can be changed as well.
WeMIPS uses npm as its package manager, which comes with node.js.
To install the required packages, run npm install
or - for a clean installation - npm ci
.
The documentation is built using jsdoc, which will be installed by npm using the commands shown above.
In order to rebuild the documentation, run npm run build-doc
from the root of the source directory.