summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2024-10-05 13:17:33 -0700
committeriximeow <me@iximeow.net>2024-10-05 13:17:33 -0700
commit27ca89a15ab51af8620859203896142958991428 (patch)
tree39f5bf31c6a7a291984f2c1bba592b9831e2b0c0
parentcb67b099aa7b15f893157f23ff8a64731465cec7 (diff)
more ops, transcription errors
-rw-r--r--notes/encoding_table2
-rw-r--r--notes/todo44
-rw-r--r--src/display.rs37
-rw-r--r--src/lib.rs162
-rw-r--r--tests/from_brain.rs29
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<Operand>,
- predicate: Option<Predicate>,
- negated: bool,
- branch_hinted: Option<BranchHint>,
+ 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<Predicate>,
+ branch_hint: Option<BranchHint>,
+ negated: bool,
+ saturate: bool,
+ rounded: Option<RoundingMode>,
+}
+
+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<T: Reader<<Hexagon as Arch>::Address, <Hexagon as Arch>::Wor
fn on_dest_decoded(&mut self, _operand: Operand) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
fn inst_predicated(&mut self, num: u8, negated: bool, pred_new: bool) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
fn negate_result(&mut self) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
+ fn saturate(&mut self) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
fn branch_hint(&mut self, hint_taken: bool) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
+ fn rounded(&mut self, mode: RoundingMode) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
fn on_word_read(&mut self, _word: <Hexagon as Arch>::Word) {}
}
@@ -773,27 +824,40 @@ impl<T: yaxpeax_arch::Reader<<Hexagon as Arch>::Address, <Hexagon as Arch>::Word
Ok(())
}
fn inst_predicated(&mut self, num: u8, negated: bool, pred_new: bool) -> Result<(), <Hexagon as Arch>::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<(), <Hexagon as Arch>::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<(), <Hexagon as Arch>::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<(), <Hexagon as Arch>::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<(), <Hexagon as Arch>::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<u32, <Hexagon as Arch>::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<Opcode>; 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)