summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2019-12-31 18:02:43 -0800
committeriximeow <me@iximeow.net>2020-01-12 17:00:43 -0800
commite70be7245eac6acd6dde565c69b55bf8f55653e9 (patch)
treed7185bd8979c5596194cbd6aef1ffc38a1961c65
parent88d6c8cd60753037c6316bc618a9d2fde14ecef9 (diff)
add the mips decoder
-rw-r--r--.gitignore1
-rw-r--r--Cargo.toml26
-rw-r--r--src/display.rs260
-rw-r--r--src/lib.rs793
-rw-r--r--src/mips_data.rs561
-rw-r--r--test/test.rs177
6 files changed, 1231 insertions, 587 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..e01e5ff
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+
+name = "yaxpeax-mips"
+version = "0.0.1"
+authors = [ "iximeow <me@iximeow.net>" ]
+license = "0BSD"
+repository = ""
+description = """
+A rust mips decoder
+"""
+
+[dependencies]
+yaxpeax-arch = { path = "../../yaxpeax-arch" }
+"termion" = "1.4.0"
+"serde" = "*"
+"serde_derive" = "*"
+"num_enum" = "*"
+
+[[test]]
+name = "test"
+path = "test/test.rs"
+
+[features]
+default = []
+
+use-serde = []
diff --git a/src/display.rs b/src/display.rs
new file mode 100644
index 0000000..036fb28
--- /dev/null
+++ b/src/display.rs
@@ -0,0 +1,260 @@
+use std::fmt;
+
+use crate::{Instruction, Opcode, Operand};
+
+impl fmt::Display for Instruction {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.opcode == Opcode::OR {
+ match (self.operand(&self.operands[0]), self.operand(&self.operands[1]), self.operand(&self.operands[2])) {
+ (Some(a), Some(b), Some(Operand::Reg(0))) => {
+ return write!(f, "move {}, {}", a, b);
+ }
+ _ => {}
+ }
+ } else if self.opcode == Opcode::BEQ {
+ match (self.operand(&self.operands[0]), self.operand(&self.operands[1]), self.operand(&self.operands[2])) {
+ (Some(Operand::Reg(a)), Some(Operand::Reg(b)), Some(Operand::Imm(offs))) => {
+ if a == b {
+ if offs < 0 {
+ return write!(f, "b $-{:#x}", -offs);
+ } else {
+ return write!(f, "b $+{:#x}", offs);
+ }
+ }
+ }
+ _ => {}
+ }
+ } else if self.opcode == Opcode::SLL {
+ match (self.operand(&self.operands[0]), self.operand(&self.operands[1]), self.operand(&self.operands[2])) {
+ (Some(Operand::Reg(dest)), Some(Operand::Reg(src)), Some(Operand::Shift(0))) => {
+ // TODO: should this also test for dest == `zero`?
+ if dest == src {
+ return write!(f, "nop");
+ }
+ }
+ _ => { }
+ }
+ }
+
+ fn display_operand(f: &mut fmt::Formatter, opcode: &Opcode, op: &Operand) -> fmt::Result {
+ if *opcode == Opcode::LUI {
+ // we show the immediate of LUI as an unsigned integer, becaue the docs say so.
+ if let Operand::Imm(imm) = op {
+ return write!(f, "{:#x}", *imm as u16);
+ }
+ } else if let Operand::Imm(imm) = op {
+ if *imm < 0 {
+ return write!(f, "-{:#x}", -imm);
+ } else {
+ return write!(f, "{:#x}", imm);
+ }
+ }
+
+ write!(f, "{}", op)
+ }
+ write!(f, "{}", self.opcode)?;
+
+ let mut wrote_operand = false;
+ for op in self.operands.iter() {
+ match self.operand(op) {
+ Some(op) => {
+ if wrote_operand {
+ write!(f, ", ")?;
+ } else {
+ write!(f, " ")?;
+ wrote_operand = true;
+ }
+ display_operand(f, &self.opcode, &op)?;
+ }
+ _ => {
+ return Ok(());
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl fmt::Display for Operand {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Operand::Reg(reg) => {
+ let name = [
+ "zero", "at",
+ "v0", "v1",
+ "a0", "a1", "a2", "a3",
+ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9",
+ "k0", "k1",
+ "gp", "sp", "fp", "ra"
+ ][*reg as usize];
+ write!(f, "{}", name)
+ }
+ Operand::Imm(imm) => {
+ write!(f, "{:#x}", imm)
+ }
+ Operand::BaseOffset(reg, offs) => {
+ let name = [
+ "zero", "at",
+ "v0", "v1",
+ "a0", "a1", "a2", "a3",
+ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9",
+ "k0", "k1",
+ "gp", "sp", "fp", "ra"
+ ][*reg as usize];
+ if *offs == 0 {
+ write!(f, "({})", name)
+ } else {
+ if *offs < 0 {
+ write!(f, "-{:#x}({})", -offs, name)
+ } else {
+ write!(f, "{:#x}({})", offs, name)
+ }
+ }
+ }
+ Operand::Shift(sa) => {
+ write!(f, "{:#x}", sa)
+ }
+ Operand::LongImm(imm) => {
+ write!(f, "{:#x}", imm)
+ }
+ Operand::JOffset(offs) => {
+ write!(f, "$+{:#x}", offs)
+ }
+ }
+ }
+}
+
+impl fmt::Display for Opcode {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Opcode::J => write!(f, "j"),
+ Opcode::JAL => write!(f, "jal"),
+ Opcode::BEQ => write!(f, "beq"),
+ Opcode::BNE => write!(f, "bne"),
+ Opcode::BLEZ => write!(f, "blez"),
+ Opcode::BGTZ => write!(f, "bgtz"),
+ Opcode::ADDI => write!(f, "addi"),
+ Opcode::ADDIU => write!(f, "addiu"),
+ Opcode::SLTI => write!(f, "slti"),
+ Opcode::SLTIU => write!(f, "sltiu"),
+ Opcode::ANDI => write!(f, "andi"),
+ Opcode::ORI => write!(f, "ori"),
+ Opcode::XORI => write!(f, "xori"),
+ Opcode::LUI => write!(f, "lui"),
+ Opcode::COP1 => write!(f, "cop1"),
+ Opcode::COP2 => write!(f, "cop2"),
+ Opcode::COP3 => write!(f, "cop3"),
+ Opcode::COP4 => write!(f, "cop4"),
+ Opcode::BEQL => write!(f, "beql"),
+ Opcode::BNEL => write!(f, "bnel"),
+ Opcode::BLEZL => write!(f, "blezl"),
+ Opcode::BGTZL => write!(f, "bgtzl"),
+ Opcode::DADDI => write!(f, "daddi"),
+ Opcode::DADDIU => write!(f, "daddiu"),
+ Opcode::LDL => write!(f, "ldl"),
+ Opcode::LDR => write!(f, "ldr"),
+ Opcode::LB => write!(f, "lb"),
+ Opcode::LH => write!(f, "lh"),
+ Opcode::LWL => write!(f, "lwl"),
+ Opcode::LW => write!(f, "lw"),
+ Opcode::LBU => write!(f, "lbu"),
+ Opcode::LHU => write!(f, "lhu"),
+ Opcode::LWR => write!(f, "lwr"),
+ Opcode::LWU => write!(f, "lwu"),
+ Opcode::SB => write!(f, "sb"),
+ Opcode::SH => write!(f, "sh"),
+ Opcode::SWL => write!(f, "swl"),
+ Opcode::SW => write!(f, "sw"),
+ Opcode::SDL => write!(f, "sdl"),
+ Opcode::SDR => write!(f, "sdr"),
+ Opcode::SWR => write!(f, "swr"),
+ Opcode::LL => write!(f, "ll"),
+ Opcode::LWC1 => write!(f, "lwc1"),
+ Opcode::LWC2 => write!(f, "lwc2"),
+ Opcode::PREF => write!(f, "pref"),
+ Opcode::LLD => write!(f, "lld"),
+ Opcode::LDC1 => write!(f, "ldc1"),
+ Opcode::LDC2 => write!(f, "ldc2"),
+ Opcode::LD => write!(f, "ld"),
+ Opcode::SC => write!(f, "sc"),
+ Opcode::SWC1 => write!(f, "swc1"),
+ Opcode::SWC2 => write!(f, "swc2"),
+ Opcode::SCD => write!(f, "scd"),
+ Opcode::SDC1 => write!(f, "sdc1"),
+ Opcode::SDC2 => write!(f, "sdc2"),
+ Opcode::SD => write!(f, "sd"),
+ Opcode::SLL => write!(f, "sll"),
+ Opcode::SRL => write!(f, "srl"),
+ Opcode::SRA => write!(f, "sra"),
+ Opcode::SLLV => write!(f, "sllv"),
+ Opcode::SRLV => write!(f, "srlv"),
+ Opcode::SRAV => write!(f, "srav"),
+ Opcode::JR => write!(f, "jr"),
+ Opcode::JALR => write!(f, "jalr"),
+ Opcode::MOVZ => write!(f, "movz"),
+ Opcode::MOVN => write!(f, "movn"),
+ Opcode::SYSCALL => write!(f, "syscall"),
+ Opcode::BREAK => write!(f, "break"),
+ Opcode::SYNC => write!(f, "sync"),
+ Opcode::MFHI => write!(f, "mfhi"),
+ Opcode::MTHI => write!(f, "mthi"),
+ Opcode::MFLO => write!(f, "mflo"),
+ Opcode::MTLO => write!(f, "mtlo"),
+ Opcode::DSLLV => write!(f, "dsllv"),
+ Opcode::DSRLV => write!(f, "dsrlv"),
+ Opcode::DSRAV => write!(f, "dsrav"),
+ Opcode::MULT => write!(f, "mult"),
+ Opcode::MULTU => write!(f, "multu"),
+ Opcode::DIV => write!(f, "div"),
+ Opcode::DIVU => write!(f, "divu"),
+ Opcode::DMULT => write!(f, "dmult"),
+ Opcode::DMULTU => write!(f, "dmultu"),
+ Opcode::DDIV => write!(f, "ddiv"),
+ Opcode::DDIVU => write!(f, "ddivu"),
+ Opcode::ADD => write!(f, "add"),
+ Opcode::ADDU => write!(f, "addu"),
+ Opcode::SUB => write!(f, "sub"),
+ Opcode::SUBU => write!(f, "subu"),
+ Opcode::AND => write!(f, "and"),
+ Opcode::OR => write!(f, "or"),
+ Opcode::XOR => write!(f, "xor"),
+ Opcode::NOR => write!(f, "nor"),
+ Opcode::SLT => write!(f, "slt"),
+ Opcode::DADD => write!(f, "dadd"),
+ Opcode::DADDU => write!(f, "daddu"),
+ Opcode::DSUB => write!(f, "dsub"),
+ Opcode::DSUBU => write!(f, "dsubu"),
+ Opcode::TGE => write!(f, "tge"),
+ Opcode::TGEU => write!(f, "tgeu"),
+ Opcode::TLT => write!(f, "tlt"),
+ Opcode::TLTU => write!(f, "tltu"),
+ Opcode::TEQ => write!(f, "teq"),
+ Opcode::TNE => write!(f, "tne"),
+ Opcode::DSLL => write!(f, "dsll"),
+ Opcode::DSRL => write!(f, "dsrl"),
+ Opcode::DSRA => write!(f, "dsra"),
+ Opcode::DSLL32 => write!(f, "dsll32"),
+ Opcode::DSRL32 => write!(f, "dsrl32"),
+ Opcode::DSRA32 => write!(f, "dsra32"),
+ Opcode::BLTZ => write!(f, "bltz"),
+ Opcode::BGEZ => write!(f, "bgez"),
+ Opcode::BLTZL => write!(f, "bltzl"),
+ Opcode::BGEZL => write!(f, "bgezl"),
+ Opcode::TGEI => write!(f, "tgei"),
+ Opcode::TGEIU => write!(f, "tgeiu"),
+ Opcode::TLTI => write!(f, "tlti"),
+ Opcode::TLTIU => write!(f, "tltiu"),
+ Opcode::TEQI => write!(f, "teqi"),
+ Opcode::TNEI => write!(f, "tnei"),
+ Opcode::BLTZAL => write!(f, "bltzal"),
+ Opcode::BGEZAL => write!(f, "bgezal"),
+ Opcode::BLTZALL => write!(f, "bltzall"),
+ Opcode::BGEZALL => write!(f, "bgezall"),
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 36d8589..131b6d2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1 +1,792 @@
-mod data;
+extern crate num_enum;
+extern crate yaxpeax_arch;
+
+use std::convert::TryInto;
+use std::mem;
+
+use num_enum::IntoPrimitive;
+
+use yaxpeax_arch::{Arch, Decoder, LengthedInstruction};
+
+mod display;
+
+#[derive(Debug, PartialEq)]
+pub struct Instruction {
+ word: u32,
+ operands: [OperandSpec; 3],
+ opcode: Opcode,
+}
+
+impl Instruction {
+ fn blank() -> Self {
+ Instruction {
+ word: 0,
+ operands: [OperandSpec::Nothing, OperandSpec::Nothing, OperandSpec::Nothing],
+ opcode: Opcode::J,
+ }
+ }
+
+ fn operand(&self, op: &OperandSpec) -> Option<Operand> {
+ match op {
+ OperandSpec::Nothing => None,
+ OperandSpec::Rs => { Some(Operand::Reg((self.word >> 21) as u8 & 0b11111)) },
+ OperandSpec::Rt => { Some(Operand::Reg((self.word >> 16) as u8 & 0b11111)) },
+ OperandSpec::Rd => { Some(Operand::Reg((self.word >> 11) as u8 & 0b11111)) },
+ OperandSpec::Sa => { Some(Operand::Shift((self.word >> 6) as u8 & 0b11111)) },
+ OperandSpec::Code => { Some(Operand::Imm(((self.word >> 6) as u16 & 0b11_1111_1111) as i16)) },
+ OperandSpec::Syscall => { Some(Operand::LongImm((self.word >> 6) & 0xf_ff_ff)) },
+ OperandSpec::Imm16 => { Some(Operand::Imm(self.word as u16 as i16)) },
+ OperandSpec::BaseOffset => { Some(Operand::BaseOffset(
+ ((self.word >> 21) & 0b11111) as u8,
+ (self.word & 0xffff) as u16 as i16,
+ )) },
+ OperandSpec::Stype => {
+ Some(Operand::Imm(((self.word >> 6) & 0b11111) as i16))
+ },
+ OperandSpec::JOffset => {
+ Some(Operand::JOffset(((self.word as i32) << 6) >> 4))
+ },
+ OperandSpec::CoprocessorOpcode => {
+ Some(Operand::LongImm(self.word & 0x03_ff_ff_ff))
+ },
+ }
+ }
+}
+
+impl LengthedInstruction for Instruction {
+ type Unit = u32;
+ fn min_size() -> Self::Unit {
+ 4
+ }
+
+ fn len(&self) -> Self::Unit {
+ 4
+ }
+}
+
+#[derive(Debug, IntoPrimitive, PartialEq)]
+#[repr(u8)]
+pub enum Opcode {
+ J = 0b00_000010,
+ JAL = 0b00_000011,
+ BEQ = 0b00_000100,
+ BNE = 0b00_000101,
+ BLEZ = 0b00_000110,
+ BGTZ = 0b00_000111,
+ ADDI = 0b00_001000,
+ ADDIU = 0b00_001001,
+ SLTI = 0b00_001010,
+ SLTIU = 0b00_001011,
+ ANDI = 0b00_001100,
+ ORI = 0b00_001101,
+ XORI = 0b00_001110,
+ LUI = 0b00_001111,
+ COP1 = 0b00_010000,
+ COP2 = 0b00_010001,
+ COP3 = 0b00_010010,
+ COP4 = 0b00_010011,
+ BEQL = 0b00_010100,
+ BNEL = 0b00_010101,
+ BLEZL = 0b00_010110,
+ BGTZL = 0b00_010111,
+ DADDI = 0b00_011000,
+ DADDIU = 0b00_011001,
+ LDL = 0b00_011010,
+ LDR = 0b00_011011,
+ LB = 0b00_100000,
+ LH = 0b00_100001,
+ LWL = 0b00_100010,
+ LW = 0b00_100011,
+ LBU = 0b00_100100,
+ LHU = 0b00_100101,
+ LWR = 0b00_100110,
+ LWU = 0b00_100111,
+ SB = 0b00_101000,
+ SH = 0b00_101001,
+ SWL = 0b00_101010,
+ SW = 0b00_101011,
+ SDL = 0b00_101100,
+ SDR = 0b00_101101,
+ SWR = 0b00_101110,
+ LL = 0b00_110000,
+ LWC1 = 0b00_110001,
+ LWC2 = 0b00_110010,
+ PREF = 0b00_110011,
+ LLD = 0b00_110100,
+ LDC1 = 0b00_110101,
+ LDC2 = 0b00_110110,
+ LD = 0b00_110111,
+ SC = 0b00_111000,
+ SWC1 = 0b00_111001,
+ SWC2 = 0b00_111010,
+ SCD = 0b00_111100,
+ SDC1 = 0b00_111101,
+ SDC2 = 0b00_111110,
+ SD = 0b00_111111,
+
+ SLL = 0b01_000000,
+ SRL = 0b01_000010,
+ SRA = 0b01_000011,
+ SLLV = 0b01_000100,
+ SRLV = 0b01_000110,
+ SRAV = 0b01_000111,
+ JR = 0b01_001000,
+ JALR = 0b01_001001,
+ MOVZ = 0b01_001010,
+ MOVN = 0b01_001011,
+ SYSCALL = 0b01_001100,
+ BREAK = 0b01_001101,
+ SYNC = 0b01_001111,
+ MFHI = 0b01_010000,
+ MTHI = 0b01_010001,
+ MFLO = 0b01_010010,
+ MTLO = 0b01_010011,
+ DSLLV = 0b01_010100,
+ DSRLV = 0b01_010110,
+ DSRAV = 0b01_010111,
+ MULT = 0b01_011000,
+ MULTU = 0b01_011001,
+ DIV = 0b01_011010,
+ DIVU = 0b01_011011,
+ DMULT = 0b01_011100,
+ DMULTU = 0b01_011101,
+ DDIV = 0b01_011110,
+ DDIVU = 0b01_011111,
+ ADD = 0b01_100000,
+ ADDU = 0b01_100001,
+ SUB = 0b01_100010,
+ SUBU = 0b01_100011,
+ AND = 0b01_100100,
+ OR = 0b01_100101,
+ XOR = 0b01_100110,
+ NOR = 0b01_100111,
+ SLT = 0b01_101010,
+ DADD = 0b01_101100,
+ DADDU = 0b01_101101,
+ DSUB = 0b01_101110,
+ DSUBU = 0b01_101111,
+ TGE = 0b01_110000,
+ TGEU = 0b01_110001,
+ TLT = 0b01_110010,
+ TLTU = 0b01_110011,
+ TEQ = 0b01_110100,
+ TNE = 0b01_110110,
+ DSLL = 0b01_111000,
+ DSRL = 0b01_111010,
+ DSRA = 0b01_111011,
+ DSLL32 = 0b01_111100,
+ DSRL32 = 0b01_111110,
+ DSRA32 = 0b01_111111,
+
+ BLTZ = 0b10_000000,
+ BGEZ = 0b10_000001,
+ BLTZL = 0b10_000010,
+ BGEZL = 0b10_000011,
+ TGEI = 0b10_001000,
+ TGEIU = 0b10_001001,
+ TLTI = 0b10_001010,
+ TLTIU = 0b10_001011,
+ TEQI = 0b10_001100,
+ TNEI = 0b10_001110,
+ BLTZAL = 0b10_010000,
+ BGEZAL = 0b10_010001,
+ BLTZALL = 0b10_010010,
+ BGEZALL = 0b10_010011,
+}
+
+#[derive(Debug, PartialEq, Clone, Copy)]
+enum OperandSpec {
+ Nothing = 0,
+ Rs,
+ Rt,
+ Rd,
+ Sa,
+ Code,
+ Syscall,
+ Imm16,
+ BaseOffset,
+ Stype,
+ JOffset,
+ CoprocessorOpcode,
+}
+
+#[derive(Debug)]
+pub enum Operand {
+ Reg(u8),
+ Imm(i16),
+ BaseOffset(u8, i16),
+ Shift(u8),
+ LongImm(u32),
+ JOffset(i32)
+}
+
+#[cfg(feature="use-serde")]
+#[derive(Debug, Serialize, Deserialize)]
+pub struct MIPS;
+
+#[cfg(not(feature="use-serde"))]
+#[derive(Debug)]
+pub struct MIPS;
+
+impl Arch for MIPS {
+ type Address = u32;
+ type Instruction = Instruction;
+ type Decoder = MipsDecoder;
+ type Operand = Operand;
+}
+
+#[derive(Default, Debug)]
+pub struct MipsDecoder {}
+
+impl Decoder<Instruction> for MipsDecoder {
+ fn decode<T: IntoIterator<Item=u8>>(&self, bytes: T) -> Option<Instruction> {
+ let mut blank = Instruction::blank();
+ match self.decode_into(&mut blank, bytes) {
+ Some(_) => Some(blank),
+ None => None,
+ }
+ }
+
+ fn decode_into<T: IntoIterator<Item=u8>>(&self, instruction: &mut Instruction, bytes: T) -> Option<()> {
+ let mut bytes_iter = bytes.into_iter();
+ let word: Vec<u8> = bytes_iter.by_ref().take(4).collect();
+ let word = u32::from_le_bytes(word.as_slice().try_into().ok()?);
+
+ instruction.word = word;
+
+ let opc = (word >> 26) as u8;
+
+ const SPECIAL: u8 = 0b000000;
+ const REG_IMM: u8 = 0b000001;
+
+ if opc == SPECIAL {
+ let opc = (word & 0b111111) as u8;
+
+ if [0b000101, 0b001110, 0b010101, 0b101000, 0b101001, 0b110101, 0b110111, 0b111001, 0b111101].contains(&opc) {
+ return None;
+ }
+
+ // operands in the secondary map have kind of a mess of operands. except for 0b100000
+ // and above, which have nice patterns:
+ if opc >= 0b010000 {
+ instruction.operands = match (opc >> 4) - 1 {
+ 0b000 => {
+ [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Nothing]
+ },
+ 0b001 |
+ 0b010 => {
+ [OperandSpec::Rd, OperandSpec::Rs, OperandSpec::Rt]
+ },
+ 0b011 => {
+ [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Code]
+ },
+ 0b100 => {
+ [OperandSpec::Rt, OperandSpec::Rd, OperandSpec::Sa]
+ }
+ _ => {
+ unreachable!("opc must be 0b011xxx or 0b1xxxx at this point");
+ }
+ };
+ } else {
+ // just do a table lookup...
+ instruction.operands = [
+ [OperandSpec::Rt, OperandSpec::Rd, OperandSpec::Sa],
+ [OperandSpec::Nothing, OperandSpec::Nothing, OperandSpec::Nothing],
+ [OperandSpec::Rt, OperandSpec::Rd, OperandSpec::Sa],
+ [OperandSpec::Rt, OperandSpec::Rd, OperandSpec::Sa],
+ [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Rd],
+ [OperandSpec::Nothing, OperandSpec::Nothing, OperandSpec::Nothing],
+ [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Rd],
+ [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Rd],
+ [OperandSpec::Rs, OperandSpec::Nothing, OperandSpec::Nothing],
+ [OperandSpec::Rs, OperandSpec::Rd, OperandSpec::Nothing],
+ [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Rd],
+ [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Rd],
+ [OperandSpec::Syscall, OperandSpec::Nothing, OperandSpec::Nothing],
+ [OperandSpec::Syscall, OperandSpec::Nothing, OperandSpec::Nothing],
+ [OperandSpec::Nothing, OperandSpec::Nothing, OperandSpec::Nothing],
+ [OperandSpec::Stype, OperandSpec::Nothing, OperandSpec::Nothing],
+ [OperandSpec::Rd, OperandSpec::Nothing, OperandSpec::Nothing],
+ [OperandSpec::Rd, OperandSpec::Nothing, OperandSpec::Nothing],
+ [OperandSpec::Rd, OperandSpec::Nothing, OperandSpec::Nothing],
+ [OperandSpec::Rs, OperandSpec::Nothing, OperandSpec::Nothing],
+ [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Rd],
+ [OperandSpec::Nothing, OperandSpec::Nothing, OperandSpec::Nothing],
+ [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Rd],
+ [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Rd],
+ ][opc as usize];
+ }
+
+ instruction.opcode = unsafe {
+ mem::transmute::<u8, Opcode>(0b01_000000 | opc)
+ };
+ } else if opc == REG_IMM {
+ let opc = ((word >> 16) & 0b11111) as u8 | 0b10_000000;
+ // reject all 0b11xxx patterns, and the right half of table A-40, section REGIMM,
+ // except two outliers.
+ if opc >= 0b10_011000 || (opc & 0b00_00100 > 0 && (opc != 0b10_001100 || opc != 0b10_001110)) {
+ return None;
+ }
+ instruction.opcode = unsafe {
+ mem::transmute::<u8, Opcode>(opc)
+ };
+ instruction.operands = [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Imm16];
+ } else {
+ if opc & 0b111100 == 0b011100 || opc == 0b111011 {
+ // reserved opcode
+ return None;
+ }
+ instruction.opcode = unsafe {
+ mem::transmute::<u8, Opcode>(opc)
+ };
+ if opc < 0b000100 {
+ // instruction is J or JAL, immediate offset
+ instruction.operands = [OperandSpec::JOffset, OperandSpec::Nothing, OperandSpec::Nothing];
+ } else if opc < 0b001000 {
+ if opc < 0b000110 {
+ instruction.operands = [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Imm16];
+ } else {
+ instruction.operands = [OperandSpec::Rs, OperandSpec::Imm16, OperandSpec::Nothing];
+ }
+ } else if opc < 0b010000 {
+ if opc == 0b001111 {
+ instruction.operands = [OperandSpec::Rt, OperandSpec::Imm16, OperandSpec::Nothing];
+ } else {
+ instruction.operands = [OperandSpec::Rt, OperandSpec::Rs, OperandSpec::Imm16];
+ }
+ } else if opc < 0b010100 {
+ instruction.operands = [OperandSpec::CoprocessorOpcode, OperandSpec::Nothing, OperandSpec::Nothing];
+ } else if opc < 0b011000 {
+ if opc < 0b010110 {
+ instruction.operands = [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Imm16];
+ } else {
+ instruction.operands = [OperandSpec::Rs, OperandSpec::Imm16, OperandSpec::Nothing];
+ }
+ } else if opc < 0b100000 {
+ if opc < 0b011010 {
+ instruction.operands = [OperandSpec::Rs, OperandSpec::Rt, OperandSpec::Imm16];
+ } else {
+ instruction.operands = [OperandSpec::Rt, OperandSpec::BaseOffset, OperandSpec::Nothing];
+ }
+ } else {
+ instruction.operands = [OperandSpec::Rt, OperandSpec::BaseOffset, OperandSpec::Nothing];
+ }
+ }
+ return Some(());
+ }
+}
+
+// SLL
+// SPECIAL 0 rt rd sa SLL
+// 000000 00000 XXXXX XXXXX XXXXX 000000
+//
+// SRL
+// SPECIAL 0 rt rd sa SRL
+// 000000 00000 XXXXX XXXXX XXXXX 000010
+//
+// SRA
+// SPECIAL 0 rt rd sa SRA
+// 000000 00000 XXXXX XXXXX XXXXX 000011
+//
+// SLLV
+// SPECIAL rs rt rd 0 SLLV
+// 000000 XXXXX XXXXX XXXXX 00000 000100
+//
+// SRLV
+// SPECIAL rs rt rd 0 SRLV
+// 000000 XXXXX XXXXX XXXXX 00000 000110
+//
+// SRAV
+// SPECIAL rs rt rd 0 SRAV
+// 000000 XXXXX XXXXX XXXXX 00000 000111
+//
+// JR v-----v--- reserved? might not be? unknown
+// SPECIAL rs JR
+// 000000 XXXXX 000000000000000 001000
+//
+// JALR v-------------v--- reserved? might not be? unknown
+// SPECIAL rs rd JALR
+// 000000 XXXXX 00000 XXXXX 00000 001001
+//
+// MOVZ
+// SPECIAL rs rt rd 0 MOVZ
+// 000000 XXXXX XXXXX XXXXX 00000 001010
+//
+// MOVN
+// SPECIAL rs rt rd 0 MOVN
+// 000000 XXXXX XXXXX XXXXX 00000 001011
+//
+// SYSCALL
+// SPECIAL Code SYSCALL
+// 000000 XXXXXXXXXXXXXXXXXXXX 001100
+//
+// BREAK
+// SPECIAL code BREAK
+// 000000 XXXXXXXXXXXXXXXXXXXX 001101
+//
+// SYNC
+// SPECIAL 0 stype SYNC
+// 000000 000000000000000 XXXXX 001111
+//
+// MFHI
+// SPECIAL 0 rd 0 MFHI
+// 000000 0000000000 XXXXX 00000 010000
+//
+// MTHI
+// SPECIAL rs 0 MTHI
+// 000000 XXXXX 000000000000000 010001
+//
+// MFLO
+// SPECIAL 0 rd 0 MFLO
+// 000000 0000000000 XXXXX 00000 010010
+//
+// MTLO
+// SPECIAL rs 0 MTLO
+// 000000 XXXXX 000000000000000 010011
+//
+// DSLLV
+// SPECIAL rs rt rd 0 DSLLV
+// 000000 XXXXX XXXXX XXXXX 00000 010100
+//
+// DSRLV
+// SPECIAL rs rt rd 0 DSRLV
+// 000000 XXXXX XXXXX XXXXX 00000 010110
+//
+// DSRAV
+// SPECIAL rs rt rd 0 DSRAV
+// 000000 XXXXX XXXXX XXXXX 00000 010111
+//
+// MULT
+// SPECIAL rs rt 0 MULT
+// 000000 XXXXX XXXXX 0000000000 011000
+//
+// MULTU
+// SPECIAL rs rt 0 MULTU
+// 000000 XXXXX XXXXX 0000000000 011001
+//
+// DIV
+// SPECIAL rs rt 0 DIV
+// 000000 XXXXX XXXXX 0000000000 011010
+//
+// DIVU
+// SPECIAL rs rt 0 DIVU
+// 000000 XXXXX XXXXX 0000000000 011011
+//
+// DMULT
+// SPECIAL rs rt 0 DMULT
+// 000000 XXXXX XXXXX 0000000000 011100
+//
+// DMULTU
+// SPECIAL rs rt 0 DMULTU
+// 000000 XXXXX XXXXX 0000000000 011101
+//
+// DDIV
+// SPECIAL rs rt 0 DDIV
+// 000000 XXXXX XXXXX 0000000000 011110
+//
+// DDIVU
+// SPECIAL rs rt 0 DDIVU
+// 000000 XXXXX XXXXX 0000000000 011111
+//
+// ADD
+// SPECIAL rs rt rd 0 ADD
+// 000000 XXXXX XXXXX XXXXX 00000 100000
+//
+// ADDU
+// SPECIAL rs rt rd 0 ADDU
+// 000000 XXXXX XXXXX XXXXX 00000 100001
+//
+// SUB
+// SPECIAL rs rt rd 0 SUB
+// 000000 XXXXX XXXXX XXXXX 00000 100010
+//
+// SUBU
+// SPECIAL rs rt rd 0 SUBU
+// 000000 XXXXX XXXXX XXXXX 00000 100011
+//
+// AND
+// SPECIAL rs rt rd 0 ADDU
+// 000000 XXXXX XXXXX XXXXX 00000 100100
+//
+// OR
+// SPECIAL rs rt rd 0 OR
+// 000000 XXXXX XXXXX XXXXX 00000 100101
+//
+// XOR
+// SPECIAL rs rt rd 0 XOR
+// 000000 XXXXX XXXXX XXXXX 00000 100110
+//
+// NOR
+// SPECIAL rs rt rd 0 NOR
+// 000000 XXXXX XXXXX XXXXX 00000 100111
+//
+// SLT
+// SPECIAL rs rt rd 0 SLT
+// 000000 XXXXX XXXXX XXXXX 00000 101010
+//
+// DADD
+// SPECIAL rs rt rd 0 DADD
+// 000000 XXXXX XXXXX XXXXX 00000 101100
+//
+// DADDU
+// SPECIAL rs rt rd 0 DADDU
+// 000000 XXXXX XXXXX XXXXX 00000 101101
+//
+// DSUB
+// SPECIAL rs rt rd 0 DSUB
+// 000000 XXXXX XXXXX XXXXX 00000 101110
+//
+// DSUBU
+// SPECIAL rs rt rd 0 DSUBU
+// 000000 XXXXX XXXXX XXXXX 00000 101111
+//
+// TGE
+// SPECIAL rs rt code TGE
+// 000000 XXXXX XXXXX 0000000000 110000
+//
+// TGEU
+// SPECIAL rs rt code TGEU
+// 000000 XXXXX XXXXX 0000000000 110001
+//
+// TLT
+// SPECIAL rs rt code TLT
+// 000000 XXXXX XXXXX 0000000000 110010
+//
+// TLTU
+// SPECIAL rs rt code TLTU
+// 000000 XXXXX XXXXX 0000000000 110011
+//
+// TEQ
+// SPECIAL rs rt code TEQ
+// 000000 XXXXX XXXXX 0000000000 110100
+//
+// TNE
+// SPECIAL rs rt code TNE
+// 000000 XXXXX XXXXX 0000000000 110110
+//
+// DSLL
+// SPECIAL 0 rt rd sa DSLL
+// 000000 00000 XXXXX XXXXX XXXXX 111000
+//
+// DSRL
+// SPECIAL 0 rt rd sa DSRL
+// 000000 00000 XXXXX XXXXX XXXXX 111010
+//
+// DSRA
+// SPECIAL 0 rt rd sa DSRA
+// 000000 00000 XXXXX XXXXX XXXXX 111011
+//
+// DSLL32
+// SPECIAL 0 rt rd sa DSLL32
+// 000000 00000 XXXXX XXXXX XXXXX 111100
+//
+// DSRL32
+// SPECIAL 0 rt rd sa DSRL32
+// 000000 00000 XXXXX XXXXX XXXXX 111110
+//
+// DSRA32
+// SPECIAL 0 rt rd sa DSRA32
+// 000000 00000 XXXXX XXXXX XXXXX 111111
+//
+// BLTZ
+// REGIMM rs BLTZ imm16
+// 000001 XXXXX 00000 YYYYYYYYYYYYYYYY
+//
+// BGEZ
+// REGIMM rs BGEZ imm16
+// 000001 XXXXX 00001 YYYYYYYYYYYYYYYY
+//
+// BLTZL
+// REGIMM rs BLTZL imm16
+// 000001 XXXXX 00010 YYYYYYYYYYYYYYYY
+//
+// BGEZL
+// REGIMM rs BGEZL imm16
+// 000001 XXXXX 00011 YYYYYYYYYYYYYYYY
+//
+// TGEI
+// REGIMM rs TGEI imm16
+// 000001 XXXXX 01000 YYYYYYYYYYYYYYYY
+//
+// TGEIU
+// REGIMM rs TGEIU imm16
+// 000001 XXXXX 01001 YYYYYYYYYYYYYYYY
+//
+// TLTI
+// REGIMM rs TLTI imm16
+// 000001 XXXXX 01010 YYYYYYYYYYYYYYYY
+//
+// TLTIU
+// REGIMM rs TLTIU imm16
+// 000001 XXXXX 01011 YYYYYYYYYYYYYYYY
+//
+// TEQI
+// REGIMM rs TEQI imm16
+// 000001 XXXXX 01100 YYYYYYYYYYYYYYYY
+//
+// TNEI
+// REGIMM rs TNEI imm16
+// 000001 XXXXX 01110 YYYYYYYYYYYYYYYY
+//
+// BLTZAL
+// REGIMM rs BLTZAL imm16
+// 000001 XXXXX 10000 YYYYYYYYYYYYYYYY
+//
+// BGEZAL
+// REGIMM rs BGEZAL imm16
+// 000001 XXXXX 10001 YYYYYYYYYYYYYYYY
+//
+// BLTZALL
+// REGIMM rs BLTZALLimm16
+// 000001 XXXXX 10010 YYYYYYYYYYYYYYYY
+//
+// BGEZALL
+// REGIMM rs BGEZALLimm16
+// 000001 XXXXX 10011 YYYYYYYYYYYYYYYY
+//
+// J instr_index
+// 000010 XXXXXXXXXXXXXXXXXXXXXXXXXX
+//
+// JAL instr_index
+// 000011 XXXXXXXXXXXXXXXXXXXXXXXXXX
+//
+// BEQ rs rt imm16
+// 000100 XXXXX XXXXX YYYYYYYYYYYYYYYY
+//
+// BNE rs rt imm16
+// 000101 XXXXX XXXXX YYYYYYYYYYYYYYYY
+//
+// BLEZ rs 0 imm16
+// 000110 XXXXX 00000 YYYYYYYYYYYYYYYY
+//
+// BGTZ rs 0 imm16
+// 000111 XXXXX 00000 YYYYYYYYYYYYYYYY
+//
+// ADDI rs rt imm16
+// 001000 XXXXX XXXXX YYYYYYYYYYYYYYYY
+//
+// ADDIU rs rt imm16
+// 001001 XXXXX XXXXX YYYYYYYYYYYYYYYY
+//
+// SLTI rs rt imm16
+// 001010 XXXXX XXXXX YYYYYYYYYYYYYYYY
+//
+// SLTII rs rt imm16
+// 001011 XXXXX XXXXX YYYYYYYYYYYYYYYY
+//
+// ANDI rs rt imm16
+// 001100 XXXXX XXXXX YYYYYYYYYYYYYYYY
+//
+// ORI rs rt imm16
+// 001101 XXXXX XXXXX YYYYYYYYYYYYYYYY
+//
+// XORI rs rt imm16
+// 001110 XXXXX XXXXX YYYYYYYYYYYYYYYY
+//
+// LUI 0 rt imm16
+// 001111 00000 XXXXX YYYYYYYYYYYYYYYY
+//
+// COPz cop_fun
+// 0100zz XXXXXXXXXXXXXXXXXXXXXXXXXX
+//
+// BEQL rs rt imm16
+// 010100 XXXXX XXXXX YYYYYYYYYYYYYYYY
+//
+// BNEL rs rt imm16
+// 010101 XXXXX XXXXX YYYYYYYYYYYYYYYY
+//
+// BLEZL rs 0 imm16
+// 010110 XXXXX 00000 YYYYYYYYYYYYYYYY
+//
+// BGTZL rs 0 imm16
+// 010111 XXXXX 00000 YYYYYYYYYYYYYYYY
+//
+// DADDI rs rt imm16
+// 011000 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// DADDIU rs rt imm16
+// 011001 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LDL base rt offset
+// 011010 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LDR base rt offset
+// 011011 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LB base rt offset
+// 100000 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LH base rt offset
+// 100001 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LWL base rt offset
+// 100010 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LW base rt offset
+// 100011 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LHU base rt offset
+// 100101 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LWR base rt offset
+// 100110 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LWU base rt offset
+// 100111 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LBU base rt offset
+// 100100 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// SB base rt offset
+// 101000 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LD base rt offset
+// 110111 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LDCz base rt offset
+// 1101zz XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LL base rt offset
+// 110000 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LWCz base rt offset
+// 1100zz XXXXX XXXXX XXXXXXXXXXXXXXXX
+// ^-{01,10}
+// PREF base hint offset
+// 110011 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// LLD base rt offset
+// 110100 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// SC base rt offset
+// 111000 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// SCD base rt offset
+// 111100 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// SD base rt offset
+// 111111 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// SDCz base rt offset
+// 1111zz XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// SDL base rt offset
+// 101100 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// SDR base rt offset
+// 101101 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// SH base rt offset
+// 101001 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// SW base rt offset
+// 101011 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// SWCz base rt offset
+// 1110zz XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// SWL base rt offset
+// 101010 XXXXX XXXXX XXXXXXXXXXXXXXXX
+//
+// SWR base rt offset
+// 101110 XXXXX XXXXX XXXXXXXXXXXXXXXX
diff --git a/src/mips_data.rs b/src/mips_data.rs
deleted file mode 100644
index 33c8f41..0000000
--- a/src/mips_data.rs
+++ /dev/null
@@ -1,561 +0,0 @@
-struct Instruction {
- opcode: Opcode,
- operands: Operands
-}
-
-enum Opcode {
- DADD
- DADDI
- DADDIU
- DADDU
- DSUB
- DSUBU
- DMULT
- DMULTU
- DDIV
- DDIVU
-
- ADD
- ADDU
- ADDI
- ADDIU
- SUB
- SUBU
- MULT
- MULTU
- DIV
- DIVU
-
- NOR
- AND
- OR
- XOR
- ANDI
- ORI
- XORI
-
- BEQ
- BEQL
- BGEZ
- BGEZAL
- BGEZALL
- BGEZL
- BGTZ
- BGTZL
- BLEZ
- BLEZL
- BLTZ
- BLTZAL
- BLTZALL
- BLTZL
- BNE
- BNEL
- BREAK
- COPz
- DSLL
- DSLL32
- DSLLV
- DSRA
- DSRA32
- DSRAV
- DSRL
- DSRL32
- DSRLV
- J
- JAL
- JALR
- JR
- LB
- LBU
- LD
- LDCz
- LDL
- LDR
- LH
- LHU
- LL
- LLD
- LUI
- LW
- LWCz
- LWL
- LWR
- LWU
- MFHI
- MFLO
- MOVN
- MOVZ
- MTHI
- MTLO
- PREF
- REGIMM
- SB
- SC
- SCD
- SD
- SDCz
- SDL
- SDR
- SH
- SLL
- SLLV
- SLT
- SLTI
- SLTII
- SRA
- SRAV
- SRL
- SRLV
- SW
- SWCz
- SWL
- SWR
- SYNC
- SYSCALL
-
- TEQ
- TGE
- TGEU
- TLT
- TLTU
- TNE
- TEQI
- TGEI
- TGEIU
- TLTI
- TLTIU
- TNEI
-}
-
-struct RRR(u32);
-struct RImm(u32);
-struct RRImm(u32);
-
-enum Operands {
- RRR(RRR),
- RImm(RImm),
- RRImm(RRImm),
- CoProc(u32),
- Code(u32), // 20-bit number for BREAK or SYSCALL
- Offset(u32), // J or JAL
-}
-
-// ADD
-// SPECIAL rs rt rd 0 ADD
-// 000000 XXXXX XXXXX XXXXX 00000 100000
-//
-// ADDU
-// SPECIAL rs rt rd 0 ADDU
-// 000000 XXXXX XXXXX XXXXX 00000 100001
-//
-// AND
-// SPECIAL rs rt rd 0 ADDU
-// 000000 XXXXX XXXXX XXXXX 00000 100100
-//
-// ADDI rs rt imm16
-// 001000 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// ADDIU rs rt imm16
-// 001001 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// ANDI rs rt imm16
-// 001100 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// BEQ rs rt imm16
-// 000100 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// BEQL rs rt imm16
-// 010100 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// BGEZ
-// REGIMM rs BGEZ imm16
-// 000001 XXXXX 00001 YYYYYYYYYYYYYYYY
-//
-// BGEZAL
-// REGIMM rs BGEZAL imm16
-// 000001 XXXXX 10001 YYYYYYYYYYYYYYYY
-//
-// BGEZALL
-// REGIMM rs BGEZALLimm16
-// 000001 XXXXX 10011 YYYYYYYYYYYYYYYY
-//
-// BGEZL
-// REGIMM rs BGEZL imm16
-// 000001 XXXXX 00011 YYYYYYYYYYYYYYYY
-//
-// BGTZ rs 0 imm16
-// 000111 XXXXX 00000 YYYYYYYYYYYYYYYY
-//
-// BGTZL rs 0 imm16
-// 010111 XXXXX 00000 YYYYYYYYYYYYYYYY
-//
-// BLEZ rs 0 imm16
-// 000110 XXXXX 00000 YYYYYYYYYYYYYYYY
-//
-// BLEZL rs 0 imm16
-// 010110 XXXXX 00000 YYYYYYYYYYYYYYYY
-//
-// BLTZ
-// REGIMM rs BLTZ imm16
-// 000001 XXXXX 00000 YYYYYYYYYYYYYYYY
-//
-// BLTZAL
-// REGIMM rs BLTZAL imm16
-// 000001 XXXXX 10000 YYYYYYYYYYYYYYYY
-//
-// BLTZALL
-// REGIMM rs BLTZALLimm16
-// 000001 XXXXX 10010 YYYYYYYYYYYYYYYY
-//
-// BLTZL
-// REGIMM rs BLTZL imm16
-// 000001 XXXXX 00010 YYYYYYYYYYYYYYYY
-//
-// BNE rs rt imm16
-// 000101 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// BNEL rs rt imm16
-// 010101 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// BREAK
-// SPECIAL code BREAK
-// 000000 XXXXXXXXXXXXXXXXXXXX 001101
-//
-// COPz cop_fun
-// 0100zz XXXXXXXXXXXXXXXXXXXXXXXXXX
-//
-// DADD
-// SPECIAL rs rt rd 0 DADD
-// 000000 XXXXX XXXXX XXXXX 00000 101100
-//
-// DADDU
-// SPECIAL rs rt rd 0 DADDU
-// 000000 XXXXX XXXXX XXXXX 00000 101101
-//
-// DADDI rs rt imm16
-// 011000 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// DADDIU rs rt imm16
-// 011001 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// DSUB
-// SPECIAL rs rt rd 0 DSUB
-// 000000 XXXXX XXXXX XXXXX 00000 101110
-//
-// DSUBU
-// SPECIAL rs rt rd 0 DSUBU
-// 000000 XXXXX XXXXX XXXXX 00000 101111
-//
-// DIV
-// SPECIAL rs rt 0 DIV
-// 000000 XXXXX XXXXX 0000000000 011010
-//
-// DIVU
-// SPECIAL rs rt 0 DIVU
-// 000000 XXXXX XXXXX 0000000000 011011
-//
-// DDIV
-// SPECIAL rs rt 0 DDIV
-// 000000 XXXXX XXXXX 0000000000 011110
-//
-// DDIVU
-// SPECIAL rs rt 0 DDIVU
-// 000000 XXXXX XXXXX 0000000000 011111
-//
-// DMULT
-// SPECIAL rs rt 0 DMULT
-// 000000 XXXXX XXXXX 0000000000 011100
-//
-// DMULTU
-// SPECIAL rs rt 0 DMULTU
-// 000000 XXXXX XXXXX 0000000000 011101
-//
-// DSLL
-// SPECIAL 0 rt rd sa DSLL
-// 000000 00000 XXXXX XXXXX XXXXX 111000
-//
-// DSLL32
-// SPECIAL 0 rt rd sa DSLL32
-// 000000 00000 XXXXX XXXXX XXXXX 111100
-//
-// DSLLV
-// SPECIAL rs rt rd 0 DSLLV
-// 000000 XXXXX XXXXX XXXXX 00000 010100
-//
-// DSRA
-// SPECIAL 0 rt rd sa DSRA
-// 000000 00000 XXXXX XXXXX XXXXX 111011
-//
-// DSRA32
-// SPECIAL 0 rt rd sa DSRA32
-// 000000 00000 XXXXX XXXXX XXXXX 111111
-//
-// DSRAV
-// SPECIAL rs rt rd 0 DSRAV
-// 000000 XXXXX XXXXX XXXXX 00000 010111
-//
-// DSRL
-// SPECIAL 0 rt rd sa DSRL
-// 000000 00000 XXXXX XXXXX XXXXX 111010
-//
-// DSRL32
-// SPECIAL 0 rt rd sa DSRL32
-// 000000 00000 XXXXX XXXXX XXXXX 111110
-//
-// DSRLV
-// SPECIAL rs rt rd 0 DSRLV
-// 000000 XXXXX XXXXX XXXXX 00000 010110
-//
-// J instr_index
-// 000010 XXXXXXXXXXXXXXXXXXXXXXXXXX
-//
-// JAL instr_index
-// 000011 XXXXXXXXXXXXXXXXXXXXXXXXXX
-//
-// JALR v-------------v--- reserved? might not be? unknown
-// SPECIAL rs rd JALR
-// 000000 XXXXX 00000 XXXXX 00000 001001
-//
-// JR v-----v--- reserved? might not be? unknown
-// SPECIAL rs JR
-// 000000 XXXXX 000000000000000 001000
-//
-// LB base rt offset
-// 100000 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LBU base rt offset
-// 100100 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LD base rt offset
-// 110111 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LDCz base rt offset
-// 1101zz XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LDL base rt offset
-// 011010 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LDR base rt offset
-// 011011 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LH base rt offset
-// 100001 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LHU base rt offset
-// 100101 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LL base rt offset
-// 110000 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LLD base rt offset
-// 110100 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LUI 0 rt imm16
-// 001111 00000 XXXXX XXXXXXXXXXXXXXXX
-//
-// LW base rt offset
-// 100011 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LWCz base rt offset
-// 1100zz XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LWL base rt offset
-// 100010 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LWR base rt offset
-// 100110 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// LWU base rt offset
-// 100111 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// MFHI
-// SPECIAL 0 rd 0 MFHI
-// 000000 0000000000 XXXXX 00000 010000
-//
-// MFLO
-// SPECIAL 0 rd 0 MFLO
-// 000000 0000000000 XXXXX 00000 010010
-//
-// MOVN
-// SPECIAL rs rt rd 0 MOVN
-// 000000 XXXXX XXXXX XXXXX 00000 001011
-//
-// MOVZ
-// SPECIAL rs rt rd 0 MOVZ
-// 000000 XXXXX XXXXX XXXXX 00000 001010
-//
-// MTHI
-// SPECIAL rs 0 MTHI
-// 000000 XXXXX 000000000000000 010001
-//
-// MTLO
-// SPECIAL rs 0 MTLO
-// 000000 XXXXX 000000000000000 010011
-//
-// MULT
-// SPECIAL rs rt 0 MULT
-// 000000 XXXXX XXXXX 0000000000 011000
-//
-// MULTU
-// SPECIAL rs rt 0 MULTU
-// 000000 XXXXX XXXXX 0000000000 011001
-//
-// NOR
-// SPECIAL rs rt rd 0 NOR
-// 000000 XXXXX XXXXX XXXXX 00000 100111
-//
-// OR
-// SPECIAL rs rt rd 0 OR
-// 000000 XXXXX XXXXX XXXXX 00000 100101
-//
-// ORI rs rt imm16
-// 001101 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// PREF base hint imm16
-// 1100111 XXXXX XXXXX XXXXXXXXXXXXXXXX
-//
-// SB base rt imm16
-// 101000 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SC base rt imm16
-// 111000 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SCD base rt imm16
-// 111100 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SD base rt imm16
-// 111111 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SDCz base rt imm16
-// 1111zz XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SDL base rt imm16
-// 101100 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SDR base rt imm16
-// 101101 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SH base rt imm16
-// 101001 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SLL
-// SPECIAL 0 rt rd sa SLL
-// 000000 00000 XXXXX XXXXX XXXXX 000000
-//
-// SLLV
-// SPECIAL rs rt rd 0 SLLV
-// 000000 XXXXX XXXXX XXXXX 00000 000100
-//
-// SLT
-// SPECIAL rs rt rd 0 SLT
-// 000000 XXXXX XXXXX XXXXX 00000 101010
-//
-// SLTI rs rt imm16
-// 001010 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SLTII rs rt imm16
-// 001011 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SRA
-// SPECIAL 0 rt rd sa SRA
-// 000000 00000 XXXXX XXXXX XXXXX 000011
-//
-// SRAV
-// SPECIAL rs rt rd 0 SRAV
-// 000000 XXXXX XXXXX XXXXX 00000 000111
-//
-// SRL
-// SPECIAL 0 rt rd sa SRL
-// 000000 00000 XXXXX XXXXX XXXXX 000010
-//
-// SRLV
-// SPECIAL rs rt rd 0 SRLV
-// 000000 XXXXX XXXXX XXXXX 00000 000110
-//
-// SUB
-// SPECIAL rs rt rd 0 SUB
-// 000000 XXXXX XXXXX XXXXX 00000 100010
-//
-// SUBU
-// SPECIAL rs rt rd 0 SUBU
-// 000000 XXXXX XXXXX XXXXX 00000 100011
-//
-// SW base rt imm16
-// 101011 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SWCz base rt imm16
-// 1110zz XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SWL base rt imm16
-// 101010 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SWR base rt imm16
-// 101110 XXXXX XXXXX YYYYYYYYYYYYYYYY
-//
-// SYNC
-// SPECIAL 0 stype SYNC
-// 000000 000000000000000 XXXXX 001111
-//
-// SYSCALL
-// SPECIAL Code SYSCALL
-// 000000 XXXXXXXXXXXXXXXXXXXX 001100
-//
-// TEQ
-// SPECIAL rs rt code TEQ
-// 000000 XXXXX XXXXX 0000000000 110100
-//
-// TEQI
-// REGIMM rs TEQI imm16
-// 000001 XXXXX 01100 XXXXXXXXXXXXXXXX
-//
-// TGE
-// SPECIAL rs rt code TGE
-// 000000 XXXXX XXXXX 0000000000 110000
-//
-// TGEI
-// REGIMM rs TGEI imm16
-// 000001 XXXXX 01000 XXXXXXXXXXXXXXXX
-//
-// TGEU
-// SPECIAL rs rt code TGEU
-// 000000 XXXXX XXXXX 0000000000 110001
-//
-// TGEIU
-// REGIMM rs TGEIU imm16
-// 000001 XXXXX 01001 XXXXXXXXXXXXXXXX
-//
-// TLT
-// SPECIAL rs rt code TLT
-// 000000 XXXXX XXXXX 0000000000 110010
-//
-// TLTI
-// REGIMM rs TLTI imm16
-// 000001 XXXXX 01010 XXXXXXXXXXXXXXXX
-//
-// TLTU
-// SPECIAL rs rt code TLTU
-// 000000 XXXXX XXXXX 0000000000 110011
-//
-// TLTIU
-// REGIMM rs TLTIU imm16
-// 000001 XXXXX 01011 XXXXXXXXXXXXXXXX
-//
-// TNE
-// SPECIAL rs rt code TNE
-// 000000 XXXXX XXXXX 0000000000 110110
-//
-// TNEI
-// REGIMM rs TNEI imm16
-// 000001 XXXXX 01110 XXXXXXXXXXXXXXXX
-//
-// XOR
-// SPECIAL rs rt rd 0 XOR
-// 000000 XXXXX XXXXX XXXXX 00000 100110
-//
-// XORI rs rt imm16
-// 001110 XXXXX XXXXX XXXXXXXXXXXXXXXX
-
-
-
-
-
diff --git a/test/test.rs b/test/test.rs
index 7af242d..45ec234 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -1,43 +1,170 @@
+extern crate yaxpeax_arch;
+extern crate yaxpeax_mips;
+
+use yaxpeax_arch::{Arch, Decoder, LengthedInstruction};
+use yaxpeax_mips::{MIPS, Instruction, Opcode};
+
+fn test_decode(data: [u8; 4], expected: Instruction) {
+ let instr = <MIPS as Arch>::Decoder::default().decode(data.to_vec()).unwrap();
+ assert!(
+ instr == expected,
+ "decode error for {:02x}{:02x}{:02x}{:02x}:\n decoded: {:?}\n expected: {:?}\n",
+ data[0], data[1], data[2], data[3],
+ instr, expected
+ );
+}
+
+fn test_display(data: [u8; 4], expected: &'static str) {
+ let instr = <MIPS as Arch>::Decoder::default().decode(data.to_vec()).unwrap();
+ let text = format!("{}", instr);
+ assert!(
+ text == expected,
+ "display error for {:02x}{:02x}{:02x}{:02x}:\n decoded: {:?}\n displayed: {}\n expected: {}\n",
+ data[0], data[1], data[2], data[3],
+ instr,
+ text, expected
+ );
+}
+
#[test]
fn test_arithmetic() {
-// 21080008 addi t0, t0, 8
-// 2129fff8 addi t1, t1, -8
-// 2404010c addiu a0, zero, 0x10c
-// 2508ae20 addui t0, t0, -0x51e0
-// 352923a0 ori t1, t1, 0x23a0
-// 00042300 sll a0, a0, 0xc
+ test_display(
+ [0x08, 0x00, 0x00, 0x21],
+ "addi zero, t0, 0x8"
+ );
+ test_display(
+ [0xf8, 0xff, 0x29, 0x21],
+ "addi t1, t1, -0x8"
+ );
+ test_display(
+ [0x0c, 0x01, 0x04, 0x24],
+ "addiu a0, zero, 0x10c"
+ );
+ test_display(
+ [0x20, 0xae, 0x08, 0x25],
+ "addiu t0, t0, -0x51e0"
+ );
+ test_display(
+ [0xa0, 0x23, 0x29, 0x35],
+ "ori t1, t1, 0x23a0"
+ );
+ test_display(
+ [0x00, 0x23, 0x04, 0x00],
+ "sll a0, a0, 0xc"
+ );
}
#[test]
fn test_br() {
-// 1520fffc bnez t1, 0x80001010
-// 01400008 jr t2
-// 03e00008 jr ra
-// 10000008 b 0x8000171c
-// 0c0005ab jal 0x800016ac
+ test_display(
+ [0xfc, 0xff, 0x20, 0x15],
+ "bne t1, zero, -0x4"
+ );
+ test_display(
+ [0x08, 0x00, 0x40, 0x01],
+ "jr t2"
+ );
+ test_display(
+ [0x08, 0x00, 0xe0, 0x03],
+ "jr ra"
+ );
+ test_display(
+ [0x08, 0x00, 0x00, 0x10],
+ "b $+0x8"
+ );
+ // TODO: this is inaccurate! this really is setting the low 28 bits of $pc, not branching
+ // forward or something.
+ test_display(
+ [0xab, 0x05, 0x00, 0x0c],
+ "jal $+0x16ac"
+ );
}
#[test]
fn test_cmp() {
// slt
// sltu
// slti
-// 2de10007 sltiu at, t7, 1
+ test_display(
+ [0x07, 0x00, 0xe1, 0x2d],
+ "sltiu at, t7, 0x7"
+ );
}
#[test]
fn test_mov() {
-// 8fbf0000 lw ra, (sp)
-// 3c088009 lui t0, 0x8009
-// 3c090002 lui t1, 2
-// 6fc07f00 ldr zero, 0x7f00(fp)
-// a429d266 sh t1, -0x2d9a(at)
-// ad000000 sw zero, (t0)
-// ad000004 sw zero, 4(t0)
-// 02002025 move a0, s0
+ test_display(
+ [0x00, 0x00, 0xbf, 0x8f],
+ "lw ra, (sp)"
+ );
+ test_display(
+ [0x09, 0x80, 0x08, 0x3c],
+ "lui t0, 0x8009"
+ );
+ test_display(
+ [0x02, 0x00, 0x09, 0x3c],
+ "lui t1, 0x2"
+ );
+ test_display(
+ [0x00, 0x7f, 0xc0, 0x6f],
+ "ldr zero, 0x7f00(fp)"
+ );
+ test_display(
+ [0x66, 0xd2, 0x29, 0xa4],
+ "sh t1, -0x2d9a(at)"
+ );
+ test_display(
+ [0x00, 0x00, 0x00, 0xad],
+ "sw zero, (t0)"
+ );
+ test_display(
+ [0x04, 0x00, 0x00, 0xad],
+ "sw zero, 0x4(t0)"
+ );
+ test_display(
+ [0x25, 0x20, 0x00, 0x02],
+ "move a0, s0"
+ );
}
#[test]
fn test_misc() {
-// 00000000 nop
-// 40882800 mtc0 t0, a1, 0
-// 42000002 tlbwi
-// 42000008 tlbp
-// 40085000 mfc t0, t2, 0
+ test_display(
+ [0x00, 0x00, 0x00, 0x00],
+ "nop"
+ );
+ /*test_display(
+ [0x00, 0x28, 0x88, 0x40],
+ "mtc0 t0, a1, 0"
+ );*/
+ test_display(
+ [0x00, 0x28, 0x88, 0x40],
+ "cop1 0x882800"
+ );
+ /*
+ test_display(
+ [0x02, 0x00, 0x00, 0x42],
+ "tlbwi"
+ );
+ */
+ test_display(
+ [0x02, 0x00, 0x00, 0x42],
+ "cop1 0x2000002"
+ );
+ /*
+ test_display(
+ [0x08, 0x00, 0x00, 0x42],
+ "tlbp"
+ );
+ */
+ test_display(
+ [0x08, 0x00, 0x00, 0x42],
+ "cop1 0x2000008"
+ );
+ /*
+ test_display(
+ [0x00, 0x50, 0x08, 0x40],
+ "mfc t0, t2, 0"
+ );
+ */
+ test_display(
+ [0x00, 0x50, 0x08, 0x40],
+ "cop1 0x85000"
+ );
}