summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2024-10-05 11:15:05 -0700
committeriximeow <me@iximeow.net>2024-10-05 11:15:05 -0700
commitffa1378fa8fa5f5eab79c08c45c21efdd0154ed5 (patch)
tree3d8ed60169a09800677b169f89a49ff59a9c2ffb
parentb47c41140ad955ebeb3ce606944d36445b4c33a5 (diff)
broader support, maybe 1/8th through. also v73 manual does not list supervisor instructions...
-rw-r--r--notes/encoding_table6
-rw-r--r--notes/todo254
-rw-r--r--src/display.rs87
-rw-r--r--src/lib.rs546
-rw-r--r--tests/from_brain.rs69
5 files changed, 816 insertions, 146 deletions
diff --git a/notes/encoding_table b/notes/encoding_table
index 2431fc6..4da12fe 100644
--- a/notes/encoding_table
+++ b/notes/encoding_table
@@ -136,6 +136,12 @@ 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|1 0 1 1 0 0 0|1 - - 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 1 0 0|0 - - s s| P P |0 - - - - - - - -|- - - d d| Pd=any8(Ps) - CR/slot 3
|0 1 1 0|1 0 1 1 1 0 1|0 - - s s| P P |0 - - - - - - - -|- - - d d| Pd=all8(Ps) - CR/slot 3
+|0 1 1 0|1 1 0 0 0 0 0|s s s s s| P P |0 t t t t t - - -|- - - - -| tlbw(Rss,Rt) - SYSTEM/slot 3
+|0 1 1 0|1 1 0 0 0 1 0|s s s s s| P P |- - - - - - - - -|d d d d d| Rdd=tlbr(Rs) - SYSTEM/slot 3
+|0 1 1 0|1 1 0 0 1 0 0|s s s s s| P P |- - - - - - - - -|d d d d d| Rd=tlbp(Rs) - SYSTEM/slot 3
+|0 1 1 0|1 1 0 0 1 0 1|s s s s s| P P |- - - - - - - - -|- - - - -| tlbinvasid(Rs) - SYSTEM/slot 3
+|0 1 1 0|1 1 0 0 1 1 0|s s s s s| P P |0 t t t t t - - -|d d d d d| Rd=ctlbw(Rss,Rt) - SYSTEM/slot 3
+|0 1 1 0|1 1 0 0 1 1 1|s s s s s| P P |- - - - - - - - -|d d d d d| Rd=tlboc(Rss) - SYSTEM/slot 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|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
diff --git a/notes/todo b/notes/todo
index 21fdfd1..7f0591b 100644
--- a/notes/todo
+++ b/notes/todo
@@ -74,132 +74,132 @@ 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 0 1|0 1 0 1 0 1 i|i s s s s| P P |1 1 t t t t i i i|i i i i -| p1=cmp.gtu(Rs,Rt); if (!p1.new) jump:t #r9:2 - J/slot 0,1,2,3
|0 0 0 1|0 1 1 0 - - i|i d d d d| P P |l l l l l l i i i|i i i i -| Rd=#U6; jump #r9:2 - J/slot 2,3
|0 0 0 1|0 1 1 1 - - i|i s s s s| P P |- - d d d d i i i|i i i i -| Rd=Rs; jump #r9:2 - J/slot 2,3
-|0 0 1 0|0 0 0 0 0 0 i i - s s s| P P |0 t t t t t i i i|i i i i -| if(cmp.eq(Ns.new,Rt)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 0 0 0 i i - s s s| P P |1 t t t t t i i i|i i i i -| if(cmp.eq(Ns.new,Rt)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 0 0 1 i i - s s s| P P |0 t t t t t i i i|i i i i -| if(!cmp.eq(Ns.new,Rt)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 0 0 1 i i - s s s| P P |1 t t t t t i i i|i i i i -| if(!cmp.eq(Ns.new,Rt)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 0 1 0 i i - s s s| P P |0 t t t t t i i i|i i i i -| if(cmp.gt(Ns.new,Rt)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 0 1 0 i i - s s s| P P |1 t t t t t i i i|i i i i -| if(cmp.gt(Ns.new,Rt)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 0 1 1 i i - s s s| P P |0 t t t t t i i i|i i i i -| if(!cmp.gt(Ns.new,Rt)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 0 1 1 i i - s s s| P P |1 t t t t t i i i|i i i i -| if(!cmp.gt(Ns.new,Rt)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 1 0 0 i i - s s s| P P |0 t t t t t i i i|i i i i -| if(cmp.gtu(Ns.new,Rt)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 1 0 0 i i - s s s| P P |1 t t t t t i i i|i i i i -| if(cmp.gtu(Ns.new,Rt)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 1 0 1 i i - s s s| P P |0 t t t t t i i i|i i i i -| if(!cmp.gtu(Ns.new,Rt)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 1 0 1 i i - s s s| P P |1 t t t t t i i i|i i i i -| if(!cmp.gtu(Ns.new,Rt)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 1 1 0 i i - s s s| P P |0 t t t t t i i i|i i i i -| if(cmp.gt(Rt,Ns.new)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 1 1 0 i i - s s s| P P |1 t t t t t i i i|i i i i -| if(cmp.gt(Rt,Ns.new)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 1 1 1 i i - s s s| P P |0 t t t t t i i i|i i i i -| if(!cmp.gt(Rt,Ns.new)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 0 0 1 1 1 i i - s s s| P P |1 t t t t t i i i|i i i i -| if(!cmp.gt(Rt,Ns.new)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 0 1 0 0 0 i i - s s s| P P |0 t t t t t i i i|i i i i -| if(cmp.gtu(Rt,Ns.new)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 0 1 0 0 0 i i - s s s| P P |1 t t t t t i i i|i i i i -| if(cmp.gtu(Rt,Ns.new)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 0 1 0 0 1 i i - s s s| P P |0 t t t t t i i i|i i i i -| if(!cmp.gtu(Rt,Ns.new)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 0 1 0 0 1 i i - s s s| P P |1 t t t t t i i i|i i i i -| if(!cmp.gtu(Rt,Ns.new)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 0 0 0 i i - s s s| P P |0 l l l l l i i i|i i i i -| if (cmp.eq(Ns.new,#U5)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 0 0 0 i i - s s s| P P |1 l l l l l i i i|i i i i -| if (cmp.eq(Ns.new,#U5)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 0 0 1 i i - s s s| P P |0 l l l l l i i i|i i i i -| if (!cmp.eq(Ns.new,#U5)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 0 0 1 i i - s s s| P P |1 l l l l l i i i|i i i i -| if (!cmp.eq(Ns.new,#U5)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 0 1 0 i i - s s s| P P |0 l l l l l i i i|i i i i -| if (cmp.gt(Ns.new,#U5)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 0 1 0 i i - s s s| P P |1 l l l l l i i i|i i i i -| if (cmp.gt(Ns.new,#U5)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 0 1 1 i i - s s s| P P |0 l l l l l i i i|i i i i -| if (!cmp.gt(Ns.new,#U5)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 0 1 1 i i - s s s| P P |1 l l l l l i i i|i i i i -| if (!cmp.gt(Ns.new,#U5)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 1 0 0 i i - s s s| P P |0 l l l l l i i i|i i i i -| if (cmp.gtu(Ns.new,#U5)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 1 0 0 i i - s s s| P P |1 l l l l l i i i|i i i i -| if (cmp.gtu(Ns.new,#U5)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 1 0 1 i i - s s s| P P |0 l l l l l i i i|i i i i -| if (!cmp.gtu(Ns.new,#U5)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 1 0 1 i i - s s s| P P |1 l l l l l i i i|i i i i -| if (!cmp.gtu(Ns.new,#U5)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 1 1 0 i i - s s s| P P |0 - - - - - i i i|i i i i -| if (tstbit(Ns.new,#0)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 1 1 0 i i - s s s| P P |1 - - - - - i i i|i i i i -| if (tstbit(Ns.new,#0)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 1 1 1 i i - s s s| P P |0 - - - - - i i i|i i i i -| if (!tstbit(Ns.new,#0)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 1 0 1 1 1 i i - s s s| P P |1 - - - - - i i i|i i i i -| if (!tstbit(Ns.new,#0)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 1 1 0 0 0 i i - s s s| P P |0 - - - - - i i i|i i i i -| if (cmp.eq(Ns.new,#-1)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 1 1 0 0 0 i i - s s s| P P |1 - - - - - i i i|i i i i -| if (cmp.eq(Ns.new,#-1)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 1 1 0 0 1 i i - s s s| P P |0 - - - - - i i i|i i i i -| if (!cmp.eq(Ns.new,#-1)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 1 1 0 0 1 i i - s s s| P P |1 - - - - - i i i|i i i i -| if (!cmp.eq(Ns.new,#-1)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 1 1 0 1 0 i i - s s s| P P |0 - - - - - i i i|i i i i -| if (cmp.gt(Ns.new,#-1)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 1 1 0 1 0 i i - s s s| P P |1 - - - - - i i i|i i i i -| if (cmp.gt(Ns.new,#-1)) jump:t #r9:2 - NV/slot 0
-|0 0 1 0|0 1 1 0 1 1 i i - s s s| P P |0 - - - - - i i i|i i i i -| if (!cmp.gt(Ns.new,#-1)) jump:nt #r9:2 - NV/slot 0
-|0 0 1 0|0 1 1 0 1 1 i i - s s s| P P |1 - - - - - i i i|i i i i -| if (!cmp.gt(Ns.new,#-1)) jump:t #r9:2 - NV/slot 0
-|0 0 1 1|0 0 0 0 0 0 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (Pv) Rd=memb(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 0 0 0 0 1|s s s s s| P P |i t t t t t i v v|d d d d d| if (Pv) Rd=memub(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 0 0 0 1 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (Pv) Rd=memh(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 0 0 0 1 1|s s s s s| P P |i t t t t t i v v|d d d d d| if (Pv) Rd=memuh(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 0 0 1 0 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (Pv) Rd=memw(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 0 0 1 1 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (Pv) Rdd=memd(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 0 1 0 0 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (!Pv) Rd=memb(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 0 1 0 0 1|s s s s s| P P |i t t t t t i v v|d d d d d| if (!Pv) Rd=memub(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 0 1 0 1 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (!Pv) Rd=memh(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 0 1 0 1 1|s s s s s| P P |i t t t t t i v v|d d d d d| if (!Pv) Rd=memuh(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 0 1 1 0 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (!Pv) Rd=memw(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 0 1 1 1 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (!Pv) Rdd=memd(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 1 0 0 0 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (Pv.new) Rd=memb(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 1 0 0 0 1|s s s s s| P P |i t t t t t i v v|d d d d d| if (Pv.new) Rd=memub(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 1 0 0 1 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (Pv.new) Rd=memh(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 1 0 0 1 1|s s s s s| P P |i t t t t t i v v|d d d d d| if (Pv.new) Rd=memuh(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 1 0 1 0 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (Pv.new) Rd=memw(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 1 0 1 1 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (Pv.new) Rdd=memd(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 1 1 0 0 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (!Pv.new) Rd=memb(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 1 1 0 0 1|s s s s s| P P |i t t t t t i v v|d d d d d| if (!Pv.new) Rd=memub(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 1 1 0 1 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (!Pv.new) Rd=memh(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 1 1 0 1 1|s s s s s| P P |i t t t t t i v v|d d d d d| if (!Pv.new) Rd=memuh(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 1 1 1 0 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (!Pv.new) Rd=memw(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 0 1 1 1 1 0|s s s s s| P P |i t t t t t i v v|d d d d d| if (!Pv.new) Rdd=memd(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|0 1 0 0 0 0 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (Pv) memb(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|0 1 0 0 0 1 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (Pv) memh(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|0 1 0 0 0 1 1|s s s s s| P P |i u u u u u i v v|t t t t t| if (Pv) memh(Rs+Ru<<#u2)=Rt.H - ST/slot 0,1
-|0 0 1 1|0 1 0 0 1 0 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (Pv) memw(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|0 1 0 0 1 0 1|s s s s s| P P |i u u u u u i v v|0 0 t t t| if (Pv) memb(Rs+Ru<<#u2)=Nt.new - NV/slot 0
-|0 0 1 1|0 1 0 0 1 0 1|s s s s s| P P |i u u u u u i v v|0 1 t t t| if (Pv) memh(Rs+Ru<<#u2)=Nt.new - NV/slot 0
-|0 0 1 1|0 1 0 0 1 0 1|s s s s s| P P |i u u u u u i v v|1 0 t t t| if (Pv) memw(Rs+Ru<<#u2)=Nt.new - NV/slot 0
-|0 0 1 1|0 1 0 0 1 1 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (Pv) memd(Rs+Ru<<#u2)=Rtt - ST/slot 0,1
-|0 0 1 1|0 1 0 1 0 0 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (!Pv) memb(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|0 1 0 1 0 1 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (!Pv) memh(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|0 1 0 1 0 1 1|s s s s s| P P |i u u u u u i v v|t t t t t| if (!Pv) memh(Rs+Ru<<#u2)=Rt.H - ST/slot 0,1
-|0 0 1 1|0 1 0 1 1 0 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (!Pv) memw(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|0 1 0 1 1 0 1|s s s s s| P P |i u u u u u i v v|0 0 t t t| if (!Pv) memb(Rs+Ru<<#u2)=Nt.new - NV/slot 0
-|0 0 1 1|0 1 0 1 1 0 1|s s s s s| P P |i u u u u u i v v|0 1 t t t| if (!Pv) memh(Rs+Ru<<#u2)=Nt.new - NV/slot 0
-|0 0 1 1|0 1 0 1 1 0 1|s s s s s| P P |i u u u u u i v v|1 0 t t t| if (!Pv) memw(Rs+Ru<<#u2)=Nt.new - NV/slot 0
-|0 0 1 1|0 1 0 1 1 1 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (!Pv) memd(Rs+Ru<<#u2)=Rtt - ST/slot 0,1
-|0 0 1 1|0 1 1 0 0 0 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (Pv.new) memb(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|0 1 1 0 0 1 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (Pv.new) memh(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|0 1 1 0 0 1 1|s s s s s| P P |i u u u u u i v v|t t t t t| if (Pv.new) memh(Rs+Ru<<#u2)=Rt.H - ST/slot 0,1
-|0 0 1 1|0 1 1 0 1 0 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (Pv.new) memw(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|0 1 1 0 1 0 1|s s s s s| P P |i u u u u u i v v|0 0 t t t| if (Pv.new) memb(Rs+Ru<<#u2)=Nt.new - NV/slot 0
-|0 0 1 1|0 1 1 0 1 0 1|s s s s s| P P |i u u u u u i v v|0 1 t t t| if (Pv.new) memh(Rs+Ru<<#u2)=Nt.new - NV/slot 0
-|0 0 1 1|0 1 1 0 1 0 1|s s s s s| P P |i u u u u u i v v|1 0 t t t| if (Pv.new) memw(Rs+Ru<<#u2)=Nt.new - NV/slot 0
-|0 0 1 1|0 1 1 0 1 1 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (Pv.new) memd(Rs+Ru<<#u2)=Rtt - ST/slot 0,1
-|0 0 1 1|0 1 1 1 0 0 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (!Pv.new) memb(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|0 1 1 1 0 1 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (!Pv.new) memh(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|0 1 1 1 0 1 1|s s s s s| P P |i u u u u u i v v|t t t t t| if (!Pv.new) memh(Rs+Ru<<#u2)=Rt.H - ST/slot 0,1
-|0 0 1 1|0 1 1 1 1 0 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (!Pv.new) memw(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|0 1 1 1 1 0 1|s s s s s| P P |i u u u u u i v v|0 0 t t t| if (!Pv.new) memb(Rs+Ru<<#u2)=Nt.new - NV/slot 0
-|0 0 1 1|0 1 1 1 1 0 1|s s s s s| P P |i u u u u u i v v|0 1 t t t| if (!Pv.new) memh(Rs+Ru<<#u2)=Nt.new - NV/slot 0
-|0 0 1 1|0 1 1 1 1 0 1|s s s s s| P P |i u u u u u i v v|1 0 t t t| if (!Pv.new) memw(Rs+Ru<<#u2)=Nt.new - NV/slot 0
-|0 0 1 1|0 1 1 1 1 1 0|s s s s s| P P |i u u u u u i v v|t t t t t| if (!Pv.new) memd(Rs+Ru<<#u2)=Rtt - ST/slot 0,1
-|0 0 1 1|1 0 0 0 0 0 0|s s s s s| P P |l i i i i i i v v|l l l l l| if (Pv) memb(Rs+#u6:0)=#S6 - ST/slot 0,1
-|0 0 1 1|1 0 0 0 0 0 1|s s s s s| P P |l i i i i i i v v|l l l l l| if (Pv) memh(Rs+#u6:1)=#S6 - ST/slot 0,1
-|0 0 1 1|1 0 0 0 0 1 0|s s s s s| P P |l i i i i i i v v|l l l l l| if (Pv) memw(Rs+#u6:2)=#S6 - ST/slot 0,1
-|0 0 1 1|1 0 0 0 1 0 0|s s s s s| P P |l i i i i i i v v|l l l l l| if (!Pv) memb(Rs+#u6:0)=#S6 - ST/slot 0,1
-|0 0 1 1|1 0 0 0 1 0 1|s s s s s| P P |l i i i i i i v v|l l l l l| if (!Pv) memh(Rs+#u6:1)=#S6 - ST/slot 0,1
-|0 0 1 1|1 0 0 0 1 1 0|s s s s s| P P |l i i i i i i v v|l l l l l| if (!Pv) memw(Rs+#u6:2)=#S6 - ST/slot 0,1
-|0 0 1 1|1 0 0 1 0 0 0|s s s s s| P P |l i i i i i i v v|l l l l l| if (Pv.new) memb(Rs+#u6:0)=#S6 - ST/slot 0,1
-|0 0 1 1|1 0 0 1 0 0 1|s s s s s| P P |l i i i i i i v v|l l l l l| if (Pv.new) memh(Rs+#u6:1)=#S6 - ST/slot 0,1
-|0 0 1 1|1 0 0 1 0 1 0|s s s s s| P P |l i i i i i i v v|l l l l l| if (Pv.new) memw(Rs+#u6:2)=#S6 - ST/slot 0,1
-|0 0 1 1|1 0 0 1 1 0 0|s s s s s| P P |l i i i i i i v v|l l l l l| if (!Pv.new) memb(Rs+#u6:0)=#S6 - ST/slot 0,1
-|0 0 1 1|1 0 0 1 1 0 1|s s s s s| P P |l i i i i i i v v|l l l l l| if (!Pv.new) memh(Rs+#u6:1)=#S6 - ST/slot 0,1
-|0 0 1 1|1 0 0 1 1 1 0|s s s s s| P P |l i i i i i i v v|l l l l l| if (!Pv.new) memw(Rs+#u6:2)=#S6 - ST/slot 0,1
-|0 0 1 1|1 0 1 0 0 0 0|s s s s s| P P |i t t t t t i - -|d d d d d| Rd=memb(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|1 0 1 0 0 0 1|s s s s s| P P |i t t t t t i - -|d d d d d| Rdd=memub(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|1 0 1 0 0 1 0|s s s s s| P P |i t t t t t i - -|d d d d d| Rd=memh(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|1 0 1 0 0 1 1|s s s s s| P P |i t t t t t i - -|d d d d d| Rdd=memuh(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|1 0 1 0 1 0 0|s s s s s| P P |i t t t t t i - -|d d d d d| Rd=memw(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|1 0 1 0 1 1 0|s s s s s| P P |i t t t t t i - -|d d d d d| Rdd=memd(Rs+Rt<<#u2) - LD/slot 0,1
-|0 0 1 1|1 0 1 1 0 1 0|s s s s s| P P |i u u u u u i - -|t t t t t| memh(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|1 0 1 1 0 1 1|s s s s s| P P |i u u u u u i - -|t t t t t| memh(Rs+Ru<<#u2)=Rt.H - ST/slot 0,1
-|0 0 1 1|1 0 1 1 1 0 0|s s s s s| P P |i u u u u u i - -|t t t t t| memb(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|1 0 1 1 1 0 0|s s s s s| P P |i u u u u u i - -|t t t t t| memw(Rs+Ru<<#u2)=Rt - ST/slot 0,1
-|0 0 1 1|1 0 1 1 1 0 1|s s s s s| P P |i u u u u u i - -|0 0 t t t| memb(Rs+Ru<<#u2)=Nt.new - NV ST/slot 0
-|0 0 1 1|1 0 1 1 1 0 1|s s s s s| P P |i u u u u u i - -|0 1 t t t| memh(Rs+Ru<<#u2)=Nt.new - NV ST/slot 0
-|0 0 1 1|1 0 1 1 1 0 1|s s s s s| P P |i u u u u u i - -|1 0 t t t| memw(Rs+Ru<<#u2)=Nt.new - NV ST/slot 0
-|0 0 1 1|1 0 1 1 1 1 0|s s s s s| P P |i u u u u u i - -|t t t t t| memd(Rs+Ru<<#u2)=Rtt - ST/slot 0,1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|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
@@ -921,7 +921,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)
|1 0 1 0|1 1 1 1 1 1 0|- - - i i| P P |1 t t t t t 1 i i|i i 0 v v| if (Pv.new) memd(#u6)=Rtt - ST/slot 0,1
|1 0 1 0|1 1 1 1 1 1 0|- - - i i| P P |1 t t t t t 1 i i|i i 1 v v| if (!Pv.new) memd(#u6)=Rtt - ST/slot 0,1
|1 0 1 0|1 1 1 1 1 1 0|x x x x x| P P |u t t t t t 0 - -|- - - - -| memd(Rx++Mu:brev)=Rtt - ST/slot 0,1
-|1 0 1 1|i i i i i i i|s s s s s| P P |i i i i i i i i i|d d d d d| Rd=add(Rs,#s16) - ALU32/slots 0 1 2 3
+
|1 1 0 0|0 0 0 0|0 - -|s s s s s| P P |- t t t t t|i i i|d d d d d| Rdd=valignb(Rtt,Rss,#u3) - XTYPE PERM/slot 2,3
|1 1 0 0|0 0 0 0|1 - -|s s s s s| P P |- t t t t t|i i i|d d d d d| Rdd=vspliceb(Rss,Rtt,#u3) - XTYPE PERM/slot 2,3
|1 1 0 0|0 0 0 1|0 0 -|s s s s s| P P |- t t t t t|0 0 -|d d d d d| Rdd=extractu(Rss,Rtt) - XTYPE ALU/slot 2,3
diff --git a/src/display.rs b/src/display.rs
index 84bc06b..8970a50 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -43,6 +43,38 @@ impl fmt::Display for Instruction {
// | Rd = not(Rs) | Rd = sub(#-1,Rs) |
// | Rd = neg(Rs) | Rd = sub(#0,Rs) |
// | Rdd = Rss | Rdd = combine(Rss.H32, Rss.L32) |
+
+ // stores put the mnemonic on LHS
+ static STORES: &[Opcode] = &[
+ Opcode::StoreMemb, Opcode::StoreMemh, Opcode::StoreMemw, Opcode::StoreMemd
+ ];
+ if STORES.contains(&self.opcode) {
+ write!(f, "{}({}) = {}",
+ self.opcode, self.dest.expect("TODO: unreachable; store has a destination"),
+ self.sources[0]
+ )?;
+ return Ok(());
+ }
+
+ static 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.branch_hinted.unwrap() {
+ BranchHint::Taken => { "t" },
+ BranchHint::NotTaken => { "nt" },
+ };
+ write!(f, "if ({}({}, {})) jump:{} {}",
+ self.opcode.cmp_str().unwrap(), // TODO: unwrap_unchecked??
+ self.sources[0],
+ self.sources[1],
+ hint_label,
+ self.dest.unwrap(),
+ )?;
+ return Ok(());
+ }
if let Some(o) = self.dest.as_ref() {
write!(f, "{} = ", o)?;
}
@@ -77,12 +109,26 @@ impl fmt::Display for Opcode {
Opcode::BUG => { f.write_str("BUG") },
Opcode::Nop => { f.write_str("nop") },
Opcode::Jump => { f.write_str("jump") },
+ Opcode::Call => { f.write_str("call") },
Opcode::Memb => { f.write_str("memb") },
Opcode::Memub => { f.write_str("memub") },
Opcode::Memh => { f.write_str("memh") },
Opcode::Memuh => { f.write_str("memuh") },
Opcode::Memw => { f.write_str("memw") },
Opcode::Memd => { f.write_str("memd") },
+
+ Opcode::LoadMemb => { f.write_str("memb") },
+ Opcode::LoadMemub => { f.write_str("memub") },
+ Opcode::LoadMemh => { f.write_str("memh") },
+ Opcode::LoadMemuh => { f.write_str("memuh") },
+ Opcode::LoadMemw => { f.write_str("memw") },
+ Opcode::LoadMemd => { f.write_str("memd") },
+
+ Opcode::StoreMemb => { f.write_str("memb") },
+ Opcode::StoreMemh => { f.write_str("memh") },
+ Opcode::StoreMemw => { f.write_str("memw") },
+ Opcode::StoreMemd => { f.write_str("memd") },
+
Opcode::Membh => { f.write_str("membh") },
Opcode::MemhFifo => { f.write_str("memh_fifo") },
Opcode::Memubh => { f.write_str("memubh") },
@@ -105,6 +151,22 @@ impl fmt::Display for Opcode {
Opcode::And => { f.write_str("and") },
Opcode::Sub => { f.write_str("sub") },
Opcode::Or => { f.write_str("or") },
+
+ Opcode::JumpEq => { f.write_str("cmp.eq+jump") },
+ Opcode::JumpNeq => { f.write_str("cmp.neq+jump") },
+ Opcode::JumpGt => { f.write_str("cmp.gt+jump") },
+ Opcode::JumpLe => { f.write_str("cmp.le+jump") },
+ Opcode::JumpGtu => { f.write_str("cmp.gtu+jump") },
+ Opcode::JumpLeu => { f.write_str("cmp.leu+jump") },
+ Opcode::JumpBitSet => { f.write_str("tstbit+jump") },
+ Opcode::JumpBitClear => { f.write_str("!tstbit+jump") },
+
+ Opcode::Tlbw => { f.write_str("tlbw") },
+ Opcode::Tlbr => { f.write_str("tlbr") },
+ Opcode::Tlbp => { f.write_str("tlbp") },
+ Opcode::TlbInvAsid => { f.write_str("tlbinvasid") },
+ Opcode::Ctlbw => { f.write_str("ctlbw") },
+ Opcode::Tlboc => { f.write_str("tlboc") },
}
}
}
@@ -116,11 +178,20 @@ impl fmt::Display for Operand {
f.write_str("BUG (operand)")
}
Operand::PCRel32 { rel } => {
- f.write_str("idk!")
+ write!(f, "#{}", rel)
}
Operand::Gpr { reg } => {
write!(f, "R{}", reg)
}
+ Operand::Cr { reg } => {
+ write!(f, "C{}", reg)
+ }
+ Operand::Sr { reg } => {
+ write!(f, "S{}", reg)
+ }
+ Operand::GprNew { reg } => {
+ write!(f, "R{}.new", reg)
+ }
Operand::GprLow { reg } => {
write!(f, "R{}.L", reg)
}
@@ -130,6 +201,12 @@ impl fmt::Display for Operand {
Operand::Gpr64b { reg_low } => {
write!(f, "R{}:{}", reg_low + 1, reg_low)
}
+ Operand::Cr64b { reg_low } => {
+ write!(f, "C{}:{}", reg_low + 1, reg_low)
+ }
+ Operand::Sr64b { reg_low } => {
+ write!(f, "S{}:{}", reg_low + 1, reg_low)
+ }
Operand::PredicateReg { reg } => {
write!(f, "P{}", reg)
}
@@ -137,7 +214,7 @@ impl fmt::Display for Operand {
write!(f, "R{}+#{}", base, offset)
}
Operand::RegShiftedReg { base, index, shift } => {
- write!(f, "R{} + R{} << {}", base, index, shift)
+ write!(f, "R{} + R{}<<{}", base, index, shift)
}
Operand::ImmU8 { imm } => {
write!(f, "#0x{:x}", imm)
@@ -151,6 +228,12 @@ impl fmt::Display for Operand {
Operand::ImmI16 { imm } => {
write!(f, "#{:}", imm)
}
+ Operand::ImmI32 { imm } => {
+ write!(f, "#{:}", imm)
+ }
+ Operand::ImmU32 { imm } => {
+ write!(f, "#{:}", imm)
+ }
}
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 1a97e22..d8093ae 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -32,6 +32,12 @@ struct Predicate {
state: u8,
}
+#[derive(Debug, Copy, Clone)]
+enum BranchHint {
+ Taken,
+ NotTaken,
+}
+
macro_rules! opcode_check {
($e:expr) => {
if !$e {
@@ -192,6 +198,7 @@ pub struct Instruction {
dest: Option<Operand>,
predicate: Option<Predicate>,
negated: bool,
+ branch_hinted: Option<BranchHint>,
sources: [Operand; 3],
sources_count: u8,
}
@@ -246,13 +253,21 @@ pub enum Opcode {
// V73 page 214 ("Jump to address")
Jump,
+ Call,
+
+ LoadMemb,
+ LoadMemub,
+ LoadMemh,
+ LoadMemuh,
+ LoadMemw,
+ LoadMemd,
+
+ StoreMemb,
+ StoreMemh,
+ StoreMemw,
+ StoreMemd,
- Memb,
- Memub,
- Memh,
- Memuh,
- Memw,
- Memd,
+ Memb, Memub, Memh, Memuh, Memw, Memd,
Membh,
MemhFifo,
@@ -276,10 +291,42 @@ pub enum Opcode {
CmpGt,
CmpGtu,
+ JumpEq,
+ JumpNeq,
+ JumpGt,
+ JumpLe,
+ JumpGtu,
+ JumpLeu,
+ JumpBitSet,
+ JumpBitClear,
+
Add,
And,
Sub,
Or,
+
+ Tlbw,
+ Tlbr,
+ Tlbp,
+ TlbInvAsid,
+ Ctlbw,
+ Tlboc,
+}
+
+impl Opcode {
+ fn cmp_str(&self) -> Option<&'static str> {
+ match self {
+ Opcode::JumpEq => { Some("cmp.eq") },
+ Opcode::JumpNeq => { Some("!cmp.eq") },
+ Opcode::JumpGt => { Some("cmp.gt") },
+ Opcode::JumpLe => { Some("!cmp.gt") },
+ Opcode::JumpGtu => { Some("cmp.gtu") },
+ Opcode::JumpLeu => { Some("!cmp.gtu") },
+ Opcode::JumpBitSet => { Some("tstbit") },
+ Opcode::JumpBitClear => { Some("!tstbit") },
+ _ => None
+ }
+ }
}
/// TODO: don't know if this will be useful, but this is how V73 is described.. it also appears to
@@ -474,6 +521,7 @@ impl Default for Instruction {
dest: None,
predicate: None,
negated: false,
+ branch_hinted: None,
sources: [Operand::Nothing, Operand::Nothing, Operand::Nothing],
sources_count: 0,
}
@@ -510,17 +558,28 @@ pub enum Operand {
/// `Rn`, a 32-bit register `R<reg>`
Gpr { reg: u8 },
+ /// `Cn`, a 32-bit control register `C<reg>`
+ Cr { reg: u8 },
+ /// `Sn`, a 32-bit supervisor register `S<reg>`
+ Sr { reg: u8 },
+ /// `Rn.new`, the version of a 32-bit register `R<reg>` after being written in this instruction
+ /// packet.
+ GprNew { reg: u8 },
/// `Rn.L`, low 16 bits of `R<reg>`
GprLow { reg: u8 },
/// `Rn.H`, high 16 bits of `R<reg>`
GprHigh { reg: u8 },
/// `Rn:m`, register pair forming a 64-bit location
Gpr64b { 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
+ Sr64b { reg_low: u8 },
/// `Pn`, a predicate register
PredicateReg { reg: u8 },
- RegOffset { base: u8, offset: u32, },
+ RegOffset { base: u8, offset: u32 },
RegShiftedReg { base: u8, index: u8, shift: u8 },
@@ -531,6 +590,10 @@ pub enum Operand {
ImmI8 { imm: i8 },
ImmI16 { imm: i16 },
+
+ ImmI32 { imm: i32 },
+
+ ImmU32 { imm: u32 },
}
impl Operand {
@@ -538,8 +601,31 @@ impl Operand {
Self::Gpr { reg: num }
}
- fn gprpair(num: u8) -> Self {
- Self::Gpr64b { reg_low: num }
+ fn cr(num: u8) -> Self {
+ Self::Cr { reg: num }
+ }
+
+ fn sr(num: u8) -> Self {
+ Self::Sr { reg: num }
+ }
+
+ fn gpr_new(num: u8) -> Self {
+ Self::GprNew { reg: num }
+ }
+
+ fn gprpair(num: u8) -> Result<Self, yaxpeax_arch::StandardDecodeError> {
+ operand_check!(num & 1 == 0);
+ Ok(Self::Gpr64b { reg_low: num })
+ }
+
+ fn crpair(num: u8) -> Result<Self, yaxpeax_arch::StandardDecodeError> {
+ operand_check!(num & 1 == 0);
+ Ok(Self::Cr64b { reg_low: num })
+ }
+
+ fn srpair(num: u8) -> Result<Self, yaxpeax_arch::StandardDecodeError> {
+ operand_check!(num & 1 == 0);
+ Ok(Self::Sr64b { reg_low: num })
}
fn pred(num: u8) -> Self {
@@ -561,6 +647,14 @@ impl Operand {
fn imm_u16(num: u16) -> Self {
Self::ImmU16 { imm: num }
}
+
+ fn imm_i32(num: i32) -> Self {
+ Self::ImmI32 { imm: num }
+ }
+
+ fn imm_u32(num: u32) -> Self {
+ Self::ImmU32 { imm: num }
+ }
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -649,6 +743,7 @@ 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 branch_hint(&mut self, hint_taken: bool) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) }
fn on_word_read(&mut self, _word: <Hexagon as Arch>::Word) {}
}
@@ -689,6 +784,16 @@ impl<T: yaxpeax_arch::Reader<<Hexagon as Arch>::Address, <Hexagon as Arch>::Word
inst.negated = 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());
+ if hint_taken {
+ inst.branch_hinted = Some(BranchHint::Taken);
+ } else {
+ inst.branch_hinted = Some(BranchHint::NotTaken);
+ }
+ Ok(())
+ }
#[inline(always)]
fn read_inst_word(&mut self, words: &mut T) -> Result<u32, <Hexagon as Arch>::DecodeError> {
self.word_count += 1;
@@ -818,6 +923,7 @@ fn decode_instruction<
>(decoder: &<Hexagon as Arch>::Decoder, handler: &mut H, inst: u32, extender: Option<u32>) -> Result<(), <Hexagon as Arch>::DecodeError> {
let iclass = (inst >> 28) & 0b1111;
+ use Opcode::*;
// V73 Section 10.9
// > A constant extender must be positioned in a packet immediately before the
@@ -836,11 +942,84 @@ fn decode_instruction<
let min_op = (inst >> 21) & 0b111;
match iclass {
+ 0b0010 => {
+ if (inst >> 27) & 1 == 1 {
+ // everything at
+ // 0010 |1xxxxxxx.. is an undefined encoding
+ return Err(DecodeError::InvalidOpcode);
+ }
+
+ let hint_taken = (inst >> 13) & 1 == 1;
+ let op = (inst >> 22) & 0b11111;
+
+ let r_lo = (inst >> 1) & 0b111_1111;
+ let r_hi = (inst >> 20) & 0b11;
+ let r = (((r_hi << 7) | r_lo) << 2) as i16;
+ let r = r << 5 >> 5;
+
+ let sss = ((inst >> 16) & 0b111) as u8;
+
+ handler.on_dest_decoded(Operand::PCRel32 {
+ rel: r as i32
+ })?;
+
+ handler.branch_hint(hint_taken)?;
+
+ if op < 0b10000 {
+ // these are `if([!]cmp.op(Ns.new,Rt)) jump:[n]t #r9:2`
+ let ttttt = reg_b8(inst);
+
+ if op < 0b0110 {
+ handler.on_source_decoded(Operand::GprNew { reg: sss })?;
+ handler.on_source_decoded(Operand::gpr(ttttt))?;
+ } else {
+ handler.on_source_decoded(Operand::gpr(ttttt))?;
+ handler.on_source_decoded(Operand::GprNew { reg: sss })?;
+ }
+
+ static OPS: [Option<Opcode>; 16] = [
+ Some(JumpEq), Some(JumpNeq), Some(JumpGt), Some(JumpLe),
+ Some(JumpGtu), Some(JumpLeu), Some(JumpGt), Some(JumpLe),
+ Some(JumpGtu), Some(JumpLeu), None, None,
+ None, None, None, None,
+ ];
+
+ handler.on_opcode_decoded(decode_opcode!(OPS[op as usize]))?;
+ } else {
+ handler.on_source_decoded(Operand::GprNew { reg: sss })?;
+
+ if op < 0b10110 {
+ let lllll = reg_b8(inst);
+ static OPS: &[Opcode; 6] = &[
+ JumpEq, JumpNeq, JumpGt, JumpLe,
+ JumpGtu, JumpLeu
+ ];
+ handler.on_source_decoded(Operand::imm_u32(lllll as u8 as u32))?;
+ handler.on_opcode_decoded(OPS[op as usize - 0b10000])?;
+ } else if op < 0b11000 {
+ let opc = if op == 0b10110 {
+ JumpBitSet
+ } else {
+ JumpBitClear
+ };
+ handler.on_source_decoded(Operand::imm_u32(0))?;
+ handler.on_opcode_decoded(opc)?;
+ } else if op < 0b11100 {
+ static OPS: &[Opcode; 4] = &[
+ JumpEq, JumpNeq, JumpGt, JumpLe,
+ ];
+ handler.on_source_decoded(Operand::imm_i32(-1))?;
+ handler.on_opcode_decoded(OPS[op as usize - 0b11000])?;
+ } else {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
0b0011 => {
let upper = reg_type >> 2;
match upper {
0b00 => {
- // 00011 | 00xxxxxxx
+ // 0011 | 00xxxxxxx
// everything under this is a predicated load
let nn = (inst >> 24) & 0b11;
@@ -857,17 +1036,184 @@ fn decode_instruction<
let op = (inst >> 21) & 0b111;
handler.inst_predicated(vv, negated, pred_new)?;
+
handler.on_source_decoded(Operand::RegShiftedReg { base: sssss, index: ttttt, shift: ii })?;
- handler.on_dest_decoded(Operand::Gpr { reg: ddddd })?;
+ if op == 0b110 {
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
+ } else {
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ }
use Opcode::*;
static OPCODES: [Option<Opcode>; 8] = [
- Some(Memb), Some(Memub), Some(Memh), Some(Memuh),
- Some(Memw), None, Some(Memd), None,
+ Some(LoadMemb), Some(LoadMemub), Some(LoadMemh), Some(LoadMemuh),
+ Some(LoadMemw), None, Some(LoadMemd), None,
];
handler.on_opcode_decoded(OPCODES[op as usize].ok_or(DecodeError::InvalidOpcode)?)?;
}
+ 0b01 => {
+ // 00011 | 01xxxxxxx
+ // everything under this is a predicated store
+ let nn = (inst >> 24) & 0b11;
+
+ let negated = nn & 1 == 1;
+ let pred_new = nn >> 1 == 1;
+
+ let ttttt = reg_b0(inst);
+ let vv = ((inst >> 5) & 0b11) as u8;
+ let i_lo = (inst >> 7) & 0b1;
+ let uuuuu = reg_b8(inst);
+ let i_hi = ((inst >> 13) & 0b1) << 1;
+ let ii = (i_lo | i_hi) as u8;
+ let sssss = reg_b16(inst);
+ let op = (inst >> 21) & 0b111;
+
+ handler.inst_predicated(vv, negated, pred_new)?;
+ handler.on_dest_decoded(Operand::RegShiftedReg { base: sssss, index: uuuuu, shift: ii })?;
+
+ if op == 0b101 {
+ // more complicated procedure, and registers are `Nt.new`
+ let op = (inst >> 3) & 0b11;
+ let ttt = inst & 0b111;
+ static OPCODES: [Option<Opcode>; 4] = [
+ Some(StoreMemb), Some(StoreMemh),
+ Some(StoreMemw), None,
+ ];
+ handler.on_opcode_decoded(decode_opcode!(OPCODES[op as usize]))?;
+ handler.on_source_decoded(Operand::gpr_new(ttt as u8))?;
+ } else {
+ static OPCODES: [Option<Opcode>; 8] = [
+ Some(StoreMemb), None, Some(StoreMemh), Some(StoreMemh),
+ Some(StoreMemw), None, Some(StoreMemd), None,
+ ];
+ handler.on_opcode_decoded(decode_opcode!(OPCODES[op as usize]))?;
+ if op == 0b011 {
+ handler.on_source_decoded(Operand::GprHigh { reg: ttttt })?;
+ } else if op == 0b110 {
+ handler.on_source_decoded(Operand::gpr(ttttt))?;
+ } else {
+ handler.on_source_decoded(Operand::gprpair(ttttt)?)?;
+ }
+ }
+ }
+ 0b10 => {
+ // 00011 | 10xxxxxxx
+ // some predicated stores, but also some predicated loads
+ let sssss = reg_b16(inst);
+
+ let predicate_store = (inst >> 25) & 0b1 == 0;
+ if predicate_store {
+ let nn = (inst >> 23) & 0b11;
+
+ let negated = nn & 1 == 1;
+ let pred_new = nn >> 1 == 1;
+
+ let l_lo = reg_b0(inst);
+ let vv = ((inst >> 5) & 0b11) as u8;
+ let iiiiii = (inst >> 7) & 0b11_1111;
+ let l_hi = (((inst >> 13) & 0b1) << 5) as u8;
+ let llllll = (l_lo | l_hi) as u8;
+ let op = (inst >> 21) & 0b11;
+
+ let negated = nn & 1 == 1;
+ let pred_new = nn >> 1 == 1;
+
+ handler.inst_predicated(vv, negated, pred_new)?;
+
+ match op {
+ 0b00 => {
+ handler.on_opcode_decoded(Opcode::StoreMemb)?;
+ let offset = iiiiii;
+ let imm = (llllll as i8) << 2 >> 2;
+ handler.on_dest_decoded(Operand::RegOffset { base: sssss, offset })?;
+ handler.on_source_decoded(Operand::imm_i8(imm))?;
+ }
+ 0b01 => {
+ handler.on_opcode_decoded(Opcode::StoreMemh)?;
+ let offset = iiiiii << 1;
+ let imm = (llllll as i16) << 10 >> 10;
+ handler.on_dest_decoded(Operand::RegOffset { base: sssss, offset })?;
+ handler.on_source_decoded(Operand::imm_i16(imm))?;
+ }
+ 0b10 => {
+ handler.on_opcode_decoded(Opcode::StoreMemw)?;
+ let offset = iiiiii << 2;
+ let imm = (llllll as i32) << 26 >> 26;
+ handler.on_dest_decoded(Operand::RegOffset { base: sssss, offset })?;
+ handler.on_source_decoded(Operand::imm_i32(imm))?;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ } else {
+ // op determined by min_op
+ let store = (inst >> 24) & 1 == 1;
+
+ let reg_low = reg_b0(inst);
+ let reg_mid = reg_b8(inst);
+ let sssss = reg_b16(inst);
+
+ let i_lo = ((inst >> 7) & 1) as u8;
+ let i_hi = (((inst >> 13) & 0b1) << 1) as u8;
+ let ii = i_hi | i_lo;
+
+ if store {
+ // StoreMem*
+ handler.on_dest_decoded(Operand::RegShiftedReg { base: sssss, index: reg_mid, shift: ii })?;
+ match min_op {
+ 0b010 => {
+ handler.on_opcode_decoded(Opcode::StoreMemh)?;
+ handler.on_source_decoded(Operand::gpr(reg_low))?;
+ },
+ 0b011 => {
+ handler.on_opcode_decoded(Opcode::StoreMemh)?;
+ handler.on_source_decoded(Operand::GprHigh { reg: reg_low})?;
+ },
+ 0b100 => {
+ handler.on_opcode_decoded(Opcode::StoreMemb)?;
+ handler.on_source_decoded(Operand::gprpair(reg_low)?)?;
+ }
+ 0b101 => {
+ // more complicated procedure, and registers are `Nt.new`
+ let op = (inst >> 3) & 0b11;
+ let ttt = inst & 0b111;
+ static OPCODES: [Option<Opcode>; 4] = [
+ Some(StoreMemb), Some(StoreMemh),
+ Some(StoreMemw), None,
+ ];
+ handler.on_opcode_decoded(decode_opcode!(OPCODES[op as usize]))?;
+ handler.on_source_decoded(Operand::gpr_new(ttt as u8))?;
+ },
+ 0b0110 => {
+ handler.on_opcode_decoded(Opcode::StoreMemd)?;
+ handler.on_source_decoded(Operand::gprpair(reg_low)?)?;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ } else {
+ // LoadMem*
+ static OPCODES: [Option<Opcode>; 8] = [
+ Some(LoadMemb), Some(LoadMemub), Some(LoadMemh), Some(LoadMemh),
+ Some(LoadMemw), None, Some(LoadMemd), None,
+ ];
+
+ handler.on_opcode_decoded(decode_opcode!(OPCODES[min_op as usize]))?;
+ handler.on_source_decoded(Operand::RegShiftedReg { base: sssss, index: reg_mid, shift: ii })?;
+ if min_op == 0b001 || min_op == 0b011 || min_op == 0b110 {
+ handler.on_dest_decoded(Operand::gprpair(reg_low)?)?;
+ } else {
+ handler.on_dest_decoded(Operand::gpr(reg_low))?;
+ }
+ }
+ }
+ }
other => {
+ // 0b11, so bits are like 0011|11xxxx
+ // these are all stores to Rs+#u6:N, shift is determined by op size.
+ // the first few are stores of immediates, most others operate on registers.
panic!("TODO: other: {}", other);
}
}
@@ -875,6 +1221,16 @@ fn decode_instruction<
0b0101 => {
let majop = (inst >> 25) & 0b111;
match majop {
+ 0b000 => {
+ // 0 1 0 1 | 0 0 0 ...
+ // call to register, may be predicated
+ panic!("TODO");
+ },
+ 0b000 => {
+ // 0 1 0 1 | 0 0 1 ...
+ // jump to register, may be predicated
+ panic!("TODO");
+ },
0b100 => {
// V73 Jump to address
// 0 1 0 1 | 1 0 0 i...
@@ -883,11 +1239,153 @@ fn decode_instruction<
let imm = ((imm as i32) << 10) >> 10;
handler.on_source_decoded(Operand::PCRel32 { rel: imm & !0b11 })?;
},
+ 0b101 => {
+ // V73 Call to address
+ // 0 1 0 1 | 1 0 1 i...
+ if inst & 0 != 0 {
+ // unlike jump, for some reason, the last bit is defined to be 0
+ return Err(DecodeError::InvalidOpcode);
+ }
+ handler.on_opcode_decoded(Opcode::Call)?;
+ let imm = ((inst >> 1) & 0x7fff) | ((inst >> 3) & 0xff8000);
+ let imm = ((imm as i32) << 10) >> 10;
+ handler.on_source_decoded(Operand::PCRel32 { rel: imm & !0b11 })?;
+ },
_ => {
// TODO: exhaustive
}
}
},
+ 0b0110 => {
+ let opbits = (inst >> 21) & 0b1111111;
+
+ match opbits {
+ 0b0010001 => {
+ let sssss = reg_b16(inst);
+ let ddddd = reg_b0(inst);
+ handler.on_opcode_decoded(Opcode::TransferRegister)?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ handler.on_dest_decoded(Operand::cr(ddddd))?;
+ }
+ 0b0111000 => {
+ // not in V73! store to supervisor register?
+ let sssss = reg_b16(inst);
+ let ddddddd = inst & 0b111_1111;
+ handler.on_opcode_decoded(Opcode::TransferRegister)?;
+ handler.on_dest_decoded(Operand::sr(ddddddd as u8))?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ }
+ 0b1101000 => {
+ // not in V73! store to supervisor register?
+ let sssss = reg_b16(inst);
+ let ddddddd = inst & 0b111_1111;
+ handler.on_opcode_decoded(Opcode::TransferRegister)?;
+ handler.on_dest_decoded(Operand::srpair(ddddddd as u8)?)?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ }
+ 0b1110100 | 0b1110101 |
+ 0b1110110 | 0b1110111 => {
+ // not in V73! load supervisor register?
+ let sssss = reg_b0(inst);
+ let ddddddd = (inst >> 16) & 0b111_1111;
+ handler.on_opcode_decoded(Opcode::TransferRegister)?;
+ handler.on_source_decoded(Operand::sr(ddddddd as u8))?;
+ handler.on_dest_decoded(Operand::gpr(sssss))?;
+ }
+ 0b1111000 | 0b1111001 |
+ 0b1111010 | 0b1111011 => {
+ // not in V73! load supervisor register?
+ let sssss = reg_b0(inst);
+ let ddddddd = (inst >> 16) & 0b111_1111;
+ handler.on_opcode_decoded(Opcode::TransferRegister)?;
+ handler.on_source_decoded(Operand::srpair(ddddddd as u8)?)?;
+ handler.on_dest_decoded(Operand::gprpair(sssss)?)?;
+ }
+ 0b0011001 => {
+ let sssss = reg_b16(inst);
+ let ddddd = reg_b0(inst);
+ handler.on_opcode_decoded(Opcode::TransferRegister)?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.on_dest_decoded(Operand::crpair(ddddd)?)?;
+ }
+ 0b1000000 => {
+ 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)?)?;
+ }
+ 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))?;
+ }
+ 0b1010010 => {
+ if (inst >> 16) & 0b11111 != 0b01001 {
+ // TODO: this is checking for register number 9 aka PC.
+ // if other register numbers are specified here, can you add from other
+ // control registers into a GPR?
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ let iiiiii = (inst >> 7) & 0b111111;
+ let ddddd = reg_b0(inst);
+ handler.on_opcode_decoded(Opcode::Add)?;
+ handler.on_source_decoded(Operand::cr(9))?;
+ handler.on_source_decoded(Operand::imm_u8(iiiiii as u8))?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ }
+ 0b1100000 => {
+ opcode_check!(inst & 0x2000 == 0);
+ let sssss = reg_b16(inst);
+ let ttttt = reg_b8(inst);
+ handler.on_opcode_decoded(Opcode::Tlbw)?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.on_source_decoded(Operand::gpr(ttttt))?;
+ }
+ 0b1100010 => {
+ let sssss = reg_b16(inst);
+ let ddddd = reg_b0(inst);
+ handler.on_opcode_decoded(Opcode::Tlbr)?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
+ }
+ 0b1100100 => {
+ let sssss = reg_b16(inst);
+ let ddddd = reg_b0(inst);
+ handler.on_opcode_decoded(Opcode::Tlbp)?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ }
+ 0b1100101 => {
+ let sssss = reg_b16(inst);
+ handler.on_opcode_decoded(Opcode::TlbInvAsid)?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ }
+ 0b1100110 => {
+ opcode_check!(inst & 0x2000 == 0);
+ let sssss = reg_b16(inst);
+ let ttttt = reg_b8(inst);
+ let ddddd = reg_b0(inst);
+ handler.on_opcode_decoded(Opcode::Ctlbw)?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.on_source_decoded(Operand::gpr(ttttt))?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ }
+ 0b1100111 => {
+ let sssss = reg_b16(inst);
+ let ddddd = reg_b0(inst);
+ handler.on_opcode_decoded(Opcode::Tlboc)?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ }
+ _ => {
+ eprintln!("!!! TODO: {:07b} !!!", opbits);
+ }
+ }
+ }
0b0111 => {
match reg_type {
0b0000 => {
@@ -960,8 +1458,7 @@ fn decode_instruction<
let ddddd = reg_b0(inst);
let op = if min_op & 0b010 == 0 {
- operand_check!(ddddd & 1 == 0);
- handler.on_dest_decoded(Operand::gprpair(ddddd))?;
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
Opcode::Combine
} else {
handler.on_dest_decoded(Operand::gpr(ddddd))?;
@@ -1120,7 +1617,7 @@ fn decode_instruction<
let l = l_lo | (l_hi << 1);
handler.on_opcode_decoded(Opcode::Combine)?;
- handler.on_dest_decoded(Operand::gprpair(ddddd))?;
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
handler.on_source_decoded(Operand::imm_i8(i))?;
if min_op & 0b100 == 0 {
handler.on_source_decoded(Operand::imm_i8(l))?;
@@ -1195,6 +1692,23 @@ fn decode_instruction<
];
handler.on_opcode_decoded(OPCODES[op as usize].ok_or(DecodeError::InvalidOpcode)?)?;
}
+ 0b1010 => {
+ eprintln!("TODO: 1010");
+ }
+ 0b1011 => {
+ handler.on_opcode_decoded(Opcode::Add)?;
+
+ let ddddd = reg_b0(inst);
+ let sssss = reg_b16(inst);
+
+ let i_hi = (inst >> 21) & 0b111_1111;
+ let i_lo = (inst >> 5) & 0b1_1111_1111;
+ let i = (i_hi << 9) | i_lo;
+
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ handler.on_source_decoded(Operand::imm_i16(i as i16))?;
+ }
_ => {
eprintln!("iclass: {:04b}", iclass);
// TODO: exhaustive
diff --git a/tests/from_brain.rs b/tests/from_brain.rs
index 4c9dad9..3e9bb16 100644
--- a/tests/from_brain.rs
+++ b/tests/from_brain.rs
@@ -11,6 +11,7 @@ fn test_display(bytes: &[u8], text: &str) {
assert_eq!(rendered, text);
}
+#[track_caller]
fn test_invalid(bytes: &[u8], expected: DecodeError) {
let decoder = yaxpeax_hexagon::InstDecoder::default();
let err = decoder.decode(&mut yaxpeax_arch::U8Reader::new(bytes)).unwrap_err();
@@ -18,7 +19,26 @@ fn test_invalid(bytes: &[u8], expected: DecodeError) {
}
#[test]
-fn alu32() {
+fn supervisor() {
+ test_display(&0b0110_0111000_00010_11_0011010_0000110u32.to_le_bytes(), "{ S6 = R2 }");
+ test_display(&0b0110_1101000_00010_11_0011010_0000110u32.to_le_bytes(), "{ S7:6 = R3:2 }");
+
+ test_display(&0b0110_11101_0100010_11_000000000_00110u32.to_le_bytes(), "{ R6 = S34 }");
+ test_display(&0b0110_11110_0100010_11_000000000_00110u32.to_le_bytes(), "{ R7:6 = S35:34 }");
+
+ test_display(&0b0110_1100000_00010_11_0_01101_00000000u32.to_le_bytes(), "{ tlbw(R3:2, R13) }");
+ test_invalid(&0b0110_1100000_00010_11_1_01101_00000000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0110_1100010_00010_11_0_00000000_01000u32.to_le_bytes(), "{ R9:8 = tlbr(R2) }");
+ test_display(&0b0110_1100100_00010_11_0_00000000_01000u32.to_le_bytes(), "{ R8 = tlbp(R2) }");
+
+ test_display(&0b0110_1100101_00010_11_0_00000000_01000u32.to_le_bytes(), "{ tlbinvasid(R2) }");
+ test_display(&0b0110_1100110_00010_11_0_01001000_01000u32.to_le_bytes(), "{ R8 = ctlbw(R3:2, R9) }");
+ test_invalid(&0b0110_1100110_00010_11_1_00000000_01000u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_display(&0b0110_1100111_00010_11_0_00000000_01000u32.to_le_bytes(), "{ R8 = tlboc(R3:2) }");
+}
+
+#[test]
+fn general() {
test_invalid(&0b0111_0000010_00000_11_0_0_0000_000_00000u32.to_le_bytes(), DecodeError::InvalidOpcode);
test_display(&0b0111_0000000_00011_11_1_0_1101_000_00100u32.to_le_bytes(), "{ if (!P1.new) R4 = aslh(R3) }");
@@ -63,4 +83,51 @@ fn alu32() {
test_display(&0b0111_1110010_00100_11_0_0_0000_111_10000u32.to_le_bytes(), "{ if (P2) R16 = #1031 }");
test_display(&0b0111_1110110_00100_11_1_0_0000_111_10000u32.to_le_bytes(), "{ if (!P2.new) R16 = #1031 }");
+
+ test_display(&0b0011_0010110_00100_11_1_0_0010_101_10000u32.to_le_bytes(), "{ if (P1.new) R17:16 = memd(R4 + R2<<3) }");
+ test_display(&0b0011_0010110_00100_11_1_0_0010_101_10000u32.to_le_bytes(), "{ if (P1.new) R17:16 = memd(R4 + R2<<3) }");
+
+ test_display(&0b0011_0101011_00100_11_1_0_0010_101_10000u32.to_le_bytes(), "{ if (!P1) memh(R4 + R2<<3) = R16.H }");
+ test_display(&0b0011_0101101_00100_11_1_0_0010_101_10010u32.to_le_bytes(), "{ if (!P1) memw(R4 + R2<<3) = R2.new }");
+
+ test_display(&0b0011_0101101_00100_11_1_0_0010_101_10010u32.to_le_bytes(), "{ if (!P1) memw(R4 + R2<<3) = R2.new }");
+
+ test_invalid(&0b0011_0101111_00100_11_1_0_0010_101_10010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_invalid(&0b0011_0110001_00100_11_1_0_0010_101_10010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_invalid(&0b0011_0110111_00100_11_1_0_0010_101_10010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_invalid(&0b0011_0111001_00100_11_1_0_0010_101_10010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+ test_invalid(&0b0011_0111111_00100_11_1_0_0010_101_10010u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b0011_1000000_00100_11_1_0_0010_101_11111u32.to_le_bytes(), "{ if (P1) memb(R4+#5) = #-1 }");
+ test_display(&0b0011_1000100_00100_11_1_0_0010_101_11111u32.to_le_bytes(), "{ if (!P1) memb(R4+#5) = #-1 }");
+ test_invalid(&0b0011_1000111_00100_11_1_0_0010_101_11111u32.to_le_bytes(), DecodeError::InvalidOpcode);
+
+ test_display(&0b0011_1010000_00100_11_1_0_0010_100_11111u32.to_le_bytes(), "{ R31 = memb(R4 + R2<<3) }");
+ test_display(&0b0011_1010001_00100_11_1_0_0010_100_11110u32.to_le_bytes(), "{ R31:30 = memub(R4 + R2<<3) }");
+
+ 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(&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(&0b1011_1000001_00100_11_1_0_0000_001_10110u32.to_le_bytes(), "{ R22 = add(R4, #-31999) }");
+
+ // TODO: testcase for Rn=add(pc,#nn)
}