Skip to main content

Op

Enum Op 

Source
pub enum Op {
Show 143 variants Reserved, Add, Addu, Sub, Subu, Dadd, Daddu, Dsub, Dsubu, Slt, Sltu, And, Or, Xor, Nor, Addi, Addiu, Daddi, Daddiu, Slti, Sltiu, Andi, Ori, Xori, Lui, Sll, Srl, Sra, Dsll, Dsrl, Dsra, Dsll32, Dsrl32, Dsra32, Sllv, Srlv, Srav, Dsllv, Dsrlv, Dsrav, Mult, Multu, Div, Divu, Dmult, Dmultu, Ddiv, Ddivu, Mfhi, Mthi, Mflo, Mtlo, Lb, Lbu, Lh, Lhu, Lw, Lwu, Ld, Sb, Sh, Sw, Sd, Ll, Lld, Sc, Scd, Lwl, Lwr, Ldl, Ldr, Swl, Swr, Sdl, Sdr, J, Jal, Jr, Jalr, Beq, Bne, Blez, Bgtz, Bltz, Bgez, Bltzal, Bgezal, Beql, Bnel, Blezl, Bgtzl, Bltzl, Bgezl, Bltzall, Bgezall, Bc1f, Bc1t, Bc1fl, Bc1tl, Tge, Tgeu, Tlt, Tltu, Teq, Tne, Tgei, Tgeiu, Tlti, Tltiu, Teqi, Tnei, Cache, Cop0Extension, Cfc1, Ctc1, Mfc1, Dmfc1, Mtc1, Dmtc1, Lwc1, Ldc1, Swc1, Sdc1, Cop1Unimplemented, Cop1ReservedControl, Cop2ReservedControl, Mfc2, Dmfc2, Mtc2, Cop2, FpArith, Tlbr, Tlbwi, Tlbwr, Tlbp, Eret, Mfc0, Dmfc0, Mtc0, Dmtc0, Sync, Syscall, Break,
}
Expand description

The decoded operation. Only the integer subset so far; see the module docs.

Variants§

§

Reserved

Not (yet) a recognized encoding — raises a reserved-instruction exception rather than behaving as a NOP.

§

Add

ADD rd, rs, rt — traps on overflow.

§

Addu

ADDU rd, rs, rt.

§

Sub

SUB rd, rs, rt — traps on overflow.

§

Subu

SUBU rd, rs, rt.

§

Dadd

DADD rd, rs, rt — traps on overflow.

§

Daddu

DADDU rd, rs, rt.

§

Dsub

DSUB rd, rs, rt — traps on overflow.

§

Dsubu

DSUBU rd, rs, rt.

§

Slt

SLT rd, rs, rt.

§

Sltu

SLTU rd, rs, rt.

§

And

AND rd, rs, rt.

§

Or

OR rd, rs, rt.

§

Xor

XOR rd, rs, rt.

§

Nor

NOR rd, rs, rt.

§

Addi

ADDI rt, rs, imm — traps on overflow.

§

Addiu

ADDIU rt, rs, imm.

§

Daddi

DADDI rt, rs, imm — traps on overflow.

§

Daddiu

DADDIU rt, rs, imm.

§

Slti

SLTI rt, rs, imm.

§

Sltiu

SLTIU rt, rs, imm.

§

Andi

ANDI rt, rs, imm — immediate is zero-extended.

§

Ori

ORI rt, rs, imm — immediate is zero-extended.

§

Xori

XORI rt, rs, imm — immediate is zero-extended.

§

Lui

LUI rt, imm.

§

Sll

SLL rd, rt, sa. SLL $0, $0, 0 is the canonical NOP.

§

Srl

SRL rd, rt, sa.

§

Sra

SRA rd, rt, sa — reproduces the VR4300 erratum.

§

Dsll

DSLL rd, rt, sa.

§

Dsrl

DSRL rd, rt, sa.

§

Dsra

DSRA rd, rt, sa.

§

Dsll32

DSLL32 rd, rt, sasa + 32.

§

Dsrl32

DSRL32 rd, rt, sasa + 32.

§

Dsra32

DSRA32 rd, rt, sasa + 32.

§

Sllv

SLLV rd, rt, rs.

§

Srlv

SRLV rd, rt, rs.

§

Srav

SRAV rd, rt, rs — reproduces the VR4300 erratum.

