From 27ca89a15ab51af8620859203896142958991428 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sat, 5 Oct 2024 13:17:33 -0700 Subject: more ops, transcription errors --- notes/encoding_table | 2 +- notes/todo | 44 +++++++------- src/display.rs | 37 ++++++++++-- src/lib.rs | 162 ++++++++++++++++++++++++++++++++++++++++++++------- tests/from_brain.rs | 29 +++++++++ 5 files changed, 226 insertions(+), 48 deletions(-) diff --git a/notes/encoding_table b/notes/encoding_table index 4da12fe..2b23488 100644 --- a/notes/encoding_table +++ b/notes/encoding_table @@ -937,7 +937,7 @@ A L I A S A L I A S A L I A S A L I A S A L I A S | Rd=zxtb(Rs) |0 1 0 1|0 1 0 0 1 0 -|x x x x x| P P |- i i i i i - - -|i i i - -| trap1(Rx,#u8) - SYSTEM/slot 2 |0 1 0 1|0 1 1 1 1 1 1|x x x x x| P P |0 1 - - - - 0 0 0|- - - - -| unpause - SYSTEM/slot 2 |ICLASS |RegType|MajOp|s5 |Parse| |MinOp|d5 | -|1 0 0 0|0 0 0 0|1 0 0|s s s s s| P P |- - - - - -|1 1 0|- - - - -| Rdd=abs(Rss) - XTYPE ALU/slot 2,3 +|1 0 0 0|0 0 0 0|1 0 0|s s s s s| P P |- - - - - -|1 1 0|d d d d d| Rdd=abs(Rss) - XTYPE ALU/slot 2,3 |1 0 0 0|1 1 0 0|1 0 0|s s s s s| P P |- - - - - -|1 0 0|d d d d d| Rd=abs(Rs) - XTYPE ALU/slot 2,3 |1 0 0 0|1 1 0 0|1 0 0|s s s s s| P P |- - - - - -|1 0 1|d d d d d| Rd=abs(Rs) - XTYPE ALU/slot 2,3 diff --git a/notes/todo b/notes/todo index 7f0591b..7a395e9 100644 --- a/notes/todo +++ b/notes/todo @@ -343,20 +343,20 @@ A L I A S A L I A S A L I A S A L I A S A L I A S | Rd=zxtb(Rs) |0 1 1 0|0 0 0 1 0 1 i|s s s s s| P P |i 1 i i i i i i i|i i i i -| if (Rs>=#0) jump:t #r13:2 - J/slot 3 |0 1 1 0|0 0 0 1 1 1 i|s s s s s| P P |i 0 i i i i i i i|i i i i -| if (Rs<=#0) jump:nt #r13:2 - J/slot 3 |0 1 1 0|0 0 0 1 1 1 i|s s s s s| P P |i 1 i i i i i i i|i i i i -| if (Rs<=#0) jump:t #r13:2 - J/slot 3 -|0 1 1 0|0 0 1 0 0 0 1|s s s s s| P P |- - - - - - - - -|d d d d d| Cd=Rs - CR/slot 3 - CONTROL REGISTERS ARE NOT NUMBERED NORMALLY + |0 1 1 0|0 0 1 0 0 1 0|s s s s s| P P |- - - - - - 0 0 0|- - - - -| trace(Rs) - SYSTEM/slot 3 |0 1 1 0|0 0 1 0 0 1 0|s s s s s| P P |- - - - - - 0 0 1|- - - - -| diag(Rs) - SYSTEM/slot 3 |0 1 1 0|0 0 1 0 0 1 0|s s s s s| P P |- t t t t t 0 1 0|- - - - -| diag0(Rss,Rtt) - SYSTEM/slot 3 |0 1 1 0|0 0 1 0 0 1 0|s s s s s| P P |- t t t t t 0 1 1|- - - - -| diag1(Rss,Rtt) - SYSTEM/slot 3 -|0 1 1 0|0 0 1 1 0 0 1|s s s s s| P P |- - - - - - - - -|d d d d d| Cdd=Rss - CR/slot 3 - CONTROL REGISTERS ARE NOT NUMBERED NORMALLY -|0 1 1 0|1 0 0 0 0 0 0|s s s s s| P P |- - - - - - - - -|d d d d d| Rss=Cdd - CR/slot 3 - CONTROL REGISTERS ARE NOT NUMBERED NORMALLY + + |0 1 1 0|1 0 0 1 0 0 0|l l l l l| P P |- i i i i i l l l|i i - l l| loop1(#r7:2,#U10) - CR/slot 3 |0 1 1 0|1 0 0 1 0 0 1|l l l l l| P P |- i i i i i l l l|i i - l l| loop1(#r7:2,#U10) - CR/slot 3 |0 1 1 0|1 0 0 1 1 0 1|l l l l l| P P |- i i i i i l l l|i i - l l| p3=sp1loop0(#r7:2,#U10) - CR/slot 3 |0 1 1 0|1 0 0 1 1 1 0|l l l l l| P P |- i i i i i l l l|i i - l l| p3=sp2loop0(#r7:2,#U10) - CR/slot 3 |0 1 1 0|1 0 0 1 1 1 1|l l l l l| P P |- i i i i i l l l|i i - l l| p3=sp3loop0(#r7:2,#U10) - CR/slot 3 -|0 1 1 0|1 0 1 0 0 0 0|s s s s s| P P |- - - - - - - - -|d d d d d| Rs=Cd - CR/slot 3 - CONTROL REGISTERS ARE NOT NUMBERED NORMALLY -|0 1 1 0|1 0 1 0 0 1 0|0 1 0 0 1| P P |- i i i i i i - -|d d d d d| Rd=add(pc,#u6) - CR/slot 3 + + |0 1 1 0|1 0 1 1 0 0 0|0 - - s s| P P |0 - - - t t - - -|- - - d d| Pd=and(Pt,Ps) - CR/slot 3 |0 1 1 0|1 0 1 1 0 0 0|0 - - s s| P P |1 - - - t t 1 - -|1 - - d d| Pd=fastcorner9(Ps,Pt) - CR/slot 3 |0 1 1 0|1 0 1 1 0 0 0|1 - - s s| P P |0 - - - t t u u -|- - - d d| Pd=and(Ps,and(Pt,Pu)) - CR/slot 3 @@ -437,25 +437,25 @@ A L I A S A L I A S A L I A S A L I A S A L I A S | Rd=zxtb(Rs) -|1 0 0 0|0 0 0 0|0 0 0|s s s s s| P P |- - - - - -|1 0 0|d d d d d| Rdd=vsathub(Rss) - XTYPE PERM/slot 2,3 -|1 0 0 0|0 0 0 0|0 0 0|s s s s s| P P |- - - - - -|1 0 1|d d d d d| Rdd=vsatwuh(Rss) - XTYPE PERM/slot 2,3 -|1 0 0 0|0 0 0 0|0 0 0|s s s s s| P P |- - - - - -|1 1 0|d d d d d| Rdd=vsatwh(Rss) - XTYPE PERM/slot 2,3 -|1 0 0 0|0 0 0 0|0 0 0|s s s s s| P P |- - - - - -|1 1 1|d d d d d| Rdd=vsathb(Rss) - XTYPE PERM/slot 2,3 -|1 0 0 0|0 0 0 0|0 0 0|s s s s s| P P |i i i i i i|0 0 0|d d d d d| Rdd=asr(Rss,#u6) - XTYPE PERM/slot 2,3 -|1 0 0 0|0 0 0 0|0 0 0|s s s s s| P P |i i i i i i|0 0 1|d d d d d| Rdd=lsr(Rss,#u6) - XTYPE PERM/slot 2,3 -|1 0 0 0|0 0 0 0|0 0 0|s s s s s| P P |i i i i i i|0 1 0|d d d d d| Rdd=asl(Rss,#u6) - XTYPE PERM/slot 2,3 -|1 0 0 0|0 0 0 0|0 0 0|s s s s s| P P |i i i i i i|0 1 1|d d d d d| Rdd=rol(Rss,#u6) - XTYPE PERM/slot 2,3 -|1 0 0 0|0 0 0 0|0 0 1|s s s s s| P P |0 0 i i i i|0 0 0|d d d d d| Rdd=vasrh(Rss,#u4):raw - XTYPE PERM/slot 2,3 -|1 0 0 0|0 0 0 0|0 1 0|s s s s s| P P |- - - - - -|1 0 0|d d d d d| Rdd=vabsh(Rss) - XTYPE ALU/slot 2,3 -|1 0 0 0|0 0 0 0|0 1 0|s s s s s| P P |- - - - - -|1 0 1|d d d d d| Rdd=vabsh(Rss):sat - XTYPE ALU/slot 2,3 -|1 0 0 0|0 0 0 0|0 1 0|s s s s s| P P |- - - - - -|1 1 0|d d d d d| Rdd=vabsw(Rss) - XTYPE ALU/slot 2,3 -|1 0 0 0|0 0 0 0|0 1 0|s s s s s| P P |- - - - - -|1 1 1|d d d d d| Rdd=vabsw(Rss):sat - XTYPE ALU/slot 2,3 -|1 0 0 0|0 0 0 0|0 1 0|s s s s s| P P |0 i i i i i|0 0 0|d d d d d| Rdd=vasrw(Rss,#u5) - XTYPE PERM/slot 2,3 -|1 0 0 0|0 0 0 0|0 1 0|s s s s s| P P |0 i i i i i|0 0 1|d d d d d| Rdd=vlsrw(Rss,#u5) - XTYPE PERM/slot 2,3 -|1 0 0 0|0 0 0 0|0 1 0|s s s s s| P P |0 i i i i i|0 1 0|d d d d d| Rdd=vaslw(Rss,#u5) - XTYPE PERM/slot 2,3 + + + + + + + + + + + + + + + + |1 0 0 0|0 0 0 0|1 0 0|s s s s s| P P |- - - - - -|1 0 0|d d d d d| Rdd=not(Rss) - XTYPE ALU/slot 2,3 |1 0 0 0|0 0 0 0|1 0 0|s s s s s| P P |- - - - - -|1 0 1|d d d d d| Rdd=neg(Rss) - XTYPE ALU/slot 2,3 -|1 0 0 0|0 0 0 0|1 0 0|s s s s s| P P |- - - - - -|1 1 0|- - - - -| Rdd=abs(Rss) - XTYPE ALU/slot 2,3 +|1 0 0 0|0 0 0 0|1 0 0|s s s s s| P P |- - - - - -|1 1 0|d d d d d| Rdd=abs(Rss) - XTYPE ALU/slot 2,3 |1 0 0 0|0 0 0 0|1 0 0|s s s s s| P P |- - - - - -|1 1 1|d d d d d| Rdd=vconj(Rss):sat - XTYPE COMPLEX/slot 2,3 |1 0 0 0|0 0 0 0|1 0 0|s s s s s| P P |0 0 i i i i|0 0 0|d d d d d| Rdd=vasrh(Rss,#u4) - XTYPE PERM/slot 2,3 |1 0 0 0|0 0 0 0|1 0 0|s s s s s| P P |0 0 i i i i|0 0 1|d d d d d| Rdd=vlsrh(Rss,#u4) - XTYPE PERM/slot 2,3 diff --git a/src/display.rs b/src/display.rs index 8970a50..9a584a5 100644 --- a/src/display.rs +++ b/src/display.rs @@ -24,7 +24,7 @@ impl fmt::Display for InstructionPacket { impl fmt::Display for Instruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(predication) = self.predicate { + if let Some(predication) = self.flags.predicate { write!(f, "if ({}P{}{}) ", if predication.negated() { "!" } else { "" }, predication.num(), @@ -62,7 +62,7 @@ impl fmt::Display for Instruction { ]; if JUMPS.contains(&self.opcode) { use crate::BranchHint; - let hint_label = match self.branch_hinted.unwrap() { + let hint_label = match self.flags.branch_hint.unwrap() { BranchHint::Taken => { "t" }, BranchHint::NotTaken => { "nt" }, }; @@ -85,7 +85,7 @@ impl fmt::Display for Instruction { return Ok(()); } - if self.negated { + if self.flags.negated { f.write_str("!")?; } write!(f, "{}", self.opcode)?; @@ -99,6 +99,12 @@ impl fmt::Display for Instruction { f.write_str(")")?; } + if let Some(mode) = self.flags.rounded { + write!(f, "{}", mode.as_label())?; + } + if self.flags.saturate { + f.write_str(":sat")?; + } Ok(()) } } @@ -167,6 +173,22 @@ impl fmt::Display for Opcode { Opcode::TlbInvAsid => { f.write_str("tlbinvasid") }, Opcode::Ctlbw => { f.write_str("ctlbw") }, Opcode::Tlboc => { f.write_str("tlboc") }, + + Opcode::Asr => { f.write_str("asr") }, + Opcode::Lsr => { f.write_str("lsr") }, + Opcode::Asl => { f.write_str("asl") }, + Opcode::Rol => { f.write_str("rol") }, + Opcode::Vsathub => { f.write_str("vsathub") }, + Opcode::Vsatwuh => { f.write_str("vsatwuh") }, + Opcode::Vsatwh => { f.write_str("vsatwh") }, + Opcode::Vsathb => { f.write_str("vsathb") }, + Opcode::Vasrh => { f.write_str("vasrh") }, + + Opcode::Vabsh => { f.write_str("vabsh") }, + Opcode::Vabsw => { f.write_str("vabsw") }, + Opcode::Vasrw => { f.write_str("vasrw") }, + Opcode::Vlsrw => { f.write_str("vlsrw") }, + Opcode::Vaslw => { f.write_str("vaslw") }, } } } @@ -184,7 +206,14 @@ impl fmt::Display for Operand { write!(f, "R{}", reg) } Operand::Cr { reg } => { - write!(f, "C{}", reg) + match reg { + 9 => { + f.write_str("pc") + } + reg => { + write!(f, "C{}", reg) + } + } } Operand::Sr { reg } => { write!(f, "S{}", reg) diff --git a/src/lib.rs b/src/lib.rs index f3e69c6..a332b53 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -196,13 +196,48 @@ pub struct InstructionPacket { pub struct Instruction { opcode: Opcode, dest: Option, - predicate: Option, - negated: bool, - branch_hinted: Option, + flags: InstFlags, + sources: [Operand; 3], sources_count: u8, } +#[derive(Debug, Copy, Clone)] +enum RoundingMode { + Round, + Raw, +} + +impl RoundingMode { + fn as_label(&self) -> &'static str { + match self { + RoundingMode::Round => ":rnd", + RoundingMode::Raw => ":raw", + } + } +} + +#[derive(Debug, Copy, Clone)] +struct InstFlags { + predicate: Option, + branch_hint: Option, + negated: bool, + saturate: bool, + rounded: Option, +} + +impl Default for InstFlags { + fn default() -> Self { + Self { + predicate: None, + branch_hint: None, + negated: false, + saturate: false, + rounded: None, + } + } +} + /// V73 Section 3.1 indicates that jumps have taken/not-taken hints, saturation can be a hint, /// rounding can be a hint, predicate can be used for carry in/out, result shifting by fixed /// counts, and load/store reordering prevention are all kinds of hints that may be present. @@ -311,6 +346,22 @@ pub enum Opcode { TlbInvAsid, Ctlbw, Tlboc, + + Asr, + Lsr, + Asl, + Rol, + Vsathub, + Vsatwuh, + Vsatwh, + Vsathb, + Vasrh, + + Vabsh, + Vabsw, + Vasrw, + Vlsrw, + Vaslw, } impl Opcode { @@ -519,9 +570,7 @@ impl Default for Instruction { Instruction { opcode: Opcode::BUG, dest: None, - predicate: None, - negated: false, - branch_hinted: None, + flags: InstFlags::default(), sources: [Operand::Nothing, Operand::Nothing, Operand::Nothing], sources_count: 0, } @@ -743,7 +792,9 @@ trait DecodeHandler::Address, ::Wor fn on_dest_decoded(&mut self, _operand: Operand) -> Result<(), ::DecodeError> { Ok(()) } fn inst_predicated(&mut self, num: u8, negated: bool, pred_new: bool) -> Result<(), ::DecodeError> { Ok(()) } fn negate_result(&mut self) -> Result<(), ::DecodeError> { Ok(()) } + fn saturate(&mut self) -> Result<(), ::DecodeError> { Ok(()) } fn branch_hint(&mut self, hint_taken: bool) -> Result<(), ::DecodeError> { Ok(()) } + fn rounded(&mut self, mode: RoundingMode) -> Result<(), ::DecodeError> { Ok(()) } fn on_word_read(&mut self, _word: ::Word) {} } @@ -773,27 +824,40 @@ impl::Address, ::Word Ok(()) } fn inst_predicated(&mut self, num: u8, negated: bool, pred_new: bool) -> Result<(), ::DecodeError> { - let mut inst = &mut self.instructions[self.instruction_count as usize]; - assert!(inst.predicate.is_none()); - inst.predicate = Some(Predicate::reg(num).set_negated(negated).set_pred_new(pred_new)); + let mut flags = &mut self.instructions[self.instruction_count as usize].flags; + assert!(flags.predicate.is_none()); + flags.predicate = Some(Predicate::reg(num).set_negated(negated).set_pred_new(pred_new)); Ok(()) } fn negate_result(&mut self) -> Result<(), ::DecodeError> { - let mut inst = &mut self.instructions[self.instruction_count as usize]; - assert!(!inst.negated); - inst.negated = true; + let mut flags = &mut self.instructions[self.instruction_count as usize].flags; + assert!(!flags.negated); + flags.negated = true; + Ok(()) + } + fn saturate(&mut self) -> Result<(), ::DecodeError> { + let mut flags = &mut self.instructions[self.instruction_count as usize].flags; + assert!(!flags.saturate); + flags.saturate = true; Ok(()) + } fn branch_hint(&mut self, hint_taken: bool) -> Result<(), ::DecodeError> { - let mut inst = &mut self.instructions[self.instruction_count as usize]; - assert!(inst.branch_hinted.is_none()); + let mut flags = &mut self.instructions[self.instruction_count as usize].flags; + assert!(flags.branch_hint.is_none()); if hint_taken { - inst.branch_hinted = Some(BranchHint::Taken); + flags.branch_hint = Some(BranchHint::Taken); } else { - inst.branch_hinted = Some(BranchHint::NotTaken); + flags.branch_hint = Some(BranchHint::NotTaken); } Ok(()) } + fn rounded(&mut self, mode: RoundingMode) -> Result<(), ::DecodeError> { + let mut flags = &mut self.instructions[self.instruction_count as usize].flags; + assert!(flags.rounded.is_none()); + flags.rounded = Some(mode); + Ok(()) + } #[inline(always)] fn read_inst_word(&mut self, words: &mut T) -> Result::DecodeError> { self.word_count += 1; @@ -1309,15 +1373,15 @@ fn decode_instruction< let sssss = reg_b16(inst); let ddddd = reg_b0(inst); handler.on_opcode_decoded(Opcode::TransferRegister)?; - handler.on_source_decoded(Operand::crpair(ddddd)?)?; - handler.on_dest_decoded(Operand::gprpair(sssss)?)?; + handler.on_source_decoded(Operand::crpair(sssss)?)?; + handler.on_dest_decoded(Operand::gprpair(ddddd)?)?; } 0b1010000 => { let sssss = reg_b16(inst); let ddddd = reg_b0(inst); handler.on_opcode_decoded(Opcode::TransferRegister)?; - handler.on_source_decoded(Operand::cr(ddddd))?; - handler.on_dest_decoded(Operand::gpr(sssss))?; + handler.on_source_decoded(Operand::cr(sssss))?; + handler.on_dest_decoded(Operand::gpr(ddddd))?; } 0b1010010 => { if (inst >> 16) & 0b11111 != 0b01001 { @@ -1658,9 +1722,65 @@ fn decode_instruction< } } } + 0b1000 => { + let ddddd = reg_b0(inst); + let iiiiii = ((inst >> 8) & 0b111111) as u8; + let sssss = reg_b16(inst); + + let majbits = (inst >> 24) & 0b1111; + let minbits = (inst >> 21) & 0b111; + let op_low = (inst >> 5) & 0b111; + + match majbits { + 0b0000 => { + handler.on_source_decoded(Operand::gprpair(sssss)?)?; + handler.on_dest_decoded(Operand::gprpair(ddddd)?)?; + match minbits { + 0b000 => { + static OPS: [Opcode; 8] = [ + Asr, Lsr, Asl, Rol, + Vsathub, Vsatwuh, Vsatwh, Vsathb, + ]; + handler.on_opcode_decoded(OPS[op_low as usize])?; + if op_low < 0b100 { + handler.on_source_decoded(Operand::imm_u8(iiiiii))?; + } + } + 0b001 => { + opcode_check!(inst & 0x00e0 == 0); + operand_check!(inst & 0x3000 == 0); + handler.on_source_decoded(Operand::imm_u8(iiiiii))?; + handler.on_opcode_decoded(Opcode::Vasrh)?; + handler.rounded(RoundingMode::Raw)?; + } + 0b010 => { + static OPS: [Option; 8] = [ + Some(Vasrw), Some(Vlsrw), Some(Vaslw), None, + Some(Vabsh), Some(Vabsh), Some(Vabsw), Some(Vabsw), + ]; + handler.on_opcode_decoded(decode_opcode!(OPS[op_low as usize]))?; + if op_low < 0b100 { + operand_check!(inst & 0x2000 == 0); + handler.on_source_decoded(Operand::imm_u8(iiiiii))?; + } else { + if op_low & 1 == 1 { + handler.saturate()?; + } + } + } + _ => { +// todo!("the rest"); + } + } + }, + _ => { + // todo!("the rest"); + } + } + } 0b1001 => { if (inst >> 27) & 1 != 0 { - panic!("other mem op"); + todo!("other mem op"); } let ddddd = reg_b0(inst); diff --git a/tests/from_brain.rs b/tests/from_brain.rs index 3e9bb16..bd74631 100644 --- a/tests/from_brain.rs +++ b/tests/from_brain.rs @@ -127,6 +127,35 @@ fn general() { test_display(&0b0010_01011101_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (!tstbit(R4.new, #0)) jump:t #812 }"); test_display(&0b0010_01101101_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gt(R4.new, #-1)) jump:t #812 }"); + test_display(&0b0110_0010001_00110_11_0_000101_00_10110u32.to_le_bytes(), "{ C22 = R6 }"); + test_display(&0b0110_0011001_00110_11_0_000101_00_10110u32.to_le_bytes(), "{ C23:22 = R7:6 }"); + test_display(&0b0110_1000000_00110_11_0_000101_00_10110u32.to_le_bytes(), "{ R23:22 = C7:6 }"); + test_display(&0b0110_1010000_00110_11_0_000101_00_10110u32.to_le_bytes(), "{ R22 = C6 }"); + test_display(&0b0110_1010010_01001_11_0_000101_00_10110u32.to_le_bytes(), "{ R22 = add(pc, #0x5) }"); + + test_display(&0b1000_0000000_00100_11_000110_000_10110u32.to_le_bytes(), "{ R23:22 = asr(R5:4, #0x6) }"); + test_display(&0b1000_0000000_00100_11_000110_001_10110u32.to_le_bytes(), "{ R23:22 = lsr(R5:4, #0x6) }"); + test_display(&0b1000_0000000_00100_11_000110_010_10110u32.to_le_bytes(), "{ R23:22 = asl(R5:4, #0x6) }"); + test_display(&0b1000_0000000_00100_11_000110_011_10110u32.to_le_bytes(), "{ R23:22 = rol(R5:4, #0x6) }"); + test_display(&0b1000_0000000_00100_11_000000_100_10110u32.to_le_bytes(), "{ R23:22 = vsathub(R5:4) }"); + test_display(&0b1000_0000000_00100_11_000000_101_10110u32.to_le_bytes(), "{ R23:22 = vsatwuh(R5:4) }"); + test_display(&0b1000_0000000_00100_11_000000_110_10110u32.to_le_bytes(), "{ R23:22 = vsatwh(R5:4) }"); + test_display(&0b1000_0000000_00100_11_000000_111_10110u32.to_le_bytes(), "{ R23:22 = vsathb(R5:4) }"); + test_display(&0b1000_0000001_00100_11_000110_000_10110u32.to_le_bytes(), "{ R23:22 = vasrh(R5:4, #0x6):raw }"); + test_invalid(&0b1000_0000001_00100_11_000110_001_10110u32.to_le_bytes(), DecodeError::InvalidOpcode); + test_invalid(&0b1000_0000001_00100_11_000110_010_10110u32.to_le_bytes(), DecodeError::InvalidOpcode); + test_invalid(&0b1000_0000001_00100_11_000110_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode); + test_invalid(&0b1000_0000001_00100_11_010110_000_10110u32.to_le_bytes(), DecodeError::InvalidOperand); + + test_display(&0b1000_0000010_00100_11_000110_000_10110u32.to_le_bytes(), "{ R23:22 = vasrw(R5:4, #0x6) }"); + test_display(&0b1000_0000010_00100_11_000110_001_10110u32.to_le_bytes(), "{ R23:22 = vlsrw(R5:4, #0x6) }"); + test_display(&0b1000_0000010_00100_11_000110_010_10110u32.to_le_bytes(), "{ R23:22 = vaslw(R5:4, #0x6) }"); + test_invalid(&0b1000_0000010_00100_11_000110_011_10110u32.to_le_bytes(), DecodeError::InvalidOpcode); + test_display(&0b1000_0000010_00100_11_000110_100_10110u32.to_le_bytes(), "{ R23:22 = vabsh(R5:4) }"); + test_display(&0b1000_0000010_00100_11_000110_101_10110u32.to_le_bytes(), "{ R23:22 = vabsh(R5:4):sat }"); + test_display(&0b1000_0000010_00100_11_000110_110_10110u32.to_le_bytes(), "{ R23:22 = vabsw(R5:4) }"); + test_display(&0b1000_0000010_00100_11_000110_111_10110u32.to_le_bytes(), "{ R23:22 = vabsw(R5:4):sat }"); + test_display(&0b1011_1000001_00100_11_1_0_0000_001_10110u32.to_le_bytes(), "{ R22 = add(R4, #-31999) }"); // TODO: testcase for Rn=add(pc,#nn) -- cgit v1.1