summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--notes/todo166
-rw-r--r--src/display.rs52
-rw-r--r--src/lib.rs197
-rw-r--r--tests/from_brain.rs137
4 files changed, 433 insertions, 119 deletions
diff --git a/notes/todo b/notes/todo
index a3cb149..e616890 100644
--- a/notes/todo
+++ b/notes/todo
@@ -200,89 +200,89 @@ 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 0 1 1|1 1 0 - - 0 0|s s s s s| P P |l i i i i i i l l|l l l l l| memb(Rs+#u6:0)=#S8 - ST/slot 0,1
-|0 0 1 1|1 1 0 - - 0 1|s s s s s| P P |l i i i i i i l l|l l l l l| memh(Rs+#u6:1)=#S8 - ST/slot 0,1
-|0 0 1 1|1 1 0 - - 1 0|s s s s s| P P |l i i i i i i l l|l l l l l| memw(Rs+#u6:2)=#S8 - ST/slot 0,1
-|0 0 1 1|1 1 1 0 - 0 0|s s s s s| P P |0 i i i i i i 0 0|t t t t t| memb(Rs+#u6:0)+=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 0 - 0 0|s s s s s| P P |0 i i i i i i 0 1|t t t t t| memb(Rs+#u6:0)-=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 0 - 0 0|s s s s s| P P |0 i i i i i i 1 0|t t t t t| memb(Rs+#u6:0)&=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 0 - 0 0|s s s s s| P P |0 i i i i i i 1 1|t t t t t| memb(Rs+#u6:0)|=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 0 - 0 1|s s s s s| P P |0 i i i i i i 0 0|t t t t t| memh(Rs+#u6:0)+=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 0 - 0 1|s s s s s| P P |0 i i i i i i 0 1|t t t t t| memh(Rs+#u6:0)-=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 0 - 0 1|s s s s s| P P |0 i i i i i i 1 0|t t t t t| memh(Rs+#u6:0)&=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 0 - 0 1|s s s s s| P P |0 i i i i i i 1 1|t t t t t| memh(Rs+#u6:0)|=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 0 - 1 0|s s s s s| P P |0 i i i i i i 0 0|t t t t t| memw(Rs+#u6:0)+=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 0 - 1 0|s s s s s| P P |0 i i i i i i 0 1|t t t t t| memw(Rs+#u6:0)-=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 0 - 1 0|s s s s s| P P |0 i i i i i i 1 0|t t t t t| memw(Rs+#u6:0)&=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 0 - 1 0|s s s s s| P P |0 i i i i i i 1 1|t t t t t| memw(Rs+#u6:0)|=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 1 - 0 0|s s s s s| P P |0 i i i i i i 0 0|l l l l l| memb(Rs+#u6:0)+=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 1 - 0 0|s s s s s| P P |0 i i i i i i 0 1|l l l l l| memb(Rs+#u6:0)-=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 1 - 0 0|s s s s s| P P |0 i i i i i i 1 0|l l l l l| memb(Rs+#u6:0)=clrbit(#U5) - MEMOP/slot 0
-|0 0 1 1|1 1 1 1 - 0 0|s s s s s| P P |0 i i i i i i 1 1|l l l l l| memb(Rs+#u6:0)=setbit(#U5) - MEMOP/slot 0
-|0 0 1 1|1 1 1 1 - 0 1|s s s s s| P P |0 i i i i i i 0 0|l l l l l| memh(Rs+#u6:0)+=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 1 - 0 1|s s s s s| P P |0 i i i i i i 0 1|l l l l l| memh(Rs+#u6:0)-=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 1 - 0 1|s s s s s| P P |0 i i i i i i 1 0|l l l l l| memh(Rs+#u6:0)=clrbit(#U5) - MEMOP/slot 0
-|0 0 1 1|1 1 1 1 - 0 1|s s s s s| P P |0 i i i i i i 1 1|l l l l l| memh(Rs+#u6:0)=setbit(#U5) - MEMOP/slot 0
-|0 0 1 1|1 1 1 1 - 1 0|s s s s s| P P |0 i i i i i i 0 0|l l l l l| memw(Rs+#u6:0)+=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 1 - 1 0|s s s s s| P P |0 i i i i i i 0 1|l l l l l| memw(Rs+#u6:0)-=Rt - MEMOP/slot 0
-|0 0 1 1|1 1 1 1 - 1 0|s s s s s| P P |0 i i i i i i 1 0|l l l l l| memw(Rs+#u6:0)=clrbit(#U5) - MEMOP/slot 0
-|0 0 1 1|1 1 1 1 - 1 0|s s s s s| P P |0 i i i i i i 1 1|l l l l l| memw(Rs+#u6:0)=setbit(#U5) - MEMOP/slot 0
-test |0 1 0 0|0 0 0 0 0 0 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (Pv) memb(Rs+#u6:0)=Rt - ST/slot 0,1
-|0 1 0 0|0 0 0 0 0 1 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (Pv) memh(Rs+#u6:1)=Rt - ST/slot 0,1
-|0 1 0 0|0 0 0 0 0 1 1|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (Pv) memh(Rs+#u6:1)=Rt.H - ST/slot 0,1
-|0 1 0 0|0 0 0 0 1 0 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (Pv) memw(Rs+#u6:2)=Rt - ST/slot 0,1
-|0 1 0 0|0 0 0 0 1 0 1|s s s s s| P P |i 0 0 t t t i i i|i i 0 v v| if (Pv) memb(Rs+#u6:0)=Nt.new - NV/slot 0
-|0 1 0 0|0 0 0 0 1 0 1|s s s s s| P P |i 0 1 t t t i i i|i i 0 v v| if (Pv) memh(Rs+#u6:1)=Nt.new - NV/slot 0
-|0 1 0 0|0 0 0 0 1 0 1|s s s s s| P P |i 1 0 t t t i i i|i i 0 v v| if (Pv) memw(Rs+#u6:2)=Nt.new - NV/slot 0
-|0 1 0 0|0 0 0 0 1 1 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (Pv) memd(Rs+#u6:2)=Rtt - ST/slot 0,1
-|0 1 0 0|0 0 1 0 0 0 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (!Pv) memb(Rs+#u6:0)=Rt - ST/slot 0,1
-|0 1 0 0|0 0 1 0 0 1 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (!Pv) memh(Rs+#u6:1)=Rt - ST/slot 0,1
-|0 1 0 0|0 0 1 0 0 1 1|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (!Pv) memh(Rs+#u6:1)=Rt.H - ST/slot 0,1
-|0 1 0 0|0 0 1 0 1 0 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (!Pv) memw(Rs+#u6:2)=Rt - ST/slot 0,1
-|0 1 0 0|0 0 1 0 1 0 1|s s s s s| P P |i 0 0 t t t i i i|i i 0 v v| if (!Pv) memb(Rs+#u6:0)=Nt.new - NV/slot 0
-|0 1 0 0|0 0 1 0 1 0 1|s s s s s| P P |i 0 1 t t t i i i|i i 0 v v| if (!Pv) memh(Rs+#u6:1)=Nt.new - NV/slot 0
-|0 1 0 0|0 0 1 0 1 0 1|s s s s s| P P |i 1 0 t t t i i i|i i 0 v v| if (!Pv) memw(Rs+#u6:2)=Nt.new - NV/slot 0
-|0 1 0 0|0 0 1 0 1 1 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (!Pv) memd(Rs+#u6:2)=Rtt - ST/slot 0,1
-|0 1 0 0|0 1 0 0 0 0 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (Pv.new) memb(Rs+#u6:0)=Rt - ST/slot 0,1
-|0 1 0 0|0 1 0 0 0 1 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (Pv.new) memh(Rs+#u6:1)=Rt - ST/slot 0,1
-|0 1 0 0|0 1 0 0 0 1 1|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (Pv.new) memh(Rs+#u6:1)=Rt.H - ST/slot 0,1
-|0 1 0 0|0 1 0 0 1 0 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (Pv.new) memw(Rs+#u6:2)=Rt - ST/slot 0,1
-|0 1 0 0|0 1 0 0 1 0 1|s s s s s| P P |i 0 0 t t t i i i|i i 0 v v| if (Pv.new) memb(Rs+#u6:0)=Nt.new - NV/slot 0
-|0 1 0 0|0 1 0 0 1 0 1|s s s s s| P P |i 0 1 t t t i i i|i i 0 v v| if (Pv.new) memh(Rs+#u6:1)=Nt.new - NV/slot 0
-|0 1 0 0|0 1 0 0 1 0 1|s s s s s| P P |i 1 0 t t t i i i|i i 0 v v| if (Pv.new) memw(Rs+#u6:2)=Nt.new - NV/slot 0
-|0 1 0 0|0 1 0 0 1 1 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (Pv.new) memd(Rs+#u6:2)=Rtt - ST/slot 0,1
-|0 1 0 0|0 1 1 0 0 0 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (!Pv.new) memb(Rs+#u6:0)=Rt - ST/slot 0,1
-|0 1 0 0|0 1 1 0 0 1 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (!Pv.new) memh(Rs+#u6:1)=Rt - ST/slot 0,1
-|0 1 0 0|0 1 1 0 0 1 1|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (!Pv.new) memh(Rs+#u6:1)=Rt.H - ST/slot 0,1
-|0 1 0 0|0 1 1 0 1 0 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (!Pv.new) memw(Rs+#u6:2)=Rt - ST/slot 0,1
-|0 1 0 0|0 1 1 0 1 0 1|s s s s s| P P |i 0 0 t t t i i i|i i 0 v v| if (!Pv.new) memb(Rs+#u6:0)=Nt.new - NV/slot 0
-|0 1 0 0|0 1 1 0 1 0 1|s s s s s| P P |i 0 1 t t t i i i|i i 0 v v| if (!Pv.new) memh(Rs+#u6:1)=Nt.new - NV/slot 0
-|0 1 0 0|0 1 1 0 1 0 1|s s s s s| P P |i 1 0 t t t i i i|i i 0 v v| if (!Pv.new) memw(Rs+#u6:2)=Nt.new - NV/slot 0
-|0 1 0 0|0 1 1 0 1 1 0|s s s s s| P P |i t t t t t i i i|i i 0 v v| if (!Pv.new) memd(Rs+#u6:2)=Rtt - ST/slot 0,1
-|0 1 0 0|0 1 1 1 0 0 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (Pt.new) Rd=memb(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 1 1 1 0 0 1|s s s s s| P P |0 t t i i i i i i|d d d d d| if (Pt.new) Rd=memub(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 1 1 1 0 1 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (Pt.new) Rd=memh(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 1 1 1 0 1 1|s s s s s| P P |0 t t i i i i i i|d d d d d| if (Pt.new) Rd=memuh(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 1 1 1 1 0 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (Pt.new) Rd=memw(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 1 1 1 1 1 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (Pt.new) Rdd=memd(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 0 0 1 0 0 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (!Pt) Rd=memb(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 0 0 1 0 0 1|s s s s s| P P |0 t t i i i i i i|d d d d d| if (!Pt) Rd=memub(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 0 0 1 0 1 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (!Pt) Rd=memh(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 0 0 1 0 1 1|s s s s s| P P |0 t t i i i i i i|d d d d d| if (!Pt) Rd=memuh(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 0 0 1 1 0 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (!Pt) Rd=memw(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 0 0 1 1 1 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (!Pt) Rdd=memd(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 0 1 1 0 0 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (Pt) Rd=memb(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 0 1 1 0 0 1|s s s s s| P P |0 t t i i i i i i|d d d d d| if (Pt) Rd=memub(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 0 1 1 0 1 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (Pt) Rd=memh(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 0 1 1 0 1 1|s s s s s| P P |0 t t i i i i i i|d d d d d| if (Pt) Rd=memuh(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 0 1 1 1 0 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (Pt) Rd=memw(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 0 1 1 1 1 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (Pt) Rdd=memd(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 1 0 1 0 0 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (!Pt.new) Rd=memb(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 1 0 1 0 0 1|s s s s s| P P |0 t t i i i i i i|d d d d d| if (!Pt.new) Rd=memub(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 1 0 1 0 1 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (!Pt.new) Rd=memh(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 1 0 1 0 1 1|s s s s s| P P |0 t t i i i i i i|d d d d d| if (!Pt.new) Rd=memuh(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 1 0 1 1 0 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (!Pt.new) Rd=memw(Rs+#u6:3) - LD/slot 0,1
-|0 1 0 0|0 1 0 1 1 1 0|s s s s s| P P |0 t t i i i i i i|d d d d d| if (!Pt.new) Rdd=memd(Rs+#u6:3) - LD/slot 0,1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
test |0 1 0 0|1 i i 0 0 0 0|i i i i i| P P |i t t t t t i i i|i i i i i| memb(gp+#u16:0)=Rt - ST/slot 0,1
test |0 1 0 0|1 i i 0 0 1 0|i i i i i| P P |i t t t t t i i i|i i i i i| memh(gp+#u16:1)=Rt - ST/slot 0,1
test |0 1 0 0|1 i i 0 0 1 1|i i i i i| P P |i t t t t t i i i|i i i i i| memh(gp+#u16:1)=Rt.H - ST/slot 0,1
diff --git a/src/display.rs b/src/display.rs
index 11d5489..5063350 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -1,7 +1,7 @@
use core::fmt;
use crate::{Instruction, InstructionPacket, Opcode, Operand};
-use crate::{BranchHint, DomainHint};
+use crate::{AssignMode, BranchHint, DomainHint};
impl fmt::Display for InstructionPacket {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -77,19 +77,34 @@ impl fmt::Display for Instruction {
static STORES: &[Opcode] = &[
Opcode::StoreMemb, Opcode::StoreMemh, Opcode::StoreMemw, Opcode::StoreMemd, Opcode::MemwRl, Opcode::MemdRl
];
+ let mut needs_parens = self.sources_count > 0;
if STORES.contains(&self.opcode) {
- write!(f, "{}({}){} = {}",
+ let (assign_op, needs_parens) = match self.flags.assign_mode {
+ None => ("=", false),
+ Some(AssignMode::AddAssign) => ("+=", false),
+ Some(AssignMode::SubAssign) => ("-=", false),
+ Some(AssignMode::AndAssign) => ("&=", false),
+ Some(AssignMode::OrAssign) => ("|=", false),
+ Some(AssignMode::XorAssign) => ("^=", false),
+ Some(AssignMode::ClrBit) => ("= clrbit", true),
+ Some(AssignMode::SetBit) => ("= setbit", true),
+ };
+ write!(f, "{}({}){} {}{}{}{}",
self.opcode, self.dest.expect("TODO: unreachable; store has a destination"),
match self.flags.threads {
Some(DomainHint::Same) => { ":st" },
Some(DomainHint::All) => { ":at" },
None => { "" }
},
- self.sources[0]
+ assign_op,
+ if needs_parens { "(" } else { " " },
+ self.sources[0],
+ if needs_parens { ")" } else { "" },
)?;
return Ok(());
}
+ // TODO: do store conditionals have assign_merge?
static SC_STORES: &[Opcode] = &[
Opcode::MemwStoreCond, Opcode::MemdStoreCond,
];
@@ -147,8 +162,20 @@ impl fmt::Display for Instruction {
self.dest.unwrap())?;
return Ok(());
}
+
if let Some(o) = self.dest.as_ref() {
- write!(f, "{} = ", o)?;
+ let (assign_op, p) = match self.flags.assign_mode {
+ None => ("=", false),
+ Some(AssignMode::AddAssign) => ("+=", false),
+ Some(AssignMode::SubAssign) => ("-=", false),
+ Some(AssignMode::AndAssign) => ("&=", false),
+ Some(AssignMode::OrAssign) => ("|=", false),
+ Some(AssignMode::XorAssign) => ("^=", false),
+ Some(AssignMode::ClrBit) => ("=clrbit", true),
+ Some(AssignMode::SetBit) => ("=setbit", true),
+ };
+ needs_parens |= p;
+ write!(f, "{} {} ", o, assign_op)?;
}
// TransferRegister and TransferImmediate display the source operand atypically.
@@ -161,27 +188,29 @@ impl fmt::Display for Instruction {
f.write_str("!")?;
}
write!(f, "{}", self.opcode)?;
+ if needs_parens { f.write_str("(")?; }
if self.opcode == Opcode::And_nRR || self.opcode == Opcode::Or_nRR {
// while operand order does not matter here at all, the hexagon (v73) manual reverses
// Rs and Rt for these specific instructions.
- write!(f, "({}, ~{})", self.sources[1], self.sources[0])?;
+ write!(f, "{}, ~{}", self.sources[1], self.sources[0])?;
+ if needs_parens { f.write_str(")")?; }
return Ok(());
}
if self.opcode == Opcode::And_RnR || self.opcode == Opcode::Or_RnR {
- write!(f, "({}, ~{})", self.sources[0], self.sources[1])?;
+ write!(f, "{}, ~{}", self.sources[0], self.sources[1])?;
+ if needs_parens { f.write_str(")")?; }
return Ok(());
}
if self.sources_count > 0 {
- f.write_str("(")?;
write!(f, "{}", self.sources[0])?;
for i in 1..self.sources_count {
write!(f, ", {}", self.sources[i as usize])?;
}
- f.write_str(")")?;
}
+ if needs_parens { f.write_str(")")?; }
if let Some(mode) = self.flags.rounded {
write!(f, "{}", mode.as_label())?;
@@ -244,13 +273,6 @@ impl fmt::Display for Opcode {
Opcode::StoreMemw => { f.write_str("memw") },
Opcode::StoreMemd => { f.write_str("memd") },
- Opcode::MembAdd => { f.write_str("memb") },
- Opcode::MembSub => { f.write_str("memb") },
- Opcode::MembAnd => { f.write_str("memb") },
- Opcode::MembOr => { f.write_str("memb") },
- Opcode::MembClr => { f.write_str("memb") },
- Opcode::MembSet => { f.write_str("memb") },
-
Opcode::Membh => { f.write_str("membh") },
Opcode::MemhFifo => { f.write_str("memh_fifo") },
Opcode::Memubh => { f.write_str("memubh") },
diff --git a/src/lib.rs b/src/lib.rs
index 6537bfd..a046abd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -292,6 +292,17 @@ impl RoundingMode {
}
#[derive(Debug, Copy, Clone)]
+enum AssignMode {
+ AddAssign,
+ SubAssign,
+ AndAssign,
+ OrAssign,
+ XorAssign,
+ ClrBit,
+ SetBit,
+}
+
+#[derive(Debug, Copy, Clone)]
struct InstFlags {
predicate: Option<Predicate>,
branch_hint: Option<BranchHint>,
@@ -300,6 +311,7 @@ struct InstFlags {
chop: bool,
rounded: Option<RoundingMode>,
threads: Option<DomainHint>,
+ assign_mode: Option<AssignMode>,
}
#[derive(Debug, Copy, Clone)]
@@ -318,6 +330,7 @@ impl Default for InstFlags {
chop: false,
rounded: None,
threads: None,
+ assign_mode: None,
}
}
}
@@ -994,6 +1007,7 @@ trait DecodeHandler<T: Reader<<Hexagon as Arch>::Address, <Hexagon as Arch>::Wor
fn on_opcode_decoded(&mut self, _opcode: Opcode) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
fn on_source_decoded(&mut self, _operand: Operand) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
fn on_dest_decoded(&mut self, _operand: Operand) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
+ fn assign_mode(&mut self, _assign_mode: AssignMode) -> 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(()) }
@@ -1033,6 +1047,11 @@ impl<T: yaxpeax_arch::Reader<<Hexagon as Arch>::Address, <Hexagon as Arch>::Word
}
Ok(())
}
+ fn assign_mode(&mut self, assign_mode: AssignMode) -> Result<(), <Hexagon as Arch>::DecodeError> {
+ let mut inst = &mut self.instructions[self.instruction_count as usize];
+ inst.flags.assign_mode = Some(assign_mode);
+ Ok(())
+ }
fn inst_predicated(&mut self, num: u8, negated: bool, pred_new: bool) -> Result<(), <Hexagon as Arch>::DecodeError> {
let mut flags = &mut self.instructions[self.instruction_count as usize].flags;
assert!(flags.predicate.is_none());
@@ -1164,6 +1183,52 @@ fn decode_store_ops<
Ok(())
}
+// very much like `decode_store_ops`, except for some instructions the strategy is for loads
+// instead.
+fn decode_load_ops<
+ T: Reader<<Hexagon as Arch>::Address, <Hexagon as Arch>::Word>,
+ H: DecodeHandler<T>,
+>(handler: &mut H, opbits: u8, dstreg: u8, src_op: impl Fn(u8) -> Operand) -> Result<(), DecodeError> {
+ // for loads, there's none of the carveout for `R<n>.new` or high register halves.
+ // just mem{b,ub,h,uh,w,d}
+ match opbits {
+ 0b000 => {
+ handler.on_opcode_decoded(Opcode::LoadMemb)?;
+ handler.on_dest_decoded(Operand::gpr(dstreg))?;
+ handler.on_source_decoded(src_op(0))?;
+ }
+ 0b001 => {
+ handler.on_opcode_decoded(Opcode::LoadMemub)?;
+ handler.on_dest_decoded(Operand::gpr(dstreg))?;
+ handler.on_source_decoded(src_op(0))?;
+ }
+ 0b010 => {
+ handler.on_opcode_decoded(Opcode::LoadMemh)?;
+ handler.on_dest_decoded(Operand::gpr(dstreg))?;
+ handler.on_source_decoded(src_op(1))?;
+ }
+ 0b011 => {
+ handler.on_opcode_decoded(Opcode::LoadMemuh)?;
+ handler.on_dest_decoded(Operand::gpr(dstreg))?;
+ handler.on_source_decoded(src_op(1))?;
+ }
+ 0b100 => {
+ handler.on_opcode_decoded(Opcode::LoadMemw)?;
+ handler.on_dest_decoded(Operand::gpr(dstreg))?;
+ handler.on_source_decoded(src_op(2))?;
+ }
+ 0b110 => {
+ handler.on_opcode_decoded(Opcode::LoadMemd)?;
+ handler.on_dest_decoded(Operand::gprpair(dstreg)?)?;
+ handler.on_source_decoded(src_op(3))?;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Ok(())
+}
+
fn decode_packet<
T: Reader<<Hexagon as Arch>::Address, <Hexagon as Arch>::Word>,
H: DecodeHandler<T>,
@@ -1640,6 +1705,7 @@ fn decode_instruction<
let opc_upper = opc_bits >> 3;
let opc_lower = opc_bits & 0b11;
let uuuuuu = (inst >> 7) & 0b111111;
+ let sssss = (inst >> 16) & 0b11111;
match opc_upper {
0b00 |
@@ -1648,25 +1714,81 @@ fn decode_instruction<
let i_hi = ((inst >> 13) & 0b1) << 7;
let i = i_hi | i7;
- (match opc_upper {
+ handler.on_opcode_decoded(match opc_lower {
0b00 => {
- handler.on_opcode_decoded(Opcode::StoreMemb)?;
+ Opcode::StoreMemb
}
0b01 => {
- Ok(Opcode::StoreMemh),
+ Opcode::StoreMemh
}
0b10 => {
- Ok(Opcode::StoreMemd),
+ Opcode::StoreMemw
}
- _ => Err(DecodeError::InvalidOpcode)
- }?)?;
+ _ => { return Err(DecodeError::InvalidOpcode); }
+ })?;
handler.on_source_decoded(Operand::imm_i8(i as i8))?;
+ handler.on_dest_decoded(Operand::RegOffset {
+ base: sssss as u8,
+ offset: (uuuuuu as u32) << opc_lower,
+ })?;
},
0b10 => {
+ opcode_check!(inst & 0b0010_0000_0000_0000 == 0);
+ let ttttt = inst & 0b11111;
+ let assign_mode = (inst >> 5) & 0b11;
+ handler.on_opcode_decoded(match opc_lower {
+ 0b00 => {
+ Opcode::StoreMemb
+ }
+ 0b01 => {
+ Opcode::StoreMemh
+ }
+ 0b10 => {
+ Opcode::StoreMemw
+ }
+ _ => { return Err(DecodeError::InvalidOpcode); }
+ })?;
+ handler.assign_mode(match assign_mode {
+ 0b00 => AssignMode::AddAssign,
+ 0b01 => AssignMode::SubAssign,
+ 0b10 => AssignMode::AndAssign,
+ _ => AssignMode::OrAssign,
+ })?;
+ handler.on_source_decoded(Operand::gpr(ttttt as u8))?;
+ handler.on_dest_decoded(Operand::RegOffset {
+ base: sssss as u8,
+ offset: (uuuuuu as u32) << opc_lower,
+ })?;
},
_ => {
- panic!("TODO: other: {}", other);
+ opcode_check!(inst & 0b0010_0000_0000_0000 == 0);
+ let ttttt = inst & 0b11111;
+ let assign_mode = (inst >> 5) & 0b11;
+
+ handler.on_opcode_decoded(match opc_lower {
+ 0b00 => {
+ Opcode::StoreMemb
+ }
+ 0b01 => {
+ Opcode::StoreMemh
+ }
+ 0b10 => {
+ Opcode::StoreMemw
+ }
+ _ => { return Err(DecodeError::InvalidOpcode); }
+ })?;
+ handler.assign_mode(match assign_mode {
+ 0b00 => AssignMode::AddAssign,
+ 0b01 => AssignMode::SubAssign,
+ 0b10 => AssignMode::ClrBit,
+ _ => AssignMode::SetBit,
+ })?;
+ handler.on_source_decoded(Operand::imm_u8(ttttt as u8))?;
+ handler.on_dest_decoded(Operand::RegOffset {
+ base: sssss as u8,
+ offset: (uuuuuu as u32) << opc_lower,
+ })?;
}
}
}
@@ -1676,34 +1798,67 @@ fn decode_instruction<
// 0 1 0 0|...
// loads and stores with large (6b+) offsets
let predicated = (inst >> 27) & 1 == 0;
- let load = (inst >> 24) & 1 == 0;
+ let store = (inst >> 24) & 1 == 0;
if predicated {
- let dotnew = (inst >> 23) & 0b1 == 1;
- let negated = (inst >> 22) & 0b1 == 0;
- let pred_reg = (inst >> 11) & 0b11;
- handler.inst_predicated(pred_reg as u8, negated, dotnew)?;
+ let dotnew = (inst >> 26) & 0b1 == 1;
+ let negated = (inst >> 25) & 0b1 == 1;
+
+ let opbits = (inst >> 21) & 0b111;
+ let sssss = reg_b16(inst);
+
+ if store {
+ let pred_reg = inst & 0b11;
+ handler.inst_predicated(pred_reg as u8, negated, dotnew)?;
- if load {
+ let srcreg = reg_b8(inst);
+ let i5 = (inst >> 3) & 0b11111;
+ let i = ((inst >> 13) & 1) << 5;
+ let iiiiii = i | i5;
+
+ decode_store_ops(handler, opbits as u8, srcreg as u8, |shamt| {
+ Operand::RegOffset {
+ base: sssss as u8,
+ offset: iiiiii << shamt
+ }
+ })?;
} else {
+ let pred_reg = (inst >> 11) & 0b11;
+ handler.inst_predicated(pred_reg as u8, negated, dotnew)?;
+
+ let dstreg = reg_b0(inst);
+ let iiiiii = (inst >> 5) & 0b111111;
+
+ decode_load_ops(handler, opbits as u8, dstreg as u8, |shamt| {
+ Operand::RegOffset {
+ base: sssss as u8,
+ offset: iiiiii << shamt
+ }
+ })?;
}
} else {
let i14 = (inst >> 25) & 0b11;
let i9 = (inst >> 16) & 0b11111;
let i_8 = (inst >> 13) & 0b1;
- if load {
- let i_lo = (inst >> 5) & 0b11111111;
+ let opbits = ((inst >> 21) & 0b111) as u8;
+
+ if store {
+ let i_lo = inst & 0b1111_1111;
let i = (i14 << 14) | (i9 << 9) | (i_8 << 8) | i_lo;
- let ddddd = reg_b0(inst);
- let opc = (inst >> 21) & 0b111;
+ let ttttt = reg_b8(inst);
+
+ decode_store_ops(handler, opbits, ttttt, |shamt| {
+ Operand::GpOffset {
+ offset: i << shamt
+ }
+ })?;
} else {
- let i_lo = inst & 0b11111111;
+ let i_lo = (inst >> 5) & 0b1111_1111;
let i = (i14 << 14) | (i9 << 9) | (i_8 << 8) | i_lo;
- let ttttt = reg_b8(inst);
- let opc = ((inst >> 21) & 0b111) as u8;
+ let ddddd = reg_b0(inst);
- decode_store_ops(handler, opc, ttttt, |shamt| {
+ decode_load_ops(handler, opbits, ddddd, |shamt| {
Operand::GpOffset { offset: i << shamt }
})?;
}
diff --git a/tests/from_brain.rs b/tests/from_brain.rs
index 8473617..194ff8a 100644
--- a/tests/from_brain.rs
+++ b/tests/from_brain.rs
@@ -100,6 +100,143 @@ fn inst_0011() {
test_display(&0b0011_1011010_00100_11_1_0_0010_100_11110u32.to_le_bytes(), "{ memh(R4 + R2<<3) = R30 }");
test_display(&0b0011_1011011_00100_11_1_0_0010_100_11110u32.to_le_bytes(), "{ memh(R4 + R2<<3) = R30.H }");
test_display(&0b0011_1011101_00100_11_1_0_0010_100_10110u32.to_le_bytes(), "{ memw(R4 + R2<<3) = R6.new }");
+
+ test_display(&0b0011_1100000_00100_11_1_1_0010_100_10110u32.to_le_bytes(), "{ memb(R4+#37) = #-106 }");
+ test_display(&0b0011_1100001_00100_11_1_1_0010_100_10110u32.to_le_bytes(), "{ memh(R4+#74) = #-106 }");
+ test_display(&0b0011_1100010_00100_11_1_1_0010_100_10110u32.to_le_bytes(), "{ memw(R4+#148) = #-106 }");
+ test_invalid(&0b0011_1100011_00100_11_1_1_0010_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b0011_1110000_00100_11_0_1_0010_100_10110u32.to_le_bytes(), "{ memb(R4+#37) += R22 }");
+ test_display(&0b0011_1110000_00100_11_0_1_0010_101_10110u32.to_le_bytes(), "{ memb(R4+#37) -= R22 }");
+ test_display(&0b0011_1110000_00100_11_0_1_0010_110_10110u32.to_le_bytes(), "{ memb(R4+#37) &= R22 }");
+ test_display(&0b0011_1110000_00100_11_0_1_0010_111_10110u32.to_le_bytes(), "{ memb(R4+#37) |= R22 }");
+ test_display(&0b0011_1110001_00100_11_0_1_0010_100_10110u32.to_le_bytes(), "{ memh(R4+#74) += R22 }");
+ test_display(&0b0011_1110001_00100_11_0_1_0010_101_10110u32.to_le_bytes(), "{ memh(R4+#74) -= R22 }");
+ test_display(&0b0011_1110001_00100_11_0_1_0010_110_10110u32.to_le_bytes(), "{ memh(R4+#74) &= R22 }");
+ test_display(&0b0011_1110001_00100_11_0_1_0010_111_10110u32.to_le_bytes(), "{ memh(R4+#74) |= R22 }");
+ test_display(&0b0011_1110010_00100_11_0_1_0010_100_10110u32.to_le_bytes(), "{ memw(R4+#148) += R22 }");
+ test_display(&0b0011_1110010_00100_11_0_1_0010_101_10110u32.to_le_bytes(), "{ memw(R4+#148) -= R22 }");
+ test_display(&0b0011_1110010_00100_11_0_1_0010_110_10110u32.to_le_bytes(), "{ memw(R4+#148) &= R22 }");
+ test_display(&0b0011_1110010_00100_11_0_1_0010_111_10110u32.to_le_bytes(), "{ memw(R4+#148) |= R22 }");
+ test_invalid(&0b0011_1110011_00100_11_0_1_0010_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b0011_1111000_00100_11_0_1_0010_100_10110u32.to_le_bytes(), "{ memb(R4+#37) += #0x16 }");
+ test_display(&0b0011_1111000_00100_11_0_1_0010_101_10110u32.to_le_bytes(), "{ memb(R4+#37) -= #0x16 }");
+ test_display(&0b0011_1111000_00100_11_0_1_0010_110_10110u32.to_le_bytes(), "{ memb(R4+#37) = clrbit(#0x16) }");
+ test_display(&0b0011_1111000_00100_11_0_1_0010_111_10110u32.to_le_bytes(), "{ memb(R4+#37) = setbit(#0x16) }");
+ test_display(&0b0011_1111001_00100_11_0_1_0010_100_10110u32.to_le_bytes(), "{ memh(R4+#74) += #0x16 }");
+ test_display(&0b0011_1111001_00100_11_0_1_0010_101_10110u32.to_le_bytes(), "{ memh(R4+#74) -= #0x16 }");
+ test_display(&0b0011_1111001_00100_11_0_1_0010_110_10110u32.to_le_bytes(), "{ memh(R4+#74) = clrbit(#0x16) }");
+ test_display(&0b0011_1111001_00100_11_0_1_0010_111_10110u32.to_le_bytes(), "{ memh(R4+#74) = setbit(#0x16) }");
+ test_display(&0b0011_1111010_00100_11_0_1_0010_100_10110u32.to_le_bytes(), "{ memw(R4+#148) += #0x16 }");
+ test_display(&0b0011_1111010_00100_11_0_1_0010_101_10110u32.to_le_bytes(), "{ memw(R4+#148) -= #0x16 }");
+ test_display(&0b0011_1111010_00100_11_0_1_0010_110_10110u32.to_le_bytes(), "{ memw(R4+#148) = clrbit(#0x16) }");
+ test_display(&0b0011_1111010_00100_11_0_1_0010_111_10110u32.to_le_bytes(), "{ memw(R4+#148) = setbit(#0x16) }");
+ test_invalid(&0b0011_1111011_00100_11_0_1_0010_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+}
+
+#[test]
+fn inst_0100() {
+ test_display(&0b0100_0000_000_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (P2) memb(R10+#45) = R7 }");
+ test_display(&0b0100_0000_010_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (P2) memh(R10+#90) = R7 }");
+ test_display(&0b0100_0000_011_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (P2) memh(R10+#90) = R7.H }");
+ test_display(&0b0100_0000_100_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (P2) memw(R10+#180) = R7 }");
+ test_display(&0b0100_0000_101_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (P2) memb(R10+#45) = R7.new }");
+ test_display(&0b0100_0000_101_01010_11_1_01111_011_01010u32.to_le_bytes(), "{ if (P2) memh(R10+#90) = R7.new }");
+ test_display(&0b0100_0000_101_01010_11_1_10111_011_01010u32.to_le_bytes(), "{ if (P2) memw(R10+#180) = R7.new }");
+ test_invalid(&0b0100_0000_101_01010_11_1_11111_011_01010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0100_0000_110_01010_11_1_00110_011_01010u32.to_le_bytes(), "{ if (P2) memd(R10+#360) = R7:6 }");
+ test_invalid(&0b0100_0000_111_01010_11_1_11111_011_01010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b0100_0010_000_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (!P2) memb(R10+#45) = R7 }");
+ test_display(&0b0100_0010_010_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (!P2) memh(R10+#90) = R7 }");
+ test_display(&0b0100_0010_011_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (!P2) memh(R10+#90) = R7.H }");
+ test_display(&0b0100_0010_100_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (!P2) memw(R10+#180) = R7 }");
+ test_display(&0b0100_0010_101_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (!P2) memb(R10+#45) = R7.new }");
+ test_display(&0b0100_0010_101_01010_11_1_01111_011_01010u32.to_le_bytes(), "{ if (!P2) memh(R10+#90) = R7.new }");
+ test_display(&0b0100_0010_101_01010_11_1_10111_011_01010u32.to_le_bytes(), "{ if (!P2) memw(R10+#180) = R7.new }");
+ test_invalid(&0b0100_0010_101_01010_11_1_11111_011_01010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0100_0010_110_01010_11_1_00110_011_01010u32.to_le_bytes(), "{ if (!P2) memd(R10+#360) = R7:6 }");
+ test_invalid(&0b0100_0010_111_01010_11_1_11111_011_01010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b0100_0100_000_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (P2.new) memb(R10+#45) = R7 }");
+ test_display(&0b0100_0100_010_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (P2.new) memh(R10+#90) = R7 }");
+ test_display(&0b0100_0100_011_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (P2.new) memh(R10+#90) = R7.H }");
+ test_display(&0b0100_0100_100_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (P2.new) memw(R10+#180) = R7 }");
+ test_display(&0b0100_0100_101_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (P2.new) memb(R10+#45) = R7.new }");
+ test_display(&0b0100_0100_101_01010_11_1_01111_011_01010u32.to_le_bytes(), "{ if (P2.new) memh(R10+#90) = R7.new }");
+ test_display(&0b0100_0100_101_01010_11_1_10111_011_01010u32.to_le_bytes(), "{ if (P2.new) memw(R10+#180) = R7.new }");
+ test_invalid(&0b0100_0100_101_01010_11_1_11111_011_01010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0100_0100_110_01010_11_1_00110_011_01010u32.to_le_bytes(), "{ if (P2.new) memd(R10+#360) = R7:6 }");
+ test_invalid(&0b0100_0100_111_01010_11_1_11111_011_01010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b0100_0110_000_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (!P2.new) memb(R10+#45) = R7 }");
+ test_display(&0b0100_0110_010_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (!P2.new) memh(R10+#90) = R7 }");
+ test_display(&0b0100_0110_011_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (!P2.new) memh(R10+#90) = R7.H }");
+ test_display(&0b0100_0110_100_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (!P2.new) memw(R10+#180) = R7 }");
+ test_display(&0b0100_0110_101_01010_11_1_00111_011_01010u32.to_le_bytes(), "{ if (!P2.new) memb(R10+#45) = R7.new }");
+ test_display(&0b0100_0110_101_01010_11_1_01111_011_01010u32.to_le_bytes(), "{ if (!P2.new) memh(R10+#90) = R7.new }");
+ test_display(&0b0100_0110_101_01010_11_1_10111_011_01010u32.to_le_bytes(), "{ if (!P2.new) memw(R10+#180) = R7.new }");
+ test_invalid(&0b0100_0110_101_01010_11_1_11111_011_01010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0100_0110_110_01010_11_1_00110_011_01010u32.to_le_bytes(), "{ if (!P2.new) memd(R10+#360) = R7:6 }");
+ test_invalid(&0b0100_0110_111_01010_11_1_11111_011_01010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ // now for some loads
+ test_display(&0b0100_0001_000_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (P2) R8 = memb(R10+#45) }");
+ test_display(&0b0100_0001_001_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (P2) R8 = memub(R10+#45) }");
+ test_display(&0b0100_0001_010_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (P2) R8 = memh(R10+#90) }");
+ test_display(&0b0100_0001_011_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (P2) R8 = memuh(R10+#90) }");
+ test_display(&0b0100_0001_100_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (P2) R8 = memw(R10+#180) }");
+ test_invalid(&0b0100_0001_101_01010_11_1_11101_101_01000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0100_0001_110_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (P2) R9:8 = memd(R10+#360) }");
+ test_invalid(&0b0100_0001_111_01010_11_1_11101_101_01000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b0100_0011_000_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (!P2) R8 = memb(R10+#45) }");
+ test_display(&0b0100_0011_001_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (!P2) R8 = memub(R10+#45) }");
+ test_display(&0b0100_0011_010_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (!P2) R8 = memh(R10+#90) }");
+ test_display(&0b0100_0011_011_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (!P2) R8 = memuh(R10+#90) }");
+ test_display(&0b0100_0011_100_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (!P2) R8 = memw(R10+#180) }");
+ test_invalid(&0b0100_0011_101_01010_11_1_11101_101_01000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0100_0011_110_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (!P2) R9:8 = memd(R10+#360) }");
+ test_invalid(&0b0100_0011_111_01010_11_1_11101_101_01000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b0100_0101_000_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (P2.new) R8 = memb(R10+#45) }");
+ test_display(&0b0100_0101_001_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (P2.new) R8 = memub(R10+#45) }");
+ test_display(&0b0100_0101_010_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (P2.new) R8 = memh(R10+#90) }");
+ test_display(&0b0100_0101_011_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (P2.new) R8 = memuh(R10+#90) }");
+ test_display(&0b0100_0101_100_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (P2.new) R8 = memw(R10+#180) }");
+ test_invalid(&0b0100_0101_101_01010_11_1_11101_101_01000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0100_0101_110_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (P2.new) R9:8 = memd(R10+#360) }");
+ test_invalid(&0b0100_0101_111_01010_11_1_11101_101_01000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b0100_0111_000_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (!P2.new) R8 = memb(R10+#45) }");
+ test_display(&0b0100_0111_001_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (!P2.new) R8 = memub(R10+#45) }");
+ test_display(&0b0100_0111_010_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (!P2.new) R8 = memh(R10+#90) }");
+ test_display(&0b0100_0111_011_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (!P2.new) R8 = memuh(R10+#90) }");
+ test_display(&0b0100_0111_100_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (!P2.new) R8 = memw(R10+#180) }");
+ test_invalid(&0b0100_0111_101_01010_11_1_11101_101_01000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0100_0111_110_01010_11_1_10101_101_01000u32.to_le_bytes(), "{ if (!P2.new) R9:8 = memd(R10+#360) }");
+ test_invalid(&0b0100_0111_111_01010_11_1_11101_101_01000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b0100_100_0000_01010_11_1_00110_001_10011u32.to_le_bytes(), "{ memb(gp+#0x1533) = R6 }");
+ test_display(&0b0100_100_0010_01010_11_1_00110_001_10011u32.to_le_bytes(), "{ memh(gp+#0x2a66) = R6 }");
+ test_display(&0b0100_100_0011_01010_11_1_00110_001_10011u32.to_le_bytes(), "{ memh(gp+#0x2a66) = R6.H }");
+ test_display(&0b0100_100_0100_01010_11_1_00110_001_10011u32.to_le_bytes(), "{ memw(gp+#0x54cc) = R6 }");
+ test_display(&0b0100_100_0101_01010_11_1_00110_001_10011u32.to_le_bytes(), "{ memb(gp+#0x1533) = R6.new }");
+ test_display(&0b0100_100_0101_01010_11_1_01110_001_10011u32.to_le_bytes(), "{ memh(gp+#0x2a66) = R6.new }");
+ test_display(&0b0100_100_0101_01010_11_1_10110_001_10011u32.to_le_bytes(), "{ memw(gp+#0x54cc) = R6.new }");
+ test_invalid(&0b0100_100_0101_01010_11_1_11110_001_10011u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0100_100_0110_01010_11_1_00110_001_10011u32.to_le_bytes(), "{ memd(gp+#0xa998) = R7:6 }");
+ test_invalid(&0b0100_100_0111_01010_11_1_11110_001_10011u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b0100_100_1000_01010_11_1_00110011_00110u32.to_le_bytes(), "{ R6 = memb(gp+#0x1533) }");
+ test_display(&0b0100_100_1001_01010_11_1_00110011_00110u32.to_le_bytes(), "{ R6 = memub(gp+#0x1533) }");
+ test_display(&0b0100_100_1010_01010_11_1_00110011_00110u32.to_le_bytes(), "{ R6 = memh(gp+#0x2a66) }");
+ test_display(&0b0100_100_1011_01010_11_1_00110011_00110u32.to_le_bytes(), "{ R6 = memuh(gp+#0x2a66) }");
+ test_display(&0b0100_100_1100_01010_11_1_00110011_00110u32.to_le_bytes(), "{ R6 = memw(gp+#0x54cc) }");
+ test_invalid(&0b0100_100_1101_01010_11_1_00110011_00110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0100_100_1110_01010_11_1_00110011_00110u32.to_le_bytes(), "{ R7:6 = memd(gp+#0xa998) }");
+ test_invalid(&0b0100_100_1111_01010_11_1_00110011_00110u32.to_le_bytes(), DecodeError::InvalidOpcode);
}
#[test]