§

Dsllv

DSLLV rd, rt, rs.

§

Dsrlv

DSRLV rd, rt, rs.

§

Dsrav

DSRAV rd, rt, rs.

§

Mult

MULT rs, rt.

§

Multu

MULTU rs, rt.

§

Div

DIV rs, rt.

§

Divu

DIVU rs, rt.

§

Dmult

DMULT rs, rt.

§

Dmultu

DMULTU rs, rt.

§

Ddiv

DDIV rs, rt.

§

Ddivu

DDIVU rs, rt.

§

Mfhi

MFHI rd.

§

Mthi

MTHI rs.

§

Mflo

MFLO rd.

§

Mtlo

MTLO rs.

§

Lb

LB rt, off(base) — signed byte.

§

Lbu

LBU rt, off(base).

§

Lh

LH rt, off(base) — signed halfword.

§

Lhu

LHU rt, off(base).

§

Lw

LW rt, off(base) — sign-extended into the 64-bit register.

§

Lwu

LWU rt, off(base) — zero-extended.

§

Ld

LD rt, off(base).

§

Sb

SB rt, off(base).

§

Sh

SH rt, off(base).

§

Sw

SW rt, off(base).

§

Sd

SD rt, off(base).

§

Ll

LL rt, off(base) — load word, sign-extend, set LLbit and LLAddr.

§

Lld

LLD rt, off(base) — the doubleword form.

§

Sc

SC rt, off(base) — store word iff LLbit; write the outcome to rt.

§

Scd

SCD rt, off(base) — the doubleword form.

§

Lwl

LWL rt, off(base).

§

Lwr

LWR rt, off(base).

§

Ldl

LDL rt, off(base).

§

Ldr

LDR rt, off(base).

§

Swl

SWL rt, off(base).

§

Swr

SWR rt, off(base).

§

Sdl

SDL rt, off(base).

§

Sdr

SDR rt, off(base).

§

J

J target — 26-bit region form.

§

Jal

JAL target — links to $31.

§

Jr

JR rs — register indirect.

§

Jalr

JALR rd, rs — register indirect, links to rd.

§

Beq

BEQ rs, rt, off.

§

Bne

BNE rs, rt, off.

§

Blez

BLEZ rs, off.

§

Bgtz

BGTZ rs, off.

§

Bltz

BLTZ rs, off.

§

Bgez

BGEZ rs, off.

§

Bltzal

BLTZAL rs, off — links to $31.

§

Bgezal

BGEZAL rs, off — links to $31.

§

Beql

BEQL — branch-likely.

§

Bnel

BNEL — branch-likely.

§

Blezl

BLEZL — branch-likely.

§

Bgtzl

BGTZL — branch-likely.

§

Bltzl

BLTZL — branch-likely.

§

Bgezl

BGEZL — branch-likely.

§

Bltzall

BLTZALL — branch-likely, links.

§

Bgezall

BGEZALL — branch-likely, links.

§

Bc1f

BC1F off — branch if the FP condition is clear.

§

Bc1t

BC1T off — branch if the FP condition is set.

§

Bc1fl

BC1FL — branch-likely on a clear FP condition.

§

Bc1tl

BC1TL — branch-likely on a set FP condition.

§

Tge

TGE rs, rt.

§

Tgeu

TGEU rs, rt.

§

Tlt

TLT rs, rt.

§

Tltu

TLTU rs, rt.

§

Teq

TEQ rs, rt.

§

Tne

TNE rs, rt.

§

Tgei

TGEI rs, imm.

§

Tgeiu

TGEIU rs, imm.

§

Tlti

TLTI rs, imm.

§

Tltiu

TLTIU rs, imm.

§

Teqi

TEQI rs, imm.

§

Tnei

TNEI rs, imm.

§

Cache

CACHE op, off(base) — a cache maintenance operation.

Operates on modeled cache state as of T-11-003: both primary caches hold real tags and data, so invalidate, write-back and the tag moves all act. This doc said “executed as an address-translating no-op” until the caches landed, which was true under ledger D-5 and is not any more — D-5 is superseded by D-6.

op’s rt slot is the operation selector, not a destination. What mattered first is that it does not raise — IPL3 and libdragon both issue it, so a Reserved decode blocks every real ROM. See docs/cpu.md.

§

Cop0Extension

