#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"
u32int r[16];
u32int curpc;
u32int ps;
int trace;
enum {
ADD,
SUB,
MUL,
DIV,
CMP,
TST,
BIC,
BIS,
XOR,
BIT,
};
#define fetch8() memread8(r[15]++)
static u16int
fetch16(void)
{
u16int v;
v = memread16(r[15]);
r[15] += 2;
return v;
}
static u32int
fetch32(void)
{
u32int v;
v = memread32(r[15]);
r[15] += 4;
return v;
}
static u32int
sxt(u32int v, int s)
{
switch(s){
case 0: return (s8int) v;
case 1: return (s16int) v;
default: return v;
}
}
static void
nz(u32int v, int s)
{
int i;
i = sxt(v, s);
ps &= ~(FLAGN|FLAGZ);
if(i == 0) ps |= FLAGZ;
if(i < 0) ps |= FLAGN;
}
static void
nz64(u64int v, int s)
{
if(s < 3)
nz(v, s);
else{
if(v == 0) ps |= FLAGZ;
else if((s64int)v < 0) ps |= FLAGN;
}
}
static void
nzv(u32int v, int s)
{
nz(v, s);
ps &= ~FLAGV;
}
u32int
addrof(vlong v)
{
if(v < 0) sysfatal("addr of register or literal (pc=%.8ux)", curpc);
return v;
}
vlong
amode(int s)
{
u8int c;
u32int v;
s &= 0xf;
c = fetch8();
switch(c >> 4){
case 0: case 1: case 2: case 3: return ~(vlong)(64 | c & 63);
case 4: v = addrof(amode(s)); v += r[c & 15] << s; return v;
case 5: return ~(vlong)(c & 15);
case 6: return r[c & 15];
case 7: return r[c & 15] -= 1<<s;
case 8: v = r[c & 15]; r[c & 15] += 1<<s; return v;
case 9: v = r[c & 15]; r[c & 15] += 4; return memread32(v);
case 10: v = fetch8(); return (u32int)(r[c & 15] + (s8int) v);
case 11: v = fetch8(); return memread32(r[c & 15] + (s8int) v);
case 12: v = fetch16(); return (u32int)(r[c & 15] + (s16int) v);
case 13: v = fetch16(); return memread32(r[c & 15] + (s16int) v);
case 14: v = fetch32(); return (u32int)(r[c & 15] + v);
case 15: v = fetch32(); return memread32(r[c & 15] + v);
default: sysfatal("unimplemented addressing mode %.2x", c); return -1;
}
}
u32int
readm(vlong a, int s)
{
vlong v;
if(a < 0){
if(a <= ~64LL){
if(s >= 0x10)
return (~a & 63) << 4 | 0x4000;
return ~a & 63;
}
assert(a >= ~15LL);
v = r[~a];
switch(s & 0xf){
case 0: return (uchar) v;
case 1: return (ushort) v;
case 2: return v;
}
}
switch(s & 0xf){
case 0: return memread8(a);
case 1: return memread16(a);
case 2: return memread32(a);
default: sysfatal("readm: unimplemented size %d (a=%.llx, pc=%.8x)", s, a, curpc); return -1;
}
}
static vlong
highw(vlong v)
{
if(v >= 0)
return (u32int)(v + 4);
if(v <= ~64LL)
return ~64LL;
return v - 1 | ~15LL;
}
u64int
readm64(vlong a, int s)
{
u64int v;
if((s & 0xf) == 3){
v = readm(a, s - 1);
if(a > ~64LL)
v |= (u64int)readm(highw(a), 2) << 32;
return v;
}
return readm(a, s);
}
void
writem(vlong a, u32int v, int s)
{
int n;
assert(a >= ~15LL);
s &= 0xf;
if(a < 0){
switch(s){
case 0: r[~a] = r[~a] & ~0xff | v & 0xff; break;
case 1: r[~a] = r[~a] & ~0xffff | v & 0xffff; break;
case 2: r[~a] = v; break;
default: sysfatal("writem: unimplemented size %d", s);
}
return;
}
switch(s){
case 0:
n = (a & 3) << 3;
memwrite(a & -4, v << n, 0xff << n);
break;
case 1:
n = (a & 3) << 3;
memwrite(a & -4, v << n, 0xffff << n);
if(n == 24) memwrite(-(-a & -4), v >> 8, 0xff);
break;
case 2:
n = (a & 3) << 3;
memwrite(a & -4, v << n, -1 << n);
if(n != 0) memwrite(-(-a & -4), v >> 32 - n, (u32int)-1 >> 32 - n);
break;
default: sysfatal("writem: unimplemented size %d", s);
}
}
void
writem64(vlong a, u64int v, int s)
{
if((s & 0xf) == 3){
writem(a, v, 2);
writem(highw(a), v >> 32, 2);
}else
writem(a, v, s);
}
static u32int
add(u32int a, u32int b, int s)
{
int v;
ps &= ~(FLAGC|FLAGV);
switch(s){
case 0:
v = (u8int)a + (u8int)b;
if(v >= 0x100) ps |= FLAGC;
if(((a ^ ~b) & (v ^ a) & 0x80) != 0) ps |= FLAGV;
return v;
case 1:
v = (u16int)a + (u16int)b;
if(v >= 0x10000) ps |= FLAGC;
if(((a ^ ~b) & (v ^ a) & 0x8000) != 0) ps |= FLAGV;
return v;
case 2:
v = a + b;
if((u32int)v < a) ps |= FLAGC;
if(((a ^ ~b) & (v ^ a) & 0x80000000) != 0) ps |= FLAGV;
return v;
default:
sysfatal("subtract: unimplemented size %d", s);
return 0;
}
}
static void
adwc(void)
{
vlong ad;
u32int a, b, v;
u8int c;
a = readm(amode(2), 2);
ad = amode(2);
b = readm(ad, 2);
c = ps & FLAGC;
ps &= ~15;
v = a + b + c;
if(v < a || c && v == a) ps |= FLAGC;
if(((a ^ ~b) & (v ^ a) & 0x80000000) != 0) ps |= FLAGV;
writem(ad, v, 2);
nzv(v, 2);
}
static u32int
subtract(u32int a, u32int b, int s)
{
int v;
ps &= ~(FLAGC|FLAGV);
switch(s){
case 0:
v = (u8int)b - (u8int)a;
if(v < 0) ps |= FLAGC;
if(((a ^ b) & (v ^ a) & 0x80) != 0) ps |= FLAGV;
return v;
case 1:
v = (u16int)b - (u16int)a;
if(v < 0) ps |= FLAGC;
if(((a ^ b) & (v ^ a) & 0x8000) != 0) ps |= FLAGV;
return v;
case 2:
v = b - a;
if((u32int)v > b) ps |= FLAGC;
if(((a ^ b) & (v ^ a) & 0x80000000) != 0) ps |= FLAGV;
return v;
default:
sysfatal("subtract: unimplemented size %d", s);
return 0;
}
}
static void
sbwc(void)
{
vlong ad;
u32int a, b, v;
u8int c;
a = readm(amode(2), 2);
ad = amode(2);
b = readm(ad, 2);
c = ps & FLAGC;
ps &= ~15;
v = a - b - c;
if(v > a || c && v == a) ps |= FLAGC;
if(((a ^ b) & (v ^ a) & 0x80000000) != 0) ps |= FLAGV;
writem(ad, v, 2);
nzv(v, 2);
}
static void
cmp(u32int a, u32int b, int s)
{
ps &= ~15;
switch(s){
case 0:
if((s8int) a < (s8int) b) ps |= FLAGN;
if((u8int) a == (u8int) b) ps |= FLAGZ;
if((u8int) a < (u8int) b) ps |= FLAGC;
break;
case 1:
if((s16int) a < (s16int) b) ps |= FLAGN;
if((u16int) a == (u16int) b) ps |= FLAGZ;
if((u16int) a < (u16int) b) ps |= FLAGC;
break;
case 2:
if((s32int) a < (s32int) b) ps |= FLAGN;
if(a == b) ps |= FLAGZ;
if(a < b) ps |= FLAGC;
break;
default:
sysfatal("cmp: unimplemented size %d", s);
}
}
static u32int
mul(u32int a, u32int b, int s)
{
vlong v;
ps &= ~(FLAGC|FLAGV);
switch(s){
case 0:
v = (s8int) a * (s8int) b;
if((uvlong)(v + 0x80) > 0xff) ps |= FLAGV;
return v;
case 1:
v = (s16int) a * (s16int) b;
if((uvlong)(v + 0x8000) > 0xffff) ps |= FLAGV;
return v;
case 2:
v = (s32int)a * (s32int) b;
if((uvlong)(v + 0x80000000) > 0xffffffff) ps |= FLAGV;
return v;
default:
sysfatal("mul: unimplemented size %d", s);
return 0;
}
}
static u32int
div(u32int a, u32int b, int s)
{
vlong v;
ps &= ~(FLAGC|FLAGV);
switch(s){
case 0:
if((s8int) a == 0 || (s8int) b == -0x80 && (s8int) a == -1){
ps |= FLAGV;
return b;
}
v = (s8int) b / (s8int) a;
return v;
case 1:
if((s16int) b == 0 || (s16int) b == -0x8000 && (s16int) a == -1){
ps |= FLAGV;
return b;
}
v = (s16int) b / (s16int) a;
return v;
case 2:
if(b == 0 || (s32int) b == -0x8000 && (s32int) a == -1){
ps |= FLAGV;
return b;
}
v = (s32int) b / (s32int) a;
return v;
default:
sysfatal("div: unimplemented size %d", s);
return 0;
}
}
static void
alu(int o, int r, int s)
{
u32int a, b, v;
vlong c;
switch(r){
case 1:
c = amode(s);
if(o == ADD || o == SUB)
a = 1;
else
a = 0;
b = readm(c, s);
break;
case 2:
a = readm(amode(s), s);
c = amode(s);
b = readm(c, s);
break;
case 3:
a = readm(amode(s), s);
b = readm(amode(s), s);
c = amode(s);
break;
case 4:
a = readm(amode(s), s);
if(o == XOR)
b = -1;
else
b = 0;
c = amode(s);
break;
default:
sysfatal("alu: unimplemented %d", r);
return;
}
switch(o){
case ADD: v = add(a, b, s); break;
case SUB: v = subtract(a, b, s); break;
case MUL: v = mul(a, b, s); break;
case DIV: v = div(a, b, s); break;
case CMP: cmp(a, b, s); return;
case TST: cmp(b, 0, s); return;
case BIC: v = ~a & b; ps &= ~FLAGV; break;
case BIS: v = a | b; ps &= ~FLAGV; break;
case XOR: v = a ^ b; ps &= ~FLAGV; break;
case BIT: nzv(a & b, s); return;
default: sysfatal("unimplemented %d in alu", o); v = 0;
}
nz(v, s);
writem(c, v, s);
}
static void
ediv(void)
{
s32int divr;
vlong divd;
vlong q;
s32int r;
vlong quo, rem;
divr = readm(amode(2), 2);
divd = readm64(amode(3), 3);
quo = amode(2);
rem = amode(2);
ps &= ~15;
if(divr == 0){
nope:
writem(quo, divd, 2);
writem(rem, 0, 2);
nz(divd, 2);
return;
}
q = divd / divr;
r = divd % divr;
if((uvlong)(q + 0x80000000) > 0xffffffff)
goto nope;
writem(quo, q, 2);
writem(rem, r, 2);
nz(q, 2);
}
static void
move(int s)
{
u32int v, w;
vlong src, dst;
src = amode(s);
dst = amode(s);
if(s != 3){
v = readm(src, s);
writem(dst, v, s);
nzv(v, s);
}else{
v = readm(src, 2);
w = readm(highw(src), 2);
writem(dst, v, 2);
writem(highw(dst), w, 2);
nzv(w, 2);
if(v != 0) ps &= ~FLAGZ;
}
}
static void
cvt(int s, int t)
{
u32int v;
v = readm(amode(s), s);
v = sxt(v, s);
writem(amode(t), v, t);
nzv(v, t);
switch(t){
case 0: if((uvlong)(v + 0x80) > 0xff) ps |= FLAGV; break;
case 1: if((uvlong)(v + 0x8000) > 0xffff) ps |= FLAGV; break;
}
ps &= ~FLAGC;
}
static void
movez(int s, int t)
{
u32int v;
v = readm(amode(s), s);
writem(amode(t), v, t);
nzv(v, t);
}
static void
movea(int s)
{
vlong v;
v = amode(s);
if(v < 0) sysfatal("invalid movea (pc=%.8x)", curpc);
writem(amode(2), v, 2);
nzv(v, 2);
}
static void
pusha(int s)
{
vlong v;
v = amode(s);
if(v < 0) sysfatal("invalid pusha (pc=%.8x)", curpc);
writem(r[14] -= 4, v, 2);
nzv(v, 2);
}
static void
pushl(void)
{
u32int v;
v = readm(amode(2), 2);
writem(r[14] -= 4, v, 2);
nzv(v, 2);
}
static void
branch(int s, int c)
{
int off;
if(s == 0)
off = (s8int) fetch8();
else
off = (s16int) fetch16();
if(c)
r[15] += off;
}
static void
calls(void)
{
u32int narg, sp;
vlong dst;
u16int m;
int i;
narg = readm(amode(2), 2);
dst = amode(0);
if(dst < 0) sysfatal("call to illegal location pc=%.8ux", curpc);
writem(r[14] -= 4, narg, 2);
sp = r[14];
r[14] &= -4;
m = readm(dst, 1);
for(i = 12; --i >= 0; )
if((m & 1<<i) != 0)
writem(r[14] -= 4, r[i], 2);
writem(r[14] -= 4, r[15], 2);
writem(r[14] -= 4, r[13], 2);
writem(r[14] -= 4, r[12], 2);
ps &= ~0xf;
writem(r[14] -= 4, (sp & 3)<<30|1<<29|(m & 0xfff)<<16|ps&~0x10, 2);
ps &= ~0xc0;
if((m & 0x8000) != 0) ps |= 0x80;
if((m & 0x4000) != 0) ps |= 0x40;
writem(r[14] -= 4, 0, 2);
r[13] = r[14];
r[12] = sp;
r[15] = dst + 2;
}
static void
ret(void)
{
u32int m;
u8int n;
int i;
r[14] = r[13] + 4;
m = readm(r[14], 2);
r[14] += 4;
r[12] = readm(r[14], 2); r[14] += 4;
r[13] = readm(r[14], 2); r[14] += 4;
r[15] = readm(r[14], 2); r[14] += 4;
for(i = 0; i < 12; i++)
if((m & 1<<16+i) != 0){
r[i] = readm(r[14], 2);
r[14] += 4;
}
r[14] += m >> 30;
ps = (u16int) m;
if((m & 1<<29) != 0){
n = readm(r[14], 2);
r[14] += 4 + 4 * n;
}
}
static void
bbs(int inv, int new)
{
u32int pos;
vlong base;
s8int displ;
u32int val;
pos = readm(amode(2), 2);
base = amode(0);
displ = fetch8();
if(base < 0){
if(pos >= 32) sysfatal("invalid bbs (pc=%.8ux)", curpc);
val = readm(base, 2);
if((val >> pos & 1) != inv)
r[15] += displ;
if(new != 0){
if(new > 0) val |= 1<<pos;
else val &= ~(1<<pos);
writem(base, val, 2);
}
}else{
base += pos >> 3;
pos &= 7;
val = readm(base, 0);
if((val >> pos & 1) != inv)
r[15] += displ;
if(new != 0){
if(new > 0) val |= 1<<pos;
else val &= ~(1<<pos);
writem(base, val, 0);
}
}
}
static void
ashl(void)
{
s8int cnt;
s32int v;
cnt = readm(amode(0), 0);
v = readm(amode(2), 2);
ps &= ~15;
if(cnt >= 32){
if(v != 0) ps |= FLAGV;
v = 0;
}else if(cnt >= 0){
if(v + (v & 1<<31 >> cnt) != 0)
ps |= FLAGV;
v <<= cnt;
}else if(cnt > -32)
v >>= -cnt;
else
v >>= 31;
nz(v, 2);
writem(amode(2), v, 2);
}
static void
rotl(void)
{
s8int cnt;
s32int v;
cnt = readm(amode(0), 0);
v = readm(amode(2), 2);
ps &= ~FLAGV;
cnt &= 31;
v = v << cnt | v >> 32 - cnt;
nz(v, 2);
writem(amode(2), v, 2);
}
static void
ashq(void)
{
s8int cnt;
s64int v;
cnt = readm(amode(0), 0);
v = readm64(amode(3), 3);
ps &= ~15;
if(cnt >= 64){
if(v != 0) ps |= FLAGV;
v = 0;
}else if(cnt >= 0){
if(v + (v & 1ULL<<63 >> cnt) != 0)
ps |= FLAGV;
v <<= cnt;
}else if(cnt > -64)
v >>= -cnt;
else
v >>= 63;
nz64(v, 3);
writem64(amode(3), v, 3);
}
static void
blb(int val)
{
u32int v;
s8int disp;
v = readm(amode(2), 2);
disp = fetch8();
if((v & 1) == val)
r[15] += disp;
}
static void
sob(int geq)
{
vlong v;
s32int i;
s8int disp;
v = amode(2);
disp = fetch8();
i = readm(v, 2) - 1;
writem(v, i, 2);
nzv(i, 2);
if(i == 0x7fffffff) ps |= FLAGV;
if(i > 0 || i == 0 && geq)
r[15] += disp;
}
static void
aob(int leq)
{
s32int l, v;
vlong a;
s8int disp;
l = readm(amode(2), 2);
a = amode(2);
disp = fetch8();
v = readm(a, 2) + 1;
writem(a, v, 2);
nzv(v, 2);
if(v == 0x80000000) ps |= FLAGV;
if(v < l || v == l && leq)
r[15] += disp;
}
static void
bsb(int s)
{
u32int v;
switch(s){
case 0:
v = fetch8();
writem(r[14] -= 4, r[15], 2);
r[15] += (s8int) v;
break;
case 1:
v = fetch16();
writem(r[14] -= 4, r[15], 2);
r[15] += (s16int) v;
break;
case 2:
v = addrof(amode(0));
writem(r[14] -= 4, r[15], 2);
r[15] = v;
break;
}
}
static void
casei(int s)
{
u32int sel, base, lim;
sel = readm(amode(s), s);
base = readm(amode(s), s);
lim = readm(amode(s), s);
sel -= base;
if(sel <= lim)
r[15] += (s16int) readm(r[15] + 2 * sel, 1);
else
r[15] += 2 * (lim + 1);
}
static void
pushr(void)
{
u16int m;
u32int sp;
int i;
m = readm(amode(1), 1);
sp = r[14];
for(i = 15; --i >= 0; )
if((m & 1<<i) != 0)
writem(sp -= 4, r[i], 2);
r[14] = sp;
}
static void
popr(void)
{
u16int m;
u32int sp;
int i;
m = readm(amode(1), 1);
sp = r[14];
for(i = 0; i < 15; i++)
if((m & 1<<i) != 0){
r[i] = readm(sp, 2);
sp += 4;
}
if((m & 1<<14) == 0)
r[14] = sp;
}
static void
acb(int s)
{
vlong a;
s32int lim, n, v;
s16int disp;
int c;
lim = readm(amode(s), s);
n = readm(amode(s), s);
a = amode(s);
v = readm(a, s);
disp = fetch16();
c = ps & FLAGC;
v = add(v, n, s);
nz(v, s);
ps |= c;
writem(a, v, s);
if(n >= 0 && v <= lim || n < 0 && v >= lim)
r[15] += disp;
}
static void
extv(int sx)
{
u32int pos, v;
u8int c;
u8int size;
int i, s;
vlong base;
vlong dst;
pos = readm(amode(2), 2);
size = readm(amode(0), 0);
base = amode(0);
dst = amode(2);
if(size > 32 || pos >= 32 && base < 0) sysfatal("extv size=%d pos=%d (pc=%#.8ux)", size, pos, curpc);
if(base < 0){
v = readm(base, 2) >> pos;
if(size < 32)
v &= (1<<size) - 1;
}else{
base += pos >> 3;
pos &= 7;
v = 0;
for(i = 0; i < size; i += s){
c = readm(base, 0);
c >>= pos;
s = 8 - pos;
if(s > size) s = size;
v |= (c & (1<<s) - 1) << i;
base++;
pos = 0;
}
}
if(sx)
v = (s32int)(v << 32 - size) >> 32 - size;
writem(dst, v, 2);
ps &= ~FLAGC;
nzv(v, 2);
}
static void
insv(void)
{
u32int src, pos;
u8int size;
vlong base;
u32int v, m;
int i, s;
src = readm(amode(2), 2);
pos = readm(amode(2), 2);
size = readm(amode(0), 0);
base = amode(0);
if(size > 32 || pos >= 32 && base < 0) sysfatal("extv");
if(base < 0){
v = readm(base, 2);
m = (size == 32 ? 0 : 1<<size) - 1 << pos;
v = v & ~m | src << pos & m;
writem(base, v, 2);
}else{
base += pos >> 3;
pos &= 7;
for(i = 0; i < size; i += s){
v = readm(base, 0);
s = 8 - pos;
if(s > size) s = size;
m = (1<<s) - 1 << pos;
v = v & ~m | src << pos & m;
writem(base, v, 0);
src >>= s;
base++;
}
}
ps &= ~15;
}
void addp(int, int);
void editpc(void);
void cvtlp(void);
void movp(void);
void cmpp(int);
void ashp(void);
void alufp(int, int, int);
void movefp(int, int);
void cvtfp(int, int, int);
void locc(int);
void cmpc(int);
void movc(int);
void emod(int);
void
step(void)
{
uchar op;
curpc = r[15];
op = fetch8();
if(trace || 0 && op >= 0x40 && op < 0x78)
print("%.8ux %.2ux %.2ux %.8ux %.8ux %.8ux %.8ux\n", curpc, op, ps, r[14], r[0], r[1], r[5]);
switch(op){
case 0x04: ret(); break;
case 0x05: r[15] = readm(r[14], 2); r[14] += 4; break;
case 0x10: bsb(0); break;
case 0x11: branch(0, 1); break;
case 0x12: branch(0, (ps & FLAGZ) == 0); break;
case 0x13: branch(0, (ps & FLAGZ) != 0); break;
case 0x14: branch(0, (ps & (FLAGZ|FLAGN)) == 0); break;
case 0x15: branch(0, (ps & (FLAGZ|FLAGN)) != 0); break;
case 0x16: bsb(2); break;
case 0x17: r[15] = amode(0); break;
case 0x18: branch(0, (ps & FLAGN) == 0); break;
case 0x19: branch(0, (ps & FLAGN) != 0); break;
case 0x1a: branch(0, (ps & (FLAGZ|FLAGC)) == 0); break;
case 0x1b: branch(0, (ps & (FLAGZ|FLAGC)) != 0); break;
case 0x1c: branch(0, (ps & FLAGV) == 0); break;
case 0x1d: branch(0, (ps & FLAGV) != 0); break;
case 0x1e: branch(0, (ps & FLAGC) == 0); break;
case 0x1f: branch(0, (ps & FLAGC) != 0); break;
case 0x20: addp(4, 0); break;
case 0x21: addp(6, 0); break;
case 0x22: addp(4, 1); break;
case 0x23: addp(6, 1); break;
case 0x28: movc(0); break;
case 0x29: cmpc(0); break;
case 0x2c: movc(1); break;
case 0x2d: cmpc(1); break;
case 0x30: bsb(1); break;
case 0x31: branch(1, 1); break;
case 0x32: cvt(1, 2); break;
case 0x33: cvt(1, 0); break;
case 0x34: movp(); break;
case 0x35: cmpp(3); break;
case 0x37: cmpp(4); break;
case 0x38: editpc(); break;
case 0x3a: locc(0); break;
case 0x3b: locc(1); break;
case 0x3c: movez(1, 2); break;
case 0x3d: acb(1); break;
case 0x3e: movea(1); break;
case 0x3f: pusha(1); break;
case 0x40: alufp(ADD, 2, 0x12); break;
case 0x41: alufp(ADD, 3, 0x12); break;
case 0x42: alufp(SUB, 2, 0x12); break;
case 0x43: alufp(SUB, 3, 0x12); break;
case 0x44: alufp(MUL, 2, 0x12); break;
case 0x45: alufp(MUL, 3, 0x12); break;
case 0x46: alufp(DIV, 2, 0x12); break;
case 0x47: alufp(DIV, 3, 0x12); break;
case 0x48: cvtfp(0x12, 0, 0); break;
case 0x49: cvtfp(0x12, 1, 0); break;
case 0x4a: cvtfp(0x12, 2, 0); break;
case 0x4b: cvtfp(0x12, 2, 1); break;
case 0x4c: cvtfp(0, 0x12, 0); break;
case 0x4d: cvtfp(1, 0x12, 0); break;
case 0x4e: cvtfp(2, 0x12, 0); break;
case 0x50: movefp(0x12, 0); break;
case 0x51: alufp(CMP, 2, 0x12); break;
case 0x52: movefp(0x12, 1); break;
case 0x53: alufp(CMP, 1, 0x12); break;
case 0x54: emod(0x12); break;
case 0x56: cvtfp(0x12, 0x13, 0); break;
case 0x60: alufp(ADD, 2, 0x13); break;
case 0x61: alufp(ADD, 3, 0x13); break;
case 0x62: alufp(SUB, 2, 0x13); break;
case 0x63: alufp(SUB, 3, 0x13); break;
case 0x64: alufp(MUL, 2, 0x13); break;
case 0x65: alufp(MUL, 3, 0x13); break;
case 0x66: alufp(DIV, 2, 0x13); break;
case 0x67: alufp(DIV, 3, 0x13); break;
case 0x68: cvtfp(0x13, 0, 0); break;
case 0x69: cvtfp(0x13, 1, 0); break;
case 0x6a: cvtfp(0x13, 2, 0); break;
case 0x6b: cvtfp(0x13, 2, 1); break;
case 0x6c: cvtfp(0, 0x13, 0); break;
case 0x6d: cvtfp(1, 0x13, 0); break;
case 0x6e: cvtfp(2, 0x13, 0); break;
case 0x70: movefp(0x13, 0); break;
case 0x71: alufp(CMP, 2, 0x13); break;
case 0x72: movefp(0x13, 1); break;
case 0x73: alufp(CMP, 1, 0x13); break;
case 0x74: emod(0x13); break;
case 0x76: cvtfp(0x13, 0x12, 0); break;
case 0x78: ashl(); break;
case 0x79: ashq(); break;
case 0x7b: ediv(); break;
case 0x7c: writem64(amode(3), 0, 3); nzv(0, 0); break;
case 0x7d: move(3); break;
case 0x7e: movea(3); break;
case 0x7f: pusha(3); break;
case 0x80: alu(ADD, 2, 0); break;
case 0x81: alu(ADD, 3, 0); break;
case 0x82: alu(SUB, 2, 0); break;
case 0x83: alu(SUB, 3, 0); break;
case 0x84: alu(MUL, 2, 0); break;
case 0x85: alu(MUL, 3, 0); break;
case 0x86: alu(DIV, 2, 0); break;
case 0x87: alu(DIV, 3, 0); break;
case 0x88: alu(BIS, 2, 0); break;
case 0x89: alu(BIS, 3, 0); break;
case 0x8a: alu(BIC, 2, 0); break;
case 0x8b: alu(BIC, 3, 0); break;
case 0x8c: alu(XOR, 2, 0); break;
case 0x8d: alu(XOR, 3, 0); break;
case 0x8e: alu(SUB, 4, 0); break;
case 0x8f: casei(0); break;
case 0x90: move(0); break;
case 0x91: alu(CMP, 2, 0); break;
case 0x92: alu(XOR, 4, 0); break;
case 0x93: alu(BIT, 2, 0); break;
case 0x94: writem(amode(0), 0, 0); nzv(0, 0); break;
case 0x95: alu(TST, 1, 0); break;
case 0x96: alu(ADD, 1, 0); break;
case 0x97: alu(SUB, 1, 0); break;
case 0x98: cvt(0, 2); break;
case 0x99: cvt(0, 1); break;
case 0x9a: movez(0, 2); break;
case 0x9b: movez(0, 1); break;
case 0x9c: rotl(); break;
case 0x9d: acb(0); break;
case 0x9e: movea(0); break;
case 0x9f: pusha(0); break;
case 0xa0: alu(ADD, 2, 1); break;
case 0xa1: alu(ADD, 3, 1); break;
case 0xa2: alu(SUB, 2, 1); break;
case 0xa3: alu(SUB, 3, 1); break;
case 0xa4: alu(MUL, 2, 1); break;
case 0xa5: alu(MUL, 3, 1); break;
case 0xa6: alu(DIV, 2, 1); break;
case 0xa7: alu(DIV, 3, 1); break;
case 0xa8: alu(BIS, 2, 1); break;
case 0xa9: alu(BIS, 3, 1); break;
case 0xaa: alu(BIC, 2, 1); break;
case 0xab: alu(BIC, 3, 1); break;
case 0xac: alu(XOR, 2, 1); break;
case 0xad: alu(XOR, 3, 1); break;
case 0xae: alu(SUB, 4, 1); break;
case 0xaf: casei(1); break;
case 0xb0: move(1); break;
case 0xb1: alu(CMP, 2, 1); break;
case 0xb2: alu(XOR, 4, 1); break;
case 0xb3: alu(BIT, 2, 1); break;
case 0xb4: writem(amode(1), 0, 1); nzv(0, 1); break;
case 0xb5: alu(TST, 1, 1); break;
case 0xb6: alu(ADD, 1, 1); break;
case 0xb7: alu(SUB, 1, 1); break;
case 0xba: popr(); break;
case 0xbb: pushr(); break;
case 0xbc: syscall(readm(amode(1), 1)); break;
case 0xc0: alu(ADD, 2, 2); break;
case 0xc1: alu(ADD, 3, 2); break;
case 0xc2: alu(SUB, 2, 2); break;
case 0xc3: alu(SUB, 3, 2); break;
case 0xc4: alu(MUL, 2, 2); break;
case 0xc5: alu(MUL, 3, 2); break;
case 0xc6: alu(DIV, 2, 2); break;
case 0xc7: alu(DIV, 3, 2); break;
case 0xc8: alu(BIS, 2, 2); break;
case 0xc9: alu(BIS, 3, 2); break;
case 0xca: alu(BIC, 2, 2); break;
case 0xcb: alu(BIC, 3, 2); break;
case 0xcc: alu(XOR, 2, 2); break;
case 0xcd: alu(XOR, 3, 2); break;
case 0xce: alu(SUB, 4, 2); break;
case 0xcf: casei(2); break;
case 0xd0: move(2); break;
case 0xd1: alu(CMP, 2, 2); break;
case 0xd2: alu(XOR, 4, 2); break;
case 0xd3: alu(BIT, 2, 2); break;
case 0xd4: writem(amode(2), 0, 2); nzv(0, 2); break;
case 0xd5: alu(TST, 1, 2); break;
case 0xd6: alu(ADD, 1, 2); break;
case 0xd7: alu(SUB, 1, 2); break;
case 0xd8: adwc(); break;
case 0xd9: sbwc(); break;
case 0xdd: pushl(); break;
case 0xde: movea(2); break;
case 0xdf: pusha(2); break;
case 0xe0: bbs(0, 0); break;
case 0xe1: bbs(1, 0); break;
case 0xe2: bbs(0, 1); break;
case 0xe3: bbs(1, 1); break;
case 0xe4: bbs(0, -1); break;
case 0xe5: bbs(1, -1); break;
case 0xe8: blb(1); break;
case 0xe9: blb(0); break;
case 0xee: extv(1); break;
case 0xef: extv(0); break;
case 0xf0: insv(); break;
case 0xf1: acb(2); break;
case 0xf2: aob(0); break;
case 0xf3: aob(1); break;
case 0xf4: sob(1); break;
case 0xf5: sob(0); break;
case 0xf6: cvt(2, 0); break;
case 0xf7: cvt(2, 1); break;
case 0xf8: ashp(); break;
case 0xf9: cvtlp(); break;
case 0xfb: calls(); break;
default: sysfatal("unimplemented op %.2x (pc=%.8x)", op, curpc);
}
}