mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-19 16:42:33 +00:00
118 lines
4.9 KiB
Odin
118 lines
4.9 KiB
Odin
package rexcode_mips
|
|
|
|
// =============================================================================
|
|
// INSTRUCTION
|
|
// =============================================================================
|
|
|
|
Instruction_Flags :: bit_field u8 {
|
|
// Reserved for per-instance hints (e.g. taken-prediction, atomic
|
|
// suffixes, addressing-mode overrides for future extensions). The
|
|
// base ISA needs none of these at the instance level -- everything
|
|
// semantic is already in the mnemonic.
|
|
_: u8 | 8,
|
|
}
|
|
|
|
Instruction :: struct #packed {
|
|
ops: [4]Operand `fmt:"v,operand_count"`, // 64 bytes
|
|
mnemonic: Mnemonic, // 2 bytes
|
|
operand_count: u8, // 1 byte
|
|
flags: Instruction_Flags, // 1 byte
|
|
length: u8, // 1 byte — always 4 for now; will be 2 for future μMIPS / MIPS16e
|
|
_: [3]u8, // 3 bytes
|
|
}
|
|
#assert(size_of(Instruction) == 72)
|
|
|
|
// =============================================================================
|
|
// Builders (mirror x86's `inst_*` shapes; per the cross-arch contract)
|
|
// =============================================================================
|
|
|
|
@(require_results)
|
|
inst_none :: #force_inline proc "contextless" (m: Mnemonic) -> Instruction {
|
|
return Instruction{mnemonic = m, operand_count = 0, length = 4}
|
|
}
|
|
|
|
@(require_results)
|
|
inst_r :: #force_inline proc "contextless" (m: Mnemonic, a: Register) -> Instruction {
|
|
return Instruction{mnemonic = m, operand_count = 1, length = 4,
|
|
ops = {op_reg(a), {}, {}, {}}}
|
|
}
|
|
|
|
@(require_results)
|
|
inst_r_r :: #force_inline proc "contextless" (m: Mnemonic, dst, src: Register) -> Instruction {
|
|
return Instruction{mnemonic = m, operand_count = 2, length = 4,
|
|
ops = {op_reg(dst), op_reg(src), {}, {}}}
|
|
}
|
|
|
|
@(require_results)
|
|
inst_r_r_r :: #force_inline proc "contextless" (m: Mnemonic, dst, s1, s2: Register) -> Instruction {
|
|
return Instruction{mnemonic = m, operand_count = 3, length = 4,
|
|
ops = {op_reg(dst), op_reg(s1), op_reg(s2), {}}}
|
|
}
|
|
|
|
// MIPS three-operand immediate: $rt, $rs, imm (e.g. ADDI rt, rs, imm).
|
|
@(require_results)
|
|
inst_r_r_i :: #force_inline proc "contextless" (m: Mnemonic, rt, rs: Register, imm: i64) -> Instruction {
|
|
return Instruction{mnemonic = m, operand_count = 3, length = 4,
|
|
ops = {op_reg(rt), op_reg(rs), op_imm(imm, 2), {}}}
|
|
}
|
|
|
|
// Two-operand immediate (e.g. LUI rt, imm; LI variants).
|
|
@(require_results)
|
|
inst_r_i :: #force_inline proc "contextless" (m: Mnemonic, rt: Register, imm: i64) -> Instruction {
|
|
return Instruction{mnemonic = m, operand_count = 2, length = 4,
|
|
ops = {op_reg(rt), op_imm(imm, 2), {}, {}}}
|
|
}
|
|
|
|
// Load/store: reg + memory (LW $rt, disp($rs)).
|
|
@(require_results)
|
|
inst_r_m :: #force_inline proc "contextless" (m: Mnemonic, r: Register, mm: Memory, size: u8 = 4) -> Instruction {
|
|
return Instruction{mnemonic = m, operand_count = 2, length = 4,
|
|
ops = {op_reg(r), op_mem(mm, size), {}, {}}}
|
|
}
|
|
|
|
// Shift by immediate: $rd, $rt, shamt (SLL/SRL/SRA).
|
|
@(require_results)
|
|
inst_shift :: #force_inline proc "contextless" (m: Mnemonic, rd, rt: Register, shamt: u8) -> Instruction {
|
|
return Instruction{mnemonic = m, operand_count = 3, length = 4,
|
|
ops = {op_reg(rd), op_reg(rt), op_imm(i64(shamt), 1), {}}}
|
|
}
|
|
|
|
// Variable shift: $rd, $rt, $rs (SLLV/SRLV/SRAV).
|
|
inst_shift_v :: inst_r_r_r
|
|
|
|
// Single-operand: JR $rs, JALR $rd (with implicit RA), MFHI/MFLO/MTHI/MTLO,
|
|
// SYSCALL/BREAK take an imm code so they use inst_i below.
|
|
@(require_results)
|
|
inst_i :: #force_inline proc "contextless" (m: Mnemonic, imm: i64) -> Instruction {
|
|
return Instruction{mnemonic = m, operand_count = 1, length = 4,
|
|
ops = {op_imm(imm, 4), {}, {}, {}}}
|
|
}
|
|
|
|
// Two-reg branch + label (BEQ/BNE: rs, rt, target).
|
|
@(require_results)
|
|
inst_branch2 :: #force_inline proc "contextless" (m: Mnemonic, rs, rt: Register, label_id: u32) -> Instruction {
|
|
return Instruction{mnemonic = m, operand_count = 3, length = 4,
|
|
ops = {op_reg(rs), op_reg(rt), op_label(label_id), {}}}
|
|
}
|
|
|
|
// One-reg branch + label (BLTZ/BGEZ/BLEZ/BGTZ/BLTZAL/BGEZAL/...).
|
|
@(require_results)
|
|
inst_branch1 :: #force_inline proc "contextless" (m: Mnemonic, rs: Register, label_id: u32) -> Instruction {
|
|
return Instruction{mnemonic = m, operand_count = 2, length = 4,
|
|
ops = {op_reg(rs), op_label(label_id), {}, {}}}
|
|
}
|
|
|
|
// J-type jump (J/JAL: target only).
|
|
@(require_results)
|
|
inst_jump :: #force_inline proc "contextless" (m: Mnemonic, label_id: u32) -> Instruction {
|
|
return Instruction{mnemonic = m, operand_count = 1, length = 4,
|
|
ops = {op_label(label_id), {}, {}, {}}}
|
|
}
|
|
|
|
// COP0 move with explicit selector: MFC0 $rt, $rd, sel (R2+).
|
|
@(require_results)
|
|
inst_cp0_sel :: #force_inline proc "contextless" (m: Mnemonic, rt, rd: Register, sel: u8) -> Instruction {
|
|
return Instruction{mnemonic = m, operand_count = 3, length = 4,
|
|
ops = {op_reg(rt), op_reg(rd), op_imm(i64(sel), 1), {}}}
|
|
}
|