summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--notes/encoding_table4
-rw-r--r--notes/reordered_encodings4
-rw-r--r--src/display.rs28
-rw-r--r--src/lib.rs59
-rw-r--r--tests/from_brain.rs67
5 files changed, 142 insertions, 20 deletions
diff --git a/notes/encoding_table b/notes/encoding_table
index 1e9c6f1..e2c2fba 100644
--- a/notes/encoding_table
+++ b/notes/encoding_table
@@ -1307,8 +1307,8 @@ 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 1 1 0|1 0 1 0|0 0 0|s s s s s| P P |0 t t t t t|0 1 1|x x x x x| Rxx+=dfmpylh(Rss,Rtt) - XTYPE FP/slot 2,3
|1 1 1 0|1 0 1 0|1 0 0|s s s s s| P P |0 t t t t t|0 1 1|x x x x x| Rxx+=dfmpyhh(Rss,Rtt) - XTYPE FP/slot 2,3
-|1 1 1 0|1 1 1 1|0 0 0|s s s s s| P P |0 t t t t t|1 0 0|x x x x x| Rx+=sfmpy(Rss,Rtt) - XTYPE FP/slot 2,3
-|1 1 1 0|1 1 1 1|0 0 0|s s s s s| P P |0 t t t t t|1 0 1|x x x x x| Rx-=sfmpy(Rss,Rtt) - XTYPE FP/slot 2,3
+|1 1 1 0|1 1 1 1|0 0 0|s s s s s| P P |0 t t t t t|1 0 0|x x x x x| Rx+=sfmpy(Rs,Rt) - XTYPE FP/slot 2,3
+|1 1 1 0|1 1 1 1|0 0 0|s s s s s| P P |0 t t t t t|1 0 1|x x x x x| Rx-=sfmpy(Rs,Rt) - XTYPE FP/slot 2,3
|1 1 1 0|1 1 1 1|0 1 1|s s s s s| P P |0 t t t t t|1 u u|x x x x x| Rx+=sfmpy(Rs,Rt,Pu):scale - XTYPE FP/slot 2,3
diff --git a/notes/reordered_encodings b/notes/reordered_encodings
index 135fbc8..ab8d5ee 100644
--- a/notes/reordered_encodings
+++ b/notes/reordered_encodings
@@ -1397,8 +1397,8 @@ 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 1 1 0|1 1 1 1|0 0 0|s s s s s| P P |0 t t t t t|0 0 0|x x x x x| Rx+=mpyi(Rs,Rt) - XTYPE FP/slot 2,3
|1 1 1 0|1 1 1 1|0 0 0|s s s s s| P P |0 t t t t t|0 0 1|x x x x x| Rx+=add(Rs,Rt) - XTYPE ALU/slot 2,3
|1 1 1 0|1 1 1 1|0 0 0|s s s s s| P P |0 t t t t t|0 1 1|x x x x x| Rx+=sub(Rt,Rs) - XTYPE ALU/slot 2,3
-|1 1 1 0|1 1 1 1|0 0 0|s s s s s| P P |0 t t t t t|1 0 0|x x x x x| Rx+=sfmpy(Rss,Rtt) - XTYPE FP/slot 2,3
-|1 1 1 0|1 1 1 1|0 0 0|s s s s s| P P |0 t t t t t|1 0 1|x x x x x| Rx-=sfmpy(Rss,Rtt) - XTYPE FP/slot 2,3
+|1 1 1 0|1 1 1 1|0 0 0|s s s s s| P P |0 t t t t t|1 0 0|x x x x x| Rx+=sfmpy(Rs,Rt) - XTYPE FP/slot 2,3
+|1 1 1 0|1 1 1 1|0 0 0|s s s s s| P P |0 t t t t t|1 0 1|x x x x x| Rx-=sfmpy(Rs,Rt) - XTYPE FP/slot 2,3
|1 1 1 0|1 1 1 1|0 0 0|s s s s s| P P |0 t t t t t|1 1 0|x x x x x| Rx+=sfmpy(Rs,Rt):lib - XTYPE FP/slot 2,3
|1 1 1 0|1 1 1 1|0 0 0|s s s s s| P P |0 t t t t t|1 1 1|x x x x x| Rx-=sfmpy(Rs,Rt):lib - XTYPE FP/slot 2,3
|1 1 1 0|1 1 1 1|0 0 1|s s s s s| P P |0 t t t t t|0 0 0|x x x x x| Rx|=and(Rs,~Rt) - XTYPE ALU/slot 2,3
diff --git a/src/display.rs b/src/display.rs
index babff2c..352ff3f 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -27,6 +27,19 @@ impl fmt::Display for InstructionPacket {
}
}
+fn assign_mode_label(mode: Option<AssignMode>) -> &'static str {
+ match mode {
+ None => "=",
+ Some(AssignMode::AddAssign) => "+=",
+ Some(AssignMode::SubAssign) => "-=",
+ Some(AssignMode::AndAssign) => "&=",
+ Some(AssignMode::OrAssign) => "|=",
+ Some(AssignMode::XorAssign) => "^=",
+ Some(AssignMode::ClrBit) => "BUG",
+ Some(AssignMode::SetBit) => "BUG",
+ }
+}
+
impl fmt::Display for Instruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if special_display_rules(&self.opcode) {
@@ -44,7 +57,8 @@ impl fmt::Display for Instruction {
self.sources[0], self.sources[1], self.sources[2]);
}
Opcode::AndNot => {
- return write!(f, "{} = and({}, !{})", self.dest.as_ref().unwrap(),
+ return write!(f, "{} {} and({}, ~{})", self.dest.as_ref().unwrap(),
+ assign_mode_label(self.flags.assign_mode),
self.sources[0], self.sources[1]);
}
Opcode::OrOr => {
@@ -64,7 +78,8 @@ impl fmt::Display for Instruction {
self.sources[0], self.sources[1], self.sources[2]);
}
Opcode::OrNot => {
- return write!(f, "{} = or({}, !{})", self.dest.as_ref().unwrap(),
+ return write!(f, "{} {} or({}, !{})", self.dest.as_ref().unwrap(),
+ assign_mode_label(self.flags.assign_mode),
self.sources[0], self.sources[1]);
}
Opcode::OrOrNot => {
@@ -398,6 +413,12 @@ impl fmt::Display for Instruction {
f.write_str(":sat")?;
}
}
+ if self.flags.scale {
+ f.write_str(":scale")?;
+ }
+ if self.flags.library {
+ f.write_str(":lib")?;
+ }
if self.flags.deprecated {
f.write_str(":deprecated")?;
}
@@ -894,6 +915,9 @@ impl fmt::Display for Operand {
Operand::Gpr64b { reg_low } => {
write!(f, "R{}:{}", reg_low + 1, reg_low)
}
+ Operand::Gpr64bConjugate { reg_low } => {
+ write!(f, "R{}:{}*", reg_low + 1, reg_low)
+ }
Operand::Cr64b { reg_low } => {
write!(f, "C{}:{}", reg_low + 1, reg_low)
}
diff --git a/src/lib.rs b/src/lib.rs
index d58b4fe..fcffc1b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -324,6 +324,8 @@ struct InstFlags {
branch_hint: Option<BranchHint>,
negated: bool,
saturate: bool,
+ scale: bool,
+ library: bool,
chop: bool,
rounded: Option<RoundingMode>,
threads: Option<DomainHint>,
@@ -348,6 +350,8 @@ impl Default for InstFlags {
branch_hint: None,
negated: false,
saturate: false,
+ scale: false,
+ library: false,
chop: false,
rounded: None,
threads: None,
@@ -1134,7 +1138,7 @@ pub enum Operand {
/// the complex conjugate of `R<reg>`. this is only used in a few instructions performing
/// complex multiplies, and is displayed as `Rn*`.
GprConjugate { reg: u8 },
- /// `Rn:m`, register pair forming a 64-bit location
+ /// `Rn:m`, register pair forming a 64-bit value
///
/// V73 Section 2.1:
/// > the general registers can be specified as a pair that represent a single 64-bit register.
@@ -1144,6 +1148,10 @@ pub enum Operand {
///
/// from Table 2-2, note there is an entry of `R31:R30 (LR:FP)`
Gpr64b { reg_low: u8 },
+ /// `Rn:m*`, a register pair interpreted as a complex number, conjugated
+ ///
+ /// this is only used for forms of `cmpy*w`
+ Gpr64bConjugate { reg_low: u8 },
/// `Cn:m`, control register pair forming a 64-bit location
Cr64b { reg_low: u8 },
/// `Sn:m`, control register pair forming a 64-bit location
@@ -1231,6 +1239,11 @@ impl Operand {
Ok(Self::Gpr64b { reg_low: num })
}
+ fn gprpair_conjugate(num: u8) -> Result<Self, yaxpeax_arch::StandardDecodeError> {
+ operand_check!(num & 1 == 0);
+ Ok(Self::Gpr64bConjugate { reg_low: num })
+ }
+
fn crpair(num: u8) -> Result<Self, yaxpeax_arch::StandardDecodeError> {
operand_check!(num & 1 == 0);
Ok(Self::Cr64b { reg_low: num })
@@ -1360,6 +1373,8 @@ trait DecodeHandler<T: Reader<<Hexagon as Arch>::Address, <Hexagon as Arch>::Wor
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 scale(&mut self) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
+ fn library(&mut self) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
fn branch_hint(&mut self, _hint_taken: bool) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
fn domain_hint(&mut self, _domain: DomainHint) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
fn rounded(&mut self, _mode: RoundingMode) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
@@ -1423,7 +1438,18 @@ impl<T: yaxpeax_arch::Reader<<Hexagon as Arch>::Address, <Hexagon as Arch>::Word
assert!(!flags.saturate);
flags.saturate = true;
Ok(())
-
+ }
+ fn scale(&mut self) -> Result<(), <Hexagon as Arch>::DecodeError> {
+ let flags = &mut self.instructions[self.instruction_count as usize].flags;
+ assert!(!flags.scale);
+ flags.scale = true;
+ Ok(())
+ }
+ fn library(&mut self) -> Result<(), <Hexagon as Arch>::DecodeError> {
+ let flags = &mut self.instructions[self.instruction_count as usize].flags;
+ assert!(!flags.scale);
+ flags.library = true;
+ Ok(())
}
fn branch_hint(&mut self, hint_taken: bool) -> Result<(), <Hexagon as Arch>::DecodeError> {
let flags = &mut self.instructions[self.instruction_count as usize].flags;
@@ -5956,12 +5982,12 @@ fn decode_instruction<
// all of these may have `<<N`, though some are only valid with `<<1`.
let n = (op_hi >> 2) & 1;
handler.shift_left(n)?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.on_source_decoded(Operand::gprpair(ttttt)?)?;
+
if op_lo == 0b010 && op_hi & 0b011 == 0b001 {
handler.on_opcode_decoded(Vrmpywoh)?;
} else {
- handler.on_source_decoded(Operand::gprpair(sssss)?)?;
- handler.on_source_decoded(Operand::gprpair(ttttt)?)?;
-
let opc = (op_lo & 0b11) | ((op_hi & 0b11) << 2);
match opc {
0b0000 => {
@@ -6051,17 +6077,17 @@ fn decode_instruction<
let opc = (op_lo & 0b11) | (op_hi << 2);
handler.on_opcode_decoded(decode_opcode!(OPCODES[opc as usize]))?;
- if opc == 0b0101 {
+ if opc == 0b0101 || opc == 0b10101 {
handler.saturate()?;
}
+ eprintln!("ok op_lo: {:02b}, opc: {:05b}", op_lo, opc);
if (op_lo & 0b11) == 0b00 {
handler.on_source_decoded(Operand::gprpair(ttttt)?)?;
handler.on_source_decoded(Operand::gprpair(sssss)?)?;
- } else if opc == 0b1010 || opc == 0b1110 {
- // cmpyiw(Rss,Rtt*)
+ } else if opc == 0b11010 || opc == 0b11110 {
handler.on_source_decoded(Operand::gprpair(sssss)?)?;
- // TODO: Rtt*?
+ handler.on_source_decoded(Operand::gprpair_conjugate(ttttt)?)?;
} else {
handler.on_source_decoded(Operand::gprpair(sssss)?)?;
handler.on_source_decoded(Operand::gprpair(ttttt)?)?;
@@ -6504,7 +6530,7 @@ fn decode_instruction<
Some((AddAssign, Mpyi)), Some((AddAssign, Add)), None, Some((AddAssign, Sub)),
Some((AddAssign, SfMpy)), Some((SubAssign, SfMpy)), Some((AddAssign, SfMpy)), Some((SubAssign, SfMpy)),
// 001_000
- Some((OrAssign, AndNot)), Some((AddAssign, AndNot)), Some((XorAssign, AndNot)), None,
+ Some((OrAssign, AndNot)), Some((AndAssign, AndNot)), Some((XorAssign, AndNot)), None,
None, None, None, None,
// 010_000
Some((AndAssign, And)), Some((AndAssign, Or)), Some((AndAssign, Xor)), Some((OrAssign, And)),
@@ -6529,21 +6555,26 @@ fn decode_instruction<
let (assign_mode, opcode) = decode_operand!(OPCODES[opc as usize]);
handler.on_opcode_decoded(opcode)?;
handler.assign_mode(assign_mode)?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
- if opc == 0b000100 || opc == 0b000101 {
- handler.on_source_decoded(Operand::gprpair(sssss)?)?;
- handler.on_source_decoded(Operand::gprpair(ttttt)?)?;
+ if opcode == Opcode::Sub {
+ handler.on_source_decoded(Operand::gpr(ttttt))?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
} else {
handler.on_source_decoded(Operand::gpr(sssss))?;
handler.on_source_decoded(Operand::gpr(ttttt))?;
}
+ if opc == 0b000110 || opc == 0b000111 {
+ handler.library()?;
+ }
+
if opc == 0b011000 || opc == 0b011001 {
handler.shift_left(1)?;
handler.saturate()?;
} else if opc >= 0b011100 && opc < 0b100000 {
handler.on_source_decoded(Operand::pred(op_lo & 0b11))?;
- // TODO: :scale?
+ handler.scale()?;
}
}
}
diff --git a/tests/from_brain.rs b/tests/from_brain.rs
index a715e9f..dae984f 100644
--- a/tests/from_brain.rs
+++ b/tests/from_brain.rs
@@ -1539,6 +1539,73 @@ fn inst_1110() {
test_display(&0b1110_0111_110_10100_11_000110_110_10110u32.to_le_bytes(), "{ R23:22 += cmpy(R20, R6*):<<1:sat }");
test_display(&0b1110_0111_100_10100_11_000110_111_10110u32.to_le_bytes(), "{ R23:22 -= cmpy(R20, R6):<<1:sat }");
test_display(&0b1110_0111_110_10100_11_000110_111_10110u32.to_le_bytes(), "{ R23:22 -= cmpy(R20, R6*):<<1:sat }");
+
+ test_display(&0b1110_1000_000_10100_11_000110_010_10110u32.to_le_bytes(), "{ R23:22 = vrmpyh(R21:20, R7:6) }");
+ test_display(&0b1110_1000_000_10100_11_000110_011_10110u32.to_le_bytes(), "{ R23:22 = dfadd(R21:20, R7:6) }");
+ test_display(&0b1110_1000_001_10100_11_000110_000_10110u32.to_le_bytes(), "{ R23:22 = vabsdiffw(R7:6, R21:20) }");
+ test_display(&0b1110_1000_001_10100_11_000110_011_10110u32.to_le_bytes(), "{ R23:22 = dfmax(R21:20, R7:6) }");
+ test_display(&0b1110_1000_010_10100_11_000110_001_10110u32.to_le_bytes(), "{ R23:22 = vraddub(R21:20, R7:6) }");
+ test_display(&0b1110_1000_010_10100_11_000110_010_10110u32.to_le_bytes(), "{ R23:22 = vrsadub(R21:20, R7:6) }");
+ test_display(&0b1110_1000_010_10100_11_000110_011_10110u32.to_le_bytes(), "{ R23:22 = dfmpyfix(R21:20, R7:6) }");
+ test_display(&0b1110_1000_011_10100_11_000110_000_10110u32.to_le_bytes(), "{ R23:22 = vabsdiffh(R7:6, R21:20) }");
+ test_display(&0b1110_1000_011_10100_11_000110_010_10110u32.to_le_bytes(), "{ R23:22 = cmpyiw(R21:20, R7:6) }");
+ test_display(&0b1110_1000_100_10100_11_000110_001_10110u32.to_le_bytes(), "{ R23:22 = vrmpyu(R21:20, R7:6) }");
+ test_display(&0b1110_1000_100_10100_11_000110_010_10110u32.to_le_bytes(), "{ R23:22 = cmpyrw(R21:20, R7:6) }");
+ test_display(&0b1110_1000_100_10100_11_000110_011_10110u32.to_le_bytes(), "{ R23:22 = dfsub(R21:20, R7:6) }");
+ test_display(&0b1110_1000_101_10100_11_000110_000_10110u32.to_le_bytes(), "{ R23:22 = vabsdiffub(R7:6, R21:20) }");
+ test_display(&0b1110_1000_101_10100_11_000110_001_10110u32.to_le_bytes(), "{ R23:22 = vdmpybsu(R21:20, R7:6):sat }");
+ test_display(&0b1110_1000_101_10100_11_000110_011_10110u32.to_le_bytes(), "{ R23:22 = dfmpyll(R21:20, R7:6) }");
+ test_display(&0b1110_1000_110_10100_11_000110_001_10110u32.to_le_bytes(), "{ R23:22 = vrmpysu(R21:20, R7:6) }");
+ test_display(&0b1110_1000_110_10100_11_000110_010_10110u32.to_le_bytes(), "{ R23:22 = cmpyrw(R21:20, R7:6*) }");
+ test_display(&0b1110_1000_110_10100_11_000110_011_10110u32.to_le_bytes(), "{ R23:22 = dfmin(R21:20, R7:6) }");
+ test_display(&0b1110_1000_111_10100_11_000110_000_10110u32.to_le_bytes(), "{ R23:22 = vabsdiffb(R7:6, R21:20) }");
+ test_display(&0b1110_1000_111_10100_11_000110_010_10110u32.to_le_bytes(), "{ R23:22 = cmpyiw(R21:20, R7:6*) }");
+ test_display(&0b1110_1000_101_10100_11_000110_100_10110u32.to_le_bytes(), "{ R23:22 = vrcmpys(R21:20, R7:6):<<1:sat:raw:hi }");
+ test_display(&0b1110_1000_111_10100_11_000110_100_10110u32.to_le_bytes(), "{ R23:22 = vrcmpys(R21:20, R7:6):<<1:sat:raw:lo }");
+
+ /*
+ test_display(&0b1110_1000_000_10100_11_000110_100_10110u32.to_le_bytes(), "{ R23:22 = vdmpy(R21:20, R7:6):sat }");
+ test_display(&0b1110_1000_000_10100_11_000110_101_10110u32.to_le_bytes(), "{ R23:22 = vmpyweh(R21:20, R7:6):sat }");
+ test_display(&0b1110_1000_000_10100_11_000110_110_10110u32.to_le_bytes(), "{ R23:22 = vmpyeh(R21:20, R7:6):sat }");
+ test_display(&0b1110_1000_000_10100_11_000110_111_10110u32.to_le_bytes(), "{ R23:22 = vmpywoh(R21:20, R7:6):sat }");
+ test_display(&0b1110_1000_001_10100_11_000110_010_10110u32.to_le_bytes(), "{ R23:22 = vrmpywoh(R21:20, R7:6) }");
+ test_display(&0b1110_1000_001_10100_11_000110_101_10110u32.to_le_bytes(), "{ R23:22 = vmpyweh(R21:20, R7:6):rnd:sat }");
+ test_display(&0b1110_1000_001_10100_11_000110_110_10110u32.to_le_bytes(), "{ R23:22 = vcmpyr(R21:20, R7:6):sat }");
+ test_display(&0b1110_1000_001_10100_11_000110_111_10110u32.to_le_bytes(), "{ R23:22 = vmpywoh(R21:20, R7:6):rnd:sat }");
+ test_display(&0b1110_1000_010_10100_11_000110_100_10110u32.to_le_bytes(), "{ R23:22 = vrmpywoh(R21:20, R7:6) }");
+ test_display(&0b1110_1000_010_10100_11_000110_101_10110u32.to_le_bytes(), "{ R23:22 = vmpyweuh(R21:20, R7:6):sat }");
+ test_display(&0b1110_1000_010_10100_11_000110_110_10110u32.to_le_bytes(), "{ R23:22 = vcmpyi(R21:20, R7:6):sat }");
+ test_display(&0b1110_1000_010_10100_11_000110_111_10110u32.to_le_bytes(), "{ R23:22 = vmpywouh(R21:20, R7:6):sat }");
+ test_display(&0b1110_1000_011_10100_11_000110_101_10110u32.to_le_bytes(), "{ R23:22 = vmpyweuh(R21:20, R7:6):rnd:sat }");
+ test_display(&0b1110_1000_011_10100_11_000110_111_10110u32.to_le_bytes(), "{ R23:22 = vmpywouh(R21:20, R7:6):rnd:sat }");
+ */
+
+ test_display(&0b1110_1111_000_10100_11_000110_000_10110u32.to_le_bytes(), "{ R22 += mpyi(R20, R6) }");
+ test_display(&0b1110_1111_000_10100_11_000110_001_10110u32.to_le_bytes(), "{ R22 += add(R20, R6) }");
+ test_invalid(&0b1110_1111_000_10100_11_000110_010_10110u32.to_le_bytes(), DecodeError::InvalidOperand);
+ test_display(&0b1110_1111_000_10100_11_000110_011_10110u32.to_le_bytes(), "{ R22 += sub(R6, R20) }");
+ test_display(&0b1110_1111_000_10100_11_000110_100_10110u32.to_le_bytes(), "{ R22 += sfmpy(R20, R6) }");
+ test_display(&0b1110_1111_000_10100_11_000110_101_10110u32.to_le_bytes(), "{ R22 -= sfmpy(R20, R6) }");
+ test_display(&0b1110_1111_000_10100_11_000110_110_10110u32.to_le_bytes(), "{ R22 += sfmpy(R20, R6):lib }");
+ test_display(&0b1110_1111_000_10100_11_000110_111_10110u32.to_le_bytes(), "{ R22 -= sfmpy(R20, R6):lib }");
+ test_display(&0b1110_1111_001_10100_11_000110_000_10110u32.to_le_bytes(), "{ R22 |= and(R20, ~R6) }");
+ test_display(&0b1110_1111_001_10100_11_000110_001_10110u32.to_le_bytes(), "{ R22 &= and(R20, ~R6) }");
+ test_display(&0b1110_1111_001_10100_11_000110_010_10110u32.to_le_bytes(), "{ R22 ^= and(R20, ~R6) }");
+ test_display(&0b1110_1111_010_10100_11_000110_000_10110u32.to_le_bytes(), "{ R22 &= and(R20, R6) }");
+ test_display(&0b1110_1111_010_10100_11_000110_001_10110u32.to_le_bytes(), "{ R22 &= or(R20, R6) }");
+ test_display(&0b1110_1111_010_10100_11_000110_010_10110u32.to_le_bytes(), "{ R22 &= xor(R20, R6) }");
+ test_display(&0b1110_1111_010_10100_11_000110_011_10110u32.to_le_bytes(), "{ R22 |= and(R20, R6) }");
+ test_display(&0b1110_1111_011_10100_11_000110_000_10110u32.to_le_bytes(), "{ R22 += mpy(R20, R6):<<1:sat }");
+ test_display(&0b1110_1111_011_10100_11_000110_001_10110u32.to_le_bytes(), "{ R22 -= mpy(R20, R6):<<1:sat }");
+ test_display(&0b1110_1111_011_10100_11_000110_101_10110u32.to_le_bytes(), "{ R22 += sfmpy(R20, R6, P1):scale }");
+ test_display(&0b1110_1111_100_10100_11_000110_000_10110u32.to_le_bytes(), "{ R22 -= mpyi(R20, R6) }");
+ test_display(&0b1110_1111_100_10100_11_000110_001_10110u32.to_le_bytes(), "{ R22 -= add(R20, R6) }");
+ test_invalid(&0b1110_1111_100_10100_11_000110_010_10110u32.to_le_bytes(), DecodeError::InvalidOperand);
+ test_display(&0b1110_1111_100_10100_11_000110_011_10110u32.to_le_bytes(), "{ R22 ^= xor(R20, R6) }");
+ test_display(&0b1110_1111_110_10100_11_000110_000_10110u32.to_le_bytes(), "{ R22 |= or(R20, R6) }");
+ test_display(&0b1110_1111_110_10100_11_000110_001_10110u32.to_le_bytes(), "{ R22 |= xor(R20, R6) }");
+ test_display(&0b1110_1111_110_10100_11_000110_010_10110u32.to_le_bytes(), "{ R22 ^= and(R20, R6) }");
+ test_display(&0b1110_1111_110_10100_11_000110_011_10110u32.to_le_bytes(), "{ R22 ^= or(R20, R6) }");
}
#[test]