summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs809
1 files changed, 677 insertions, 132 deletions
diff --git a/src/lib.rs b/src/lib.rs
index f7a1ef5..1eaf33a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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);
}