diff options
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 809 |
1 files changed, 677 insertions, 132 deletions
@@ -15,6 +15,7 @@ impl Arch for RX { type Operand = Operand; } +#[derive(Debug)] pub struct Instruction { opcode: Opcode, operands: [Operand; 3], @@ -27,12 +28,24 @@ impl Instruction { } pub fn operands(&self) -> &[Operand] { - &self.operands[self.operand_count()] + &self.operands[..self.operand_count() as usize] } pub fn length(&self) -> u8 { self.length } + + fn operand_count(&self) -> u8 { + let mut operands = 0; + for op in self.operands.iter() { + if op == &Operand::Nothing { + return operands; + } + operands += 1; + } + + operands + } } impl Default for Instruction { @@ -78,11 +91,6 @@ impl yaxpeax_arch::Instruction for Instruction { } #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum SizeSpec { - B, W, L, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum PSWBit { C, Z, @@ -92,9 +100,23 @@ pub enum PSWBit { U, } +impl fmt::Display for PSWBit { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + PSWBit::C => f.write_str("c"), + PSWBit::Z => f.write_str("z"), + PSWBit::S => f.write_str("s"), + PSWBit::O => f.write_str("o"), + PSWBit::I => f.write_str("i"), + PSWBit::U => f.write_str("u"), + } + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ControlReg { PSW, + PC, USP, FPSW, BPSW, @@ -102,27 +124,96 @@ pub enum ControlReg { ISP, FINTV, INTB, - EXTB + EXTB, + DPSW, + DCMR, + DECNT, + DEPC, +} + +impl fmt::Display for ControlReg { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ControlReg::PSW => f.write_str("psw"), + ControlReg::PC => f.write_str("pc"), + ControlReg::USP => f.write_str("usp"), + ControlReg::FPSW => f.write_str("fpsw"), + ControlReg::BPSW => f.write_str("bpsw"), + ControlReg::BPC => f.write_str("bpc"), + ControlReg::ISP => f.write_str("isp"), + ControlReg::FINTV => f.write_str("fintv"), + ControlReg::INTB => f.write_str("intb"), + ControlReg::EXTB => f.write_str("extb"), + ControlReg::DPSW => f.write_str("dpsw"), + ControlReg::DCMR => f.write_str("dcmr"), + ControlReg::DECNT => f.write_str("decnt"), + ControlReg::DEPC => f.write_str("DEPC") + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct BitfieldSpec { + bits: u16, +} + +impl fmt::Display for BitfieldSpec { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "#{}, #{}, #{}", self.source_start_bit(), self.destination_start_bit(), self.width()) + } +} + +impl BitfieldSpec { + /// the least-significant bit to start moving from the source operand. this is also described + /// as `slsb` in the `rx` manuals. + fn source_start_bit(&self) -> u8 { + let dslb_and_slsb = ((self.bits >> 10) & 0b11111) as u8; + self.destination_start_bit().wrapping_sub(dslb_and_slsb) & 0x1f + } + + /// the least-significant bit to start moving into in the destination operand. this is also + /// described as `dlsb` in the `rx` manuals. + fn destination_start_bit(&self) -> u8 { + ((self.bits >> 5) & 0b11111) as u8 + } + + /// the number of bits to move from the source operand to the destination operand. + fn width(&self) -> u8 { + let dslb_and_width = ((self.bits >> 10) & 0b11111) as u8; + dslb_and_width.wrapping_sub(self.destination_start_bit()) & 0x1f + } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Operand { + Nothing, /// one of the 16 32-bit general purpose registers: `R0 (sp)` through `R15`. Register { num: u8 }, + /// a range of registers, from `start_gpr` to `end_gpr` + RegisterRange { start_gpr: u8, end_gpr: u8 }, /// one of the 16 32-bit general purpose registers, but a smaller part of it. typically /// sign-extended to 32b for processing. Subreg { num: u8, width: SizeCode }, + Accumulator { num: u8 }, + /// `bfmov` and `bfmovz`, textually, describe the bitfield to be moved with three parameters. + /// those three parameters are expressed as this one operand. + BitfieldSpec { bf_spec: BitfieldSpec }, /// one of the 16 64-bit double-precision floating point registers: `DR0` through `DR15`. DoubleReg { num: u8 }, DoubleRegLow { num: u8 }, DoubleRegHigh { num: u8 }, ControlReg { reg: ControlReg }, + PSWBit { bit: PSWBit }, Deref { gpr: u8, disp: u32, width: SizeCode }, DerefIndexed { base: u8, index: u8, width: SizeCode }, DoubleRegisterRange { start_reg: u8, end_reg: u8 }, DoubleControlRegisterRange { start_reg: u8, end_reg: u8 }, - ImmS(u8), + BrS(u8), ImmB { imm: u8 }, + ImmW { imm: u16 }, + /// a 24-bit immediate. this is used as a branch offset, and is treated as a sign-extended + /// 24-bit value, so it is represented as that extended form here. + BrA { offset: i32 }, ImmL { imm: u32 }, } @@ -150,49 +241,458 @@ impl SizeCode { impl fmt::Display for Operand { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Operand::GPR { num } => { + Operand::Nothing => { + f.write_str("") + }, + Operand::Register { num } => { write!(f, "r{}", num) }, - Operand::ControlRg { reg } => { + Operand::RegisterRange { start_gpr, end_gpr } => { + write!(f, "r{}-r{}", start_gpr, end_gpr) + } + Operand::Subreg { num, width: _unused } => { + // the width of this register is communicated, textually, by a suffix on the + // mnemonic... + write!(f, "r{}", num) + } + Operand::Accumulator { num } => { + write!(f, "a{}", num) + }, + Operand::BitfieldSpec { bf_spec } => { + fmt::Display::fmt(bf_spec, f) + } + Operand::DoubleReg { num } => { + write!(f, "dr{}", num) + }, + Operand::DoubleRegLow { num } => { + write!(f, "drl{}", num) + }, + Operand::DoubleRegHigh { num } => { + write!(f, "drh{}", num) + }, + Operand::ControlReg { reg } => { fmt::Display::fmt(reg, f) }, + Operand::PSWBit { bit } => { + fmt::Display::fmt(bit, f) + } Operand::Deref { gpr, disp, .. } => { - if disp == 0 { + if *disp == 0 { write!(f, "[r{}]", gpr) } else { write!(f, "{}[r{}]", disp, gpr) } }, - Operand::RegisterRange { start_gpr, end_gpr } => { - write!(f, "r{}-r{}", start_gpr, end_gpr) + Operand::DerefIndexed { base, index, .. } => { + // `ri` *is* scaled by the size of the access, but this is communicated as a suffix + // on the instruction... + write!(f, "[r{}, r{}]", base, index) + } + Operand::DoubleRegisterRange { start_reg, end_reg } => { + write!(f, "dr{}-dr{}", start_reg, end_reg) + } + Operand::DoubleControlRegisterRange { start_reg, end_reg } => { + // TODO: give the control registers names... + write!(f, "dcr{}-dcr{}", start_reg, end_reg) + } + Operand::BrS(disp) => { + // a short branch `disp` bytes forward + write!(f, "$+{}", disp) + } + Operand::BrA { offset } => { + // a branch by signed `offset` bytes + write!(f, "$+{}", offset) + } + Operand::ImmB { imm } => { + write!(f, "#{}", imm) + } + Operand::ImmW { imm } => { + write!(f, "#{}", imm) + } + Operand::ImmL { imm } => { + write!(f, "#{}", imm) } } } } +#[allow(non_camel_case_types)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Opcode { + REVW, + REVL, + MSBHI, + MSBLH, + MSBLO, + EMSBA, + MVFACHI, + MVFACLO, + MVFACMI, + MVFACGU, + RACW, + RACL, + RDACW, + RDACL, + MVTACHI, + MVTACLO, + MVTACGU, + XOR, + OR, + AND, + MUL, + ADD, + SUB, + MOVU, + SHLL, + SHAR, + SHLR, BRA, - SUNTIL_B, - SUNTIL_W, - SUNTIL_L, NOP, + MOV, + DMOV, + ROTR, + ROTL, + SCEQ, + SCNE, + SCGEU, + SCLTU, + SCGTU, + SCLEU, + SCPZ, + SCN, + SCGE, + SCLT, + SCGT, + SCLE, + SCO, + SCNO, + BMEQ, + BMNE, + BMGEU, + BMLTU, + BMGTU, + BMLEU, + BMPZ, + BMN, + BMGE, + BMLT, + BMGT, + BMLE, + BMO, + BMNO, + BNOT, FSUB, FCMP, FADD, FMUL, - MOV, - DMOV, + FDIV, + MVFC, + MVFDC, + MVTC, + MVTDC, + STNZ, + STZ, + TST, + DIVU, + DIV, + EMULU, + EMUL, + MIN, + MAX, + ITOD, + FTOD, + UTOD, + ADC, + RSTR, + SAVE, + MULHI, + MULLO, + MULLH, + EMULA, + MACHI, + MACLO, + MACLH, + EMACA, + FTOI, + ITOF, + FTOU, + UTOF, + FSQRT, + ROUND, + BSET, + BCLR, + BTST, + BFMOV, + BFMOVZ, + ABS, + NOT, + XCHG, + SBB, + RTFI, + RTE, + WAIT, + SETPSW, + CLRPSW, + RMPA_B, + RMPA_W, + RMPA_L, + SMOVF, + SATR, + SSTR_B, + SSTR_W, + SSTR_L, + SMOVB, + SWHILE_B, + SWHILE_W, + SWHILE_L, + SMOVU, + SUNTIL_B, + SUNTIL_W, + SUNTIL_L, + SCMPU, + JMP, + JSR, + POP, + POPC, + POPM, + PUSH, + PUSHC, + PUSHM, + RORC, + ROLC, + NEG, + DPUSHM, + DPOP, + DTOF, + DROUND, + DSQRT, + DTOI, + DTOU, + DABS, + DNEG, + DADD, + DSUB, + DMUL, + DDIV, + DCMPUN, + DCMPEQ, + DCMPLT, + DCMPLE, + INT, + MVTIPL, + MVFDR, + CMP, + SAT, + RTSD, + BSR, + BRK, + BEQ, + BNE, + BGEU, + BLTU, + BGTU, + BLEU, + BPZ, + BN, + BGE, + BLT, + BGT, + BLE, + BO, + BNO, + RTS, } impl fmt::Display for Opcode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + Opcode::REVW => f.write_str("revw"), + Opcode::REVL => f.write_str("revl"), + Opcode::MSBHI => f.write_str("msbhi"), + Opcode::MSBLH => f.write_str("msblh"), + Opcode::MSBLO => f.write_str("msblo"), + Opcode::EMSBA => f.write_str("emsba"), + Opcode::MVFACHI => f.write_str("mvfachi"), + Opcode::MVFACLO => f.write_str("mvfaclo"), + Opcode::MVFACMI => f.write_str("mvfacmi"), + Opcode::MVFACGU => f.write_str("mvfacgu"), + Opcode::RACW => f.write_str("racw"), + Opcode::RACL => f.write_str("racl"), + Opcode::RDACW => f.write_str("rdacw"), + Opcode::RDACL => f.write_str("rdacl"), + Opcode::MVTACHI => f.write_str("mvtachi"), + Opcode::MVTACLO => f.write_str("mvtaclo"), + Opcode::MVTACGU => f.write_str("mvtacgu"), + Opcode::XOR => f.write_str("xor"), + Opcode::OR => f.write_str("or"), + Opcode::AND => f.write_str("and"), + Opcode::MUL => f.write_str("mul"), + Opcode::ADD => f.write_str("add"), + Opcode::SUB => f.write_str("sub"), + Opcode::MOVU => f.write_str("movu"), + Opcode::SHLL => f.write_str("shll"), + Opcode::SHAR => f.write_str("shar"), + Opcode::SHLR => f.write_str("shlr"), + Opcode::BRA => f.write_str("bra"), + Opcode::NOP => f.write_str("nop"), + Opcode::MOV => f.write_str("mov"), + Opcode::DMOV => f.write_str("dmov"), + Opcode::ROTR => f.write_str("rotr"), + Opcode::ROTL => f.write_str("rotl"), + Opcode::SCEQ => f.write_str("sceq"), + Opcode::SCNE => f.write_str("scne"), + Opcode::SCGEU => f.write_str("scgeu"), + Opcode::SCLTU => f.write_str("scltu"), + Opcode::SCGTU => f.write_str("scgtu"), + Opcode::SCLEU => f.write_str("scleu"), + Opcode::SCPZ => f.write_str("scpz"), + Opcode::SCN => f.write_str("scn"), + Opcode::SCGE => f.write_str("scge"), + Opcode::SCLT => f.write_str("sclt"), + Opcode::SCGT => f.write_str("scgt"), + Opcode::SCLE => f.write_str("scle"), + Opcode::SCO => f.write_str("sco"), + Opcode::SCNO => f.write_str("scno"), + Opcode::BMEQ => f.write_str("bmeq"), + Opcode::BMNE => f.write_str("bmne"), + Opcode::BMGEU => f.write_str("bmgeu"), + Opcode::BMLTU => f.write_str("bmltu"), + Opcode::BMGTU => f.write_str("bmgtu"), + Opcode::BMLEU => f.write_str("bmleu"), + Opcode::BMPZ => f.write_str("bmpz"), + Opcode::BMN => f.write_str("bmn"), + Opcode::BMGE => f.write_str("bmge"), + Opcode::BMLT => f.write_str("bmlt"), + Opcode::BMGT => f.write_str("bmgt"), + Opcode::BMLE => f.write_str("bmle"), + Opcode::BMO => f.write_str("bmo"), + Opcode::BMNO => f.write_str("bmno"), + Opcode::BNOT => f.write_str("bnot"), + Opcode::FSUB => f.write_str("fsub"), + Opcode::FCMP => f.write_str("fcmp"), + Opcode::FADD => f.write_str("fadd"), + Opcode::FMUL => f.write_str("fmul"), + Opcode::FDIV => f.write_str("fdiv"), + Opcode::MVFC => f.write_str("mvfc"), + Opcode::MVFDC => f.write_str("mvfdc"), + Opcode::MVTC => f.write_str("mvtc"), + Opcode::MVTDC => f.write_str("mvtdc"), + Opcode::STNZ => f.write_str("stnz"), + Opcode::STZ => f.write_str("stz"), + Opcode::TST => f.write_str("tst"), + Opcode::DIVU => f.write_str("divu"), + Opcode::DIV => f.write_str("div"), + Opcode::EMULU => f.write_str("emulu"), + Opcode::EMUL => f.write_str("emul"), + Opcode::MIN => f.write_str("min"), + Opcode::MAX => f.write_str("max"), + Opcode::ITOD => f.write_str("itod"), + Opcode::FTOD => f.write_str("ftod"), + Opcode::UTOD => f.write_str("utod"), + Opcode::ADC => f.write_str("adc"), + Opcode::RSTR => f.write_str("rstr"), + Opcode::SAVE => f.write_str("save"), + Opcode::MULHI => f.write_str("mulhi"), + Opcode::MULLO => f.write_str("mullo"), + Opcode::MULLH => f.write_str("mullh"), + Opcode::EMULA => f.write_str("emula"), + Opcode::MACHI => f.write_str("machi"), + Opcode::MACLO => f.write_str("maclo"), + Opcode::MACLH => f.write_str("maclh"), + Opcode::EMACA => f.write_str("emaca"), + Opcode::FTOI => f.write_str("ftoi"), + Opcode::ITOF => f.write_str("itof"), + Opcode::FTOU => f.write_str("ftou"), + Opcode::UTOF => f.write_str("utof"), + Opcode::FSQRT => f.write_str("fsqrt"), + Opcode::ROUND => f.write_str("round"), + Opcode::BSET => f.write_str("bset"), + Opcode::BCLR => f.write_str("bclr"), + Opcode::BTST => f.write_str("btst"), + Opcode::BFMOV => f.write_str("bfmov"), + Opcode::BFMOVZ => f.write_str("bfmovz"), + Opcode::ABS => f.write_str("abs"), + Opcode::NOT => f.write_str("not"), + Opcode::XCHG => f.write_str("xchg"), + Opcode::SBB => f.write_str("sbb"), + Opcode::RTFI => f.write_str("rtfi"), + Opcode::RTE => f.write_str("rte"), + Opcode::WAIT => f.write_str("wait"), + Opcode::SETPSW => f.write_str("setpsw"), + Opcode::CLRPSW => f.write_str("clrpsw"), + Opcode::RMPA_B => f.write_str("rmpa_b"), + Opcode::RMPA_W => f.write_str("rmpa_w"), + Opcode::RMPA_L => f.write_str("rmpa_l"), + Opcode::SMOVF => f.write_str("smovf"), + Opcode::SATR => f.write_str("satr"), + Opcode::SSTR_B => f.write_str("sstr_b"), + Opcode::SSTR_W => f.write_str("sstr_w"), + Opcode::SSTR_L => f.write_str("sstr_l"), + Opcode::SMOVB => f.write_str("smovb"), + Opcode::SWHILE_B => f.write_str("swhile_b"), + Opcode::SWHILE_W => f.write_str("swhile_w"), + Opcode::SWHILE_L => f.write_str("swhile_l"), + Opcode::SMOVU => f.write_str("smovu"), + Opcode::SUNTIL_B => f.write_str("suntil_b"), + Opcode::SUNTIL_W => f.write_str("suntil_w"), + Opcode::SUNTIL_L => f.write_str("suntil_l"), + Opcode::SCMPU => f.write_str("scmpu"), + Opcode::JMP => f.write_str("jmp"), + Opcode::JSR => f.write_str("jsr"), + Opcode::POP => f.write_str("pop"), + Opcode::POPC => f.write_str("popc"), + Opcode::POPM => f.write_str("popm"), + Opcode::PUSH => f.write_str("push"), + Opcode::PUSHC => f.write_str("pushc"), + Opcode::PUSHM => f.write_str("pushm"), + Opcode::RORC => f.write_str("rorc"), + Opcode::ROLC => f.write_str("rolc"), + Opcode::NEG => f.write_str("neg"), + Opcode::DPUSHM => f.write_str("dpushm"), + Opcode::DPOP => f.write_str("dpop"), + Opcode::DTOF => f.write_str("dtof"), + Opcode::DROUND => f.write_str("dround"), + Opcode::DSQRT => f.write_str("dsqrt"), + Opcode::DTOI => f.write_str("dtoi"), + Opcode::DTOU => f.write_str("dtou"), + Opcode::DABS => f.write_str("dabs"), + Opcode::DNEG => f.write_str("dneg"), + Opcode::DADD => f.write_str("dadd"), + Opcode::DSUB => f.write_str("dsub"), + Opcode::DMUL => f.write_str("dmul"), + Opcode::DDIV => f.write_str("ddiv"), + Opcode::DCMPUN => f.write_str("dcmpun"), + Opcode::DCMPEQ => f.write_str("dcmpeq"), + Opcode::DCMPLT => f.write_str("dcmplt"), + Opcode::DCMPLE => f.write_str("dcmple"), + Opcode::INT => f.write_str("int"), + Opcode::MVTIPL => f.write_str("mvtipl"), + Opcode::MVFDR => f.write_str("mvfdr"), + Opcode::CMP => f.write_str("cmp"), + Opcode::SAT => f.write_str("sat"), + Opcode::RTSD => f.write_str("rtsd"), + Opcode::BSR => f.write_str("bsr"), + Opcode::BRK => f.write_str("brk"), + Opcode::BEQ => f.write_str("beq"), + Opcode::BNE => f.write_str("bne"), + Opcode::BGEU => f.write_str("bgeu"), + Opcode::BLTU => f.write_str("bltu"), + Opcode::BGTU => f.write_str("bgtu"), + Opcode::BLEU => f.write_str("bleu"), + Opcode::BPZ => f.write_str("bpz"), + Opcode::BN => f.write_str("bn"), + Opcode::BGE => f.write_str("bge"), + Opcode::BLT => f.write_str("blt"), + Opcode::BGT => f.write_str("bgt"), + Opcode::BLE => f.write_str("ble"), + Opcode::BO => f.write_str("bo"), + Opcode::BNO => f.write_str("bno"), + Opcode::RTS => f.write_str("rts"), } } } -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord)] #[repr(u8)] pub enum RxVersion { V1, @@ -202,12 +702,10 @@ pub enum RxVersion { impl PartialOrd for RxVersion { fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { - (self as u8).partial_cmp(other) + (*self as u8).partial_cmp(&(*other as u8)) } } -impl Ord for RxVersion {} - #[test] fn versions_compare_right() { assert!(RxVersion::V1 < RxVersion::V2); @@ -289,7 +787,7 @@ trait DecodeHandler<T: Reader<<RX as Arch>::Address, <RX as Arch>::Word>> { words.next_n(&mut buf).ok().ok_or(StandardDecodeError::ExhaustedInput)?; self.on_word_read(buf[0]); self.on_word_read(buf[1]); - Ok(u16::from_le_bytes(buf)); + Ok(u16::from_le_bytes(buf)) } #[inline(always)] fn read_u24(&mut self, words: &mut T) -> Result<u32, <RX as Arch>::DecodeError> { @@ -300,7 +798,12 @@ trait DecodeHandler<T: Reader<<RX as Arch>::Address, <RX as Arch>::Word>> { self.on_word_read(buf[0]); self.on_word_read(buf[1]); self.on_word_read(buf[2]); - Ok(u32::from_le_bytes(buf)); + Ok(u32::from_le_bytes(buf)) + } + #[inline(always)] + fn read_i24(&mut self, words: &mut T) -> Result<i32, <RX as Arch>::DecodeError> { + let v = self.read_u24(words)?; + Ok(((v as i32) << 8) >> 8) } #[inline(always)] fn read_u32(&mut self, words: &mut T) -> Result<u32, <RX as Arch>::DecodeError> { @@ -310,7 +813,7 @@ trait DecodeHandler<T: Reader<<RX as Arch>::Address, <RX as Arch>::Word>> { self.on_word_read(buf[1]); self.on_word_read(buf[2]); self.on_word_read(buf[3]); - Ok(u32::from_le_bytes(buf)); + Ok(u32::from_le_bytes(buf)) } /// helper to decode the bits for an `ld`-style operand, with variants like "deref", "deref /// with displacement", and "deref with larger displacement", into an `Operand`. @@ -321,25 +824,25 @@ trait DecodeHandler<T: Reader<<RX as Arch>::Address, <RX as Arch>::Word>> { /// cases are that either size!=L would trap, or is ignored and means full register width /// regardless. fn decode_mem_op(&mut self, rs: u8, ld: u8, size: SizeCode, words: &mut T) -> Result<Operand, <RX as Arch>::DecodeError> { - match ld { + Ok(match ld { 0b00 => { - Operand::Deref { gpr: rs, disp: 0, size } + Operand::Deref { gpr: rs, disp: 0, width: size } }, 0b01 => { let disp = self.read_u8(words)? as u32; - Operand::Deref { gpr: rs, disp, size } + Operand::Deref { gpr: rs, disp, width: size } } 0b10 => { let disp = self.read_u16(words)? as u32; - Operand::Deref { gpr: rs, disp, size } + Operand::Deref { gpr: rs, disp, width: size } } _ => { // callers (should all be internal) should never pass larger `ld`.. // it's not clear how `` debug_assert!(ld == 0b11); - Operand::GPR { num: rs } + Operand::Register { num: rs } } - } + }) } fn on_decode_start(&mut self) {} fn on_decode_end(&mut self) {} @@ -369,6 +872,7 @@ impl<T: yaxpeax_arch::Reader<<RX as Arch>::Address, <RX as Arch>::Word>> DecodeH impl Decoder<RX> for InstDecoder { fn decode_into<T: Reader<<RX as Arch>::Address, <RX as Arch>::Word>>(&self, inst: &mut Instruction, words: &mut T) -> Result<(), <RX as Arch>::DecodeError> { + decode_inst(self, inst, words) } } @@ -378,23 +882,25 @@ fn decode_inst< >(decoder: &<RX as Arch>::Decoder, handler: &mut H, words: &mut T) -> Result<(), <RX as Arch>::DecodeError> { handler.on_decode_start(); - let b: u8 = handler.read_u8(words)?; + let opc: u8 = handler.read_u8(words)?; - if b == 0b0000_0000 { + if opc == 0b0000_0000 { handler.on_opcode_decoded(Opcode::BRK)?; - } else if b == 0b0000_0001 { + } else if opc == 0b0000_0001 { return Err(StandardDecodeError::InvalidOpcode); - } else if b == 0b0000_0010 { + } else if opc == 0b0000_0010 { handler.on_opcode_decoded(Opcode::RTS)?; - } else if b == 0b0000_0011 { + } else if opc == 0b0000_0011 { handler.on_opcode_decoded(Opcode::NOP)?; - } else if b == 0b0000_0100 { + } else if opc == 0b0000_0100 { handler.on_opcode_decoded(Opcode::BRA)?; - handler.on_operand_decoded(0, Operand::ImmA(handler.read_u24(words)?))?; - } else if b == 0b0000_0101 { + let offset = handler.read_i24(words)?; + handler.on_operand_decoded(0, Operand::BrA { offset })?; + } else if opc == 0b0000_0101 { handler.on_opcode_decoded(Opcode::BSR)?; - handler.on_operand_decoded(0, Operand::ImmA(handler.read_u24(words)?))?; - } else if b == 0b0000_0110 { + let offset = handler.read_i24(words)?; + handler.on_operand_decoded(0, Operand::BrA { offset })?; + } else if opc == 0b0000_0110 { let next: u8 = handler.read_u8(words)?; let mi = (next >> 6) & 0b11; let ld = next & 0b11; @@ -403,7 +909,7 @@ fn decode_inst< if opc < 0b0110 { const OPC_TABLE: [Opcode; 6] = [Opcode::SUB, Opcode::CMP, Opcode::ADD, Opcode::MUL, Opcode::AND, Opcode::OR]; - handler.on_opcode_decoded(OPC_TABLE[opc])?; + handler.on_opcode_decoded(OPC_TABLE[opc as usize])?; } else if opc == 0b1000 { handler.on_opcode_decoded(match next { 0b0_0000 => { @@ -472,39 +978,40 @@ fn decode_inst< let rd = next & 0b1111; let size = [SizeCode::B, SizeCode::W, SizeCode::L, SizeCode::UW][mi as usize]; - let src = handler.decode_mem_op(rs, ld, size, words); + let src = handler.decode_mem_op(rs, ld, size, words)?; handler.on_operand_decoded(0, src)?; - handler.on_operand_decoded(1, Operand::GPR { num: rd })?; + handler.on_operand_decoded(1, Operand::Register { num: rd })?; } else if opc == 0b0000_0111 { return Err(StandardDecodeError::InvalidOpcode); } else if opc < 0b0001_0000 { - handler.on_opcode_decoded(Opcode::BRA); + handler.on_opcode_decoded(Opcode::BRA)?; let disp = opc & 0b111; // TODO: double-check the displacement offset thingy - handler.on_operand_decoded(0, Operand::ImmS(disp))?; + handler.on_operand_decoded(0, Operand::BrS(disp))?; } else if opc < 0b0010_0000 { handler.on_opcode_decoded(if opc & 0b0000_1000 == 0 { Opcode::BEQ } else { Opcode::BNE - }); + })?; let disp = opc & 0b111; // TODO: double-check the displacement offset thingy - handler.on_operand_decoded(0, Operand::ImmS(disp))?; + handler.on_operand_decoded(0, Operand::BrS(disp))?; } else if opc < 0b0011_0000 { // BCnd.B let cond = opc & 0b1111; - const OPC_TABLE: &'static [Opcode] = [ + const OPC_TABLE: &'static [Opcode] = &[ Opcode::BEQ, Opcode::BNE, Opcode::BGEU, Opcode::BLTU, Opcode::BGTU, Opcode::BLEU, Opcode::BPZ, Opcode::BN, Opcode::BGE, Opcode::BLT, Opcode::BGT, Opcode::BLE, Opcode::BO, Opcode::BNO, Opcode::BRA, /* no branch for cnd=1111 */ ]; - if let Some(op) = OPC_TABLE.get(cond) { - handler.on_opcode_decoded(op); - handler.on_operand_decoded(0, Operand::ImmB { imm: handler.read_u8(words)? })?; + if let Some(op) = OPC_TABLE.get(cond as usize) { + handler.on_opcode_decoded(*op)?; + let imm = handler.read_u8(words)?; + handler.on_operand_decoded(0, Operand::ImmB { imm })?; } else { return Err(StandardDecodeError::InvalidOpcode); } @@ -512,16 +1019,20 @@ fn decode_inst< return Err(StandardDecodeError::InvalidOpcode); } else if opc == 0b0011_1000 { handler.on_opcode_decoded(Opcode::BRA)?; - handler.on_operand_decoded(0, Operand::ImmW(handler.read_u16(words)?))?; + let imm = handler.read_u16(words)?; + handler.on_operand_decoded(0, Operand::ImmW { imm })?; } else if opc == 0b0011_1001 { handler.on_opcode_decoded(Opcode::BSR)?; - handler.on_operand_decoded(0, Operand::ImmW(handler.read_u16(words)?))?; + let imm = handler.read_u16(words)?; + handler.on_operand_decoded(0, Operand::ImmW { imm })?; } else if opc == 0b0011_1010 { handler.on_opcode_decoded(Opcode::BEQ)?; - handler.on_operand_decoded(0, Operand::ImmW(handler.read_u16(words)?))?; + let imm = handler.read_u16(words)?; + handler.on_operand_decoded(0, Operand::ImmW { imm })?; } else if opc == 0b0011_1011 { handler.on_opcode_decoded(Opcode::BNE)?; - handler.on_operand_decoded(0, Operand::ImmW(handler.read_u16(words)?))?; + let imm = handler.read_u16(words)?; + handler.on_operand_decoded(0, Operand::ImmW { imm })?; } else if opc < 0b0011_1111 { // MOV.size handler.on_opcode_decoded(Opcode::MOV)?; @@ -532,15 +1043,15 @@ fn decode_inst< match opc & 0b11 { 0b00 => { handler.on_operand_decoded(0, Operand::ImmB { imm: imm as u8 })?; - handler.on_operand_decoded(1, Operand::Deref { gpr: rd, disp, size: SizeCode::B })?; + handler.on_operand_decoded(1, Operand::Deref { gpr: rd, disp, width: SizeCode::B })?; } 0b01 => { handler.on_operand_decoded(0, Operand::ImmW { imm: imm as u8 as u16 })?; - handler.on_operand_decoded(1, Operand::Deref { gpr: rd, disp, size: SizeCode::W })?; + handler.on_operand_decoded(1, Operand::Deref { gpr: rd, disp, width: SizeCode::W })?; } 0b10 => { handler.on_operand_decoded(0, Operand::ImmL { imm: imm as u8 as u32 })?; - handler.on_operand_decoded(1, Operand::Deref { gpr: rd, disp, size: SizeCode::L })?; + handler.on_operand_decoded(1, Operand::Deref { gpr: rd, disp, width: SizeCode::L })?; } _ => { unreachable!("sz=11 is rtsd") } }; @@ -551,7 +1062,8 @@ fn decode_inst< let imm = handler.read_u8(words)?; let rd = operands >> 4; let rd2 = operands & 0b1111; - handler.on_operand_decoded(0, Operand::RegisterRange { start_gpr: rd, end_gpr: rd2 })?; + handler.on_operand_decoded(0, Operand::ImmB { imm })?; + handler.on_operand_decoded(1, Operand::RegisterRange { start_gpr: rd, end_gpr: rd2 })?; } else if opc < 0b0110_0000 { let code = (opc >> 2) & 0b111; let opcode = [ @@ -566,12 +1078,12 @@ fn decode_inst< let rd = operands & 0b1111; let size = [ - SizeSpec::L, SizeSpec::L, SizeSpec::L, SizeSpec::L, - SizeSpec::L, SizeSpec::L, SizeSpec::B, SizeSpec::W, + SizeCode::L, SizeCode::L, SizeCode::L, SizeCode::L, + SizeCode::L, SizeCode::L, SizeCode::B, SizeCode::W, ][code as usize]; let src = handler.decode_mem_op(rs, ld, size, words)?; handler.on_operand_decoded(0, src)?; - handler.on_operand_decoded(1, Operand::Register { gpr: rd })?; + handler.on_operand_decoded(1, Operand::Register { num: rd })?; } else if opc < 0b0111_0000 { // 0 1 1 0 .... let opc = opc & 0b1111; @@ -586,7 +1098,7 @@ fn decode_inst< let imm = operands >> 4; let rd = operands & 0b1111; handler.on_operand_decoded(0, Operand::ImmB { imm })?; - handler.on_operand_decoded(1, Operand::Register { gpr: rd })?; + handler.on_operand_decoded(1, Operand::Register { num: rd })?; } } else if opc < 0b1110 { // 0 1 1 0 1 ... @@ -600,7 +1112,7 @@ fn decode_inst< let imm = operands >> 3; let rd = operands & 0b111; handler.on_operand_decoded(0, Operand::ImmB { imm })?; - handler.on_operand_decoded(1, Operand::Register { gpr: rd })?; + handler.on_operand_decoded(1, Operand::Register { num: rd })?; } else { // 0 1 1 0 1 1 1 x handler.on_opcode_decoded(if opc == 0b1110 { @@ -632,12 +1144,12 @@ fn decode_inst< } _ => { debug_assert!(li == 0b11, "li is at most the low two bits set"); - (((handler.read_u24(words)? as i32) << 8) >> 8) as u32 + handler.read_i24(words)? as u32 } }; handler.on_operand_decoded(0, Operand::ImmL { imm })?; - handler.on_operand_decoded(1, Operand::Register { gpr: rs2 })?; - handler.on_operand_decoded(2, Operand::Register { gpr: rd })?; + handler.on_operand_decoded(1, Operand::Register { num: rs2 })?; + handler.on_operand_decoded(2, Operand::Register { num: rd })?; } else if opc < 0b0111_1000 { // 0 1 1 1 0 1 li let li = opc & 0b11; @@ -676,17 +1188,17 @@ fn decode_inst< handler.read_u8(words)? as i8 as i32 as u32 } 0b10 => { - handler.read_u16(words)? as i16 as i32 + handler.read_u16(words)? as i16 as i32 as u32 } _ => { debug_assert!(li == 0b11, "li is at most the low two bits set"); - ((handler.read_u24(words)? as i32) << 8) >> 8 + handler.read_i24(words)? as u32 } }; if let Some(op) = opcode { handler.on_opcode_decoded(op)?; handler.on_operand_decoded(0, Operand::ImmL { imm })?; - handler.on_operand_decoded(1, Operand::Register { gpr: rd })?; + handler.on_operand_decoded(1, Operand::Register { num: rd })?; } else { if opc == 0b0110 { // might be `int`, depends on rd @@ -696,7 +1208,7 @@ fn decode_inst< } else { return Err(StandardDecodeError::InvalidOperand); } - } else if op == 0b0111 { + } else if opc == 0b0111 { // might be `mvitpl` if rd == 0 && (imm & 0b1111_0000 == 0) { handler.on_opcode_decoded(Opcode::MVTIPL)?; @@ -704,7 +1216,7 @@ fn decode_inst< } else { return Err(StandardDecodeError::InvalidOperand); } - } else if op == 0b1001 { + } else if opc == 0b1001 { // might be `mvfdr`, or other new double-precision instructions if decoder.version < RxVersion::V3 { return Err(StandardDecodeError::InvalidOpcode); @@ -745,6 +1257,7 @@ fn decode_inst< handler.on_opcode_decoded(opc)?; handler.on_operand_decoded(0, Operand::DoubleReg { num: rs })?; handler.on_operand_decoded(1, Operand::DoubleReg { num: rs2 })?; + return Ok(()); } 0b1100 => { // dmovd or a few others, depending on "rs" @@ -759,6 +1272,7 @@ fn decode_inst< handler.on_opcode_decoded(opc)?; handler.on_operand_decoded(0, Operand::DoubleReg { num: rs })?; handler.on_operand_decoded(1, Operand::DoubleReg { num: rd })?; + return Ok(()); } 0b1101 => { // dsqrt or others, depending on "rs" @@ -775,19 +1289,20 @@ fn decode_inst< handler.on_opcode_decoded(opc)?; handler.on_operand_decoded(0, Operand::DoubleReg { num: rs })?; handler.on_operand_decoded(1, Operand::DoubleReg { num: rd })?; + return Ok(()); } _ => { return Err(StandardDecodeError::InvalidOperand); } }; - handler.on_opcode_decoded(opc)?; + handler.on_opcode_decoded(opcode)?; handler.on_operand_decoded(0, Operand::DoubleReg { num: rs })?; handler.on_operand_decoded(1, Operand::DoubleReg { num: rs2 })?; handler.on_operand_decoded(2, Operand::DoubleReg { num: rd })?; } else { return Err(StandardDecodeError::InvalidOperand); } - } else if op == 0b1010 { + } else if opc == 0b1010 { // dpushm.l/dpopm.l let opc = if rd == 0b000 { Opcode::DPUSHM @@ -804,7 +1319,7 @@ fn decode_inst< return Err(StandardDecodeError::InvalidOperand); } handler.on_operand_decoded(0, Operand::DoubleControlRegisterRange { start_reg: rs, end_reg })?; - } else if op == 0b1011 { + } else if opc == 0b1011 { // dpushm.d/dpopm.d let opc = if rd == 0b000 { Opcode::DPUSHM @@ -831,10 +1346,11 @@ fn decode_inst< let operands = handler.read_u8(words)?; let imm = ((opc & 1) << 4) | (operands >> 4); let rd = operands & 0b1111; - let opc = (match operands >> 1) & 0b11 { + let opc = match (operands >> 1) & 0b11 { 0b00 => Opcode::BSET, 0b01 => Opcode::BCLR, - 0b10 => Opcode::BTST, + // already tested for opc=11 by the `if` above, this is opc=10 + _ => Opcode::BTST, }; handler.on_opcode_decoded(opc)?; handler.on_operand_decoded(0, Operand::ImmB { imm })?; @@ -871,11 +1387,11 @@ fn decode_inst< } 0b1000 => { handler.on_opcode_decoded(Opcode::PUSH)?; - handler.on_operand_decoded(0, Operand::Subreg { num: rd, size: SizeCode::B })?; + handler.on_operand_decoded(0, Operand::Subreg { num: rd, width: SizeCode::B })?; } 0b1001 => { handler.on_opcode_decoded(Opcode::PUSH)?; - handler.on_operand_decoded(0, Operand::Subreg { num: rd, size: SizeCode::W })?; + handler.on_operand_decoded(0, Operand::Subreg { num: rd, width: SizeCode::W })?; } 0b1010 => { handler.on_opcode_decoded(Opcode::PUSH)?; @@ -957,7 +1473,7 @@ fn decode_inst< // definitely `1 0 1 1`: `1 1 1 1` would fail the branch above // disp[Rs], Rd handler.on_opcode_decoded(Opcode::MOVU)?; - let sz = (opc >> 3) & 0b1 != 0 { + let sz = if (opc >> 3) & 0b1 != 0 { SizeCode::B } else { SizeCode::W @@ -970,7 +1486,7 @@ fn decode_inst< let disphi = (opc & 0b111) << 2; let disp = displo | dispmid | disphi; handler.on_operand_decoded(0, Operand::Deref { gpr: rs, disp: disp as u32, width: sz })?; - handler.on_operand_decoded(1, Operand::Register { gpr: rd })?; + handler.on_operand_decoded(1, Operand::Register { num: rd })?; } else { handler.on_opcode_decoded(Opcode::MOV)?; let sz = [SizeCode::B, SizeCode::W, SizeCode::L][sz as usize]; @@ -984,40 +1500,50 @@ fn decode_inst< let dispmid = (operands >> 6) & 2; let disphi = (opc & 0b111) << 2; let disp = displo | dispmid | disphi; - if opc & 0b0000_1000 { - handler.on_operand_decoded(0, Operand::Register { gpr: rs })?; + if opc & 0b0000_1000 == 0 { + handler.on_operand_decoded(0, Operand::Register { num: rs })?; handler.on_operand_decoded(1, Operand::Deref { gpr: rd, disp: disp as u32, width: sz })?; } else { handler.on_operand_decoded(0, Operand::Deref { gpr: rs, disp: disp as u32, width: sz })?; - handler.on_operand_decoded(1, Operand::Register { gpr: rd })?; + handler.on_operand_decoded(1, Operand::Register { num: rd })?; } } else { // either operand may have displacement, may be mem-mem let ldd = (opc >> 2) & 0b11; let lds = opc & 0b11; let operands = handler.read_u8(words)?; + let rs = operands & 0b1111; + let rd = operands >> 4; + match (ldd, lds) { (0b11, 0b11) => { // encoding 7, explicitly reg-reg, might involve sign/zero extension - let source_op = if sz == SizeSpec::L { - Operand::Register { gpr: rs } + let source_op = if sz == SizeCode::L { + Operand::Register { num: rs } } else { - Operand::Subreg { gpr: rs, sz } + Operand::Subreg { num: rs, width: sz } }; handler.on_operand_decoded(0, source_op)?; - handler.on_operand_decoded(1, Operand::Register { gpr: rd })?; + handler.on_operand_decoded(1, Operand::Register { num: rd })?; } (ld, 0b11) => { - handler.on_operand_decoded(0, Operand::Register { gpr: rs })?; - handler.on_operand_decoded(1, handler.decode_mem_op(rd, ld, sz, words)?)?; + handler.on_operand_decoded(0, Operand::Register { num: rs })?; + let op = handler.decode_mem_op(rd, ld, sz, words)?; + handler.on_operand_decoded(1, op)?; }, (0b11, ld) => { - handler.on_operand_decoded(0, handler.decode_mem_op(rs, ld, sz, words)?)?; - handler.on_operand_decoded(1, Operand::Register { gpr: rd })?; + // for this one, rs and rd are reversed... + let rs = operands >> 4; + let rd = operands & 0b1111; + let op = handler.decode_mem_op(rs, ld, sz, words)?; + handler.on_operand_decoded(0, op)?; + handler.on_operand_decoded(1, Operand::Register { num: rd })?; }, (ldd, lds) => { - handler.on_operand_decoded(0, handler.decode_mem_op(rs, lds, sz, words)?)?; - handler.on_operand_decoded(1, handler.decode_mem_op(rd, ldd, sz, words)?)?; + let op = handler.decode_mem_op(rs, lds, sz, words)?; + handler.on_operand_decoded(0, op)?; + let op = handler.decode_mem_op(rd, ldd, sz, words)?; + handler.on_operand_decoded(1, op)?; } } } @@ -1041,7 +1567,8 @@ fn decode_inst< Opcode::BCLR }; handler.on_opcode_decoded(opcode)?; - handler.on_operand_decoded(0, operand)?; + handler.on_operand_decoded(0, Operand::ImmB { imm })?; + handler.on_operand_decoded(1, operand)?; } else if opc < 0b1111_1000 { // 1 1 1 1 0 1 x x BTST/PUSH let ld = opc & 0b11; @@ -1053,7 +1580,8 @@ fn decode_inst< let rs = operands >> 4; if operands & 0b0000_1000 == 0 { let imm = operands & 0b111; - handler.on_operand_decoded(1, handler.decode_mem_op(ld, rs, SizeCode::B, words)?)?; + let op = handler.decode_mem_op(ld, rs, SizeCode::B, words)?; + handler.on_operand_decoded(1, op)?; handler.on_operand_decoded(0, Operand::ImmB { imm })?; handler.on_opcode_decoded(Opcode::BTST)?; } else if operands & 0b0000_1100 == 0b0000_1000 { @@ -1064,7 +1592,8 @@ fn decode_inst< _ => { unreachable!("checked for ld!=11 earlier"); } }; - handler.on_operand_decoded(0, handler.decode_mem_op(ld, rs, sz, words)?)?; + let op = handler.decode_mem_op(ld, rs, sz, words)?; + handler.on_operand_decoded(0, op)?; handler.on_opcode_decoded(Opcode::PUSH)?; } else { return Err(StandardDecodeError::InvalidOperand); @@ -1087,24 +1616,25 @@ fn decode_inst< let rd = operands >> 4; match operands & 0b1111 { 0b0000 => { - handler.on_opcode_decoded(Opcode::DMOV); + handler.on_opcode_decoded(Opcode::DMOV)?; handler.on_operand_decoded(1, Operand::DoubleRegLow { num: rd })?; }, 0b0010 => { - handler.on_opcode_decoded(Opcode::DMOV); + handler.on_opcode_decoded(Opcode::DMOV)?; handler.on_operand_decoded(1, Operand::DoubleRegHigh { num: rd })?; }, 0b0011 => { // not really sure what makes the immediate D size here. does hardware // expand the 32b float into a 64b float? - handler.on_opcode_decoded(Opcode::DMOV); + handler.on_opcode_decoded(Opcode::DMOV)?; handler.on_operand_decoded(1, Operand::DoubleReg { num: rd })?; }, _ => { return Err(StandardDecodeError::InvalidOpcode); } } - handler.on_operand_decoded(0, Operand::ImmL { imm: handler.read_u32(words)? })?; + let imm = handler.read_u32(words)?; + handler.on_operand_decoded(0, Operand::ImmL { imm })?; } } else { let rd = operands >> 4; @@ -1131,7 +1661,7 @@ fn decode_inst< } _ => { debug_assert!(li == 0b11, "li is at most the low two bits set"); - (((handler.read_u24(words)? as i32) << 8) >> 8) as u32 + handler.read_i24(words)? as u32 } }; handler.on_opcode_decoded(Opcode::MOV)?; @@ -1228,7 +1758,8 @@ fn decode_inst< return Err(StandardDecodeError::InvalidOpcode); } handler.on_opcode_decoded(Opcode::UTOF)?; - handler.on_operand_decoded(0, handler.decode_mem_op(ld, rs, SizeCode::L, words)?)?; + let op = handler.decode_mem_op(ld, rs, SizeCode::L, words)?; + handler.on_operand_decoded(0, op)?; handler.on_operand_decoded(1, Operand::Register { num: rd })?; } else if opc5 < 0b11000 { // 1 1 1 1 1 1 0 0 | 0 1 1 0 x x .. @@ -1253,7 +1784,8 @@ fn decode_inst< let opcode = [Opcode::BSET, Opcode::BCLR, Opcode::BTST, Opcode::BNOT][opc5 as usize & 0b11]; handler.on_opcode_decoded(opcode)?; handler.on_operand_decoded(0, Operand::Register { num: rs })?; - handler.on_operand_decoded(1, handler.decode_mem_op(ld, rd, SizeCode::B, words)?)?; + let op = handler.decode_mem_op(ld, rd, SizeCode::B, words)?; + handler.on_operand_decoded(1, op)?; } else if opc5 == 0b11110 { if decoder.version < RxVersion::V3 { return Err(StandardDecodeError::InvalidOpcode); @@ -1363,7 +1895,8 @@ fn decode_inst< Opcode::SCO, Opcode::SCNO, Opcode::NOP, Opcode::NOP // "NOP" is never reached: cnd>=1110, invalid above ][cnd as usize]; handler.on_opcode_decoded(opcode)?; - handler.on_operand_decoded(0, handler.decode_mem_op(ld, rd, sz, words)?)?; + let op = handler.decode_mem_op(ld, rd, sz, words)?; + handler.on_operand_decoded(0, op)?; } else if opc5 >= 0b11000 { // 1 1 1 1 1 1 0 0 | 1 1 1 [imm3] .. let operands = handler.read_u8(words)?; @@ -1378,6 +1911,7 @@ fn decode_inst< let opcode = if cnd == 0b1111 { Opcode::BNOT } else if cnd == 0b1110 { + return Err(StandardDecodeError::InvalidOpcode); } else { [ Opcode::BMEQ, Opcode::BMNE, Opcode::BMGEU, Opcode::BMLTU, @@ -1388,7 +1922,8 @@ fn decode_inst< }; handler.on_opcode_decoded(opcode)?; handler.on_operand_decoded(0, Operand::ImmB { imm })?; - handler.on_operand_decoded(1, handler.decode_mem_op(ld, rd, SizeCode::B, words)?)?; + let op = handler.decode_mem_op(ld, rd, SizeCode::B, words)?; + handler.on_operand_decoded(1, op)?; } else { unreachable!("should be unreachable, fuzzing will tell.."); } @@ -1427,9 +1962,9 @@ fn decode_inst< _ => Opcode::EMACA, }; handler.on_opcode_decoded(opcode)?; - handler.on_operand_decoded(0, Opcode::Register { num: rs })?; - handler.on_operand_decoded(1, Opcode::Register { num: rs })?; - handler.on_operand_decoded(2, Opcode::Accumulator { num: a })?; + handler.on_operand_decoded(0, Operand::Register { num: rs })?; + handler.on_operand_decoded(1, Operand::Register { num: rs2 })?; + handler.on_operand_decoded(2, Operand::Accumulator { num: a })?; } else if opcode == 0b0001_0111 { let operands = handler.read_u8(words)?; let rs = operands & 0b1111; @@ -1454,14 +1989,16 @@ fn decode_inst< } }; handler.on_opcode_decoded(opcode)?; - handler.on_operand_decoded(0, Opcode::Register { num: rs })?; - handler.on_operand_decoded(1, Opcode::Accumulator { num: a })?; + handler.on_operand_decoded(0, Operand::Register { num: rs })?; + handler.on_operand_decoded(1, Operand::Accumulator { num: a })?; } else if opcode & 0b1111_1110 == 0b0001_1000 { - // we can use the lowest bit of opcode to decide if this is racw/racl (0==r==racw) - let lr = opcode & 1; + // we can use the lowest bit of opcode to decide if this is racw/racl (0==racw) + let wide = opcode & 1; let operands = handler.read_u8(words)?; - let rs = operands & 0b1111; + if operands & 0b1111 != 0 { + return Err(StandardDecodeError::InvalidOperand); + } let imm = (operands >> 4) & 0b11; let opc = (operands >> 6) & 1; let a = operands >> 7; @@ -1475,13 +2012,13 @@ fn decode_inst< } let opcode = if opc == 0 { - if lr == 0 { Opcode::RACW } else { Opcode::RACL } + if wide == 0 { Opcode::RACW } else { Opcode::RACL } } else if decoder.version >= RxVersion::V2 { - if lr == 0 { Opcode::RDACW } else { Opcode::RDACL } + if wide == 0 { Opcode::RDACW } else { Opcode::RDACL } } else { return Err(StandardDecodeError::InvalidOpcode); }; - handler.on_opcode_decoded(opcode); + handler.on_opcode_decoded(opcode)?; handler.on_operand_decoded(0, Operand::ImmB { imm: imm + 1 })?; handler.on_operand_decoded(1, Operand::Accumulator { num: a })?; } else if opcode & 0b1111_1110 == 0b0001_1110 { @@ -1577,7 +2114,7 @@ fn decode_inst< // can't move to pc return Err(StandardDecodeError::InvalidOperand); } - handler.on_opcode_deoded(Opcode::MVTC)?; + handler.on_opcode_decoded(Opcode::MVTC)?; handler.on_operand_decoded(0, Operand::Register { num: rs })?; handler.on_operand_decoded(1, decoder.reg_to_control_reg(cr)?)?; } else if opcode == 0b0110_1010 { @@ -1585,7 +2122,7 @@ fn decode_inst< let rd = operands & 0b1111; let cr = operands >> 4; - handler.on_opcode_deoded(Opcode::MVFC)?; + handler.on_opcode_decoded(Opcode::MVFC)?; handler.on_operand_decoded(0, decoder.reg_to_control_reg(cr)?)?; handler.on_operand_decoded(1, Operand::Register { num: rd })?; } else if opcode < 0b0110_1100 { @@ -1735,6 +2272,9 @@ fn decode_inst< handler.on_operand_decoded(0, Operand::Register { num: rs })?; handler.on_operand_decoded(1, Operand::DoubleReg { num: rd })?; } + _ => { + return Err(StandardDecodeError::InvalidOpcode); + } } } else if opcode < 0b0111_0000 { // any unhandled cases below 0111_0000, which need more... careful handling. @@ -1775,7 +2315,7 @@ fn decode_inst< } _ => { debug_assert!(li == 0b11, "li is at most the low two bits set"); - (((handler.read_u24(words)? as i32) << 8) >> 8) as u32 + handler.read_i24(words)? as u32 } }; handler.on_operand_decoded(0, Operand::ImmL { imm })?; @@ -1807,7 +2347,7 @@ fn decode_inst< } _ => { debug_assert!(li == 0b11, "li is at most the low two bits set"); - (((handler.read_u24(words)? as i32) << 8) >> 8) as u32 + handler.read_i24(words)? as u32 } }; handler.on_operand_decoded(0, Operand::ImmL { imm })?; @@ -1828,8 +2368,9 @@ fn decode_inst< handler.on_opcode_decoded( [Opcode::FSUB, Opcode::FCMP, Opcode::FADD, Opcode::FMUL, Opcode::FDIV][opcode as usize] )?; - handler.on_operand_decoded(0, Operand::ImmL { imm: handler.read_u32(words)? })?; - handler.on_operand_decoded(1, Operand::Register { num: rd }); + let imm = handler.read_u32(words)?; + handler.on_operand_decoded(0, Operand::ImmL { imm })?; + handler.on_operand_decoded(1, Operand::Register { num: rd })?; } else { return Err(StandardDecodeError::InvalidOpcode); } @@ -1854,7 +2395,7 @@ fn decode_inst< Opcode::BMO, Opcode::BMNO, Opcode::NOP, Opcode::BNOT // "NOP" is never reached: cnd>=1110, invalid above ][cnd as usize]; handler.on_opcode_decoded(opcode)?; - handler.on_operand_decoded(0, Operand::ImmB { imm })?; + handler.on_operand_decoded(0, Operand::ImmB { imm: imm5 })?; handler.on_operand_decoded(1, Operand::Register { num: rd })?; } else { let opcode = [Opcode::SHLR, Opcode::SHAR, Opcode::SHLL][opc as usize]; @@ -1869,7 +2410,7 @@ fn decode_inst< let operands = handler.read_u8(words)?; let next_regs = handler.read_u8(words)?; let ri = operands & 0b1111; - let rb = next_reg >> 4; + let rb = next_regs >> 4; let rd = next_regs & 0b1111; let sz = (operands >> 4) & 0b11; @@ -1877,18 +2418,22 @@ fn decode_inst< return Err(StandardDecodeError::InvalidOperand); } - if operands < 0b0100 { + let sz = [SizeCode::B, SizeCode::W, SizeCode::L][sz as usize]; + + if operands < 0b0100_0000 { handler.on_opcode_decoded(Opcode::MOV)?; - handler.on_operand_decoded(0, Operand::Register { num: rs })?; + handler.on_operand_decoded(0, Operand::Register { num: rd })?; handler.on_operand_decoded(1, Operand::DerefIndexed { base: rb, index: ri, width: sz })?; - } else if operands < 0b1000 { + } else if operands < 0b1000_0000 { handler.on_opcode_decoded(Opcode::MOV)?; handler.on_operand_decoded(0, Operand::DerefIndexed { base: rb, index: ri, width: sz })?; handler.on_operand_decoded(1, Operand::Register { num: rd })?; - } else if operands < 0b1100 { + } else if operands < 0b1100_0000 { + // 1 1 1 1 1 1 1 0 | 1 0 .. + // nothing encoded here return Err(StandardDecodeError::InvalidOpcode); - } else if operands < 0b1110 { - if sz == 0b10 { + } else if operands < 0b1110_0000 { + if sz == SizeCode::L { return Err(StandardDecodeError::InvalidOperand); } |