diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Cargo.toml | 26 | ||||
-rw-r--r-- | src/display.rs | 260 | ||||
-rw-r--r-- | src/lib.rs | 793 | ||||
-rw-r--r-- | src/mips_data.rs | 561 | ||||
-rw-r--r-- | test/test.rs | 177 |
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"), + } + } +} @@ -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" + ); } |