A COP0 CO-class instruction in the funct 0x20-0x3F extension range, executed as a no-op.

§Why this is not Reserved

n64-systemtest probes for the emux emulator by executing COP0 CO funct 0x20 (its XDETECT) and reading the result out of a GPR. It does this from init_allocator, inside entrypointbefore main installs any exception handler. If a real VR4300 raised Reserved Instruction there, the suite would derail on every N64 it has ever run on, before printing a single line. It does not, so hardware must retire these encodings harmlessly.

The range is not a guess: the suite’s own constant for the probe is named XDETECT_CODE_EXTENSIONS_20_3F, i.e. emux claims funct 0x20-0x3F as extension space precisely because the VR4300 leaves it inert.

Decoding these to Reserved is what made the suite appear to hang: the RI dispatched to an uninstalled 0x8000_0180, ran zeros as NOPs into .text, and faulted there instead.

Recorded as an inference in the accuracy ledger (C-8), not a manual citation – the writeback behavior of the target GPR is untested.

§

Cfc1

CFC1 rt, fs — read a COP1 control register.

§

Ctc1

CTC1 rt, fs — write a COP1 control register.

§

Mfc1

MFC1 rt, fs — move the low 32 bits of an FPR to a GPR, sign-extended.

§

Dmfc1

DMFC1 rt, fs — move a full 64-bit FGR to a GPR.

§

Mtc1

MTC1 rt, fs — move the low 32 bits of a GPR to an FPR.

§

Dmtc1

DMTC1 rt, fs — move a full 64-bit GPR to an FGR.

§

Lwc1

LWC1 ft, off(base) — load a word into an FPR.

§

Ldc1

LDC1 ft, off(base) — load a doubleword into an FPR.

§

Swc1

SWC1 ft, off(base) — store an FPR word.

§

Sdc1

SDC1 ft, off(base) — store an FPR doubleword.

§

Cop1Unimplemented

A COP1 encoding this crate does not implement.

Distinct from Op::Reserved: the encoding is valid, so it must raise Coprocessor Unusable when Status.CU1 is clear rather than Reserved Instruction. Conflating the two sends the handler the wrong ExcCode.

§

Cop1ReservedControl

DCFC1 / DCTC1 — the 64-bit forms of CFC1/CTC1, which the VR4300 does not implement.

They are not a silent no-op and not Reserved Instruction: with CU1 set they raise a floating-point exception whose FCSR.Cause is only the unimplemented-operation bit, every other cause bit cleared. With CU1 clear they raise Coprocessor Unusable like any COP1 instruction, and FCSR is left untouched.

Distinct from Op::Cop1Unimplemented on purpose: that one really does retire silently, and folding these into it hides a trap behind a no-op.

§

Cop2ReservedControl

DCFC2 / DCTC2 — the 64-bit COP2 control moves.

COP2 exists on the VR4300 only as a stub, and these two encodings are not implemented at all: with CU2 set they raise Reserved Instruction, and with CU2 clear, Coprocessor Unusable.

Note the asymmetry with Op::Cop1ReservedControl, which raises a floating-point exception in the equivalent position. The two coprocessors decline in different ways and the encodings are otherwise identical, so this is easy to get uniformly wrong.

§

Mfc2

MFC2 — read the COP2 latch’s low 32 bits, sign-extended.

§

Dmfc2

DMFC2 — read all 64 bits of the COP2 latch.

§

Mtc2

MTC2 / DMTC2 — write the COP2 latch.

Both write the whole 64-bit GPR, despite MTC2 being nominally a 32-bit move: n64-systemtest writes a 64-bit value with MTC2 and reads all of it back with DMFC2.

§

Cop2

Any COP2 encoding.

The VR4300 has a COP2 unit, so these are architecturally valid encodings. With Status.CU2 clear they raise Coprocessor Unusable, not Reserved Instruction — the same distinction as Op::Cop1Unimplemented, and for the same reason.

Decoding them as Reserved is what produced n64-systemtest’s “Exception storm detected. Aborting.” during MFC2/MTC2/DMFC2/DMTC2: the suite expects ExcCode 11 and got 10 five times running, which tripped its recovery limit and truncated the whole run.

§

FpArith

A COP1 arithmetic operation, format and operation carried in the already-decoded fields: rs is the format, funct the operation, with rt=ft, rd=fs and sa=fd.

