summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--notes/todo128
-rw-r--r--src/display.rs47
-rw-r--r--src/lib.rs257
-rw-r--r--tests/from_brain.rs91
4 files changed, 422 insertions, 101 deletions
diff --git a/notes/todo b/notes/todo
index 6c1317e..1aeaca1 100644
--- a/notes/todo
+++ b/notes/todo
@@ -297,39 +297,39 @@ 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 0|1 i i 1 0 1 1|i i i i i| P P |i i i i i i i i i|d d d d d| Rdd=memuh(gp+#u16:3) - LD/slot 0,1
|0 1 0 0|1 i i 1 1 0 0|i i i i i| P P |i i i i i i i i i|d d d d d| Rd=memw(gp+#u16:3) - LD/slot 0,1
|0 1 0 0|1 i i 1 1 1 0|i i i i i| P P |i i i i i i i i i|d d d d d| Rdd=memd(gp+#u16:3) - LD/slot 0,1
-|0 1 0 1|0 0 0 0 1 0 1|s s s s s| P P |- - - - - - - - -|- - - - -| callr Rs - CR/slot 2
-|0 1 0 1|0 0 0 0 1 1 0|s s s s s| P P |- - - - - - - - -|- - - - -| callrh Rs - CR/slot 2
-|0 1 0 1|0 0 0 1 0 0 0|s s s s s| P P |- - - - u u - - -|- - - - -| if (Pu) callr Rs - CR/slot 2
-|0 1 0 1|0 0 0 1 0 0 1|s s s s s| P P |- - - - u u - - -|- - - - -| if (!Pu) callr Rs - CR/slot 2
-|0 1 0 1|0 0 1 0 1 0 0|s s s s s| P P |- - - - - - - - -|- - - - -| jumpr Rs - CR/slot 2
-|0 1 0 1|0 0 1 0 1 0 1|s s s s s| P P |- - - - - - - - -|- - - - -| hintjr(Rs) - CR/slot 2,3
-|0 1 0 1|0 0 1 0 1 1 0|s s s s s| P P |- - - - - - - - -|- - - - -| jumprh Rs - CR/slot 2
-|0 1 0 1|0 0 1 1 0 1 0|s s s s s| P P |- 0 0 - u u - - -|- - - - -| if (Pu) jumpr:nt Rs - CR/slot 2
-|0 1 0 1|0 0 1 1 0 1 0|s s s s s| P P |- 0 1 - u u - - -|- - - - -| if (Pu.new) jumpr:nt Rs - CR/slot 2
-|0 1 0 1|0 0 1 1 0 1 0|s s s s s| P P |- 1 0 - u u - - -|- - - - -| if (Pu) jumpr:t Rs - CR/slot 2
-|0 1 0 1|0 0 1 1 0 1 0|s s s s s| P P |- 1 1 - u u - - -|- - - - -| if (Pu.new) jumpr:t Rs - CR/slot 2
-|0 1 0 1|0 0 1 1 0 1 1|s s s s s| P P |- 0 0 - u u - - -|- - - - -| if (!Pu) jumpr:nt Rs - CR/slot 2
-|0 1 0 1|0 0 1 1 0 1 1|s s s s s| P P |- 0 1 - u u - - -|- - - - -| if (!Pu.new) jumpr:nt Rs - CR/slot 2
-|0 1 0 1|0 0 1 1 0 1 1|s s s s s| P P |- 1 0 - u u - - -|- - - - -| if (!Pu) jumpr:t Rs - CR/slot 2
-|0 1 0 1|0 0 1 1 0 1 1|s s s s s| P P |- 1 1 - u u - - -|- - - - -| if (!Pu.new) jumpr:t Rs - CR/slot 2
-|0 1 0 1|0 1 0 0 0 0 -|- - - - -| P P |- i i i i i - - -|i i i - -| trap0(#u8) - SYSTEM/slot 2
-|0 1 0 1|0 1 0 0 0 1 -|- - - i i| P P |- i i i i i - - -|i i i - -| pause(#u10) - SYSTEM/slot 2
-|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 0 1 1 0|s s s s s| P P |0 0 0 - - - - - -|- - - - -| icinva(Rs) - SYSTEM/slot 2
-|0 1 0 1|0 1 1 1 1 1 0|0 0 0 0 0| P P |0 - - - 0 0 0 0 0|0 0 0 1 0| isync - 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
-|0 1 0 1|1 0 0 i i i i|i i i i i| P P |i i i i i i i i i|i i i i -| jump #r22:2 - J/slot 0,1,2,3
-|0 1 0 1|1 0 1 i i i i|i i i i i| P P |i i i i i i i i i|i i i i 0| call #r22:2 - CR/slot 2,3
-|0 1 0 1|1 1 0 0 i i 0|i i i i i| P P |i 0 0 - u u i i i|i i i i -| if (Pu) jump:nt #r15:2 - J/slot 0,1,2,3
-|0 1 0 1|1 1 0 0 i i 0|i i i i i| P P |i 0 1 - u u i i i|i i i i -| if (Pu.new) jump:nt #r15:2 - J/slot 0,1,2,3
-|0 1 0 1|1 1 0 0 i i 0|i i i i i| P P |i 1 0 - u u i i i|i i i i -| if (Pu) jump:t #r15:2 - J/slot 0,1,2,3
-|0 1 0 1|1 1 0 0 i i 0|i i i i i| P P |i 1 1 - u u i i i|i i i i -| if (Pu.new) jump:t #r15:2 - J/slot 0,1,2,3
-|0 1 0 1|1 1 0 0 i i 1|i i i i i| P P |i 0 0 - u u i i i|i i i i -| if (!Pu) jump:nt #r15:2 - J/slot 0,1,2,3
-|0 1 0 1|1 1 0 0 i i 1|i i i i i| P P |i 0 1 - u u i i i|i i i i -| if (!Pu.new) jump:nt #r15:2 - J/slot 0,1,2,3
-|0 1 0 1|1 1 0 0 i i 1|i i i i i| P P |i 1 0 - u u i i i|i i i i -| if (!Pu) jump:t #r15:2 - J/slot 0,1,2,3
-|0 1 0 1|1 1 0 0 i i 1|i i i i i| P P |i 1 1 - u u i i i|i i i i -| if (!Pu.new) jump:t #r15:2 - J/slot 0,1,2,3
-|0 1 0 1|1 1 0 1 i i 0|i i i i i| P P |i - 0 - u u i i i|i i i i -| if (Pu) call #r15:2 - CR/slot 2,3
-|0 1 0 1|1 1 0 1 i i 1|i i i i i| P P |i - 0 - u u i i i|i i i i -| if (!Pu) call #r15:2 - CR/slot 2,3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|0 1 1 0|0 0 0 0 0 0 0|s s s s s| P P |- i i i i i - - -|i i - - -| loop0(#r7:2,Rs) - CR/slot 3
|0 1 1 0|0 0 0 0 0 0 1|s s s s s| P P |- i i i i i - - -|i i - - -| loop1(#r7:2,Rs) - CR/slot 3
|0 1 1 0|0 0 0 0 1 0 1|s s s s s| P P |- i i i i i - - -|i i - - -| p3=sp1loop0(#r7:2,Rs) - CR/slot 3
@@ -1417,9 +1417,9 @@ 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|1 1 0|s s s s s| P P |0 t t t t t|0 0 1|x x x x x| Rx|=xor(Rs,Rt) - XTYPE ALU/slot 2,3
|1 1 1 0|1 1 1 1|1 1 0|s s s s s| P P |0 t t t t t|0 1 0|x x x x x| Rx^=and(Rs,Rt) - XTYPE ALU/slot 2,3
|1 1 1 0|1 1 1 1|1 1 0|s s s s s| P P |0 t t t t t|0 1 1|x x x x x| Rx^=or(Rs,Rt) - XTYPE ALU/slot 2,3
-|1 1 1 1|0 0 0 1 0 0 0|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=and(Rs,Rt) - ALU32/slots 0 1 2 3
-|1 1 1 1|0 0 0 1 0 0 1|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=or(Rs,Rt) - ALU32/slots 0 1 2 3
-|1 1 1 1|0 0 0 1 0 1 1|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=xor(Rs,Rt) - ALU32/slots 0 1 2 3
+test |1 1 1 1|0 0 0 1 0 0 0|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=and(Rs,Rt) - ALU32/slots 0 1 2 3
+test |1 1 1 1|0 0 0 1 0 0 1|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=or(Rs,Rt) - ALU32/slots 0 1 2 3
+test |1 1 1 1|0 0 0 1 0 1 1|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=xor(Rs,Rt) - ALU32/slots 0 1 2 3
|1 1 1 1|0 0 0 1 1 0 0|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=and(Rt,~Rs) - ALU32/slots 0 1 2 3
|1 1 1 1|0 0 0 1 1 0 1|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=and(Rt,~Rs) - ALU32/slots 0 1 2 3
|1 1 1 1|0 0 1 0 - 0 0|s s s s s| P P |- t t t t t - - -|0 0 0 d d| Pd=cmp.eq(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
@@ -1428,10 +1428,10 @@ 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 1|0 0 1 0 - 1 0|s s s s s| P P |- t t t t t - - -|1 0 0 d d| Pd=!cmp.gt(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
|1 1 1 1|0 0 1 0 - 1 1|s s s s s| P P |- t t t t t - - -|0 0 0 d d| Pd=cmp.gtu(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
|1 1 1 1|0 0 1 0 - 1 1|s s s s s| P P |- t t t t t - - -|1 0 0 d d| Pd=!cmp.gtu(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|0 0 1 1 0 0 0|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=add(Rs,Rt) - ALU32/slots 0 1 2 3
-|1 1 1 1|0 0 1 1 0 0 1|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=sub(Rt,Rs) - ALU32/slots 0 1 2 3
-|1 1 1 1|0 0 1 1 0 1 0|s s s s s| P P |- t t t t t - - -|1 0 0 d d| Rd=cmp.eq(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|0 0 1 1 0 1 1|s s s s s| P P |- t t t t t - - -|1 0 0 d d| Rd=!cmp.eq(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
+test |1 1 1 1|0 0 1 1 0 0 0|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=add(Rs,Rt) - ALU32/slots 0 1 2 3
+test |1 1 1 1|0 0 1 1 0 0 1|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=sub(Rt,Rs) - ALU32/slots 0 1 2 3
+test |1 1 1 1|0 0 1 1 0 1 0|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=cmp.eq(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
+test |1 1 1 1|0 0 1 1 0 1 1|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=!cmp.eq(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
|1 1 1 1|0 0 1 1 1 0 0|s s s s s| P P |0 t t t t t - - -|d d d d d| Rd=combine(Rt.H,Rs.H) - ALU32 PERM/slots 0 1 2 3
|1 1 1 1|0 0 1 1 1 0 1|s s s s s| P P |0 t t t t t - - -|d d d d d| Rd=combine(Rt.H,Rs.L) - ALU32 PERM/slots 0 1 2 3
|1 1 1 1|0 0 1 1 1 1 0|s s s s s| P P |0 t t t t t - - -|d d d d d| Rd=combine(Rt.L,Rs.H) - ALU32 PERM/slots 0 1 2 3
@@ -1450,27 +1450,27 @@ 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 1|0 1 1 1 - 0 0|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=vavgh(Rs,Rt) - ALU32/slots 0 1 2 3 -
|1 1 1 1|0 1 1 1 - 0 1|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=vavgh(Rs,Rt):sat - ALU32/slots 0 1 2 3 -
|1 1 1 1|0 1 1 1 - 1 1|s s s s s| P P |- t t t t t - - -|d d d d d| Rd=vnavgh(Rt,Rs) - ALU32/slots 0 1 2 3 -
-|1 1 1 1|1 0 0 1 - 0 0|s s s s s| P P |0 t t t t t 0 u u|d d d d d| if (Pu) Rd=and(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 0 1 - 0 0|s s s s s| P P |0 t t t t t 1 u u|d d d d d| if (!Pu) Rd=and(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 0 1 - 0 0|s s s s s| P P |1 t t t t t 0 u u|d d d d d| if (Pu.new) Rd=and(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 0 1 - 0 0|s s s s s| P P |1 t t t t t 1 u u|d d d d d| if (!Pu.new) Rd=and(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 0 1 - 0 1|s s s s s| P P |0 t t t t t 0 u u|d d d d d| if (Pu) Rd=or(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 0 1 - 0 1|s s s s s| P P |0 t t t t t 1 u u|d d d d d| if (!Pu) Rd=or(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 0 1 - 0 1|s s s s s| P P |1 t t t t t 0 u u|d d d d d| if (Pu.new) Rd=or(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 0 1 - 0 1|s s s s s| P P |1 t t t t t 1 u u|d d d d d| if (!Pu.new) Rd=or(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 0 1 - 1 1|s s s s s| P P |0 t t t t t 0 u u|d d d d d| if (Pu) Rd=xor(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 0 1 - 1 1|s s s s s| P P |0 t t t t t 1 u u|d d d d d| if (!Pu) Rd=xor(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 0 1 - 1 1|s s s s s| P P |1 t t t t t 0 u u|d d d d d| if (Pu.new) Rd=xor(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 0 1 - 1 1|s s s s s| P P |1 t t t t t 1 u u|d d d d d| if (!Pu.new) Rd=xor(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 1 1 0 - 0|s s s s s| P P |0 t t t t t 0 u u|d d d d d| if (Pu) Rd=add(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 1 1 0 - 0|s s s s s| P P |0 t t t t t 1 u u|d d d d d| if (!Pu) Rd=add(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 1 1 0 - 0|s s s s s| P P |1 t t t t t 0 u u|d d d d d| if (Pu.new) Rd=add(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 1 1 0 - 0|s s s s s| P P |1 t t t t t 1 u u|d d d d d| if (!Pu.new) Rd=add(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 1 1 0 - 1|s s s s s| P P |0 t t t t t 0 u u|d d d d d| if (Pu) Rd=sub(Rt,Rs) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 1 1 0 - 1|s s s s s| P P |0 t t t t t 1 u u|d d d d d| if (!Pu) Rd=sub(Rt,Rs) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 1 1 0 - 1|s s s s s| P P |1 t t t t t 0 u u|d d d d d| if (Pu.new) Rd=sub(Rt,Rs) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 0 1 1 0 - 1|s s s s s| P P |1 t t t t t 1 u u|d d d d d| if (!Pu.new) Rd=sub(Rt,Rs) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 1 0 1 0 0 0|s s s s s| P P |0 t t t t t 0 u u|d d d d d| if (Pu) Rdd=contains(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 1 0 1 0 0 0|s s s s s| P P |0 t t t t t 1 u u|d d d d d| if (!Pu) Rdd=contains(Rs,Rt)- ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 1 0 1 0 0 0|s s s s s| P P |1 t t t t t 0 u u|d d d d d| if (Pu.new) Rdd=contains(Rs,Rt) - ALU32 PRED/slots 0 1 2 3
-|1 1 1 1|1 1 0 1 0 0 0|s s s s s| P P |1 t t t t t 1 u u|d d d d d| if (!Pu.new) Rdd=contains(Rs,Rt)- ALU32 PRED/slots 0 1 2 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/display.rs b/src/display.rs
index 86de297..94d15f3 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -95,17 +95,19 @@ impl fmt::Display for Instruction {
return Ok(());
}
- static JUMPS: &[Opcode] = &[
+ use crate::BranchHint;
+
+ static CONDITIONAL_JUMPS: &[Opcode] = &[
Opcode::JumpEq, Opcode::JumpNeq, Opcode::JumpGt, Opcode::JumpLe,
Opcode::JumpGtu, Opcode::JumpLeu, Opcode::JumpBitSet, Opcode::JumpBitClear,
];
- if JUMPS.contains(&self.opcode) {
- use crate::BranchHint;
- let hint_label = match self.flags.branch_hint.unwrap() {
- BranchHint::Taken => { "t" },
- BranchHint::NotTaken => { "nt" },
+ if CONDITIONAL_JUMPS.contains(&self.opcode) {
+ let hint_label = match self.flags.branch_hint {
+ Some(BranchHint::Taken) => { ":t" },
+ Some(BranchHint::NotTaken) => { ":nt" },
+ None => { "" },
};
- write!(f, "if ({}({}, {})) jump:{} {}",
+ write!(f, "if ({}({}, {})) jump{} {}",
self.opcode.cmp_str().unwrap(), // TODO: unwrap_unchecked??
self.sources[0],
self.sources[1],
@@ -114,6 +116,21 @@ impl fmt::Display for Instruction {
)?;
return Ok(());
}
+ static UNCONDITIONAL_BRANCHES: &[Opcode] = &[
+ Opcode::Call, Opcode::Callr, Opcode::Callrh,
+ Opcode::Jump, Opcode::Jumpr, Opcode::Jumprh,
+ ];
+ if UNCONDITIONAL_BRANCHES.contains(&self.opcode) {
+ write!(f, "{}{} {}",
+ self.opcode,
+ match self.flags.branch_hint.as_ref() {
+ Some(BranchHint::Taken) => ":t",
+ Some(BranchHint::NotTaken) => ":nt",
+ None => "",
+ },
+ self.dest.unwrap())?;
+ return Ok(());
+ }
if let Some(o) = self.dest.as_ref() {
write!(f, "{} = ", o)?;
}
@@ -157,7 +174,12 @@ impl fmt::Display for Opcode {
Opcode::BUG => { f.write_str("BUG") },
Opcode::Nop => { f.write_str("nop") },
Opcode::Jump => { f.write_str("jump") },
+ Opcode::Jumpr => { f.write_str("jumpr") },
+ Opcode::Jumprh => { f.write_str("jumprh") },
Opcode::Call => { f.write_str("call") },
+ Opcode::Callr => { f.write_str("callr") },
+ Opcode::Callrh => { f.write_str("callrh") },
+ Opcode::Hintjr => { f.write_str("hintjr") },
Opcode::Memb => { f.write_str("memb") },
Opcode::Memub => { f.write_str("memub") },
Opcode::Memh => { f.write_str("memh") },
@@ -199,6 +221,8 @@ impl fmt::Display for Opcode {
Opcode::And => { f.write_str("and") },
Opcode::Sub => { f.write_str("sub") },
Opcode::Or => { f.write_str("or") },
+ Opcode::Xor => { f.write_str("xor") },
+ Opcode::Contains => { f.write_str("contains") },
Opcode::JumpEq => { f.write_str("cmp.eq+jump") },
Opcode::JumpNeq => { f.write_str("cmp.neq+jump") },
@@ -258,6 +282,13 @@ impl fmt::Display for Opcode {
Opcode::TransferRegisterJump => { f.write_str("transferregisterjump") }
Opcode::TransferImmediateJump => { f.write_str("transferimmediatejump") }
+
+ Opcode::Trap0 => { f.write_str("trap0") }
+ Opcode::Trap1 => { f.write_str("trap1") }
+ Opcode::Pause => { f.write_str("pause") }
+ Opcode::Icinva => { f.write_str("icinva") }
+ Opcode::Isync => { f.write_str("isync") }
+ Opcode::Unpause => { f.write_str("unpause") }
}
}
}
@@ -269,7 +300,7 @@ impl fmt::Display for Operand {
f.write_str("BUG (operand)")
}
Operand::PCRel32 { rel } => {
- write!(f, "#{}", rel)
+ write!(f, "$+#{}", rel)
}
Operand::Gpr { reg } => {
write!(f, "R{}", reg)
diff --git a/src/lib.rs b/src/lib.rs
index a2198f7..65fd22e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -350,7 +350,12 @@ pub enum Opcode {
// V73 page 214 ("Jump to address")
Jump,
+ Jumpr,
+ Jumprh,
Call,
+ Callr,
+ Callrh,
+ Hintjr,
LoadMemb,
LoadMemub,
@@ -401,15 +406,21 @@ pub enum Opcode {
JumpBitSet,
JumpBitClear,
+ /// predicate register used for branch condition is part of normal predication bits
TestClrJump,
+ /// predicate register used for branch condition is part of normal predication bits
CmpEqJump,
+ /// predicate register used for branch condition is part of normal predication bits
CmpGtJump,
+ /// predicate register used for branch condition is part of normal predication bits
CmpGtuJump,
Add,
And,
Sub,
Or,
+ Xor,
+ Contains,
Tlbw,
Tlbr,
@@ -452,6 +463,13 @@ pub enum Opcode {
Extractu,
Insert,
+
+ Trap0,
+ Trap1,
+ Pause,
+ Icinva,
+ Isync,
+ Unpause,
}
impl Opcode {
@@ -1475,20 +1493,109 @@ fn decode_instruction<
0b000 => {
// 0 1 0 1 | 0 0 0 ...
// call to register, may be predicated
- panic!("TODO");
+ let op = (inst >> 21) & 0b1111;
+ let sssss = reg_b16(inst);
+ handler.on_dest_decoded(Operand::gpr(sssss))?;
+
+ if op >= 0b1000 {
+ // predicated callr
+ opcode_check!(op < 0b1010);
+ handler.on_opcode_decoded(Opcode::Callr)?;
+ let negated = op & 1 == 1;
+ let uu = (inst >> 8) & 0b11;
+ handler.inst_predicated(uu as u8, negated, false)?;
+ } else {
+ // unconditional callr/callrh
+ opcode_check!(op == 0b101 || op == 0b110);
+ if op == 0b101 {
+ handler.on_opcode_decoded(Opcode::Callr)?;
+ } else {
+ handler.on_opcode_decoded(Opcode::Callrh)?;
+ }
+ }
},
- 0b000 => {
+ 0b001 => {
// 0 1 0 1 | 0 0 1 ...
// jump to register, may be predicated
- panic!("TODO");
+ let op = (inst >> 21) & 0b1111;
+ let sssss = reg_b16(inst);
+
+ eprintln!("op is {:04b}", op);
+ if op >= 0b1000 {
+ // predicated jumpr
+ opcode_check!(op == 0b0100 || op == 0b0101 || op == 0b0110 || op == 0b1010 || op == 0b1011);
+ handler.on_opcode_decoded(Opcode::Jumpr)?;
+ handler.on_dest_decoded(Operand::gpr(sssss))?;
+ let negated = op & 1 == 1;
+ let dotnew = (inst >> 11) & 1 == 1;
+ let hint_taken = (inst >> 12) & 1 == 1;
+ let uu = (inst >> 8) & 0b11;
+ handler.inst_predicated(uu as u8, negated, dotnew)?;
+ handler.branch_hint(hint_taken)?;
+ } else {
+ // unconditional jumpr/jumprh
+ opcode_check!(op == 0b100 || op == 0b101 || op == 0b110);
+ if op == 0b100 {
+ handler.on_opcode_decoded(Opcode::Jumpr)?;
+ handler.on_dest_decoded(Operand::gpr(sssss))?;
+ } else if op == 0b101 {
+ handler.on_opcode_decoded(Opcode::Hintjr)?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ } else {
+ handler.on_opcode_decoded(Opcode::Jumprh)?;
+ handler.on_dest_decoded(Operand::gpr(sssss))?;
+ }
+ }
+ },
+ 0b010 => {
+ // trap0, pause, trap1
+ let minbits = (inst >> 22) & 0b111;
+ let u_low = (inst >> 2) & 0b111;
+ let u_mid = (inst >> 8) & 0b11111;
+ let u_8 = (u_mid << 3) | u_low;
+
+ if minbits == 0b000 {
+ handler.on_opcode_decoded(Opcode::Trap0)?;
+ handler.on_source_decoded(Operand::imm_u8(u_8 as u8))?;
+ } else if minbits == 0b001 {
+ handler.on_opcode_decoded(Opcode::Pause)?;
+ let u_high = (inst >> 16) & 0b11;
+ let u_10 = (u_high << 8) | u_8;
+ handler.on_source_decoded(Operand::imm_u16(u_10 as u16))?;
+ } else if minbits == 0b010 {
+ handler.on_opcode_decoded(Opcode::Trap1)?;
+ let xxxxx = reg_b16(inst);
+ handler.on_source_decoded(Operand::gpr(xxxxx))?;
+ handler.on_source_decoded(Operand::imm_u8(u_8 as u8))?;
+ } else {
+ opcode_check!(false);
+ }
+ },
+ 0b011 => {
+ // icinva, isync, unpause
+ let minbits = (inst >> 21) & 0b1111;
+
+ if minbits == 0b0110 {
+ handler.on_opcode_decoded(Opcode::Icinva)?;
+ handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?;
+ opcode_check!(inst & 0x3800 == 0x0000);
+ } else if minbits == 0b1110 {
+ handler.on_opcode_decoded(Opcode::Isync)?;
+ opcode_check!(inst & 0x1f23ff == 0x000002);
+ } else if minbits == 0b1111 {
+ handler.on_opcode_decoded(Opcode::Unpause)?;
+ opcode_check!(inst & 0x10e0 == 0x1000);
+ } else {
+ opcode_check!(false);
+ }
},
0b100 => {
// V73 Jump to address
// 0 1 0 1 | 1 0 0 i...
handler.on_opcode_decoded(Opcode::Jump)?;
- let imm = ((inst >> 1) & 0x7fff) | ((inst >> 3) & 0xff8000);
+ let imm = ((inst >> 1) & 0x1fff) | ((inst >> 3) & 0xffe000);
let imm = ((imm as i32) << 10) >> 10;
- handler.on_source_decoded(Operand::PCRel32 { rel: imm & !0b11 })?;
+ handler.on_dest_decoded(Operand::PCRel32 { rel: imm << 2 })?;
},
0b101 => {
// V73 Call to address
@@ -1498,10 +1605,40 @@ fn decode_instruction<
return Err(DecodeError::InvalidOpcode);
}
handler.on_opcode_decoded(Opcode::Call)?;
- let imm = ((inst >> 1) & 0x7fff) | ((inst >> 3) & 0xff8000);
+ let imm = ((inst >> 1) & 0x1fff) | ((inst >> 3) & 0xffe000);
let imm = ((imm as i32) << 10) >> 10;
- handler.on_source_decoded(Operand::PCRel32 { rel: imm & !0b11 })?;
+ handler.on_dest_decoded(Operand::PCRel32 { rel: imm << 2 })?;
},
+ 0b110 => {
+ // V73 Predicated jump/call relative
+ let negated = (inst >> 21) & 1 == 1;
+ let dotnew = (inst >> 11) & 1 == 1;
+ let uu = (inst >> 8) & 0b11;
+ let hint_taken = (inst >> 11) == 1;
+
+ let i_lo = (inst >> 1) & 0x7f;
+ let i_8 = (inst >> 13) & 1;
+ let i_mid = (inst >> 16) & 0x1f;
+ let i_hi = (inst >> 22) & 0b11;
+ let i15 = i_lo | (i_8 << 7) | (i_mid << 8) | (i_hi << 13);
+ let i15 = (i15 as i32) << 17 >> 17;
+
+ let is_call = (inst >> 24) & 1 == 1;
+
+ if is_call {
+ handler.on_opcode_decoded(Opcode::Call)?;
+ handler.inst_predicated(uu as u8, negated, false)?;
+ opcode_check!(!dotnew);
+ } else {
+ handler.on_opcode_decoded(Opcode::Jump)?;
+ handler.inst_predicated(uu as u8, negated, dotnew)?;
+ handler.branch_hint(hint_taken)?;
+ }
+ handler.on_dest_decoded(Operand::PCRel32 { rel: i15 << 2 })?;
+ }
+ 0b111 => {
+ return Err(DecodeError::InvalidOpcode);
+ }
_ => {
// TODO: exhaustive
}
@@ -2079,6 +2216,112 @@ fn decode_instruction<
handler.on_source_decoded(Operand::gpr(sssss))?;
handler.on_source_decoded(Operand::imm_i16(i as i16))?;
}
+ 0b1111 => {
+ let ddddd = reg_b0(inst);
+ let ttttt = reg_b8(inst);
+ let sssss = reg_b16(inst);
+ let uu = (inst >> 5) & 0b11;
+
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ handler.on_source_decoded(Operand::gpr(ttttt))?;
+
+ let majbits = (inst >> 24) & 0b111;
+ let predicated = (inst >> 27) & 1 == 1;
+ if !predicated {
+ // one set of instructions. for most, the opcode bits actually overlap (e.g.
+ // Rd=and(Rs,Rt) predicated with this bit set). this does not apply for *all*
+ // though, so just handle the two sets of instructions individually...
+ let minbits = (inst >> 21) & 0b111;
+ match majbits {
+ 0b001 => {
+ match minbits {
+ 0b000 => {
+ handler.on_opcode_decoded(Opcode::And)?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ },
+ 0b001 => {
+ handler.on_opcode_decoded(Opcode::Or)?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ },
+ 0b011 => {
+ handler.on_opcode_decoded(Opcode::Xor)?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ },
+ 0b100 => {
+ },
+ 0b101 => {
+ },
+ _ => {
+ opcode_check!(false);
+ }
+ }
+ },
+ 0b010 => {
+ }
+ 0b011 => {
+ match minbits {
+ 0b000 => {
+ handler.on_opcode_decoded(Opcode::Add)?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ },
+ 0b001 => {
+ handler.on_opcode_decoded(Opcode::Sub)?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ }
+ 0b010 => {
+ handler.on_opcode_decoded(Opcode::CmpEq)?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ }
+ 0b011 => {
+ handler.on_opcode_decoded(Opcode::CmpEq)?;
+ handler.negate_result()?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ }
+ _ => {
+ // will become exhaustive..
+ }
+ }
+ }
+ 0b100 => {
+ }
+ 0b101 => {
+ }
+ 0b110 => {
+ }
+ 0b111 => {
+ }
+ _ => {
+ opcode_check!(false);
+ }
+ }
+ } else {
+ let negated = (inst >> 7) & 1 == 1;
+ let dotnew = (inst >> 13) & 1 == 1;
+ handler.inst_predicated(uu as u8, negated, dotnew)?;
+ if majbits == 0b001 {
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ static OPS: [Option<Opcode>; 4] = [
+ Some(Opcode::And), Some(Opcode::Or), None, Some(Opcode::Xor)
+ ];
+ let opbits = (inst >> 21) & 0b11;
+ handler.on_opcode_decoded(decode_opcode!(OPS[opbits as usize]))?;
+ } else if majbits == 0b011 {
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ opcode_check!((inst >> 23) & 1 == 0);
+ if (inst >> 21) & 1 == 0 {
+ handler.on_opcode_decoded(Opcode::Add)?;
+ } else {
+ handler.on_opcode_decoded(Opcode::Sub)?;
+ }
+ } else if majbits == 0b101 {
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
+ handler.on_opcode_decoded(Opcode::Contains)?;
+ opcode_check!((inst >> 21) & 0b111 == 0b000);
+ } else {
+ opcode_check!(false);
+ }
+ }
+ }
_ => {
eprintln!("iclass: {:04b}", iclass);
// TODO: exhaustive
diff --git a/tests/from_brain.rs b/tests/from_brain.rs
index 2440e57..57e492d 100644
--- a/tests/from_brain.rs
+++ b/tests/from_brain.rs
@@ -39,16 +39,16 @@ fn supervisor() {
#[test]
fn general() {
- test_display(&0b0001_0110000_01001_11_00_0111_000_00100u32.to_le_bytes(), "{ R17 = #7; jump #8 }");
- test_display(&0b0001_0111000_01001_11_00_0111_000_00100u32.to_le_bytes(), "{ R7 = R17; jump #8 }");
+ test_display(&0b0001_0110000_01001_11_00_0111_000_00100u32.to_le_bytes(), "{ R17 = #7; jump $+#8 }");
+ test_display(&0b0001_0111000_01001_11_00_0111_000_00100u32.to_le_bytes(), "{ R7 = R17; jump $+#8 }");
- test_display(&0b0001_0011011_11001_11_00_0011_000_00010u32.to_le_bytes(), "{ P1 = cmp.gtu(R17, #3); if (!P1.new) jump:nt #-508 }");
- test_display(&0b0001_0011101_11001_11_00_0011_000_00010u32.to_le_bytes(), "{ P1 = tstbit(R17, #0x0); if (P1.new) jump:nt #-508 }");
- test_display(&0b0001_0011111_11001_11_00_0011_000_00010u32.to_le_bytes(), "{ P1 = tstbit(R17, #0x0); if (!P1.new) jump:nt #-508 }");
- test_display(&0b0001_0011111_11001_11_10_0011_000_00010u32.to_le_bytes(), "{ P1 = tstbit(R17, #0x0); if (!P1.new) jump:t #-508 }");
+ test_display(&0b0001_0011011_11001_11_00_0011_000_00010u32.to_le_bytes(), "{ P1 = cmp.gtu(R17, #3); if (!P1.new) jump:nt $+#-508 }");
+ test_display(&0b0001_0011101_11001_11_00_0011_000_00010u32.to_le_bytes(), "{ P1 = tstbit(R17, #0x0); if (P1.new) jump:nt $+#-508 }");
+ test_display(&0b0001_0011111_11001_11_00_0011_000_00010u32.to_le_bytes(), "{ P1 = tstbit(R17, #0x0); if (!P1.new) jump:nt $+#-508 }");
+ test_display(&0b0001_0011111_11001_11_10_0011_000_00010u32.to_le_bytes(), "{ P1 = tstbit(R17, #0x0); if (!P1.new) jump:t $+#-508 }");
- test_display(&0b0001_0101011_11001_11_10_0111_000_00010u32.to_le_bytes(), "{ P0 = cmp.gtu(R17, R7); if (!P0.new) jump:t #-508 }");
- test_display(&0b0001_0101011_11001_11_11_0111_000_00010u32.to_le_bytes(), "{ P1 = cmp.gtu(R17, R7); if (!P1.new) jump:t #-508 }");
+ test_display(&0b0001_0101011_11001_11_10_0111_000_00010u32.to_le_bytes(), "{ P0 = cmp.gtu(R17, R7); if (!P0.new) jump:t $+#-508 }");
+ test_display(&0b0001_0101011_11001_11_11_0111_000_00010u32.to_le_bytes(), "{ P1 = cmp.gtu(R17, R7); if (!P1.new) jump:t $+#-508 }");
test_invalid(&0b0111_0000010_00000_11_0_0_0000_000_00000u32.to_le_bytes(), DecodeError::InvalidOpcode);
@@ -120,23 +120,59 @@ fn general() {
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(&0b0010_00000001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.eq(R4.new, R2)) jump:nt #812 }");
- test_display(&0b0010_00000001_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (cmp.eq(R4.new, R2)) jump:t #812 }");
- test_display(&0b0010_00000101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.eq(R4.new, R2)) jump:nt #812 }");
- test_display(&0b0010_00001001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.gt(R4.new, R2)) jump:nt #812 }");
- test_display(&0b0010_00001101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gt(R4.new, R2)) jump:nt #812 }");
- test_display(&0b0010_00010001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.gtu(R4.new, R2)) jump:nt #812 }");
- test_display(&0b0010_00010101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gtu(R4.new, R2)) jump:nt #812 }");
- test_display(&0b0010_00011001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.gt(R2, R4.new)) jump:nt #812 }");
- test_display(&0b0010_00100101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gtu(R2, R4.new)) jump:nt #812 }");
+ test_display(&0b0010_00000001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.eq(R4.new, R2)) jump:nt $+#812 }");
+ test_display(&0b0010_00000001_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (cmp.eq(R4.new, R2)) jump:t $+#812 }");
+ test_display(&0b0010_00000101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.eq(R4.new, R2)) jump:nt $+#812 }");
+ test_display(&0b0010_00001001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.gt(R4.new, R2)) jump:nt $+#812 }");
+ test_display(&0b0010_00001101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gt(R4.new, R2)) jump:nt $+#812 }");
+ test_display(&0b0010_00010001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.gtu(R4.new, R2)) jump:nt $+#812 }");
+ test_display(&0b0010_00010101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gtu(R4.new, R2)) jump:nt $+#812 }");
+ test_display(&0b0010_00011001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.gt(R2, R4.new)) jump:nt $+#812 }");
+ test_display(&0b0010_00100101_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gtu(R2, R4.new)) jump:nt $+#812 }");
test_invalid(&0b0010_00101101_0100_11_0_00010_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode);
test_invalid(&0b0010_00110101_0100_11_0_00010_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode);
test_invalid(&0b0010_00111101_0100_11_0_00010_100_10110u32.to_le_bytes(), DecodeError::InvalidOpcode);
- test_display(&0b0010_01000001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.eq(R4.new, #2)) jump:nt #812 }");
- test_display(&0b0010_01010101_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gtu(R4.new, #2)) jump:t #812 }");
- test_display(&0b0010_01011001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (tstbit(R4.new, #0)) jump:nt #812 }");
- 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(&0b0010_01000001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (cmp.eq(R4.new, #2)) jump:nt $+#812 }");
+ test_display(&0b0010_01010101_0100_11_1_00010_100_10110u32.to_le_bytes(), "{ if (!cmp.gtu(R4.new, #2)) jump:t $+#812 }");
+ test_display(&0b0010_01011001_0100_11_0_00010_100_10110u32.to_le_bytes(), "{ if (tstbit(R4.new, #0)) jump:nt $+#812 }");
+ 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_invalid(&0b0101_000_0100_00001_11_0_00000_000_00000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0101_000_0101_00001_11_0_00000_000_00000u32.to_le_bytes(), "{ callr R1 }");
+ test_display(&0b0101_000_0110_00001_11_0_00000_000_00000u32.to_le_bytes(), "{ callrh R1 }");
+ test_invalid(&0b0101_000_0111_00001_11_0_00000_000_00000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0101_000_1000_00001_11_0_00010_000_00000u32.to_le_bytes(), "{ if (P2) callr R1 }");
+ test_display(&0b0101_000_1001_00001_11_0_00010_000_00000u32.to_le_bytes(), "{ if (!P2) callr R1 }");
+ test_invalid(&0b0101_000_1010_00001_11_0_00000_000_00000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_invalid(&0b0101_001_0011_00001_11_0_00000_000_00000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0101_001_0100_00001_11_0_00000_000_00000u32.to_le_bytes(), "{ jumpr R1 }");
+ test_display(&0b0101_001_0101_00001_11_0_00000_000_00000u32.to_le_bytes(), "{ hintjr(R1) }");
+ test_display(&0b0101_001_0110_00001_11_0_00000_000_00000u32.to_le_bytes(), "{ jumprh R1 }");
+ test_invalid(&0b0101_001_0111_00001_11_0_00000_000_00000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_invalid(&0b0101_001_1000_00001_11_0_00000_000_00000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_invalid(&0b0101_001_1001_00001_11_0_00000_000_00000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0101_001_1010_00001_11_0_01011_000_00000u32.to_le_bytes(), "{ if (P3.new) jumpr:nt R1 }");
+ test_display(&0b0101_001_1011_00001_11_0_01011_000_00000u32.to_le_bytes(), "{ if (!P3.new) jumpr:nt R1 }");
+ test_invalid(&0b0101_001_1100_00001_11_0_00000_000_00000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b0101_010_0000_00000_11_0_01000_000_00010u32.to_le_bytes(), "{ trap0(#0x40) }");
+ test_display(&0b0101_010_0010_00010_11_0_01000_000_00010u32.to_le_bytes(), "{ pause(#0x240) }");
+ test_display(&0b0101_010_0100_00010_11_0_01000_000_00010u32.to_le_bytes(), "{ trap1(R2, #0x40) }");
+ test_invalid(&0b0101_010_0110_00010_11_0_01000_000_00010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_invalid(&0b0101_011_0101_00010_11_0_01000_000_00010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0101_011_0110_00010_11_0_00000_000_00000u32.to_le_bytes(), "{ icinva(R2) }");
+ test_display(&0b0101_011_1110_00000_11_0_00000_000_00010u32.to_le_bytes(), "{ isync }");
+ test_display(&0b0101_011_1111_00000_11_0_10000_000_00010u32.to_le_bytes(), "{ unpause }");
+
+ test_display(&0b0101_100_0000_00000_11_0_00000_000_00010u32.to_le_bytes(), "{ jump $+#4 }");
+ test_display(&0b0101_101_0000_00000_11_0_00000_000_00010u32.to_le_bytes(), "{ call $+#4 }");
+
+ test_display(&0b0101_110_0000_00000_11_0_00001_000_00010u32.to_le_bytes(), "{ if (P1) jump:nt $+#4 }");
+ test_display(&0b0101_110_0001_00000_11_0_01001_000_00010u32.to_le_bytes(), "{ if (!P1.new) jump:nt $+#4 }");
+ test_display(&0b0101_110_1001_00000_11_0_00001_000_00010u32.to_le_bytes(), "{ if (!P1) call $+#4 }");
+ test_invalid(&0b0101_110_1001_00000_11_0_01001_000_00010u32.to_le_bytes(), DecodeError::InvalidOpcode);
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 }");
@@ -205,5 +241,16 @@ fn general() {
test_display(&0b1011_1000001_00100_11_1_0_0000_001_10110u32.to_le_bytes(), "{ R22 = add(R4, #-31999) }");
+ test_display(&0b1111_1001000_00100_11_1_00011_001_00110u32.to_le_bytes(), "{ if (P1.new) R6 = and(R4, R3) }");
+ test_display(&0b1111_1001001_00100_11_1_00011_001_00110u32.to_le_bytes(), "{ if (P1.new) R6 = or(R4, R3) }");
+ test_invalid(&0b1111_1001010_00100_11_1_00011_001_00110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b1111_1001011_00100_11_1_00011_001_00110u32.to_le_bytes(), "{ if (P1.new) R6 = xor(R4, R3) }");
+
+ test_display(&0b1111_1011000_00100_11_1_00011_001_00110u32.to_le_bytes(), "{ if (P1.new) R6 = add(R4, R3) }");
+ test_display(&0b1111_1011001_00100_11_1_00011_001_00110u32.to_le_bytes(), "{ if (P1.new) R6 = sub(R4, R3) }");
+ test_invalid(&0b1111_1011101_00100_11_1_00011_001_00110u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b1111_1101000_00100_11_1_00011_001_00110u32.to_le_bytes(), "{ if (P1.new) R7:6 = contains(R4, R3) }");
+
// TODO: testcase for Rn=add(pc,#nn)
}