MIPS Complete Documentation

Instructions

abs $reg, $reg

ABSolute value : Set $t1 to absolute value of $t2 (algorithm from Hacker's Delight)

abs $t1,$t2

abs.d $freg, $freg

Floating-point absolute value (double) : Sets $f2 to the absolute value of $f4 (double-precision). Both register numbers must be even. Works by clearing the sign bit of the high word.

abs.d $f2,$f4

abs.s $freg, $freg

Floating-point absolute value (single) : Sets $f0 to the absolute value of $f1 (single-precision). Works by clearing the sign bit. Does not raise exceptions for NaN or infinity.

abs.s $f0,$f1

add $reg, $reg, [$reg / imm]

Add (signed, overflow trap) : Sets $t1 = $t2 + $t3 using signed 32-bit arithmetic. Raises an overflow exception if the true result does not fit in 32 bits. Use 'addu' when overflow should be silently ignored.

add $t1,$t2,$t3

ADDition : set $t1 to ($t2 plus 16-bit immediate)

add $t1,$t2,-100

ADDition : set $t1 to ($t2 plus 32-bit immediate)

add $t1,$t2,100000

add.d $freg, $freg, $freg

Floating-point add (double) : Sets $f2 = $f4 + $f6 using IEEE 754 double-precision (64-bit) arithmetic. Double-precision values have about 15 significant decimal digits. All three register numbers must be even, as each double occupies a pair of FP registers.

add.d $f2,$f4,$f6

add.s $freg, $freg, $freg

Floating-point add (single) : Sets $f0 = $f1 + $f3 using IEEE 754 single-precision (32-bit) arithmetic. Single-precision values have about 7 significant decimal digits. The result is stored in one FP register.

add.s $f0,$f1,$f3

addi $reg, $reg, [imm / LO(id)]

Add immediate (signed, overflow trap) : Sets $t1 = $t2 + immediate, where the immediate is a signed 16-bit constant (-32768 to 32767) sign-extended to 32 bits. Raises an overflow exception if the result overflows. Use 'addiu' to suppress the overflow check.

addi $t1,$t2,-100

ADDition Immediate : set $t1 to ($t2 plus 32-bit immediate)

addi $t1,$t2,100000

Add Lower Address : Set $t1 to $t2 plus the lower 16 bits of label's address

addi $t1,$t2,%lo(label)

addiu $reg, $reg, [imm / LO(id)]

Add immediate unsigned (no overflow trap) : Sets $t1 = $t2 + immediate. The immediate is a signed 16-bit value sign-extended to 32 bits; no overflow exception is raised. Despite the name the immediate is sign-extended, not zero-extended. The most common add-immediate instruction.

addiu $t1,$t2,-100

ADDition Immediate Unsigned: set $t1 to ($t2 plus 32-bit immediate), no overflow

addiu $t1,$t2,100000

Add Lower Address : Set $t1 to $t2 plus the lower 16 bits of label's address

addiu $t1,$t2,%lo(label)

addu $reg, $reg, [$reg / imm]

Add unsigned (no overflow trap) : Sets $t1 = $t2 + $t3. No exception is raised on overflow; the result wraps modulo 2^32. Despite the name, this works fine with signed values too when you don't need overflow detection.

addu $t1,$t2,$t3

ADDition Unsigned : set $t1 to ($t2 plus 32-bit immediate), no overflow

addu $t1,$t2,100000

and $reg, [$reg / imm], [$reg / imm]

Bitwise AND : Sets $t1 = $t2 & $t3. Each bit of $t1 is 1 only if the corresponding bit is 1 in both $t2 and $t3. Commonly used to mask (isolate) specific bits in a value.

and $t1,$t2,$t3

AND : set $t1 to ($t2 bitwise-AND 16-bit unsigned immediate)

and $t1,$t2,100

AND : set $t1 to ($t1 bitwise-AND 16-bit unsigned immediate)

and $t1,100

andi $reg, [$reg / imm], imm

Bitwise AND immediate : Sets $t1 = $t2 & immediate. The 16-bit immediate is zero-extended (upper 16 bits become 0, not sign-extended) before the AND. Commonly used to mask off the lower 16 bits of a register or to test individual bits.

andi $t1,$t2,100

AND Immediate : set $t1 to ($t2 bitwise-AND 32-bit immediate)

andi $t1,$t2,100000

AND Immediate : set $t1 to ($t1 bitwise-AND 16-bit unsigned immediate)

andi $t1,100

AND Immediate : set $t1 to ($t1 bitwise-AND 32-bit immediate)

andi $t1,100000

b id

Branch : Branch to statement at label unconditionally

b label

bal id

Branch And Link : Branch to statement at label unconditionally, saving the return address in $ra. The counterpart of 'b' for calling a subroutine whose address is a label

bal label

bc1f [id / imm], id

Branch if FP condition flag 0 is false : Branches to 'label' if Coprocessor 1 condition flag 0 is false (0). Use after a FP compare instruction when you want to branch on the condition NOT being met. Note: mnemonic is BC1F, not BCLF.

bc1f label

Branch if specified FP condition flag is false : Branches to 'label' if the FP condition flag specified by the immediate operand is false (0). Allows branching on the unset result of any of the 8 FP condition flags.

bc1f 1,label

bc1t [id / imm], id

Branch if FP condition flag 0 is true : Branches to 'label' if Coprocessor 1 condition flag 0 is true (1). Set by a preceding FP compare instruction such as 'c.eq.s' or 'c.lt.d'. Note: mnemonic is BC1T (branch Coprocessor-1 True), not BCLT.

bc1t label

Branch if specified FP condition flag is true : Branches to 'label' if the FP condition flag specified by the immediate operand is true (1). Allows branching on any of the 8 condition flags set by FP compare instructions.

bc1t 1,label

beq $reg, [$reg / imm], id

Branch on equal : Branches to 'label' if $t1 == $t2. Uses a PC-relative 16-bit signed offset (multiplied by 4) so the target must be within ±32 KB. Commonly the first half of an if/else test.

beq $t1,$t2,label

Branch if EQual : Branch to statement at label if $t1 is equal to 16-bit immediate

beq $t1,-100,label

Branch if EQual : Branch to statement at label if $t1 is equal to 32-bit immediate

beq $t1,100000,label

beqz $reg, id

Branch if EQual Zero : Branch to statement at label if $t1 is equal to zero

beqz $t1,label

bge $reg, [$reg / imm], id

Branch if Greater or Equal : Branch to statement at label if $t1 is greater or equal to $t2

bge $t1,$t2,label

Branch if Greater or Equal : Branch to statement at label if $t1 is greater or equal to 16-bit immediate

bge $t1,-100,label

Branch if Greater or Equal : Branch to statement at label if $t1 is greater or equal to 32-bit immediate

bge $t1,100000,label

bgeu $reg, [$reg / imm], id

Branch if Greater or Equal Unsigned : Branch to statement at label if $t1 is greater or equal to $t2 (unsigned compare)

bgeu $t1,$t2,label

Branch if Greater or Equal Unsigned : Branch to statement at label if $t1 is greater or equal to 16-bit immediate (unsigned compare)

bgeu $t1,-100,label

Branch if Greater or Equal Unsigned : Branch to statement at label if $t1 is greater or equal to 32-bit immediate (unsigned compare)

bgeu $t1,100000,label

bgez $reg, id

Branch on greater than or equal to zero : Branches to 'label' if $t1 >= 0 (signed comparison). Uses a PC-relative 16-bit signed offset. Commonly used to test the sign bit.

bgez $t1,label

bgezal $reg, id

Branch on greater than or equal to zero and link : Branches to 'label' if $t1 >= 0 (signed), and saves the return address (PC + 4) in $ra. Combines a conditional branch with a function call. Use 'jr $ra' to return.

bgezal $t1,label

bgt $reg, [$reg / imm], id

Branch if Greater Than : Branch to statement at label if $t1 is greater than $t2

bgt $t1,$t2,label

Branch if Greater Than : Branch to statement at label if $t1 is greater than 16-bit immediate

bgt $t1,-100,label

Branch if Greater Than : Branch to statement at label if $t1 is greater than 32-bit immediate

bgt $t1,100000,label

bgtu $reg, [$reg / imm], id

Branch if Greater Than Unsigned: Branch to statement at label if $t1 is greater than $t2 (unsigned compare)

bgtu $t1,$t2,label

Branch if Greater Than Unsigned: Branch to statement at label if $t1 is greater than 16-bit immediate (unsigned compare)

bgtu $t1,-100,label bgtu $t1,100000,label

bgtz $reg, id

Branch on greater than zero : Branches to 'label' if $t1 > 0 (signed comparison). Uses a PC-relative 16-bit signed offset.

bgtz $t1,label

ble $reg, [$reg / imm], id

Branch if Less or Equal : Branch to statement at label if $t1 is less than or equal to $t2

ble $t1,$t2,label

Branch if Less or Equal : Branch to statement at label if $t1 is less than or equal to 16-bit immediate

ble $t1,-100,label

Branch if Less or Equal : Branch to statement at label if $t1 is less than or equal to 32-bit immediate

ble $t1,100000,label

bleu $reg, [$reg / imm], id

Branch if Less or Equal Unsigned : Branch to statement at label if $t1 is less than or equal to $t2 (unsigned compare)

bleu $t1,$t2,label

Branch if Less or Equal Unsigned : Branch to statement at label if $t1 is less than or equal to 16-bit immediate (unsigned compare)

bleu $t1,-100,label

Branch if Less or Equal Unsigned : Branch to statement at label if $t1 is less than or equal to 32-bit immediate (unsigned compare)

bleu $t1,100000,label

blez $reg, id

Branch on less than or equal to zero : Branches to 'label' if $t1 <= 0 (signed comparison). Uses a PC-relative 16-bit signed offset.

blez $t1,label

blt $reg, [$reg / imm], id

Branch if Less Than : Branch to statement at label if $t1 is less than $t2

blt $t1,$t2,label

Branch if Less Than : Branch to statement at label if $t1 is less than 16-bit immediate

blt $t1,-100,label

Branch if Less Than : Branch to statement at label if $t1 is less than 32-bit immediate

blt $t1,100000,label

bltu $reg, [$reg / imm], id

Branch if Less Than Unsigned : Branch to statement at label if $t1 is less than $t2

bltu $t1,$t2,label

Branch if Less Than Unsigned : Branch to statement at label if $t1 is less than 16-bit immediate

bltu $t1,-100,label

Branch if Less Than Unsigned : Branch to statement at label if $t1 is less than 32-bit immediate

bltu $t1,100000,label

bltz $reg, id

Branch on less than zero : Branches to 'label' if $t1 < 0 (signed comparison). Uses a PC-relative 16-bit signed offset.

bltz $t1,label

bltzal $reg, id

Branch on less than zero and link : Branches to 'label' if $t1 < 0 (signed), and saves the return address (PC + 4) in $ra. Combines a conditional branch with a function call. Use 'jr $ra' to return.

bltzal $t1,label

bne $reg, [$reg / imm], id

Branch on not equal : Branches to 'label' if $t1 != $t2. Opposite of 'beq'. Uses a PC-relative 16-bit signed offset. Commonly used to branch out of loops or skip else blocks.

bne $t1,$t2,label

Branch if Not Equal : Branch to statement at label if $t1 is not equal to 16-bit immediate

bne $t1,-100,label

Branch if Not Equal : Branch to statement at label if $t1 is not equal to 32-bit immediate

bne $t1,100000,label

bnez $reg, id

Branch if Not Equal Zero : Branch to statement at label if $t1 is not equal to zero

bnez $t1,label

break imm

Breakpoint with code : Raises a breakpoint exception with the given numeric code. Halts execution in this simulator. Useful for embedding debug checkpoints in code, similar to a hardware breakpoint.

break 100

Breakpoint : Raises a breakpoint exception (no code). Halts execution in this simulator. Used as an unconditional software breakpoint — the zero-code variant of 'break N'.

break

c.eq.d [$freg / imm], $freg, $freg

FP compare eq (double) : Sets FP condition flag 0 to true if the two operands are equal, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.eq.d $f2,$f4

FP compare eq (double, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are equal, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.eq.d 1,$f2,$f4

c.eq.s [$freg / imm], $freg, $freg

FP compare eq (single) : Sets FP condition flag 0 to true if the two operands are equal, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.eq.s $f0,$f1

FP compare eq (single, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are equal, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.eq.s 1,$f0,$f1

c.f.d [$freg / imm], $freg, $freg

FP compare f (double) : Sets FP condition flag 0 to true if never; this comparison is always false, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.f.d $f2,$f4

FP compare f (double, flagged) : Sets FP condition flag N, named by the first operand, to true if never; this comparison is always false, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.f.d 1,$f2,$f4

c.f.s [$freg / imm], $freg, $freg

FP compare f (single) : Sets FP condition flag 0 to true if never; this comparison is always false, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.f.s $f0,$f1

FP compare f (single, flagged) : Sets FP condition flag N, named by the first operand, to true if never; this comparison is always false, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.f.s 1,$f0,$f1

c.le.d [$freg / imm], $freg, $freg

FP compare le (double) : Sets FP condition flag 0 to true if the first operand is less than or equal to the second, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.ole' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.le.d $f2,$f4

FP compare le (double, flagged) : Sets FP condition flag N, named by the first operand, to true if the first operand is less than or equal to the second, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.ole' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.le.d 1,$f2,$f4

c.le.s [$freg / imm], $freg, $freg

FP compare le (single) : Sets FP condition flag 0 to true if the first operand is less than or equal to the second, false otherwise. This is the signalling form, which behaves like 'c.ole' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.le.s $f0,$f1

FP compare le (single, flagged) : Sets FP condition flag N, named by the first operand, to true if the first operand is less than or equal to the second, false otherwise. This is the signalling form, which behaves like 'c.ole' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.le.s 1,$f0,$f1

c.lt.d [$freg / imm], $freg, $freg

FP compare lt (double) : Sets FP condition flag 0 to true if the first operand is less than the second, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.olt' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.lt.d $f2,$f4

FP compare lt (double, flagged) : Sets FP condition flag N, named by the first operand, to true if the first operand is less than the second, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.olt' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.lt.d 1,$f2,$f4

c.lt.s [$freg / imm], $freg, $freg

FP compare lt (single) : Sets FP condition flag 0 to true if the first operand is less than the second, false otherwise. This is the signalling form, which behaves like 'c.olt' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.lt.s $f0,$f1

FP compare lt (single, flagged) : Sets FP condition flag N, named by the first operand, to true if the first operand is less than the second, false otherwise. This is the signalling form, which behaves like 'c.olt' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.lt.s 1,$f0,$f1

c.nge.d [$freg / imm], $freg, $freg

FP compare nge (double) : Sets FP condition flag 0 to true if the two operands are unordered, or the first is less than the second; the name reads as not greater than or equal, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.ult' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.nge.d $f2,$f4

FP compare nge (double, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered, or the first is less than the second; the name reads as not greater than or equal, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.ult' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.nge.d 1,$f2,$f4

c.nge.s [$freg / imm], $freg, $freg

FP compare nge (single) : Sets FP condition flag 0 to true if the two operands are unordered, or the first is less than the second; the name reads as not greater than or equal, false otherwise. This is the signalling form, which behaves like 'c.ult' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.nge.s $f0,$f1

FP compare nge (single, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered, or the first is less than the second; the name reads as not greater than or equal, false otherwise. This is the signalling form, which behaves like 'c.ult' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.nge.s 1,$f0,$f1

c.ngl.d [$freg / imm], $freg, $freg

FP compare ngl (double) : Sets FP condition flag 0 to true if the two operands are unordered or equal; the name reads as not greater than or less than, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.ueq' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.ngl.d $f2,$f4

FP compare ngl (double, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered or equal; the name reads as not greater than or less than, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.ueq' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.ngl.d 1,$f2,$f4

c.ngl.s [$freg / imm], $freg, $freg

FP compare ngl (single) : Sets FP condition flag 0 to true if the two operands are unordered or equal; the name reads as not greater than or less than, false otherwise. This is the signalling form, which behaves like 'c.ueq' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.ngl.s $f0,$f1

FP compare ngl (single, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered or equal; the name reads as not greater than or less than, false otherwise. This is the signalling form, which behaves like 'c.ueq' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.ngl.s 1,$f0,$f1

c.ngle.d [$freg / imm], $freg, $freg

FP compare ngle (double) : Sets FP condition flag 0 to true if the two operands are unordered; the name reads as not greater than, less than or equal, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.un' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.ngle.d $f2,$f4

FP compare ngle (double, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered; the name reads as not greater than, less than or equal, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.un' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.ngle.d 1,$f2,$f4

c.ngle.s [$freg / imm], $freg, $freg

FP compare ngle (single) : Sets FP condition flag 0 to true if the two operands are unordered; the name reads as not greater than, less than or equal, false otherwise. This is the signalling form, which behaves like 'c.un' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.ngle.s $f0,$f1

FP compare ngle (single, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered; the name reads as not greater than, less than or equal, false otherwise. This is the signalling form, which behaves like 'c.un' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.ngle.s 1,$f0,$f1

c.ngt.d [$freg / imm], $freg, $freg

FP compare ngt (double) : Sets FP condition flag 0 to true if the two operands are unordered, or the first is less than or equal to the second; the name reads as not greater than, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.ule' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.ngt.d $f2,$f4

FP compare ngt (double, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered, or the first is less than or equal to the second; the name reads as not greater than, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.ule' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.ngt.d 1,$f2,$f4

c.ngt.s [$freg / imm], $freg, $freg

FP compare ngt (single) : Sets FP condition flag 0 to true if the two operands are unordered, or the first is less than or equal to the second; the name reads as not greater than, false otherwise. This is the signalling form, which behaves like 'c.ule' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.ngt.s $f0,$f1

FP compare ngt (single, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered, or the first is less than or equal to the second; the name reads as not greater than, false otherwise. This is the signalling form, which behaves like 'c.ule' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.ngt.s 1,$f0,$f1

c.ole.d [$freg / imm], $freg, $freg

FP compare ole (double) : Sets FP condition flag 0 to true if both operands are ordered and the first is less than or equal to the second, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.ole.d $f2,$f4

FP compare ole (double, flagged) : Sets FP condition flag N, named by the first operand, to true if both operands are ordered and the first is less than or equal to the second, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.ole.d 1,$f2,$f4

c.ole.s [$freg / imm], $freg, $freg

FP compare ole (single) : Sets FP condition flag 0 to true if both operands are ordered and the first is less than or equal to the second, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.ole.s $f0,$f1

FP compare ole (single, flagged) : Sets FP condition flag N, named by the first operand, to true if both operands are ordered and the first is less than or equal to the second, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.ole.s 1,$f0,$f1

c.olt.d [$freg / imm], $freg, $freg

FP compare olt (double) : Sets FP condition flag 0 to true if both operands are ordered and the first is less than the second, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.olt.d $f2,$f4

FP compare olt (double, flagged) : Sets FP condition flag N, named by the first operand, to true if both operands are ordered and the first is less than the second, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.olt.d 1,$f2,$f4

c.olt.s [$freg / imm], $freg, $freg

FP compare olt (single) : Sets FP condition flag 0 to true if both operands are ordered and the first is less than the second, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.olt.s $f0,$f1

FP compare olt (single, flagged) : Sets FP condition flag N, named by the first operand, to true if both operands are ordered and the first is less than the second, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.olt.s 1,$f0,$f1

c.seq.d [$freg / imm], $freg, $freg

FP compare seq (double) : Sets FP condition flag 0 to true if the two operands are equal, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.eq' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.seq.d $f2,$f4

FP compare seq (double, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are equal, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.eq' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.seq.d 1,$f2,$f4

c.seq.s [$freg / imm], $freg, $freg

FP compare seq (single) : Sets FP condition flag 0 to true if the two operands are equal, false otherwise. This is the signalling form, which behaves like 'c.eq' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.seq.s $f0,$f1

FP compare seq (single, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are equal, false otherwise. This is the signalling form, which behaves like 'c.eq' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.seq.s 1,$f0,$f1

c.sf.d [$freg / imm], $freg, $freg

FP compare sf (double) : Sets FP condition flag 0 to true if never; this comparison is always false, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.f' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.sf.d $f2,$f4

FP compare sf (double, flagged) : Sets FP condition flag N, named by the first operand, to true if never; this comparison is always false, false otherwise. Both register numbers must be even. This is the signalling form, which behaves like 'c.f' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.sf.d 1,$f2,$f4

c.sf.s [$freg / imm], $freg, $freg

FP compare sf (single) : Sets FP condition flag 0 to true if never; this comparison is always false, false otherwise. This is the signalling form, which behaves like 'c.f' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.sf.s $f0,$f1

FP compare sf (single, flagged) : Sets FP condition flag N, named by the first operand, to true if never; this comparison is always false, false otherwise. This is the signalling form, which behaves like 'c.f' here because FP exceptions are not tracked. Use 'bc1t' or 'bc1f' to branch on the result.

c.sf.s 1,$f0,$f1

c.ueq.d [$freg / imm], $freg, $freg

FP compare ueq (double) : Sets FP condition flag 0 to true if the two operands are unordered or equal, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.ueq.d $f2,$f4

FP compare ueq (double, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered or equal, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.ueq.d 1,$f2,$f4

c.ueq.s [$freg / imm], $freg, $freg

FP compare ueq (single) : Sets FP condition flag 0 to true if the two operands are unordered or equal, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.ueq.s $f0,$f1

FP compare ueq (single, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered or equal, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.ueq.s 1,$f0,$f1

c.ule.d [$freg / imm], $freg, $freg

FP compare ule (double) : Sets FP condition flag 0 to true if the two operands are unordered, or the first is less than or equal to the second, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.ule.d $f2,$f4

FP compare ule (double, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered, or the first is less than or equal to the second, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.ule.d 1,$f2,$f4

c.ule.s [$freg / imm], $freg, $freg

FP compare ule (single) : Sets FP condition flag 0 to true if the two operands are unordered, or the first is less than or equal to the second, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.ule.s $f0,$f1

FP compare ule (single, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered, or the first is less than or equal to the second, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.ule.s 1,$f0,$f1

c.ult.d [$freg / imm], $freg, $freg

FP compare ult (double) : Sets FP condition flag 0 to true if the two operands are unordered, or the first is less than the second, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.ult.d $f2,$f4

FP compare ult (double, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered, or the first is less than the second, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.ult.d 1,$f2,$f4

c.ult.s [$freg / imm], $freg, $freg

FP compare ult (single) : Sets FP condition flag 0 to true if the two operands are unordered, or the first is less than the second, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.ult.s $f0,$f1

FP compare ult (single, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered, or the first is less than the second, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.ult.s 1,$f0,$f1

c.un.d [$freg / imm], $freg, $freg

FP compare un (double) : Sets FP condition flag 0 to true if the two operands are unordered, which is the case when either one is NaN, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.un.d $f2,$f4

FP compare un (double, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered, which is the case when either one is NaN, false otherwise. Both register numbers must be even. Use 'bc1t' or 'bc1f' to branch on the result.

c.un.d 1,$f2,$f4

c.un.s [$freg / imm], $freg, $freg

FP compare un (single) : Sets FP condition flag 0 to true if the two operands are unordered, which is the case when either one is NaN, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.un.s $f0,$f1

FP compare un (single, flagged) : Sets FP condition flag N, named by the first operand, to true if the two operands are unordered, which is the case when either one is NaN, false otherwise. Use 'bc1t' or 'bc1f' to branch on the result.

c.un.s 1,$f0,$f1

ceil.w.d $freg, $freg

Ceiling double-precision to word : Converts the double-precision float in $f2 (even-numbered register) to a 32-bit integer by rounding toward positive infinity, storing the result in $f1.

ceil.w.d $f1,$f2

ceil.w.s $freg, $freg

Ceiling single-precision to word : Converts the single-precision float in $f1 to a 32-bit integer by rounding toward positive infinity, and stores the result in $f0.

ceil.w.s $f0,$f1

cfc1 $reg, $freg

Move control word from FPU : Copies an FPU control register into integer register $t1. Register 31 is FCSR and register 25 is FCCR, both of which report the condition codes set by the 'c.eq.s', 'c.lt.s' family. Only the condition codes are modelled here; the rounding mode and exception fields read as 0.

cfc1 $t1,$f31

clo $reg, $reg

Count leading ones : Sets $t1 to the number of consecutive 1 bits in $t2, counted from the most-significant bit downward. For example, if $t2 = 0b11100000..., then $t1 = 3. Returns 32 if all bits are 1.

clo $t1,$t2

clz $reg, $reg

Count leading zeros : Sets $t1 to the number of consecutive 0 bits in $t2, counted from the most-significant bit downward. For example, if $t2 = 0b00010000..., then $t1 = 3. Returns 32 if $t2 is 0. Often used to compute floor(log2(n)) or to normalize values.

clz $t1,$t2

ctc1 $reg, $freg

Move control word to FPU : Copies integer register $t1 into an FPU control register. Register 31 is FCSR and register 25 is FCCR. Only the condition code bits take effect; the rounding mode and exception fields are ignored because this simulator always rounds to nearest and does not track FP exceptions.

ctc1 $t1,$f31

cvt.d.s $freg, $freg

Convert single-precision to double-precision : Converts the single-precision float in $f1 to double-precision (64-bit IEEE 754) and stores the result in $f2. $f2 must be even-numbered. No data is lost because double has more precision.

cvt.d.s $f2,$f1

cvt.d.w $freg, $freg

Convert integer word to double-precision : Treats the 32-bit integer stored in $f1 as a signed integer and converts it to a double-precision float stored in $f2. $f2 must be even-numbered.

cvt.d.w $f2,$f1

cvt.s.d $freg, $freg

Convert double-precision to single-precision : Converts the double-precision float in $f2 to single-precision and stores the result in $f1. $f2 must be even-numbered. Precision may be lost since single has fewer significant digits.

cvt.s.d $f1,$f2

cvt.s.w $freg, $freg

Convert integer word to single-precision : Treats the 32-bit integer stored in $f1 as a signed integer and converts it to a single-precision float stored in $f0.

cvt.s.w $f0,$f1

cvt.w.d $freg, $freg

Convert double-precision to integer word : Converts the double-precision float in $f2 to a signed 32-bit integer by truncation and stores the result in $f1. $f2 must be even-numbered. Use 'mfc1' to move the integer result to a general-purpose register.

cvt.w.d $f1,$f2

cvt.w.s $freg, $freg

Convert single-precision to integer word : Converts the single-precision float in $f1 to a signed 32-bit integer by truncation and stores the result in $f0. Use 'mfc1' to move the integer result to a general-purpose register.

cvt.w.s $f0,$f1

div $reg, $reg, [$reg / imm]

Divide signed : Divides $t1 by $t2 (signed). Sets LO to the quotient and HI to the remainder. Division by zero produces undefined results with no exception. Use 'mflo' to get the quotient; 'mfhi' to get the remainder.

div $t1,$t2

DIVision : Set $t1 to ($t2 divided by $t3, integer division)

div $t1,$t2,$t3

DIVision : Set $t1 to ($t2 divided by 16-bit immediate, integer division)

div $t1,$t2,-100

DIVision : Set $t1 to ($t2 divided by 32-bit immediate, integer division)

div $t1,$t2,100000

div.d $freg, $freg, $freg

Floating-point divide (double) : Sets $f2 = $f4 / $f6 using IEEE 754 double-precision (64-bit) arithmetic. All register numbers must be even.

div.d $f2,$f4,$f6

div.s $freg, $freg, $freg

Floating-point divide (single) : Sets $f0 = $f1 / $f3 using IEEE 754 single-precision (32-bit) arithmetic. Dividing by zero produces +/-Infinity according to IEEE 754.

div.s $f0,$f1,$f3

divu $reg, $reg, [$reg / imm]

Divide unsigned : Divides $t1 by $t2 treating both as unsigned 32-bit integers. Sets LO to the quotient and HI to the remainder. Division by zero produces undefined results with no exception. Use 'mflo' for the quotient; 'mfhi' for the remainder.

divu $t1,$t2

DIVision Unsigned : Set $t1 to ($t2 divided by $t3, unsigned integer division)

divu $t1,$t2,$t3

DIVision Unsigned : Set $t1 to ($t2 divided by 16-bit immediate, unsigned integer division)

divu $t1,$t2,-100

DIVision Unsigned : Set $t1 to ($t2 divided by 32-bit immediate, unsigned integer division)

divu $t1,$t2,100000

eret

Exception return : Returns from an exception or interrupt handler. Restores the PC from the EPC register (Coprocessor 0 register 14) and clears the Exception Level bit (bit 1) in the Status register, re-enabling interrupts and returning to user mode.

eret

floor.w.d $freg, $freg

Floor double-precision to word : Converts the double-precision float in $f2 (even-numbered register) to a 32-bit integer by rounding toward negative infinity, storing the result in $f1.

floor.w.d $f1,$f2

floor.w.s $freg, $freg

Floor single-precision to word : Converts the single-precision float in $f1 to a 32-bit integer by rounding toward negative infinity (i.e., always truncates toward -inf), and stores the result in $f0. Use 'mfc1' to move the result to a general-purpose register.

floor.w.s $f0,$f1

j id

Jump unconditionally : Transfers execution to 'target'. The destination is encoded as a 26-bit word address; the upper 4 bits of PC are combined with this value, so the target must be in the same 256 MB region as the instruction following the jump.

j target

jal id

Jump and link : Saves the return address (PC + 4) in $ra, then jumps to 'target'. The standard function-call instruction in MIPS. The called function returns with 'jr $ra'. Same address-range restriction as 'j'.

jal target

jalr $reg, $reg

Jump and link register : Saves the return address (PC + 4) in $t1, then jumps to the address in $t2. Allows calling a function whose address is only known at runtime (function pointer). Return with 'jr $t1'.

jalr $t1,$t2

Jump and link register : Saves the return address (PC + 4) in $ra, then jumps to the address in $t1. One-operand shorthand for 'jalr $ra,$t1'. Used to call a function via a pointer stored in a register.

jalr $t1

jr $reg

Jump register : Transfers execution to the address stored in $t1. Most commonly used as 'jr $ra' to return from a function call made with 'jal' or 'jalr'.

jr $t1

l.d $freg, [($reg) / imm / imm($reg) / id / id($reg) / id+imm / id+imm($reg)]

Load floating point Double precision : Set $f2 and $f3 register pair to 64-bit value at effective memory doubleword address

l.d $f2,($t2) l.d $f2,-100 l.d $f2,100000 l.d $f2,100000($t2) l.d $f2,label l.d $f2,label($t2) l.d $f2,label+100000 l.d $f2,label+100000($t2)

l.s $freg, [($reg) / imm / imm($reg) / id / id($reg) / id+imm / id+imm($reg)]

Load floating point Single precision : Set $f1 to 32-bit value at effective memory word address

l.s $f1,($t2) l.s $f1,-100 l.s $f1,100000 l.s $f1,100000($t2) l.s $f1,label l.s $f1,label($t2) l.s $f1,label+100000 l.s $f1,label+100000($t2)

la $reg, [($reg) / imm / imm($reg) / id / id($reg) / id+imm / id+imm($reg)]

Load Address : Set $t1 to contents of $t2

la $t1,($t2)

Load Address : Set $t1 to 16-bit immediate (sign-extended)

la $t1,-100

Load Address : Set $t1 to 16-bit immediate (zero-extended)

la $t1,100

Load Address : Set $t1 to 32-bit immediate

la $t1,100000

Load Address : Set $t1 to sum (of $t2 and 16-bit immediate)

la $t1,100($t2)

Load Address : Set $t1 to sum (of $t2 and 32-bit immediate)

la $t1,100000($t2)

Load Address : Set $t1 to label's address

la $t1,label

Load Address : Set $t1 to sum (of $t2 and label's address)

la $t1,label($t2)

Load Address : Set $t1 to sum (of label's address and 32-bit immediate)

la $t1,label+100000

Load Address : Set $t1 to sum (of label's address, 32-bit immediate, and $t2)

la $t1,label+100000($t2)

lb $reg, [imm($reg) / LO(id) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)], ($reg)

Load byte (sign-extended) : Reads one byte from memory at address ($t2 + offset), sign-extends it to 32 bits, and stores the result in $t1. A byte with value 0xFF becomes -1 (0xFFFFFFFF) in $t1. Use 'lbu' if you want zero-extension (0 to 255 range).

lb $t1,-100($t2)

Load from Address : Read from label's address, reached through the %hi already in $t2

lb $t1,%lo(label)($t2)

Load Byte : Set $t1 to sign-extended 8-bit value from effective memory byte address

lb $t1,($t2) lb $t1,-100 lb $t1,100 lb $t1,100000 lb $t1,100($t2) lb $t1,100000($t2) lb $t1,label lb $t1,label($t2) lb $t1,label+100000 lb $t1,label+100000($t2)

lbu $reg, [imm($reg) / LO(id) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)], ($reg)

Load byte unsigned (zero-extended) : Reads one byte from memory at address ($t2 + offset), zero-extends it to 32 bits (upper 24 bits of $t1 are always 0), and stores the result in $t1. Values range from 0 to 255. Use 'lb' if you need sign-extension.

lbu $t1,-100($t2)

Load from Address : Read from label's address, reached through the %hi already in $t2

lbu $t1,%lo(label)($t2)

Load Byte Unsigned : Set $t1 to zero-extended 8-bit value from effective memory byte address

lbu $t1,($t2) lbu $t1,-100 lbu $t1,100 lbu $t1,100000 lbu $t1,100($t2) lbu $t1,100000($t2) lbu $t1,label lbu $t1,label($t2) lbu $t1,label+100000 lbu $t1,label+100000($t2)

ld $reg, [imm($reg) / imm / id / id+imm / ($reg) / id($reg) / id+imm($reg)]

Load Doubleword : Set $t1 and the next register to the 64 bits starting at effective memory byte address

ld $t1,-100($t2)

Load Doubleword : Set $t1 and the next register to the 64 bits starting at effective memory word address

ld $t1,100000 ld $t1,label ld $t1,label+100000 ld $t1,($t2) ld $t1,100000($t2) ld $t1,label($t2) ld $t1,label+100000($t2)

ldc1 $freg, [imm($reg) / LO(id) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)], ($reg)

Load doubleword to FP register pair : Loads a 64-bit value from memory at address ($t2 + offset) into the even FP register pair $f2/$f3. Used to load a double-precision float from memory. Address must be doubleword-aligned and $f2 must be even-numbered.

ldc1 $f2,-100($t2)

Load from Address : Read from label's address, reached through the %hi already in $t2

ldc1 $f1,%lo(label)($t2)

Load Doubleword Coprocessor 1 : Set $f2 and $f3 register pair to 64-bit value at effective memory doubleword address

ldc1 $f2,($t2) ldc1 $f2,-100 ldc1 $f2,100000 ldc1 $f2,100000($t2) ldc1 $f2,label ldc1 $f2,label($t2) ldc1 $f2,label+100000 ldc1 $f2,label+100000($t2)

lh $reg, [imm($reg) / LO(id) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)], ($reg)

Load halfword (sign-extended) : Reads a 16-bit value from memory at address ($t2 + offset), sign-extends it to 32 bits, and stores the result in $t1. The address must be halfword-aligned (divisible by 2). Use 'lhu' for zero-extension.

lh $t1,-100($t2)

Load from Address : Read from label's address, reached through the %hi already in $t2

lh $t1,%lo(label)($t2)

Load Halfword : Set $t1 to sign-extended 16-bit value from effective memory halfword address

lh $t1,($t2) lh $t1,-100 lh $t1,100 lh $t1,100000 lh $t1,100($t2) lh $t1,100000($t2) lh $t1,label lh $t1,label($t2) lh $t1,label+100000 lh $t1,label+100000($t2)

lhu $reg, [imm($reg) / LO(id) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)], ($reg)

Load halfword unsigned (zero-extended) : Reads a 16-bit value from memory at address ($t2 + offset), zero-extends it to 32 bits (upper 16 bits of $t1 are always 0), and stores the result in $t1. The address must be halfword-aligned (divisible by 2).

lhu $t1,-100($t2)

Load from Address : Read from label's address, reached through the %hi already in $t2

lhu $t1,%lo(label)($t2)

Load Halfword Unsigned : Set $t1 to zero-extended 16-bit value from effective memory halfword address

lhu $t1,($t2) lhu $t1,-100 lhu $t1,100 lhu $t1,100000 lhu $t1,100($t2) lhu $t1,100000($t2) lhu $t1,label lhu $t1,label($t2) lhu $t1,label+100000 lhu $t1,label+100000($t2)

li $reg, imm

Load Immediate : Set $t1 to 16-bit immediate (sign-extended)

li $t1,-100

Load Immediate : Set $t1 to unsigned 16-bit immediate (zero-extended)

li $t1,100

Load Immediate : Set $t1 to 32-bit immediate

li $t1,100000

ll $reg, [imm($reg) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)]

Load linked : Identical to 'lw' in this simulator (reads 32 bits from memory into $t1). In real multi-processor hardware, 'll' is the first half of an atomic read-modify-write pair with 'sc' (store conditional), allowing lock-free synchronization.

ll $t1,-100($t2)

Load Linked : Paired with Store Conditional (sc) to perform atomic read-modify-write. Treated as equivalent to Load Word (lw) because MARS does not simulate multiple processors.

ll $t1,($t2) ll $t1,-100 ll $t1,100 ll $t1,100000 ll $t1,100($t2) ll $t1,100000($t2) ll $t1,label ll $t1,label($t2) ll $t1,label+100000 ll $t1,label+100000($t2)

lui $reg, [imm / HI(id)]

Load upper immediate : Places the 16-bit immediate into the upper 16 bits of $t1 and clears the lower 16 bits to 0. Used to build a full 32-bit constant: first 'lui $t1,upper16' then 'ori $t1,$t1,lower16'. Example: to load 0x12345678 use 'lui $t1,0x1234' then 'ori $t1,$t1,0x5678'.

lui $t1,100

Load Upper Address : Set $t1 to the upper 16 bits of label's address, adjusted so that a following %lo lands on the label. Pairs with an instruction taking %lo(label)($t1)

lui $t1,%hi(label)

lw $reg, [imm($reg) / ($reg) / imm / id / id($reg) / LO(id) / id+imm / id+imm($reg)], ($reg)

Load word : Reads the 32-bit (4-byte) value at memory address ($t2 + offset) and places it in $t1. The address must be word-aligned (divisible by 4). Example: 'lw $t0,0($sp)' loads the value at the top of the stack.

lw $t1,-100($t2)

Load Word : Set $t1 to contents of effective memory word address

lw $t1,($t2) lw $t1,-100 lw $t1,100 lw $t1,100000 lw $t1,100($t2) lw $t1,100000($t2) lw $t1,label($t2) lw $t1,label+100000($t2)

Load Word : Set $t1 to contents of memory word at label's address

lw $t1,label

Load from Address : Read from label's address, reached through the %hi already in $t2

lw $t1,%lo(label)($t2)

Load Word : Set $t1 to contents of effective memory word address

lw $t1,label+100000

lwc1 $freg, [imm($reg) / LO(id) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)], ($reg)

Load word to FP register : Loads a 32-bit value from memory at address ($t2 + offset) directly into FP register $f1. Typically used to load a single-precision float from memory. Address must be word-aligned.

lwc1 $f1,-100($t2)

Load from Address : Read from label's address, reached through the %hi already in $t2

lwc1 $f1,%lo(label)($t2)

Load Word Coprocessor 1 : Set $f1 to 32-bit value from effective memory word address

lwc1 $f1,($t2) lwc1 $f1,-100 lwc1 $f1,100000 lwc1 $f1,100000($t2) lwc1 $f1,label lwc1 $f1,label($t2) lwc1 $f1,label+100000 lwc1 $f1,label+100000($t2)

lwl $reg, [imm($reg) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)]

Load word left (unaligned) : Loads 1-4 bytes into the most-significant (left) bytes of $t1 starting from the effective byte address and working toward the low byte of the containing word. Use together with 'lwr' to load a full 32-bit word from an unaligned address.

lwl $t1,-100($t2)

Load Word Left : Load from 1 to 4 bytes left-justified into $t1, starting with effective memory byte address and continuing through the low-order byte of its word

lwl $t1,($t2) lwl $t1,-100 lwl $t1,100 lwl $t1,100000 lwl $t1,100($t2) lwl $t1,100000($t2) lwl $t1,label lwl $t1,label($t2) lwl $t1,label+100000 lwl $t1,label+100000($t2)

lwr $reg, [imm($reg) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)]

Load word right (unaligned) : Loads 1-4 bytes into the least-significant (right) bytes of $t1 starting from the effective byte address and working toward the high byte of the containing word. Use together with 'lwl' to load a full 32-bit word from an unaligned address.

lwr $t1,-100($t2)

Load Word Right : Load from 1 to 4 bytes right-justified into $t1, starting with effective memory byte address and continuing through the high-order byte of its word

lwr $t1,($t2) lwr $t1,-100 lwr $t1,100 lwr $t1,100000 lwr $t1,100($t2) lwr $t1,100000($t2) lwr $t1,label lwr $t1,label($t2) lwr $t1,label+100000 lwr $t1,label+100000($t2)

madd $reg, $reg

Multiply-accumulate signed : Multiplies $t1 by $t2 (signed) to form a 64-bit product, then adds that product to the current 64-bit value in HI:LO. Useful for computing dot-products or sums of products without extra move instructions.

madd $t1,$t2

maddu $reg, $reg

Multiply-accumulate unsigned : Multiplies $t1 by $t2 treating both as unsigned 32-bit integers, then adds the 64-bit product to HI:LO. Use 'mfhi'/'mflo' to read the accumulated result.

maddu $t1,$t2

mfc0 $reg, regnum

Move from Coprocessor 0 : Reads a Coprocessor 0 (CP0) control register and places its value in general-purpose register $t1. CP0 registers hold exception/interrupt state: register 8 (BadVAddr), 12 (Status), 13 (Cause), 14 (EPC), etc.

mfc0 $t1,$8

mfc1 $reg, $freg

Move from FP register to integer register : Copies the raw 32-bit bit-pattern stored in FP register $f1 into integer register $t1. Useful for reading a single-precision float's bits or the result of 'floor.w.s', 'cvt.w.s', etc.

mfc1 $t1,$f1

mfc1.d $reg, $freg

Move From Coprocessor 1 Double : Set $t1 to contents of $f2, set next higher register from $t1 to contents of next higher register from $f2

mfc1.d $t1,$f2

mfhi $reg

Move from HI : Copies the special HI register into $t1. HI holds the upper 32 bits of a multiply result or the remainder from a divide. Always read HI/LO before executing another multiply or divide, as those instructions overwrite them.

mfhi $t1

mflo $reg

Move from LO : Copies the special LO register into $t1. LO holds the lower 32 bits of a multiply result or the quotient from a divide. Always read HI/LO before executing another multiply or divide, as those instructions overwrite them.

mflo $t1

mov.d $freg, $freg

Move double-precision FP register : Copies the double-precision value in $f4 into $f2. Both register numbers must be even. Does not perform any conversion.

mov.d $f2,$f4

mov.s $freg, $freg

Move single-precision FP register : Copies the single-precision value in $f1 into $f0. Does not perform any conversion.

mov.s $f0,$f1

move $reg, $reg

MOVE : Set $t1 to contents of $t2

move $t1,$t2

movf $reg, $reg, imm

Move if FP condition flag 0 is false : Copies $t2 into $t1 if floating-point condition flag 0 is false (0). Allows integer register updates to be conditioned on the result of a previous FP comparison (e.g., c.eq.s, c.lt.s).

movf $t1,$t2

Move if specified FP condition flag is false : Copies $t2 into $t1 if FP condition flag N (specified by the third operand) is false (0). Allows results of multiple simultaneous FP comparisons to control integer register moves.

movf $t1,$t2,1

movf.d $freg, $freg, imm

Move double-precision FP if condition flag 0 is false : Copies the double-precision value in $f4 into $f2 if FP condition flag 0 is false (0). Both register numbers must be even.

movf.d $f2,$f4

Move double-precision FP if specified condition flag is false : Copies the double-precision value in $f4 into $f2 if FP condition flag N (specified by the immediate) is false (0). Both register numbers must be even.

movf.d $f2,$f4,1

movf.s $freg, $freg, imm

Move single-precision FP if condition flag 0 is false : Copies the single-precision value in $f1 into $f0 if FP condition flag 0 is false (0).

movf.s $f0,$f1

Move single-precision FP if specified condition flag is false : Copies the single-precision value in $f1 into $f0 if FP condition flag N (specified by the immediate) is false (0).

movf.s $f0,$f1,1

movn $reg, $reg, $reg

Move if not zero : Copies $t2 into $t1 only if $t3 != 0. Allows branchless conditional assignment — avoids a branch instruction when you only need to update a register conditionally.

movn $t1,$t2,$t3

movn.d $freg, $freg, $reg

Move double-precision FP if integer register not zero : Copies the double-precision value in $f4 into $f2 if $t3 != 0. Both FP register numbers must be even.

movn.d $f2,$f4,$t3

movn.s $freg, $freg, $reg

Move single-precision FP if integer register not zero : Copies the single-precision value in $f1 into $f0 if $t3 != 0.

movn.s $f0,$f1,$t3

movt $reg, $reg, imm

Move if FP condition flag 0 is true : Copies $t2 into $t1 if floating-point condition flag 0 is true (1). Allows integer register updates to be conditioned on the result of a previous FP comparison (e.g., c.eq.s, c.lt.s).

movt $t1,$t2

Move if specified FP condition flag is true : Copies $t2 into $t1 if FP condition flag N (specified by the third operand) is true (1). Allows results of multiple simultaneous FP comparisons to control integer register moves.

movt $t1,$t2,1

movt.d $freg, $freg, imm

Move double-precision FP if condition flag 0 is true : Copies the double-precision value in $f4 into $f2 if FP condition flag 0 is true (1). Both register numbers must be even.

movt.d $f2,$f4

Move double-precision FP if specified condition flag is true : Copies the double-precision value in $f4 into $f2 if FP condition flag N (specified by the immediate) is true (1). Both register numbers must be even.

movt.d $f2,$f4,1

movt.s $freg, $freg, imm

Move single-precision FP if condition flag 0 is true : Copies the single-precision value in $f1 into $f0 if FP condition flag 0 is true (1).

movt.s $f0,$f1

Move single-precision FP if specified condition flag is true : Copies the single-precision value in $f1 into $f0 if FP condition flag N (specified by the immediate) is true (1).

movt.s $f0,$f1,1

movz $reg, $reg, $reg

Move if zero : Copies $t2 into $t1 only if $t3 == 0. Allows branchless conditional assignment — avoids a branch instruction when you only need to update a register conditionally.

movz $t1,$t2,$t3

movz.d $freg, $freg, $reg

Move double-precision FP if integer register is zero : Copies the double-precision value in $f4 into $f2 if $t3 == 0. Both FP register numbers must be even.

movz.d $f2,$f4,$t3

movz.s $freg, $freg, $reg

Move single-precision FP if integer register is zero : Copies the single-precision value in $f1 into $f0 if $t3 == 0.

movz.s $f0,$f1,$t3

msub $reg, $reg

Multiply-subtract signed : Multiplies $t1 by $t2 (signed) to form a 64-bit product, then subtracts that product from the current 64-bit value in HI:LO. Use 'mfhi'/'mflo' to read the result.

msub $t1,$t2

msubu $reg, $reg

Multiply-subtract unsigned : Multiplies $t1 by $t2 treating both as unsigned 32-bit integers, then subtracts the 64-bit product from HI:LO. Use 'mfhi'/'mflo' to read the result.

msubu $t1,$t2

mtc0 $reg, regnum

Move to Coprocessor 0 : Writes the value of general-purpose register $t1 into a Coprocessor 0 (CP0) control register. Used by exception handlers to modify the Status and Cause registers or to clear the EPC.

mtc0 $t1,$8

mtc1 $reg, $freg

Move from integer register to FP register : Copies the 32-bit value in integer register $t1 into FP register $f1 without any conversion. Useful for initializing a FP register with a specific bit pattern or loading a freshly-computed integer before 'cvt.s.w'.

mtc1 $t1,$f1

mtc1.d $reg, $freg

Move To Coprocessor 1 Double : Set $f2 to contents of $t1, set next higher register from $f2 to contents of next higher register from $t1

mtc1.d $t1,$f2

mthi $reg

Move to HI : Copies $t1 into the special HI register, overwriting any prior multiply or divide result stored there.

mthi $t1

mtlo $reg

Move to LO : Copies $t1 into the special LO register, overwriting any prior multiply or divide result stored there.

mtlo $t1

mul $reg, $reg, [$reg / imm]

Multiply (low 32-bit result to register) : Multiplies $t2 by $t3 (signed) and stores the lower 32 bits of the product directly into $t1 and also into LO. No overflow exception is raised. HI is updated with the upper 32 bits.

mul $t1,$t2,$t3

MULtiplication : Set HI to high-order 32 bits, LO and $t1 to low-order 32 bits of the product of $t2 and 16-bit signed immediate (use mfhi to access HI, mflo to access LO)

mul $t1,$t2,-100

MULtiplication : Set HI to high-order 32 bits, LO and $t1 to low-order 32 bits of the product of $t2 and 32-bit immediate (use mfhi to access HI, mflo to access LO)

mul $t1,$t2,100000

mul.d $freg, $freg, $freg

Floating-point multiply (double) : Sets $f2 = $f4 * $f6 using IEEE 754 double-precision (64-bit) arithmetic. All register numbers must be even.

mul.d $f2,$f4,$f6

mul.s $freg, $freg, $freg

Floating-point multiply (single) : Sets $f0 = $f1 * $f3 using IEEE 754 single-precision (32-bit) arithmetic.

mul.s $f0,$f1,$f3

mulo $reg, $reg, [$reg / imm]

MULtiplication with Overflow : Set $t1 to low-order 32 bits of the product of $t2 and $t3

mulo $t1,$t2,$t3

MULtiplication with Overflow : Set $t1 to low-order 32 bits of the product of $t2 and signed 16-bit immediate

mulo $t1,$t2,-100

MULtiplication with Overflow : Set $t1 to low-order 32 bits of the product of $t2 and 32-bit immediate

mulo $t1,$t2,100000

mulou $reg, $reg, [$reg / imm]

MULtiplication with Overflow Unsigned : Set $t1 to low-order 32 bits of the product of $t2 and $t3

mulou $t1,$t2,$t3

MULtiplication with Overflow Unsigned : Set $t1 to low-order 32 bits of the product of $t2 and signed 16-bit immediate

mulou $t1,$t2,-100

MULtiplication with Overflow Unsigned : Set $t1 to low-order 32 bits of the product of $t2 and 32-bit immediate

mulou $t1,$t2,100000

mult $reg, $reg

Multiply signed : Multiplies $t1 by $t2 as signed 32-bit integers. The 64-bit product is split: the upper 32 bits go into the HI register and the lower 32 bits go into the LO register. Use 'mfhi' to read HI and 'mflo' to read LO.

mult $t1,$t2

multu $reg, $reg

Multiply unsigned : Multiplies $t1 by $t2 treating both as unsigned 32-bit integers. The 64-bit product is split: upper 32 bits go into HI, lower 32 bits go into LO. Use 'mfhi'/'mflo' to retrieve the results.

multu $t1,$t2

mulu $reg, $reg, [$reg / imm]

MULtiplication Unsigned : Set HI to high-order 32 bits, LO and $t1 to low-order 32 bits of ($t2 multiplied by $t3, unsigned multiplication)

mulu $t1,$t2,$t3

MULtiplication Unsigned : Set HI to high-order 32 bits, LO and $t1 to low-order 32 bits of ($t2 multiplied by 16-bit immediate, unsigned multiplication)

mulu $t1,$t2,-100

MULtiplication Unsigned : Set HI to high-order 32 bits, LO and $t1 to low-order 32 bits of ($t2 multiplied by 32-bit immediate, unsigned multiplication)

mulu $t1,$t2,100000

neg $reg, $reg

NEGate : Set $t1 to negation of $t2

neg $t1,$t2

neg.d $freg, $freg

Floating-point negate (double) : Sets $f2 to the negation of $f4 (double-precision) by flipping the sign bit. Both register numbers must be even.

neg.d $f2,$f4

neg.s $freg, $freg

Floating-point negate (single) : Sets $f0 to the negation of $f1 (single-precision) by flipping the sign bit.

neg.s $f0,$f1

negu $reg, $reg

NEGate Unsigned : Set $t1 to negation of $t2, no overflow

negu $t1,$t2

nop

No operation : Does nothing; the processor simply advances to the next instruction. Machine code is all zeroes. Useful as a placeholder or delay-slot filler.

nop

nor $reg, $reg, $reg

Bitwise NOR : Sets $t1 = ~($t2 | $t3). Each bit of $t1 is 1 only if the corresponding bit is 0 in both $t2 and $t3. Tip: 'nor $t1,$t2,$zero' computes a bitwise NOT of $t2, since MIPS has no dedicated NOT instruction.

nor $t1,$t2,$t3

not $reg, $reg

Bitwise NOT (bit inversion)

not $t1,$t2

or $reg, [$reg / imm], [$reg / imm]

Bitwise OR : Sets $t1 = $t2 | $t3. Each bit of $t1 is 1 if the corresponding bit is 1 in either $t2 or $t3 (or both). Commonly used to set specific bits in a value.

or $t1,$t2,$t3

OR : set $t1 to ($t2 bitwise-OR 16-bit unsigned immediate)

or $t1,$t2,100

OR : set $t1 to ($t1 bitwise-OR 16-bit unsigned immediate)

or $t1,100

ori $reg, [$reg / imm], [imm / LO(id)]

Bitwise OR immediate : Sets $t1 = $t2 | immediate. The 16-bit immediate is zero-extended before the OR. Commonly used to set specific bits or to load a small non-negative constant into a register (e.g. after 'lui').

ori $t1,$t2,100

OR Immediate : set $t1 to ($t2 bitwise-OR 32-bit immediate)

ori $t1,$t2,100000

OR Immediate : set $t1 to ($t1 bitwise-OR 16-bit unsigned immediate)

ori $t1,100

OR Immediate : set $t1 to ($t1 bitwise-OR 32-bit immediate)

ori $t1,100000

Or Lower Address : Set $t1 to $t2 or the lower 16 bits of label's address

ori $t1,$t2,%lo(label)

pref imm, imm($reg)

Prefetch : Hints that the data at address ($t2 + offset) will be needed soon, so the hardware can begin moving it into cache. The first operand is the hint type. A prefetch is only ever a hint and never changes what a program computes; this simulator has no cache, so it does nothing. It is accepted so that compiler output assembles unchanged.

pref 1,-100($t2)

rem $reg, $reg, [$reg / imm]

REMainder : Set $t1 to (remainder of $t2 divided by $t3)

rem $t1,$t2,$t3

REMainder : Set $t1 to (remainder of $t2 divided by 16-bit immediate)

rem $t1,$t2,-100

REMainder : Set $t1 to (remainder of $t2 divided by 32-bit immediate)

rem $t1,$t2,100000

remu $reg, $reg, [$reg / imm]

REMainder : Set $t1 to (remainder of $t2 divided by $t3, unsigned division)

remu $t1,$t2,$t3

REMainder : Set $t1 to (remainder of $t2 divided by 16-bit immediate, unsigned division)

remu $t1,$t2,-100

REMainder : Set $t1 to (remainder of $t2 divided by 32-bit immediate, unsigned division)

remu $t1,$t2,100000

rol $reg, $reg, [$reg / imm]

ROtate Left : Set $t1 to ($t2 rotated left by number of bit positions specified in $t3)

rol $t1,$t2,$t3

ROtate Left : Set $t1 to ($t2 rotated left by number of bit positions specified in 5-bit immediate)

rol $t1,$t2,10

ror $reg, $reg, [$reg / imm]

ROtate Right : Set $t1 to ($t2 rotated right by number of bit positions specified in $t3)

ror $t1,$t2,$t3

ROtate Right : Set $t1 to ($t2 rotated right by number of bit positions specified in 5-bit immediate)

ror $t1,$t2,10

rotr $reg, $reg, imm

Rotate right : Sets $t1 = $t2 rotated right by immediate (0-31 bits). Unlike 'srl', bits shifted off the right re-enter on the left rather than being discarded, so no information is lost. Encoded as 'srl' with bit 21 set.

rotr $t1,$t2,10

rotrv $reg, $reg, $reg

Rotate right variable : Sets $t1 = $t2 rotated right by ($t3 & 31). Like 'rotr' but the rotate amount comes from the lowest 5 bits of register $t3 rather than an immediate constant.

rotrv $t1,$t2,$t3

round.w.d $freg, $freg

Round double-precision to word : Converts the double-precision float in $f2 (even-numbered register) to the nearest 32-bit integer (round half to even, per IEEE 754), storing the result in $f1.

round.w.d $f1,$f2

round.w.s $freg, $freg

Round single-precision to word : Converts the single-precision float in $f1 to the nearest 32-bit integer (round half to even, per IEEE 754), and stores the result in $f0.

round.w.s $f0,$f1

s.d $freg, [($reg) / imm / imm($reg) / id / id($reg) / id+imm / id+imm($reg)]

Store floating point Double precision : Store 64 bits from $f2 and $f3 register pair to effective memory doubleword address

s.d $f2,($t2) s.d $f2,-100 s.d $f2,100000 s.d $f2,100000($t2) s.d $f2,label s.d $f2,label($t2) s.d $f2,label+100000 s.d $f2,label+100000($t2)

s.s $freg, [($reg) / imm / imm($reg) / id / id($reg) / id+imm / id+imm($reg)]

Store floating point Single precision : Store 32-bit value from $f1 to effective memory word address

s.s $f1,($t2) s.s $f1,-100 s.s $f1,100000 s.s $f1,100000($t2) s.s $f1,label s.s $f1,label($t2) s.s $f1,label+100000 s.s $f1,label+100000($t2)

sb $reg, [imm($reg) / LO(id) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)], ($reg)

Store byte : Writes the lowest 8 bits of $t1 to memory at address ($t2 + offset). The upper 24 bits of $t1 are ignored. Useful for writing single characters or packed byte arrays.

sb $t1,-100($t2)

Store to Address : Write to label's address, reached through the %hi already in $t2

sb $t1,%lo(label)($t2)

Store Byte : Store the low-order 8 bits of $t1 into the effective memory byte address

sb $t1,($t2) sb $t1,-100 sb $t1,100 sb $t1,100000 sb $t1,100($t2) sb $t1,100000($t2) sb $t1,label sb $t1,label($t2) sb $t1,label+100000 sb $t1,label+100000($t2)

sc $reg, [imm($reg) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)]

Store conditional : Stores the value of $t1 into memory at address ($t2 + offset), then sets $t1 = 1 (success). In real multi-processor hardware this can fail (setting $t1 = 0) if another processor modified the target location since the preceding 'll'. Always succeeds in this simulator.

sc $t1,-100($t2)

Store Conditional : Paired with Load Linked (ll) to perform atomic read-modify-write. Treated as equivalent to Store Word (sw) because MARS does not simulate multiple processors.

sc $t1,($t2) sc $t1,-100 sc $t1,100 sc $t1,100000 sc $t1,100($t2) sc $t1,100000($t2) sc $t1,label sc $t1,label($t2) sc $t1,label+100000 sc $t1,label+100000($t2)

sd $reg, [imm($reg) / imm / id / id+imm / ($reg) / id($reg) / id+imm($reg)]

Store Doubleword : Store contents of $t1 and the next register to the 64 bits starting at effective memory byte address

sd $t1,-100($t2)

Store Doubleword : Store contents of $t1 and the next register to the 64 bits starting at effective memory word address

sd $t1,100000 sd $t1,label sd $t1,label+100000 sd $t1,($t2) sd $t1,100000($t2) sd $t1,label($t2) sd $t1,label+100000($t2)

sdc1 $freg, [imm($reg) / LO(id) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)], ($reg)

Store doubleword from FP register pair : Writes the 64-bit value in the even FP register pair $f2/$f3 to memory at address ($t2 + offset). Used to store a double-precision float to memory. Address must be doubleword-aligned and $f2 must be even-numbered.

sdc1 $f2,-100($t2)

Store to Address : Write to label's address, reached through the %hi already in $t2

sdc1 $f1,%lo(label)($t2)

Store Doubleword Coprocessor 1 : Store 64 bits from $f2 and $f3 register pair to effective memory doubleword address

sdc1 $f2,($t2) sdc1 $f2,-100 sdc1 $f2,100000 sdc1 $f2,100000($t2) sdc1 $f2,label sdc1 $f2,label($t2) sdc1 $f2,label+100000 sdc1 $f2,label+100000($t2)

seb $reg, $reg

Sign extend byte : Copies the low 8 bits of $t2 into $t1, with bit 7 replicated through the upper 24 bits. Turns a byte loaded with 'lbu', or one extracted by shifting, back into a signed value.

seb $t1,$t2

seh $reg, $reg

Sign extend halfword : Copies the low 16 bits of $t2 into $t1, with bit 15 replicated through the upper 16 bits. Turns a halfword loaded with 'lhu' back into a signed value.

seh $t1,$t2

seq $reg, $reg, [$reg / imm]

Set EQual : if $t2 equal to $t3 then set $t1 to 1 else 0

seq $t1,$t2,$t3

Set EQual : if $t2 equal to 16-bit immediate then set $t1 to 1 else 0

seq $t1,$t2,-100

Set EQual : if $t2 equal to 32-bit immediate then set $t1 to 1 else 0

seq $t1,$t2,100000

sge $reg, $reg, [$reg / imm]

Set Greater or Equal : if $t2 greater or equal to $t3 then set $t1 to 1 else 0

sge $t1,$t2,$t3

Set Greater or Equal : if $t2 greater or equal to 16-bit immediate then set $t1 to 1 else 0

sge $t1,$t2,-100

Set Greater or Equal : if $t2 greater or equal to 32-bit immediate then set $t1 to 1 else 0

sge $t1,$t2,100000

sgeu $reg, $reg, [$reg / imm]

Set Greater or Equal Unsigned : if $t2 greater or equal to $t3 (unsigned compare) then set $t1 to 1 else 0

sgeu $t1,$t2,$t3

Set Greater or Equal Unsigned : if $t2 greater or equal to 16-bit immediate (unsigned compare) then set $t1 to 1 else 0

sgeu $t1,$t2,-100

Set Greater or Equal Unsigned : if $t2 greater or equal to 32-bit immediate (unsigned compare) then set $t1 to 1 else 0

sgeu $t1,$t2,100000

sgt $reg, $reg, [$reg / imm]

Set Greater Than : if $t2 greater than $t3 then set $t1 to 1 else 0

sgt $t1,$t2,$t3

Set Greater Than : if $t2 greater than 16-bit immediate then set $t1 to 1 else 0

sgt $t1,$t2,-100

Set Greater Than : if $t2 greater than 32-bit immediate then set $t1 to 1 else 0

sgt $t1,$t2,100000

sgtu $reg, $reg, [$reg / imm]

Set Greater Than Unsigned : if $t2 greater than $t3 (unsigned compare) then set $t1 to 1 else 0

sgtu $t1,$t2,$t3

Set Greater Than Unsigned : if $t2 greater than 16-bit immediate (unsigned compare) then set $t1 to 1 else 0

sgtu $t1,$t2,-100

Set Greater Than Unsigned : if $t2 greater than 32-bit immediate (unsigned compare) then set $t1 to 1 else 0

sgtu $t1,$t2,100000

sh $reg, [imm($reg) / LO(id) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)], ($reg)

Store halfword : Writes the lowest 16 bits of $t1 to memory at address ($t2 + offset). The upper 16 bits of $t1 are ignored. The address must be halfword-aligned (divisible by 2).

sh $t1,-100($t2)

Store to Address : Write to label's address, reached through the %hi already in $t2

sh $t1,%lo(label)($t2)

Store Halfword : Store the low-order 16 bits of $t1 into the effective memory halfword address

sh $t1,($t2) sh $t1,-100 sh $t1,100 sh $t1,100000 sh $t1,100($t2) sh $t1,100000($t2) sh $t1,label sh $t1,label($t2) sh $t1,label+100000 sh $t1,label+100000($t2)

sle $reg, $reg, [$reg / imm]

Set Less or Equal : if $t2 less or equal to $t3 then set $t1 to 1 else 0

sle $t1,$t2,$t3

Set Less or Equal : if $t2 less or equal to 16-bit immediate then set $t1 to 1 else 0

sle $t1,$t2,-100

Set Less or Equal : if $t2 less or equal to 32-bit immediate then set $t1 to 1 else 0

sle $t1,$t2,100000

sleu $reg, $reg, [$reg / imm]

Set Less or Equal Unsigned: if $t2 less or equal to $t3 (unsigned compare) then set $t1 to 1 else 0

sleu $t1,$t2,$t3

Set Less or Equal Unsigned: if $t2 less or equal to 16-bit immediate (unsigned compare) then set $t1 to 1 else 0

sleu $t1,$t2,-100

Set Less or Equal Unsigned: if $t2 less or equal to 32-bit immediate (unsigned compare) then set $t1 to 1 else 0

sleu $t1,$t2,100000

sll $reg, $reg, imm

Shift left logical : Sets $t1 = $t2 << immediate (0-31 bits). Vacated bits on the right are filled with 0. Shifting left by n is equivalent to multiplying by 2^n (without overflow checking). Example: sll $t1,$t1,2 multiplies $t1 by 4.

sll $t1,$t2,10

sllv $reg, $reg, $reg

Shift left logical variable : Sets $t1 = $t2 << ($t3 & 31). Like 'sll' but the shift amount is taken from the lowest 5 bits of register $t3 rather than an immediate constant. The upper 27 bits of $t3 are ignored.

sllv $t1,$t2,$t3

slt $reg, $reg, $reg

Set on less than (signed) : Sets $t1 = 1 if $t2 < $t3 (signed comparison), otherwise $t1 = 0. Useful for conditional logic without branches. Pair with 'bne $t1,$zero,label' or 'beq $t1,$zero,label' to branch on the result.

slt $t1,$t2,$t3

slti $reg, $reg, imm

Set on less than immediate (signed) : Sets $t1 = 1 if $t2 < immediate (sign-extended to 32 bits), otherwise $t1 = 0. Convenient for loop bounds and range checking without a separate load instruction.

slti $t1,$t2,-100

sltiu $reg, $reg, imm

Set on less than immediate unsigned : Sets $t1 = 1 if $t2 < immediate using unsigned comparison. The immediate is sign-extended to 32 bits first, then interpreted as unsigned. Commonly used to test if a value is below a limit without needing a separate register.

sltiu $t1,$t2,-100

sltu $reg, $reg, $reg

Set on less than unsigned : Sets $t1 = 1 if $t2 < $t3 using unsigned comparison, otherwise $t1 = 0. Treats both operands as unsigned 32-bit integers (0 to 4294967295). Use this when comparing memory addresses or unsigned counters.

sltu $t1,$t2,$t3

sne $reg, $reg, [$reg / imm]

Set Not Equal : if $t2 not equal to $t3 then set $t1 to 1 else 0

sne $t1,$t2,$t3

Set Not Equal : if $t2 not equal to 16-bit immediate then set $t1 to 1 else 0

sne $t1,$t2,-100

Set Not Equal : if $t2 not equal to 32-bit immediate then set $t1 to 1 else 0

sne $t1,$t2,100000

sqrt.d $freg, $freg

Floating-point square root (double) : Sets $f2 = sqrt($f4) using double-precision arithmetic. Both register numbers must be even. Returns NaN if $f4 is negative.

sqrt.d $f2,$f4

sqrt.s $freg, $freg

Floating-point square root (single) : Sets $f0 = sqrt($f1) using single-precision arithmetic. Returns NaN if $f1 is negative.

sqrt.s $f0,$f1

sra $reg, $reg, imm

Shift right arithmetic : Sets $t1 = $t2 >> immediate (0-31 bits). Vacated bits on the left are filled with copies of the sign bit, preserving the sign of negative numbers. Shifting right by n is equivalent to signed division by 2^n rounding toward negative infinity.

sra $t1,$t2,10

srav $reg, $reg, $reg

Shift right arithmetic variable : Sets $t1 = $t2 >> ($t3 & 31). Like 'sra' but the shift amount is taken from the lowest 5 bits of register $t3. Vacated bits are sign-filled.

srav $t1,$t2,$t3

srl $reg, $reg, imm

Shift right logical : Sets $t1 = $t2 >>> immediate (0-31 bits). Vacated bits on the left are filled with 0 (unsigned shift). Shifting right by n is equivalent to unsigned division by 2^n. Use 'sra' to preserve the sign bit instead.

srl $t1,$t2,10

srlv $reg, $reg, $reg

Shift right logical variable : Sets $t1 = $t2 >>> ($t3 & 31). Like 'srl' but the shift amount is taken from the lowest 5 bits of register $t3 rather than an immediate constant. Vacated bits are zero-filled.

srlv $t1,$t2,$t3

sub $reg, $reg, [$reg / imm]

Subtract (signed, overflow trap) : Sets $t1 = $t2 - $t3 using signed 32-bit arithmetic. Raises an overflow exception if the true result does not fit in 32 bits. Use 'subu' when overflow should be silently ignored.

sub $t1,$t2,$t3

SUBtraction : set $t1 to ($t2 minus 16-bit immediate)

sub $t1,$t2,-100

SUBtraction : set $t1 to ($t2 minus 32-bit immediate)

sub $t1,$t2,100000

sub.d $freg, $freg, $freg

Floating-point subtract (double) : Sets $f2 = $f4 - $f6 using IEEE 754 double-precision (64-bit) arithmetic. All register numbers must be even.

sub.d $f2,$f4,$f6

sub.s $freg, $freg, $freg

Floating-point subtract (single) : Sets $f0 = $f1 - $f3 using IEEE 754 single-precision (32-bit) arithmetic.

sub.s $f0,$f1,$f3

subi $reg, $reg, imm

SUBtraction Immediate : set $t1 to ($t2 minus 16-bit immediate)

subi $t1,$t2,-100

SUBtraction Immediate : set $t1 to ($t2 minus 32-bit immediate)

subi $t1,$t2,100000

subiu $reg, $reg, imm

SUBtraction Immediate Unsigned : set $t1 to ($t2 minus 32-bit immediate), no overflow

subiu $t1,$t2,100000

subu $reg, $reg, [$reg / imm]

Subtract unsigned (no overflow trap) : Sets $t1 = $t2 - $t3. No exception is raised on overflow; the result wraps modulo 2^32. The most common subtract instruction in practice.

subu $t1,$t2,$t3

SUBtraction Unsigned : set $t1 to ($t2 minus 32-bit immediate), no overflow

subu $t1,$t2,100000

sw $reg, [imm($reg) / LO(id) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)], ($reg)

Store word : Writes the 32-bit value in $t1 to memory at address ($t2 + offset). The address must be word-aligned (divisible by 4). Example: 'sw $t0,0($sp)' stores a value at the top of the stack.

sw $t1,-100($t2)

Store to Address : Write to label's address, reached through the %hi already in $t2

sw $t1,%lo(label)($t2)

Store Word : Store $t1 contents into effective memory word address

sw $t1,($t2) sw $t1,-100 sw $t1,100 sw $t1,100000 sw $t1,100($t2) sw $t1,100000($t2) sw $t1,label($t2) sw $t1,label+100000 sw $t1,label+100000($t2)

Store Word : Store $t1 contents into memory word at label's address

sw $t1,label

swc1 $freg, [imm($reg) / LO(id) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)], ($reg)

Store word from FP register : Writes the 32-bit value in FP register $f1 to memory at address ($t2 + offset). Typically used to store a single-precision float to memory. Address must be word-aligned.

swc1 $f1,-100($t2)

Store to Address : Write to label's address, reached through the %hi already in $t2

swc1 $f1,%lo(label)($t2)

Store Word Coprocessor 1 : Store 32-bit value from $f1 to effective memory word address

swc1 $f1,($t2) swc1 $f1,-100 swc1 $f1,100000 swc1 $f1,100000($t2) swc1 $f1,label swc1 $f1,label($t2) swc1 $f1,label+100000 swc1 $f1,label+100000($t2)

swl $reg, [imm($reg) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)]

Store word left (unaligned) : Writes 1-4 bytes from the most-significant (left) bytes of $t1 into memory starting at the effective byte address and working toward the low byte of the containing aligned word. Use together with 'swr' to store a full word at an unaligned address.

swl $t1,-100($t2)

Store Word Left : Store high-order 1 to 4 bytes of $t1 into memory, starting with effective memory byte address and continuing through the low-order byte of its word

swl $t1,($t2) swl $t1,-100 swl $t1,100 swl $t1,100000 swl $t1,100($t2) swl $t1,100000($t2) swl $t1,label swl $t1,label($t2) swl $t1,label+100000 swl $t1,label+100000($t2)

swr $reg, [imm($reg) / ($reg) / imm / id / id($reg) / id+imm / id+imm($reg)]

Store word right (unaligned) : Writes 1-4 bytes from the least-significant (right) bytes of $t1 into memory starting at the high byte of the containing aligned word and working toward the effective byte address. Use together with 'swl' to store a full word at an unaligned address.

swr $t1,-100($t2)

Store Word Right : Store low-order 1 to 4 bytes of $t1 into memory, starting with high-order byte of word containing effective memory byte address and continuing through that byte address

swr $t1,($t2) swr $t1,-100 swr $t1,100 swr $t1,100000 swr $t1,100($t2) swr $t1,100000($t2) swr $t1,label swr $t1,label($t2) swr $t1,label+100000 swr $t1,label+100000($t2)

sync imm

Synchronize shared memory : Orders the loads and stores around it, so that another processor observes them in program order. This simulator runs a single processor and completes every access immediately, so there is nothing to reorder and 'sync' does nothing. It is accepted so that compiler output and real-world code assemble unchanged.

sync

Synchronize shared memory (typed) : Like 'sync', but the operand selects which accesses to order. This simulator completes every access immediately, so the type is ignored and the instruction does nothing.

sync 1

syscall

System call : Invokes an OS service identified by the integer in $v0. Common services: 1=print integer ($a0), 4=print string (addr in $a0), 5=read integer (result in $v0), 8=read string ($a0=buf addr, $a1=len), 10=exit. See the Help menu for the full list.

syscall

teq $reg, $reg

Trap if equal : Raises a trap exception if $t1 == $t2. In MARS this halts execution. On real hardware it triggers a trap handler. Useful as a guarded assertion or to catch forbidden conditions (e.g., division by zero guard).

teq $t1,$t2

teqi $reg, imm

Trap if equal to immediate : Raises a trap exception if $t1 == immediate (sign-extended to 32 bits). Immediate variant of 'teq'. Useful for checking a register against a known constant at runtime.

teqi $t1,-100

tge $reg, $reg

Trap if greater or equal (signed) : Raises a trap exception if $t1 >= $t2 (signed comparison).

tge $t1,$t2

tgei $reg, imm

Trap if greater or equal to immediate (signed) : Raises a trap if $t1 >= immediate (sign-extended to 32 bits).

tgei $t1,-100

tgeiu $reg, imm

Trap if greater or equal to immediate (unsigned) : Raises a trap if $t1 >= immediate using unsigned comparison. The immediate is sign-extended to 32 bits then interpreted as unsigned.

tgeiu $t1,-100

tgeu $reg, $reg

Trap if greater or equal (unsigned) : Raises a trap exception if $t1 >= $t2 using unsigned comparison. Treats both values as unsigned 32-bit integers.

tgeu $t1,$t2

tlt $reg, $reg

Trap if less than (signed) : Raises a trap exception if $t1 < $t2 (signed comparison).

tlt $t1,$t2

tlti $reg, imm

Trap if less than immediate (signed) : Raises a trap exception if $t1 < immediate (sign-extended to 32 bits).

tlti $t1,-100

tltiu $reg, imm

Trap if less than immediate (unsigned) : Raises a trap exception if $t1 < immediate using unsigned comparison. The immediate is sign-extended to 32 bits then interpreted as unsigned.

tltiu $t1,-100

tltu $reg, $reg

Trap if less than (unsigned) : Raises a trap exception if $t1 < $t2 using unsigned comparison.

tltu $t1,$t2

tne $reg, $reg

Trap if not equal : Raises a trap exception if $t1 != $t2. In MARS this halts execution. Opposite of 'teq'.

tne $t1,$t2

tnei $reg, imm

Trap if not equal to immediate : Raises a trap exception if $t1 != immediate (sign-extended to 32 bits).

tnei $t1,-100

trunc.w.d $freg, $freg

Truncate double-precision to word : Converts the double-precision float in $f2 (even-numbered register) to a 32-bit integer by rounding toward zero (dropping the fractional part), storing the result in $f1.

trunc.w.d $f1,$f2

trunc.w.s $freg, $freg

Truncate single-precision to word : Converts the single-precision float in $f1 to a 32-bit integer by rounding toward zero (drops the fractional part), and stores the result in $f0. Equivalent to C-style (int) cast.

trunc.w.s $f0,$f1

ulh $reg, [imm($reg) / imm / id / id+imm / ($reg) / id($reg) / id+imm($reg)]

Unaligned Load Halfword : Set $t1 to the 16 bits, sign-extended, starting at effective memory byte address

ulh $t1,-100($t2) ulh $t1,100000 ulh $t1,label ulh $t1,label+100000 ulh $t1,($t2) ulh $t1,100000($t2) ulh $t1,label($t2) ulh $t1,label+100000($t2)

ulhu $reg, [imm($reg) / imm / id / id+imm / ($reg) / id($reg) / id+imm($reg)]

Unaligned Load Halfword : Set $t1 to the 16 bits, zero-extended, starting at effective memory byte address

ulhu $t1,-100($t2) ulhu $t1,100000 ulhu $t1,label ulhu $t1,label+100000 ulhu $t1,($t2) ulhu $t1,100000($t2) ulhu $t1,label($t2) ulhu $t1,label+100000($t2)

ulw $reg, [imm($reg) / imm / id / id+imm / ($reg) / id($reg) / id+imm($reg)]

Unaligned Load Word : Set $t1 to the 32 bits starting at effective memory byte address

ulw $t1,-100($t2) ulw $t1,100000 ulw $t1,label ulw $t1,label+100000 ulw $t1,($t2) ulw $t1,100000($t2) ulw $t1,label($t2) ulw $t1,label+100000($t2)

ush $reg, [imm($reg) / imm / id / id+imm / ($reg) / id($reg) / id+imm($reg)]

Unaligned Store Halfword: Store low-order halfword $t1 contents into the 16 bits starting at effective memory byte address

ush $t1,-100($t2) ush $t1,100000 ush $t1,label ush $t1,label+100000 ush $t1,($t2) ush $t1,100000($t2) ush $t1,label($t2) ush $t1,label+100000($t2)

usw $reg, [imm($reg) / imm / id / id+imm / ($reg) / id($reg) / id+imm($reg)]

Unaligned Store Word : Store $t1 contents into the 32 bits starting at effective memory byte address

usw $t1,-100($t2) usw $t1,100000 usw $t1,label usw $t1,label+100000 usw $t1,($t2) usw $t1,100000($t2) usw $t1,label($t2) usw $t1,label+100000($t2)

wait

Wait for interrupt : Halts the processor until an interrupt arrives. This simulator delivers no interrupts, so there would be nothing to wake it; rather than hang, 'wait' does nothing and execution continues. It is accepted so that kernel-style code assembles unchanged.

wait

wsbh $reg, $reg

Word swap bytes within halfwords : Sets $t1 to $t2 with the two bytes of each halfword exchanged, so 0xAABBCCDD becomes 0xBBAADDCC. Combined with 'rotr $t1,$t1,16' this reverses all four bytes, converting between little and big endian.

wsbh $t1,$t2

xor $reg, [$reg / imm], [$reg / imm]

Bitwise XOR (exclusive OR) : Sets $t1 = $t2 ^ $t3. Each bit of $t1 is 1 if the corresponding bits in $t2 and $t3 differ. Used to toggle specific bits, detect differences, or implement simple encryption/checksums.

xor $t1,$t2,$t3

XOR : set $t1 to ($t2 bitwise-exclusive-OR 16-bit unsigned immediate)

xor $t1,$t2,100

XOR : set $t1 to ($t1 bitwise-exclusive-OR 16-bit unsigned immediate)

xor $t1,100

xori $reg, [$reg / imm], imm

Bitwise XOR immediate : Sets $t1 = $t2 ^ immediate. The 16-bit immediate is zero-extended before the XOR. Useful for toggling specific bits.

xori $t1,$t2,100

XOR Immediate : set $t1 to ($t2 bitwise-exclusive-OR 32-bit immediate)

xori $t1,$t2,100000

XOR Immediate : set $t1 to ($t1 bitwise-exclusive-OR 16-bit unsigned immediate)

xori $t1,100

XOR Immediate : set $t1 to ($t1 bitwise-exclusive-OR 32-bit immediate)

xori $t1,100000

Directives

MIPS directives are used to define the structure of the program. They are not instructions that are executed by the CPU, but rather instructions that are used by the assembler to define the structure of the program.

.data

Declares a section for storing initialized data, such as variables.

.text

Declares a section for storing executable instructions. This is where program logic is written.

.kdata

Declares a section for storing kernel-mode initialized data.

.ktext

Declares a section for storing kernel-mode executable instructions.

.word

Allocates one or more 32-bit (4-byte) words in memory.

Example:

values: .word 1, 2, 3, 4

.half

Allocates one or more 16-bit (2-byte) halfwords in memory.

Example:

values: .half 1234, 5678

.byte

Allocates one or more 8-bit (1-byte) values in memory.

Example:

flags: .byte 0, 1, 1, 0

.float

Allocates a single-precision floating-point (32-bit) number in memory.

.double

Allocates a double-precision floating-point (64-bit) number in memory.

.asciiz

Stores a null-terminated string (C-style string).

Example:

message: .asciiz "Hello, world!"

.ascii

Stores a string without a null terminator. Useful when manually handling string length.

.space

Reserves a specified number of bytes in memory without initializing them.

Example:

buffer: .space 100   # Reserves 100 bytes

.align

Aligns the next data to a 2^n-byte boundary.

Example:

.align 2   # Aligns to a 4-byte boundary

.globl

Marks a symbol as global, making it accessible from other files.

Example:

.globl main   # Makes 'main' visible to the linker

.extern

Declares a symbol that is defined in another file, specifying its size.

.macro

Defines a macro, which allows writing reusable code blocks.

.end_macro

Ends a macro definition.

.include

Includes an external assembly file.

Example:

.include "myfile.s"

.eqv

Defines a symbolic constant, similar to #define in C.

Example:

.eqv SIZE 10

.set

Configures assembler settings, such as allowing modifications to the $at register.

Example:

.set noat  # Allows use of register $at

.bss

Declares an uninitialized data section, typically used for reserving large blocks of memory.

.frame

Describes a function's stack frame for the debugger: base register, stack size and return register. MARS accepts it and does nothing with it, so that compiler output assembles unchanged.

.ent

Marks the start of a function for the debugger. MARS accepts it and does nothing with it, so that compiler output assembles unchanged.

.end

Marks the end of a function for the debugger. MARS accepts it and does nothing with it, so that compiler output assembles unchanged.

.local

Marks a symbol as local to this file for the linker. MARS accepts it and does nothing with it, so that compiler output assembles unchanged.

.section

Switches to the named section. A read-only or zeroed section becomes part of the data segment here.

Example:

.section .rodata

.rdata

Declares a section for read-only initialized data, such as string literals. Read-only data is not stored separately in this simulator, so it joins the data segment.

.sdata

Alias for .rdata.

.sbss

Alias for .bss.

.comm

Reserves bytes for an uninitialized global variable, the way a C compiler declares one. Takes a symbol, a size in bytes and an optional alignment, and leaves the current section unchanged.

Example:

.comm total, 4, 4

.lcomm

Like .comm, but for a symbol local to this file, as a C compiler declares an uninitialized static variable.

.zero

Reserves the given number of bytes, which read as zero. Alias for .space.

.p2align

Alias for .align: aligns the next item on a 2^n byte boundary.

.balign

Aligns the next item on the given byte boundary, written directly rather than as a power of two.

Example:

.balign 8

.2byte

Alias for .half.

.4byte

Alias for .word.

.asciz

Alias for .asciiz: stores a null-terminated string.

.string

Alias for .asciiz: stores a null-terminated string.

.global

Alias for .globl.

Syscalls

MIPS syscalls are used to make requests to the operating system. They are not instructions that are executed by the CPU, but rather instructions that are used by the simulator to make requests to the operating system.

Each syscall has a unique code that is used to identify it. You must put the syscall code inside the the $v0 register before calling the syscall instruction.

As an example:

# Load the integer 42 into register $a0, which is
# the register that will be printed by the syscall
li $a0, 42

# Set the syscall code for printing an integer
li $v0, 1
syscall

1 - Print integer

Arguments

$a0
integer to print

2 - Print float

Arguments

$f12
float to print

3 - Print double

Arguments

$f12
double to print

4 - Print string

Arguments

$a0
address of null-terminated string to print

5 - Read integer

Result

$v0
contains integer read

6 - Read float

Result

$f0
contains float read

7 - Read double

Result

$f0
contains double read

8 - Read string

Service 8 - Follows semantics of UNIX 'fgets'. For specified length n, string can be no longer than n-1. If less than that, adds newline to end. In either case, then pads with null byte If n = 1, input is ignored and null byte placed at buffer address. If n < 1, input is ignored and nothing is written to the buffer.

Arguments

$a0
address of input buffer
$a1
maximum number of characters to read

9 - Sbrk (allocate heap memory)

Result

$v0
contains address of allocated memory

Arguments

$a0
number of bytes to allocate

10 - Exit (terminate execution)

11 - Print character

Service 11 - Prints ASCII character corresponding to contents of low-order byte.

Arguments

$a0
character to print

12 - Read character

Result

$v0
contains character read

13 - Open file

Service 13 - MARS implements three flag values: 0 for read-only, 1 for write-only with create, and 9 for write-only with create and append. It ignores mode. The returned file descriptor will be negative if the operation failed. MARS maintains file descriptors internally and allocates them starting with 3. File descriptors 0, 1 and 2 are always open for: reading from standard input, writing to standard output, and writing to standard error, respectively (new in release 4.3).

Result

$v0
contains file descriptor (negative if error)

Arguments

$a0
address of null-terminated string containing filename
$a1
flags
$a2
mode

14 - Read from file

Services 13,14,15 - In MARS 3.7, the result register was changed to $v0 for SPIM compatability. It was previously $a0 as erroneously printed in Appendix B of Computer Organization and Design,.

Result

$v0
contains number of characters read (0 if end-of-file, negative if error)

Arguments

$a0
file descriptor
$a1
address of input buffer
$a2
maximum number of characters to read

15 - Write to file

Services 13,14,15 - In MARS 3.7, the result register was changed to $v0 for SPIM compatability. It was previously $a0 as erroneously printed in Appendix B of Computer Organization and Design,.

Result

$v0
contains number of characters written (negative if error)

Arguments

$a0
file descriptor
$a1
address of output buffer
$a2
number of characters to write

16 - Close file

Arguments

$a0
file descriptor

17 - Exit2 (terminate with value)

Service 17 - If the MIPS program is run under control of the MARS graphical interface (GUI), the exit code in $a0 is ignored.

Arguments

$a0
termination result

30 - Time (program time)

Service 30 - Milliseconds since the run started, rather than since 1 January 1970 as in MARS: it is the time the program can observe passing, and in a testcase it comes from a virtual clock that starts at zero and only advances through the waits of service 32.

Result

$a0
low order 32 bits of the program time
$a1
high order 32 bits of the program time

32 - Sleep

Service 32 - Lets that much program time pass before the next instruction. The editor stays responsive while it waits and the wait costs no instructions, so a program idling on the keyboard never reaches the execution limit; in a testcase it completes at once and advances the virtual clock instead.

Arguments

$a0
the length of time to sleep in milliseconds

34 - Print integer in hexadecimal

Displayed value is 8 hexadecimal digits, left-padding with zeroes if necessary.

Arguments

$a0
integer to print

35 - Print integer in binary

Displayed value is 32 bits, left-padding with zeroes if necessary.

Arguments

$a0
integer to print

36 - Print integer as unsigned

Displayed as unsigned decimal value.

Arguments

$a0
integer to print

41 - Random int

Each stream (identified by $a0 contents) is modeled by a different Random object. There are no default seed values, so use the Set Seed service (40) if replicated random sequences are desired.

Result

$a0
contains the next pseudorandom, uniformly distributed int value from this random number generator's sequence

Arguments

$a0
i.d. of pseudorandom number generator (any int)

42 - Random int range

Each stream (identified by $a0 contents) is modeled by a different Random object. There are no default seed values, so use the Set Seed service (40) if replicated random sequences are desired.

Result

$a0
contains pseudorandom, uniformly distributed int value in the range 0 <= [int] < [upper bound], drawn from this random number generator's sequence

Arguments

$a0
i.d. of pseudorandom number generator (any int)
$a1
upper bound of range of returned values

43 - Random float

Each stream (identified by $a0 contents) is modeled by a different Random object. There are no default seed values, so use the Set Seed service (40) if replicated random sequences are desired.

Result

$f0
contains the next pseudorandom, uniformly distributed float value in the range 0.0 <= f < 1.0 from this random number generator's sequence

Arguments

$a0
i.d. of pseudorandom number generator (any int)

44 - Random double

Each stream (identified by $a0 contents) is modeled by a different Random object. There are no default seed values, so use the Set Seed service (40) if replicated random sequences are desired.

Result

$f0
contains the next pseudorandom, uniformly distributed double value in the range 0.0 <= f < 1.0 from this random number generator's sequence

Arguments

$a0
i.d. of pseudorandom number generator (any int)

50 - ConfirmDialog

Result

$a0
contains value of user-chosen option 0: Yes 1: No 2: Cancel

Arguments

$a0
address of null-terminated string that is the message to user

51 - InputDialogInt

Result

$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

Arguments

$a0
address of null-terminated string that is the message to user

52 - InputDialogFloat

Result

$f0
contains float 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

Arguments

$a0
address of null-terminated string that is the message to user

53 - InputDialogDouble

Result

$f0
contains double 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

Arguments

$a0
address of null-terminated string that is the message to user

54 - InputDialogString

See Service 8 note below table

Result

$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.

Arguments

$a0
address of null-terminated string that is the message to user
$a1
address of input buffer
$a2
maximum number of characters to read

55 - MessageDialog

N/A

Arguments

$a0
address of null-terminated string that is the message to user
$a1
the type of message to be displayed: 0: error message, indicated by Error icon 1: information message, indicated by Information icon 2: warning message, indicated by Warning icon 3: question message, indicated by Question icon other: plain message (no icon displayed)

56 - MessageDialogInt

N/A

Arguments

$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

57 - MessageDialogFloat

N/A

Arguments

$a0
address of null-terminated string that is an information-type message to user
$f12
float value to display in string form after the first string

58 - MessageDialogDouble

N/A

Arguments

$a0
address of null-terminated string that is an information-type message to user
$f12
double value to display in string form after the first string

59 - MessageDialogString

N/A

Arguments

$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

Registers

MIPS has 32 general purpose registers of 32 bits each, and two coprocessors with registers of their own: the floating point registers of coprocessor 1 and the exception registers of coprocessor 0.

General purpose registers

$zero ($0)

Always contains the value 0. Any write attempt to this register is silently ignored.

$at ($1)

Assembly temporary, reserved for assembler internal use. It is used by macro instructions like li or la to break them into multiple real instructions. You can take control of it using the .set noat directive, but after that, macro instructions that rely on it will stop working.

$v0 - $v1 ($2 - $3)

Used to return non-floating point values from a subroutine. If the return value fits in 32 bits, only $v0 is used; for 64-bit values, the high word goes in $v1. $v0 also holds the system call number before a syscall instruction.

$a0 - $a3 ($4 - $7)

Arguments, used to pass the first four non-floating point arguments to a subroutine. Additional arguments are passed on the stack.

$t0 - $t7 ($8 - $15)

Temporary registers, their values are not preserved across subroutine calls. The caller is responsible for saving them if needed.

$s0 - $s7 ($16 - $23)

Saved registers, subroutines must preserve their values across calls, either by not using them or by saving and restoring them on the stack.

$t8 - $t9 ($24 - $25)

Additional temporary registers, same conventions as $t0-$t7. Note that $t9 has a special role in PIC code: by convention it holds the address of the called function, allowing the callee to compute $gp.

$k0 - $k1 ($26 - $27)

Reserved for OS/interrupt handler use. They can be overwritten at any time by an interrupt or trap handler, so user code should never rely on their values.

$gp ($28)

Global pointer, used for two distinct purposes. In PIC code (Linux shared libraries), it points to the GOT (Global Offset Table), a table of pointers that the dynamic loader fills at runtime with the real addresses of external symbols. In non-PIC code (embedded systems), it points to the center of a compact region of small global/static variables, allowing them to be accessed with a single instruction using a signed 16-bit offset (covering ±32KB, 64KB total).

$sp ($29)

Stack pointer, points to the top of the stack. It is explicitly adjusted by the callee on subroutine entry and exit.

$fp ($30)

Frame pointer, also known as $s8. Used by a subroutine to track the stack frame when the stack pointer cannot be used directly, for example when the stack size is not known at compile time (e.g. when using alloca()).

$ra ($31)

Return address, automatically written by jal with the address of the instruction following the call. The subroutine returns by executing jr $ra. Functions that themselves call other subroutines must save $ra on the stack first, since jal would otherwise overwrite it.

FPU (coprocessor 1)

Floating point numbers live in a coprocessor with registers and instructions of its own: add.s adds two single precision values the way add adds two integers, and no arithmetic instruction reads a register from each file. Crossing between them is a job of its own. mtc1 and mfc1 name one general register and one floating point register and move the bits between them without converting anything, while cvt.s.w and cvt.w.s convert between an integer and a float once the value is inside the coprocessor.

This simulator has no li.s or li.d pseudo-instruction. A constant is either written in the data section as a .float or a .double and loaded with l.s or l.d, or assembled as a bit pattern in a general register and moved across with mtc1.

$f0 - $f31 (32 bits each)

The floating point registers. Each one holds a single precision value, which is what the .s instructions read and write. By convention $f12 and $f14 pass the first two floating point arguments to a subroutine and $f0 returns the result, and the syscalls that read and print floats use the same registers.

Double precision pairs ($f0, $f2, $f4 … $f30)

A double precision value is 64 bits, so it occupies a pair of registers: the even one holds the low word and the odd one above it holds the high word. Only the even register is ever named, so l.d $f4, value fills both $f4 and $f5, and add.d $f0, $f2, $f4 reads and writes three pairs. Naming an odd register in a .d instruction is an error. This is also why the double format of the registers panel leaves the odd rows blank.

Condition flags (0 - 7)

A floating point comparison writes no register. It writes one of eight condition flags, and bc1t and bc1f branch on one of them, which is how a float comparison reaches a branch. The two operand form c.lt.s $f0, $f2 writes flag 0, the flag that bc1t label reads when it is given no number; the three operand form c.lt.s 3, $f0, $f2 writes flag 3, and bc1t 3, label is the branch that reads it. Eight flags mean eight comparisons can be kept apart at once. The registers panel shows them in the row above the registers of the file.

CP0 (coprocessor 0)

Coprocessor 0 is the part of the processor that deals with exceptions: a bad memory address, an overflow on add, a break. The machine writes these registers itself, at the moment it stops what the program was doing and jumps to the handler, which is whatever the program assembled at the exception vector with .ktext 0x80000180. A program with no handler there stops instead, with the message the simulator prints. The handler reads these registers with mfc0, as in mfc0 $k0, $13, to find out what happened and where, and writes them back with mtc0, as in mtc0 $k0, $14, which is how it steps the return address past the instruction that faulted before eret returns to it.

This simulator implements the four registers below, and it raises exceptions only: nothing in it delivers an interrupt, so the interrupt bits are values to read and write rather than something that changes what runs.

$8 (vaddr)

The address that caused the exception, when it was a memory one: the address the lw or sw failed on. It keeps whatever it held after any other kind of exception, so it is only worth reading once the cause says the exception was an address error.

$12 (status)

The interrupt mask and the enable bits. It starts at 0x0000FF11: every one of the eight interrupt levels unmasked, user mode, and interrupts enabled. The bit this simulator writes itself is bit 1, the exception level, which taking an exception sets and eret clears on the way back, so the register reads 0x0000FF13 inside a handler. A handler is free to change the mask and the enable bit with mtc0, as it would on a real processor, but since nothing here delivers an interrupt the change is only visible in the register.

$13 (cause)

Why the exception happened. Bits 2 to 6 hold the exception code, the number behind the message the simulator prints, so an address error on a load reads as 0x10, which is code 4 shifted up by two. The bits above them report pending interrupts on a real processor and stay zero here, because nothing in this simulator raises one. A handler that serves several causes reads this register first and branches on the code.

$14 (epc)

The address of the instruction that was interrupted. A handler that means to let the program continue returns to it, normally after adding 4 so that the instruction which trapped is not run a second time.

Screen and memory-mapped I/O

MIPS programs draw and read input through memory, not through system calls: the screen is a grid of words anywhere in memory, and the keyboard and the console are four words at 0xffff0000. Both are MARS's own tools, the bitmap display and the keyboard and display simulator, with the same parameters and the same register layout, so a program written for MARS runs here unchanged.

Bitmap display

One word of memory is one pixel. Its low 24 bits are the color, red in bits 23-16, green in 15-8 and blue in 7-0; the top byte is ignored. Words run left to right and then top to bottom, so the pixel below a word is one row of words further on.

The screen panel's Display button configures it, with MARS's own five parameters, and a program can ask for them itself with the @screen comment below. The parameters are saved with the project, and testcases run with them too.

1 Unit width and unit height in pixels: 1, 2, 4, 8, 16, 32. How large one word is drawn. Default 1 by 1.
2 Display width and height in pixels: 64, 128, 256, 512, 1024. Default 512 by 256. Divided by the unit size, they give the word grid: the default is 512 by 256 words, one megabyte of memory.
3 Base address for display: where the grid starts. 0x10000000 (global data), 0x10008000 ($gp), 0x10010000 (static data), 0x10040000 (heap), 0xffff0000 (memory map). Default 0x10010000 (static data), which is where .data puts your first label.
        .data
display:.space  262144          # 256 * 256 words

        .text
main:
        la      $t0, display
        li      $t1, 0x00ff8000 # low 24 bits: red 0xff, green 0x80, blue 0x00
        sw      $t1, 0($t0)     # the pixel at the top left
        sw      $t1, 1024($t0)  # 256 words further on: the one below it

Reserve the memory the grid covers, with .space or a label of your own: the screen shows whatever those words hold, and a program that writes past what it reserved is writing over something else. Undo walks the picture back with the code, because the picture is the memory the emulator rolled back.

Configuring the screen from the program

A comment line naming @screen sets those five parameters at every Build, before the first instruction runs, so opening a program and building it is all it takes. It is a comment, so the same file still assembles in MARS, where you set the parameters in the tool's window as usual.

# @screen unit=1 width=256 height=256 base=display

        .data
display:.space  262144          # 256 * 256 words

        .text
main:
        la      $t0, display
width

The display width in pixels, one of 64, 128, 256, 512, 1024.

height

The display height in pixels, one of 64, 128, 256, 512, 1024.

unit

How many pixels wide and high one word is drawn, one of 1, 2, 4, 8, 16, 32. unitWidth and unitHeight set the two separately.

base

Where the grid starts: a label the program defines, which is the point of it — the program never has to know the address — or an address such as 0x10010000 or 268500992. A label not on a word boundary is rounded down to one.

  • Order and spacing do not matter, commas are allowed between settings, and unitWidth, unit-width and unitwidth are the same name.
  • What the directive leaves out keeps the value it had, and a program with no @screen line changes nothing at all: the configuration stays yours.
  • A value MARS has no entry for, an unknown setting or a label that does not exist is a warning on the directive's line, never an error: a comment cannot stop a program from assembling. A size off the list is replaced by the nearest one on it, and anything else is left as it was.
  • Changing a parameter in the Display popover afterwards wins, until the next Build reads the comment again.

Keyboard and display registers

Four words carry one character each way. Click the screen panel to give the program the keyboard; the ring around it says the editor's own shortcuts are off while it has focus. What the program transmits is appended to the console transcript, the same one print services write to, which is also what testcases assert on.

0xffff0000 Receiver control

Bit 0 is Ready: a typed character is waiting in the receiver data register. The device sets it and clears it; a program only reads it.

0xffff0004 Receiver data

The typed character, in the low byte. Reading it takes that character; the next one, if any, appears at once and Ready stays set until the queue is empty.

0xffff0008 Transmitter control

Bit 0 is Ready, and here it is always set: the console never makes a program wait to print.

0xffff000c Transmitter data

Storing a character in the low byte prints it on the console. ASCII 12, a form feed, clears the console instead.

        li      $s0, 0xffff0000
poll:
        lw      $t0, 0($s0)     # receiver control
        andi    $t0, $t0, 1     # the Ready bit
        bnez    $t0, take
        li      $v0, 32         # nothing typed yet: a wait costs no instructions
        li      $a0, 10
        syscall
        j       poll
take:
        lw      $t1, 4($s0)     # receiver data, one character
        sw      $t1, 12($s0)    # transmitter data: print it

The receiver never loses a keystroke: what does not fit in the data register waits in a queue behind it, and Ready (1) stays set until that queue is empty. Bit 1 of either control register, MARS's interrupt-enable bit (2), stops the program with an error: this editor polls, it does not deliver device interrupts.

Program time

Service 30 ($v0 before a syscall) answers with the time in milliseconds, low word in $a0 and high word in $a1, and service 32 waits for the milliseconds in $a0. Time is counted from the start of the run rather than from 1970, so a program differences two reads exactly as it did before, and a wait costs no instructions — a program idling on the keyboard never reaches the execution limit. In a testcase both run on a virtual clock that starts at zero and only advances through the program's own waits, so a five second wait finishes at once and elapsed-time output is the same on every machine.

Differences from MARS

  • The display is always there: it is a panel next to the memory view rather than a tool you connect to the program before running it.
  • Interrupt-driven I/O is not supported. Setting the interrupt-enable bit of a control register stops the program with an error naming the feature; poll the Ready bit instead.
  • Time comes from the start of the run, and a testcase runs on a virtual clock. MARS answers with the host's wall clock.
  • There is no mouse: neither simulator's tools have one.
  • Programs live in examples/mips/ in the repository, one per feature, each naming the display it wants in an @screen comment; MARS has no such directive and ignores the line.