One variant rather than ~60, because the pipeline dispatches into crate::fpu on (fmt, funct) anyway and a variant per opcode would just be a second copy of that table.

§

Tlbr

TLBR — read the TLB entry Index names into the COP0 registers.

§

Tlbwi

TLBWI — write the COP0 registers into the entry Index names.

§

Tlbwr

TLBWR — write them into the entry Random names.

§

Tlbp

TLBP — probe for an entry matching EntryHi.

§

Eret

ERET — return from exception (UM Ch. 16, p. 434).

Has no delay slot and must not be placed in one, unlike every other control transfer in the instruction set.

§

Mfc0

MFC0 rt, rd — 32-bit read of a COP0 register, sign-extended.

§

Dmfc0

DMFC0 rt, rd — 64-bit read of a COP0 register.

§

Mtc0

MTC0 rt, rd — 32-bit write to a COP0 register.

§

Dmtc0

DMTC0 rt, rd — 64-bit write to a COP0 register.

§

Sync

SYNC“handled as a NOP” on this processor (UM §3.1).

Not folded into Op::Sll-as-NOP: it is a distinct encoding that compilers emit, and decoding it to Op::Reserved would raise a reserved-instruction exception on code that runs fine on hardware.

§

Syscall

SYSCALL.

§

Break

BREAK.

Implementations§

Source§

impl Op

Source

pub const fn is_64_bit(self) -> bool

Is this one of the MIPS III 64-bit operations?

They raise a Reserved Instruction exception when executed in 32-bit User or Supervisor mode. The manual states it once, as the epsilon marker in the opcode table (UM Figure 16-1, Key): “The operation code marked with an epsilon is valid in the 64-bit mode and 32-bit Kernel mode. In the 32-bit User or Supervisor mode, this code generates the reserved instruction exception.”

That legend — not the per-instruction “Exceptions” notes — is the authority, and reading it is what caught LWU: the set was first built from n64-systemtest’s 28 tested instructions, which do not include it. Kernel mode may use them at any width.

The *32 shift forms are included on the same rule rather than by extrapolation: DSLL32/DSRL32/DSRA32 carry the identical exception note in the manual, being 64-bit operations by the same definition.

Not included: DMFC0/DMTC0 and DMFC1/DMTC1, which the table does mark epsilon. Doubleword moves to and from a coprocessor are also governed by that coprocessor’s own usability and reserved-encoding rules (ledger C-18), and those raise a different exception; in User mode COP0 is unusable, so CpU is what hardware reports. n64-systemtest exercises neither, so rather than pick an ordering on no evidence they stay out — recorded here so the omission is a decision and not an oversight.

Source

pub const fn has_delay_slot(self) -> bool

Does this instruction have a branch delay slot?

Every jump and branch on MIPS does. The instruction after it executes before the target — which is why in_delay_slot has to travel with the instruction rather than live in a global flag.

Source

pub const fn reads_fp_condition(self) -> bool

Does this instruction read FCSR.C?

Only the BC1 family does, which is why the condition can be interlocked against rather than bypassed everywhere — see accuracy-ledger R-2 for the interlock that is still outstanding.

Source

pub const fn is_likely(self) -> bool

Is this a branch-likely form?

When a likely branch is not taken it nullifies its delay slot — the instruction is fetched and then squashed. An ordinary branch executes its delay slot either way. Getting this backwards silently executes or skips one instruction per untaken branch.

Source

pub const fn writes_hi_lo(self) -> bool

Does this operation write HI/LO rather than a general register?

Used for the MFHI/MFLO hazard window: a MFHI followed within two instructions by anything that writes HI produces hardware’s wrong result, and that is a non-interlocked hazard (see crate::alu::MFHI_MFLO_HAZARD_INSTRUCTIONS).

Trait Implementations§

Source§

impl Clone for Op

Source§

fn clone(&self) -> Op

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Op

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Op

Source§

fn default() -> Op

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for Op

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Hash for Op

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for Op

Source§

fn eq(&self, other: &Op) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for Op

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl Copy for Op

Source§

impl Eq for Op

Source§

impl StructuralPartialEq for Op

Auto Trait Implementations§

§

impl Freeze for Op

§

impl RefUnwindSafe for Op

§

impl Send for Op

§

impl Sync for Op

§

impl Unpin for Op

§

impl UnsafeUnpin for Op

§

impl UnwindSafe for Op

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,