shithub: riscv

Download patch

ref: af810c987120f915091b16ed7440ceff1933100d
parent: 4dee686ca51e20634aa66c989dabbb1cf460e32b
author: aiju <devnull@localhost>
date: Tue Nov 20 04:18:20 EST 2018

games/blit: clean up cpu.c and make it pass tests

--- a/sys/src/games/blit/cpu.c
+++ b/sys/src/games/blit/cpu.c
@@ -132,7 +132,7 @@
 			v = fetch16();
 			return (u32int)(pc + (s16int)v - 2);
 		case 3:
-			tim += s == 2 ? 14 : 4;
+			tim += s == 2 ? 14 : 10;
 			w = fetch16();
 			v = r[w >> 12];
 			if((w & 1<<11) == 0)
@@ -345,7 +345,8 @@
 	int l, ll, x, vf;
 	u32int msb;
 	
-	msb = 1 << ((8 << s) - 1);
+	/* abandon all hope ye who enter here */
+	msb = 1 << (8 << s) - 1;
 	v &= (msb << 1) - 1;
 	if(m == 0)
 		x = (v & msb) != 0;
@@ -364,7 +365,8 @@
 			l = (v & msb) != 0;
 			v <<= 1;
 		}
-		rS = rS & ~FLAGX | l << 4;
+		if((m & 6) != 6)
+			rS = rS & ~FLAGX | l << 4;
 		if(m >= 6)
 			x = l;
 		else if(m >= 4){
@@ -376,12 +378,12 @@
 				v |= msb;
 		}else
 			v |= x;
-		vf |= x ^ (v & msb) != 0;
+		vf |= l ^ (v & msb) != 0;
 		tim += 2;
 	}
 	nz(v, s);
 	rS |= l;
-	if(m <= 1 && vf)
+	if(m == 1 && vf)
 		rS |= FLAGV;
 	tim += s == 2 ? 8 : 6;
 	return v;
@@ -391,45 +393,49 @@
 addbcd(u8int a, u8int b)
 {
 	int r;
+	u8int bc, dc, s;
 	
-	r = (a & 0xf) + (b & 0xf) + ((rS & FLAGX) != 0);
-	if(r > 0x09) r += 0x06;
-	if(r > 0x1f) r -= 0x10;
-	r += (a & 0xf0) + (b & 0xf0);
-	if(r > 0x9f) r += 0x60;
-	if((u8int)r != 0)
-		rS &= ~FLAGZ;
-	if(r > 0xff)
+	r = a + b + (rS >> 4 & 1);
+	bc = ((a ^ b ^ r) & 0x110) >> 1;
+	dc = ((r + 0x66 ^ r) & 0x110) >> 1;
+	s = r + (bc | dc) - ((bc | dc) >> 2);
+	rS &= ~(FLAGC|FLAGX|FLAGN|FLAGV);
+	if(((bc | r & ~s) & 0x80) != 0)
 		rS |= FLAGC|FLAGX;
-	else
-		rS &= ~(FLAGC|FLAGX);
-	return r;
+	if(s != 0)
+		rS &= ~FLAGZ;
+	if((s & 0x80) != 0)
+		rS |= FLAGN;
+	if((~r & s & 0x80) != 0)
+		rS |= FLAGV;
+	return s;
 }
 
 static u8int
 subbcd(u8int a, u8int b)
 {
-	int x;
+	int r;
+	u8int bc, s;
 	
-	x = (a & 0xf) + (~b & 0xf) + ((rS & FLAGX) == 0);
-	if(x < 0x10) x -= 0x06;
-	if(x < 0) x += 0x10;
-	x += (a & 0xf0) + (~b & 0xf0);
-	if(x > 0xff)
-		rS &= ~(FLAGC|FLAGX);
-	else{
+	r = a - b - (rS >> 4 & 1);
+	bc = ((a ^ b ^ r) & 0x110) >> 1;
+	s = r - (bc - (bc >> 2));
+	rS &= ~(FLAGC|FLAGX|FLAGN|FLAGV);
+	if(((bc | (~r & s)) & 0x80) != 0)
 		rS |= FLAGC|FLAGX;
-		x -= 0x60;
-	}
-	if((u8int)x != 0)
+	if(s != 0)
 		rS &= ~FLAGZ;
-	return x;
+	if((s & 0x80) != 0)
+		rS |= FLAGN;
+	if((r & ~s & 0x80) != 0)
+		rS |= FLAGV;
+	return s;
 }
 
 static void
 dtime(u16int op, u8int s)
 {
-	if((op & 0x100) != 0){
+	if((op & 0x100) == 0){
 		if(s == 2)
 			if((op & 0x30) == 0 || (op & 0x3f) == 0x3c)
 				tim += 8;
@@ -501,13 +507,994 @@
 	}
 }
 
-int
-step(void)
+static void
+cputrace(void)
 {
+	int i;
+	static char buf[1024];
+	static u32int oldr[16];
+	char *p, *e;
+	
+	p = buf;
+	e = buf + sizeof(buf);
+	p = seprint(p, e, "%.6ux %.6uo %.4x %.8ux %.8ux |", curpc, op, rS, ra[7], asp);
+	for(i = 0; i < 16; i++)
+		if(oldr[i] != r[i])
+			p = seprint(p, e, " %c%d=%.8ux", i >= 8  ? 'A' : 'D', i & 7, r[i]);
+	print("%s\n", buf);
+	memcpy(oldr, r, sizeof(r));
+}
+
+static void
+ccr_sr_op(u16int op)
+{
+	int s;
 	u32int v, w;
+	
+	s = op >> 6 & 3;
+	if(s == 1 && (rS & FLAGS) == 0){
+		trap(8, curpc);
+		return;
+	}
+	v = rS;
+	w = fetch16();
+	switch(op >> 9 & 7){
+	case 0: v |= w; break;
+	case 1: v &= w; break;
+	case 5: v ^= w; break;
+	default: undef();
+	}
+	if(s != 1)
+		v = v & 0x1f | rS & 0xff00;
+	rS = v;
+	if(s == 1 && (rS & FLAGS) == 0){
+		v = ra[7];
+		ra[7] = asp;
+		asp = v;
+	}
+	tim += 20;
+}
+
+static void
+op_movep(u16int op)
+{
+	int s, n;
 	vlong a;
+	u32int v;
+
+	a = (u32int)(ra[op & 7] + (s16int)fetch16());
+	s = op >> 6 & 3;
+	n = op >> 9 & 7;
+	switch(s){
+	case 0:
+		v = (u8int)rmode(a, 0) << 8;
+		v |= (u8int)rmode(a + 2, 0);
+		r[n] = r[n] & 0xffff0000 | v;
+		tim += 16;
+		break;
+	case 1:
+		v = (u8int)rmode(a, 0) << 24;
+		v |= (u8int)rmode(a + 2, 0) << 16;
+		v |= (u8int)rmode(a + 4, 0) << 8;
+		v |= (u8int)rmode(a + 6, 0);
+		tim += 24;
+		r[n] = v;
+		break;
+	case 2:
+		wmode(a, 0, r[n] >> 8);
+		wmode(a + 2, 0, r[n]);
+		tim += 16;
+		break;
+	case 3:
+		wmode(a, 0, r[n] >> 24);
+		wmode(a + 2, 0, r[n] >> 16);
+		wmode(a + 4, 0, r[n] >> 8);
+		wmode(a + 6, 0, r[n]);
+		tim += 24;
+		break;
+	}
+}
+
+static void
+bitop(u16int op)
+{
+	int s, n;
+	u32int v, w;
+	vlong a;
+	
+	s = op >> 6 & 3;
+	n = op >> 9 & 7;
+	if((op & 0x100) != 0)
+		w = r[n];
+	else
+		w = fetch16();
+	if((op & 0x38) != 0){
+		n = 0;
+		w = 1<<(w & 7);
+	}else{
+		n = 2;
+		w = 1<<(w & 31);
+	}
+	a = amode(op >> 3, op, n);
+	v = rmode(a, n);
+	rS &= ~FLAGZ;
+	if((v & w) == 0)
+		rS |= FLAGZ;
+	switch(s){
+	case 1: v ^= w; break;
+	case 2: v &= ~w; if(n == 2) tim += 2; break;
+	case 3: v |= w; break;
+	}
+	if(s != 0){
+		wmode(a, n, v);
+		tim += (op & 0x100) != 0 ? 8 : 12;
+	}else{
+		tim += (op & 0x100) != 0 ? 4 : 8;
+		if(n == 2)
+			tim += 2;
+	}
+}
+
+static void
+immop(u16int op)
+{
+	int s, n;
+	u32int v, w;
+	vlong a;
+	
+	s = op >> 6 & 3;
+	n = op >> 9 & 7;
+	switch(s){
+	case 0: w = (s8int)fetch16(); break;
+	default: w = fetch16(); break;
+	case 2: w = fetch32(); break;
+	}
+	a = amode(op >> 3, op, s);
+	v = rmode(a, s);
+	switch(n){
+	case 0: nz(v |= w, s); break;
+	case 1: nz(v &= w, s); break;
+	case 2: rS |= FLAGZ; v = sub(v, w, 0, s); rS = rS & ~FLAGX | rS << 4 & FLAGX; break;
+	case 3: rS |= FLAGZ; v = add(v, w, 0, s); rS = rS & ~FLAGX | rS << 4 & FLAGX; break;
+	case 5: nz(v ^= w, s); break;
+	case 6: rS |= FLAGZ; sub(v, w, 0, s); break;
+	default: undef();
+	}
+	if(n == 6){
+		if(a < 0)
+			tim += s == 2 ? 14 : 8;
+		else
+			tim += s == 2 ? 12 : 8;
+	}else{
+		if(a < 0)
+			tim += s == 2 ? 16 : 8;
+		else
+			tim += s == 2 ? 20 : 12;
+	}
+	if(n != 6)
+		wmode(a, s, v);
+}
+
+void
+op_move(u16int op, int s)
+{
+	u32int v;
+
+	v = rmode(amode(op >> 3, op, s), s);
+	wmode(amode(op >> 6, op >> 9, s), s, v);
+	if((op & 0x1c0) != 0x40)
+		nz(v, s);
+	tim += 4;
+	if((op & 0700) == 0400)
+		tim -= 2;
+}
+
+static void
+op_lea(u16int op)
+{
+	int n;
+	
+	n = op >> 9 & 7;
+	ra[n] = amode(op >> 3, op, 1);
+	if((op & 070) == 060 || (op & 077) == 073) tim += 2;
+}
+
+static void
+op_chk(u16int op)
+{
+	int s, n;
+	u32int v;
+	vlong a;
+	
+	s = op >> 6 & 3;
+	n = op >> 9 & 7;
+	a = amode(op >> 3, op, s);
+	v = rmode(a, s);
+	if((s32int)r[n] < 0 || (s32int)r[n] > (s32int)v)
+		trap(6, curpc);
+	else
+		tim += 10;
+}
+
+static void
+op_movem(u16int op)
+{
+	int s, n, m;
+	u32int w;
+	vlong a;
+	
+	s = (op >> 6 & 1) + 1;
+	w = fetch16();
+	if((op & 0x38) == 0x18){
+		n = op & 7;
+		a = ra[n];
+		for(m = 0; m < 16; m++){
+			if((w & 1) != 0){
+				r[m] = rmode(a, s);
+				a += 1<<s;
+				tim += 2<<s;
+			}
+			w >>= 1;
+		}
+		ra[n] = a;
+		tim += 12;
+	}else if((op & 0x38) == 0x20){
+		n = op & 7;
+		a = ra[n];
+		for(m = 0; m < 16; m++){
+			if((w & 1) != 0){
+				a -= 1<<s;
+				wmode(a, s, r[15 - m]);
+				tim += 2<<s;
+			}
+			w >>= 1;
+		}
+		ra[n] = a;
+		tim += 8;
+	}else{
+		a = amode(op >> 3, op, s);
+		for(m = 0; m < 16; m++){
+			if((w & 1) != 0){
+				if((op & 0x400) != 0)
+					r[m] = rmode(a, s);
+				else
+					wmode(a, s, r[m]);
+				a += 1<<s;
+				tim += 2<<s;
+			}
+			w >>= 1;
+		}
+		tim += (op & 0x400) != 0 ? 8 : 4;
+		if(s == 2) tim -= 4;
+	}
+}
+
+static void
+op_move_from_sr(u16int op)
+{
+	vlong a;
+	
+	a = amode(op >> 3, op, 1);
+	wmode(a, 1, rS);
+	tim += a < 0 ? 6 : 8;
+}
+
+static void
+op_negx(u16int op)
+{
 	int s;
-	int n, m, d;
+	u32int v;
+	vlong a;
+	
+	s = op >> 6 & 3;
+	a = amode(op >> 3, op, s);
+	v = rmode(a, s);
+	wmode(a, s, sub(0, v, rS>>4 & 1, s));
+	rS = rS & ~FLAGX | rS << 4 & FLAGX;
+	stime(a < 0, s);
+}
+
+static void
+op_clr(u16int op)
+{
+	int s;
+	vlong a;
+	
+	s = op >> 6 & 3;
+	a = amode(op >> 3, op, s);
+	wmode(a, s, 0);
+	nz(0, 0);
+	stime(a < 0, s);
+}
+
+static void
+op_move_to_ccr(u16int op)
+{
+	rS = rS & 0xff00 | rmode(amode(op >> 3, op, 1), 1) & 0x1f;
+	tim += 12;
+}
+
+static void
+op_neg(u16int op)
+{
+	int s;
+	u32int v;
+	vlong a;
+	
+	s = op >> 6 & 3;
+	a = amode(op >> 3, op, s);
+	v = rmode(a, s);
+	rS |= FLAGZ;
+	wmode(a, s, sub(0, v, 0, s));
+	rS = rS & ~FLAGX | rS << 4 & FLAGX;
+	stime(a < 0, s);
+}
+
+static void
+op_move_to_sr(u16int op)
+{
+	u32int v;
+	
+	if((rS & FLAGS) != 0){
+		rS = rmode(amode(op >> 3, op, 1), 1);
+		if((rS & FLAGS) == 0){
+			v = asp;
+			asp = ra[7];
+			ra[7] = v;
+		}
+		tim += 12;
+	}else
+		trap(8, curpc);
+}
+
+static void
+op_not(u16int op)
+{
+	int s;
+	u32int v;
+	vlong a;
+	
+	s = op >> 6 & 3;
+	a = amode(op >> 3, op, s);
+	v = ~rmode(a, s);
+	nz(v, s);
+	wmode(a, s, v);
+	stime(a < 0, s);
+}
+
+static void
+op_nbcd(u16int op)
+{
+	u32int v;
+	vlong a;
+	
+	a = amode(op >> 3, op, 0);
+	v = rmode(a, 0);
+	wmode(a, 0, subbcd(0, v));
+	if(a < 0)
+		tim += 6;
+	else
+		tim += 8;
+}
+
+static void
+op_pea(u16int op)
+{
+	ra[7] -= 4;
+	wmode(ra[7], 2, amode(op >> 3, op, 1));
+	tim += 8;
+	if((op & 070) == 060 || (op & 077) == 073) tim += 2;
+}
+
+static void
+op_swap(u16int op)
+{
+	int n;
+	
+	n = op & 7;
+	nz(r[n] = r[n] >> 16 | r[n] << 16, 2);
+	tim += 4;
+}
+
+static void
+op_ext_b(u16int op)
+{
+	int n;
+	
+	n = op & 7;
+	nz(r[n] = r[n] & 0xffff0000 | (u16int)(s8int)r[n], 1);
+	tim += 4;
+}
+
+static void
+op_ext_w(u16int op)
+{
+	int n;
+	
+	n = op & 7;
+	nz(r[n] = (s16int)r[n], 2);
+	tim += 4;
+}
+
+static void
+op_tas(u16int op)
+{
+	u32int v;
+	vlong a;
+	
+	a = amode(op >> 3, op, 0);
+	v = rmode(a, 0);
+	nz(v, 0);
+	wmode(a, 0, v | 0x80);
+	tim += a < 0 ? 4 : 14;
+}
+
+static void
+op_tst(u16int op)
+{
+	int s;
+	vlong a;
+	
+	s = op >> 6 & 3;
+	a = amode(op >> 3, op, s);
+	nz(rmode(a, s), s);
+	tim += 4;
+}
+
+static void
+op_trap(u16int op)
+{
+	trap(0x20 | op & 0xf, pc);
+}
+
+static void
+op_link(u16int op)
+{
+	int n;
+	
+	n = op & 7;
+	push32(ra[n]);
+	ra[n] = ra[7];
+	ra[7] += (s16int)fetch16();
+	tim += 16;
+}
+
+static void
+op_unlk(u16int op)
+{
+	int n;
+	
+	n = op & 7;
+	ra[7] = ra[n];
+	ra[n] = pop32();
+	tim += 12;
+}
+
+static void
+op_move_usp(u16int op)
+{
+	int n;
+	
+	n = op & 7;
+	if((rS & FLAGS) != 0){
+		if((op & 8) != 0)
+			ra[n] = asp;
+		else
+			asp = ra[n];
+		tim += 4;
+	}else
+		trap(8, curpc);
+}
+
+static void
+jtime(int op)
+{
+	int a;
+	
+	a = op >> 3 & 7;
+	if(a == 2 || a == 6 || (op & 077) == 073)
+		tim += 2;
+	else if((op & 077) == 071)
+		tim -= 2;
+}
+
+static void
+op_jmp(u16int op)
+{
+	pc = amode(op >> 3, op, 1);
+	jtime(op);
+	tim += 2;
+}
+
+static void
+op_jsr(u16int op)
+{
+	vlong a;
+
+	a = amode(op >> 3, op, 1);
+	push32(pc);
+	pc = a;
+	jtime(op);
+	tim += 10;
+}
+
+static void
+op_reset(u16int op)
+{
+	USED(op);
+	tim += 132;
+}
+
+static void
+op_nop(u16int op)
+{
+	USED(op);
+	tim += 4;
+}
+
+static void
+op_stop(u16int op)
+{
+	USED(op);
+	if((rS & FLAGS) != 0){
+		rS = fetch16();
+		stop = 1;
+	}else
+		trap(8, curpc);
+	tim += 4;
+}
+
+static void
+op_rte(u16int op)
+{
+	u32int v;
+
+	USED(op);
+	if((rS & FLAGS) != 0){
+		v = rS;
+		rS = pop16();
+		pc = pop32();
+		if(((v ^ rS) & FLAGS) != 0){
+			v = asp;
+			asp = ra[7];
+			ra[7] = v;
+		}
+		tim += 20;
+	}else
+		trap(8, curpc);
+}
+
+static void
+op_rts(u16int op)
+{
+	USED(op);
+	pc = pop32();
+	tim += 16;
+}
+
+void
+op_trapv(u16int op)
+{
+	USED(op);
+	if((rS & FLAGV) != 0)
+		trap(7, curpc); 
+	tim += 4;
+}
+
+void
+op_rtr(u16int op)
+{
+	USED(op);
+	rS = rS & 0xff00 | pop16() & 0x1f;
+	pc = pop32();
+	tim += 20;
+}
+
+static void
+op_dbcc(u16int op)
+{
+	int n;
+	u32int v;
+	
+	n = op & 7;
+	v = (s16int)fetch16();
+	if(!cond((op >> 8) & 0xf)){
+		if((u16int)r[n] != 0){
+			r[n]--;
+			pc = pc + v - 2;
+			tim += 10;
+		}else{
+			r[n] |= 0xffff;
+			tim += 14;
+		}
+	}else
+		tim += 12;
+}
+
+static void
+op_scc(u16int op)
+{
+	u32int v;
+	vlong a;
+
+	a = amode(op >> 3, op, 0);
+	v = cond(op >> 8 & 0xf);
+	wmode(a, 0, -v);
+	if(a < 0)
+		tim += 4 + 2 * v;
+	else
+		tim += 8;
+}
+
+static void
+op_addq_subq(u16int op)
+{
+	int s, n;
+	u32int v;
+	vlong a;
+	
+	s = op >> 6 & 3;
+	n = op >> 9 & 7;
+	rS |= FLAGZ;
+	if((op & 0x38) == 0x08)
+		s = 2;
+	a = amode(op >> 3, op, s);
+	v = rmode(a, s);
+	if(n == 0)
+		n = 8;
+	if((op & 0x100) == 0)
+		v = add(v, n, 0, s);
+	else
+		v = sub(v, n, 0, s);
+	rS = rS & ~FLAGX | rS << 4 & FLAGX;
+	if(a < 0)
+		tim += s == 2 ? 8 : 4;
+	else
+		tim += s == 2 ? 12 : 8;
+	wmode(a, s, v);
+}
+
+static void
+op_addq_subq_a(u16int op)
+{
+	int s, n;
+	
+	s = op >> 6 & 3;
+	n = op >> 9 & 7;
+	if(n == 0)
+		n = 8;
+	tim += s == 2 || (op & 0x100) != 0 ? 8 : 4;
+	if((op & 0x100) == 0)
+		ra[op & 7] += n;
+	else
+		ra[op & 7] -= n;
+}
+
+static void
+op_bra(u16int op)
+{
+	u32int v;
+	
+	v = (s8int)op;
+	if(v == 0)
+		v = (s16int)fetch16();
+	else if(v == (u32int)-1)
+		v = fetch32();
+	if((op & 0xf00) == 0x100){ /* BSR */
+		push32(pc);
+		pc = curpc + 2 + v;
+		tim += 18;
+		return;
+	}
+	if(cond((op >> 8) & 0xf)){
+		pc = curpc + 2 + v;
+		tim += 10;
+	}else
+		tim += (u8int)(op + 1) <= 1 ? 12 : 8;
+}
+
+static void
+op_moveq(u16int op)
+{
+	int n;
+	
+	n = op >> 9 & 7;
+	r[n] = (s8int)op;
+	nz(r[n], 0);
+	tim += 4;
+}
+
+static void
+op_divu_divs(u16int op)
+{
+	int n;
+	u32int v, w;
+	vlong a;
+	
+	n = op >> 9 & 7;
+	a = amode(op >> 3, op, 1);
+	v = rmode(a, 1);
+	if(v == 0){
+		trap(5, curpc);
+		return;
+	}
+	if((op & 0x100) != 0){
+		w = (s32int)r[n] % (s16int)v;
+		v = (s32int)r[n] / (s16int)v;
+		if((s32int)(w ^ r[n]) < 0)
+			w = -w;
+		tim += 158;
+		if(v != (u32int)(s16int)v){
+			rS = rS & ~FLAGC | FLAGV;
+			return;
+		}
+	}else{
+		w = r[n] % (u16int)v;
+		v = r[n] / (u16int)v;
+		tim += 140;
+		if(v >= 0x10000){
+			rS = rS & ~FLAGC | FLAGV;
+			return;
+		}
+	}
+	r[n] = (u16int)v | w << 16;
+	nz(v, 1);
+}
+
+static void
+op_sbcd(u16int op)
+{
+	int n, m;
+	u32int v, w;
+	vlong src, dst;
+	
+	n = op >> 9 & 7;
+	m = op & 7;
+	if((op & 8) != 0){
+		src = amode(4, m, 0);
+		dst = amode(4, n, 0);
+		w = rmode(src, 0);
+		v = rmode(dst, 0);
+		v = subbcd(v, w);
+		wmode(dst, 0, v);
+	}else
+		r[n] = r[n] & 0xffffff00 | subbcd(r[n], r[m]);
+	tim += 6;
+}
+
+static void
+logic(u16int op)
+{
+	int s, n;
+	u32int v;
+	vlong a;
+	
+	s = op >> 6 & 3;
+	a = amode(op >> 3, op, s);
+	n = op >> 9 & 7;
+	v = rmode(a, s);
+	switch(op >> 12){
+	case 8: v |= r[n]; break;
+	case 11: v ^= r[n]; break;
+	case 12: v &= r[n]; break;
+	}
+	if((op & 0x100) == 0)
+		a = ~n;
+	wmode(a, s, v);
+	nz(v, s);
+	dtime(op, s);
+}
+
+static void
+op_cmpa(u16int op)
+{
+	int s, n;
+	vlong a;
+
+	n = op >> 9 & 7;
+	s = (op >> 8 & 1) + 1;
+	a = amode(op >> 3, op, s);
+	rS |= FLAGZ;
+	sub(ra[n], rmode(a, s), 0, 2);
+	tim += 6;
+}
+
+static void
+op_cmpm(u16int op)
+{
+	int s, n, m;
+	vlong src, dst;
+	u32int v, w;
+	
+	s = op >> 6 & 3;
+	n = op >> 9 & 7;
+	m = op & 7;
+	rS |= FLAGZ;
+	src = amode(3, m, s);
+	dst = amode(3, n, s);
+	v = rmode(src, s);
+	w = rmode(dst, s);
+	sub(w, v, 0, s);
+	tim += 4;
+}
+
+static void
+op_cmp(u16int op)
+{
+	int s, n;
+	vlong a;
+	
+	s = op >> 6 & 3;
+	n = op >> 9 & 7;
+	a = amode(op >> 3, op, s);
+	rS |= FLAGZ;
+	sub(r[n], rmode(a, s), 0, s);
+	tim += s == 2 ? 6 : 4;
+}
+
+static void
+op_mulu_muls(u16int op)
+{
+	int n;
+	u32int v;
+	vlong a;
+	
+	n = op >> 9 & 7;
+	a = amode(op >> 3, op, 1);
+	v = rmode(a, 1);
+	if((op & 0x100) != 0)
+		v *= (s16int)r[n];
+	else
+		v = (u16int)v * (u16int)r[n];
+	r[n] = v;
+	nz(v, 2);
+	tim += 70;
+}
+
+static void
+op_abcd(u16int op)
+{
+	int n, m;
+	u32int v, w;
+	vlong src, dst;
+	
+	n = op >> 9 & 7;
+	m = op & 7;
+	if((op & 8) != 0){
+		src = amode(4, m, 0);
+		dst = amode(4, n, 0);
+		v = rmode(src, 0);
+		w = rmode(dst, 0);
+		v = addbcd(v, w);
+		wmode(dst, 0, v);
+	}else
+		r[n] = r[n] & 0xffffff00 | addbcd(r[n], r[m]);
+	tim += 6;
+}
+
+static void
+op_exg(u16int op)
+{
+	int n, m;
+	u32int v;
+	
+	n = op >> 9 & 7;
+	m = op & 0xf;
+	if((op & 0xc8) == 0x48)
+		n |= 8;
+	v = r[n];
+	r[n] = r[m];
+	r[m] = v;
+	tim += 6;
+}
+
+static void
+op_adda_suba(u16int op)
+{
+	int s, n;
+	vlong a;
+	
+	n = op >> 9 & 7;
+	if((op & 0x100) != 0){
+		s = 2;
+		if((op & 0x30) == 0 || (op & 0x3f) == 0x3c)
+			tim += 8;
+		else
+			tim += 6;
+	}else{
+		s = 1;
+		tim += 8;
+	}
+	a = amode(op >> 3, op, s);
+	if((op >> 12) == 13)
+		ra[n] += rmode(a, s);
+	else
+		ra[n] -= rmode(a, s);
+}
+
+static void
+op_addx_subx(u16int op)
+{
+	int s, n, m;
+	u32int v, w;
+	vlong src, dst;
+	
+	s = op >> 6 & 3;
+	n = op >> 9 & 7;
+	m = op & 7;
+	if((op & 8) != 0){
+		src = amode(4, m, s);
+		dst = amode(4, n, s);
+		w = rmode(src, s);
+		v = rmode(dst, s);
+		tim += s == 2 ? 10 : 6;
+	}else{
+		w = r[m];
+		v = r[n];
+		dst = ~n;
+		tim += s == 2 ? 8 : 4;
+	}
+	if((op >> 12) == 13)
+		v = add(v, w, (rS & FLAGX) != 0, s);
+	else
+		v = sub(v, w, (rS & FLAGX) != 0, s);
+	wmode(dst, s, v);
+	rS = rS & ~FLAGX | rS << 4 & FLAGX;
+}
+
+static void
+op_add_sub(u16int op)
+{
+	int s, n, d;
+	u32int v;
+	vlong a;
+	
+	s = op >> 6 & 3;
+	n = op >> 9 & 7;
+	a = amode(op >> 3, op, s);
+	rS |= FLAGZ;
+	d = (op & 0x100) == 0;
+	v = rmode(a, s);
+	if((op >> 12) == 13)
+		v = add(v, r[n], 0, s);
+	else
+		v = sub(d ? r[n] : v, d ? v : r[n], 0, s);
+	rS = rS & ~FLAGX | rS << 4 & FLAGX;
+	if(d)
+		a = ~n;
+	wmode(a, s, v);
+	dtime(op, s);
+}
+
+static void
+shifts(u16int op)
+{
+	int s, n, m;
+	vlong a;
+
+	s = op >> 6 & 3;
+	if(s == 3){
+		m = op >> 8 & 7;
+		n = 1;
+		s = 1;
+		a = amode(op >> 3, op, s);
+	}else{
+		a = ~(uvlong)(op & 7);
+		m = op >> 2 & 6 | op >> 8 & 1;
+		n = (op >> 9) & 7;
+		if((op & 0x20) != 0)
+			n = r[n] & 63;
+		else if(n == 0)
+			n = 8;
+	}
+	wmode(a, s, rot(rmode(a, s), m, n, s));
+}
+
+int
+step(void)
+{
+	int s;
+	int n;
 	static int cnt;
 
 	if(0 && pc == 0x4118c){
@@ -514,6 +1501,7 @@
 		trace++;
 		print("%x\n", curpc);
 	}
+//	if(pc == 0x410de) trace++;
 	tim = 0;
 	curpc = pc;
 	if(irq && (irqla[(rS >> 8) & 7] & irq) != 0){
@@ -524,652 +1512,158 @@
 		return 1;
 	op = fetch16();
 	if(trace)
-		print("%.6ux %.6uo %.4ux %.8ux | %.8ux %.8ux %.8ux %.8ux | %.8ux %.8ux %.8ux\n", curpc, op, rS, memread(ra[7])<<16|memread(ra[7]+2), r[0], r[1], r[2], r[3], ra[0], ra[6], ra[7]);
+		cputrace();
 	s = op >> 6 & 3;
 	n = op >> 9 & 7;
 	switch(op >> 12){
 	case 0:
-		if((op & 0x3f) == 0x3c){ /* (ORI|ANDI|EORI) to (CCR|SR) */
-			if(s == 1 && (rS & FLAGS) == 0){
-				trap(8, curpc);
-				break;
-			}
-			v = rS;
-			w = fetch16();
-			switch(n){
-			case 0: v |= w; break;
-			case 1: v &= w; break;
-			case 5: v ^= w; break;
-			default: undef();
-			}
-			if(s != 1)
-				v = v & 0xff | rS & 0xff00;
-			rS = v;
-			if(s == 1 && (rS & FLAGS) == 0){
-				v = ra[7];
-				ra[7] = asp;
-				asp = v;
-			}
-			tim += 20;
-			break;
-		}
-		if((op & 0x138) == 0x108){ /* MOVEP */
-			a = ra[op & 7] + (s16int)fetch16();
-			switch(s){
-			case 0:
-				v = (u8int)rmode(a, 0) << 8;
-				v |= (u8int)rmode(a + 2, 0);
-				r[n] = r[n] & 0xff00 | v;
-				tim += 16;
-				break;
-			case 1:
-				v = (u8int)rmode(a, 0) << 24;
-				v |= (u8int)rmode(a + 2, 0) << 16;
-				v |= (u8int)rmode(a + 4, 0) << 8;
-				v |= (u8int)rmode(a + 6, 0);
-				tim += 24;
-				r[n] = v;
-				break;
-			case 2:
-				wmode(a, 0, r[n] >> 8);
-				wmode(a + 2, 0, r[n]);
-				tim += 16;
-				break;
-			case 3:
-				wmode(a, 0, r[n] >> 24);
-				wmode(a + 2, 0, r[n] >> 16);
-				wmode(a + 4, 0, r[n] >> 8);
-				wmode(a + 6, 0, r[n]);
-				tim += 24;
-				break;
-			}
-			break;
-		}
-		if((op & 0x100) != 0 || n == 4){ /* BTST, BCHG, BCLR, BSET */
-			if((op & 0x100) != 0)
-				w = r[n];
-			else
-				w = fetch16();
-			if((op & 0x38) != 0){
-				n = 0;
-				w = 1<<(w & 7);
-			}else{
-				n = 2;
-				w = 1<<(w & 31);
-			}
-			a = amode(op >> 3, op, n);
-			v = rmode(a, n);
-			rS &= ~FLAGZ;
-			if((v & w) == 0)
-				rS |= FLAGZ;
-			switch(s){
-			case 1: v ^= w; break;
-			case 2: v &= ~w; if(n == 2) tim += 2; break;
-			case 3: v |= w; break;
-			}
-			if(s != 0){
-				wmode(a, n, v);
-				tim += (op & 0x100) != 0 ? 8 : 12;
-			}else{
-				tim += (op & 0x100) != 0 ? 4 : 8;
-				if(n == 2)
-					tim += 2;
-			}
-			break;
-		}
-		switch(s){
-		case 0: w = (s8int)fetch16(); break;
-		default: w = fetch16(); break;
-		case 2: w = fetch32(); break;
-		}
-		a = amode(op >> 3, op, s);
-		v = rmode(a, s);
-		switch(n){
-		case 0: nz(v |= w, s); break;
-		case 1: nz(v &= w, s); break;
-		case 2: rS |= FLAGZ; v = sub(v, w, 0, s); break;
-		case 3: rS |= FLAGZ; v = add(v, w, 0, s); break;
-		case 5: nz(v ^= w, s); break;
-		case 6: rS |= FLAGZ; sub(v, w, 0, s); break;
-		default: undef();
-		}
-		if(a < 0)
-			tim += s == 2 ? (n == 1 || n == 6 ? 14 : 16) : 8;
+		if((op & 0x3f) == 0x3c)
+			ccr_sr_op(op);
+		else if((op & 0x138) == 0x108)
+			op_movep(op);
+		else if((op & 0x100) != 0 || n == 4)
+			bitop(op);
 		else
-			tim += s == 2 ? 20 : 12;
-		if(n != 6)
-			wmode(a, s, v);
+			immop(op);
 		break;
-	case 1: /* MOVE */
-		s = 0;
-		goto move;
-	case 2:
-		s = 2;
-		goto move;
-	case 3:
-		s = 1;
-	move:
-		v = rmode(amode(op >> 3, op, s), s);
-		wmode(amode(op >> 6, op >> 9, s), s, v);
-		if((op & 0x1c0) != 0x40)
-			nz(v, s);
-		tim += 4;
-		break;
+	case 1: op_move(op, 0); break;
+	case 2: op_move(op, 2); break;
+	case 3: op_move(op, 1); break;
 	case 4:
-		if((op & 0x1c0) == 0x1c0){ /* LEA */
-			ra[n] = amode(op >> 3, op, 2);
-			break;
-		}
-		if((op & 0x1c0) == 0x180){ /* CHK */
-			a = amode(op >> 3, op, s);
-			v = rmode(a, s);
-			if((s32int)r[n] < 0 || (s32int)r[n] > (s32int)v)
-				trap(6, curpc);
-			else
-				tim += 10;
-		}
-		if((op & 0xb80) == 0x880 && (op & 0x38) >= 0x10){ /* MOVEM */
-			s = (op >> 6 & 1) + 1;
-			w = fetch16();
-			if((op & 0x38) == 0x18){
-				n = op & 7;
-				a = ra[n];
-				for(m = 0; m < 16; m++){
-					if((w & 1) != 0){
-						r[m] = rmode(a, s);
-						a += 1<<s;
-						tim += 2<<s;
-					}
-					w >>= 1;
-				}
-				ra[n] = a;
-				tim += 12;
+		if((op & 0x1c0) == 0x1c0)
+			op_lea(op);
+		else if((op & 0x1c0) == 0x180)
+			op_chk(op);
+		else if((op & 0xb80) == 0x880 && (op & 0x38) >= 0x10)
+			op_movem(op);
+		else
+			switch(op >> 8 & 0xf){
+			case 0:
+				if(s == 3)
+					op_move_from_sr(op);
+				else
+					op_negx(op);
 				break;
-			}
-			if((op & 0x38) == 0x20){
-				n = op & 7;
-				a = ra[n];
-				for(m = 0; m < 16; m++){
-					if((w & 1) != 0){
-						a -= 1<<s;
-						wmode(a, s, r[15 - m]);
-						tim += 2<<s;
-					}
-					w >>= 1;
-				}
-				ra[n] = a;
-				tim += 8;
+			case 2: op_clr(op); break;
+			case 4:
+				if(s == 3)
+					op_move_to_ccr(op);
+				else
+					op_neg(op);
 				break;
-			}
-			a = amode(op >> 3, op, s);
-			for(m = 0; m < 16; m++){
-				if((w & 1) != 0){
-					if((op & 0x400) != 0)
-						r[m] = rmode(a, s);
+			case 6:
+				if(s == 3)
+					op_move_to_sr(op);
+				else
+					op_not(op);
+				break;
+			case 8:
+				switch(s){
+				case 0: op_nbcd(op); break;
+				case 1:
+					if((op >> 3 & 7) != 0)
+						op_pea(op);
 					else
-						wmode(a, s, r[m]);
-					a += 1<<s;
-					tim += 2<<s;
+						op_swap(op);
+					break;
+				case 2: op_ext_b(op); break;
+				case 3: op_ext_w(op); break;
 				}
-				w >>= 1;
-			}
-			tim += (op & 0x400) != 0 ? 8 : 12;
-			break;
-		}
-		switch(op >> 8 & 0xf){
-		case 0:
-			if(s == 3){ /* MOVE from SR */
-				if((rS & FLAGS) != 0){
-					a = amode(op >> 3, op, 1);
-					wmode(a, 1, rS);
-					tim += a < 0 ? 6 : 8;
-				}else
-					trap(8, curpc);
 				break;
-			} /* NEGX */
-			a = amode(op >> 3, op, s);
-			m = (rS & FLAGX) != 0;
-			d = 1<<(8<<s)-1;
-			v = rmode(a, s);
-			w = -(v+m) & (d << 1) - 1;
-			rS &= ~(FLAGC|FLAGX|FLAGN|FLAGV);
-			if((w & d) != 0)
-				rS |= FLAGN;
-			if(m && w == d)
-				rS |= FLAGV;
-			if(w != 0){
-				rS |= FLAGC|FLAGX;
-				rS &= ~FLAGZ;
-			}
-			wmode(a, s, w);
-			stime(a < 0, s);
-			break;
-		case 2: /* CLR */
-			a = amode(op >> 3, op, s);
-			wmode(a, s, 0);
-			nz(0, 0);
-			stime(a < 0, s);
-			break;
-		case 4:
-			if(s == 3){ /* MOVE to CCR */
-				rS = rS & 0xff00 | rmode(amode(op >> 3, op, 1), 1);
-				tim += 12;
-				break;
-			} /* NEG */
-			a = amode(op >> 3, op, s);
-			v = -rmode(a, s);
-			nz(v, s);
-			rS = rS & ~FLAGX | ~rS << 2 & FLAGX | ~rS >> 2 & FLAGC;
-			wmode(a, s, v);
-			stime(a < 0, s);
-			break;
-		case 6:
-			if(s == 3){ /* MOVE to SR */
-				if((rS & FLAGS) != 0){
-					rS = rmode(amode(op >> 3, op, 1), 1);
-					if((rS & FLAGS) == 0){
-						v = asp;
-						asp = ra[7];
-						ra[7] = v;
-					}
-					tim += 12;
-				}else
-					trap(8, curpc);
-				break;
-			} /* NOT */
-			a = amode(op >> 3, op, s);
-			v = ~rmode(a, s);
-			nz(v, s);
-			wmode(a, s, v);
-			stime(a < 0, s);
-			break;
-		case 8:
-			n = op & 7;
-			switch(s){
-			case 0: /* NBCD */
-				a = amode(op >> 3, op, 0);
-				v = rmode(a, 0);
-				wmode(a, 0, subbcd(0, v));
-				if(a < 0)
-					tim += 8;
+			case 10:
+				if(s == 3)
+					op_tas(op);
 				else
-					tim += 6;
+					op_tst(op);
 				break;
-			case 1:
-				if((op >> 3 & 7) != 0){
-					push32(amode(op >> 3, op, 0)); /* PEA */
-					tim += 8;
-				}else{
-					nz(r[n] = r[n] >> 16 | r[n] << 16, 2); /* SWAP */
-					tim += 4;
+			case 14:
+				switch(op >> 4 & 0xf){
+				case 4: op_trap(op); break;
+				case 5:
+					if((op & 8) == 0)
+						op_link(op);
+					else
+						op_unlk(op);
+					break;
+				case 6: op_move_usp(op); break;
+				default:
+					if((op & 0xc0) == 0xc0)
+						op_jmp(op);
+					else if((op & 0x80) == 0x80)
+						op_jsr(op);
+					else
+						switch(op){
+						case 0x4e70: op_reset(op); break;
+						case 0x4e71: op_nop(op); break;
+						case 0x4e72: op_stop(op); break;
+						case 0x4e73: op_rte(op); break;
+						case 0x4e75: op_rts(op); break;
+						case 0x4e76: op_trapv(op); break;
+						case 0x4e77: op_rtr(op); break;
+						default: undef();
+						}
 				}
 				break;
-			case 2: /* EXT */
-				nz(r[n] = r[n] & 0xffff0000 | (u16int)(s8int)r[n], 1);
-				tim += 4;
+			default:
+				undef();
 				break;
-			case 3: /* EXT */
-				nz(r[n] = (s16int)r[n], 2);
-				tim += 4;
-				break;
 			}
-			break;
-		case 10:
-			if(s == 3){ /* TAS */
-				a = amode(op >> 3, op, 0);
-				v = rmode(a, 0);
-				nz(v, 0);
-				wmode(a, s, v | 0x80);
-				tim += a < 0 ? 4 : 14;
-				break;
-			} /* TST */
-			a = amode(op >> 3, op, s);
-			nz(rmode(a, s), s);
-			tim += 4;
-			break;
-		case 14:
-			v = op >> 4 & 0xf;
-			n = op & 7;
-			if(v == 4){ /* TRAP */
-				trap(0x20 | op & 0xf, pc);
-				break;
-			}else if(v == 5){
-				if((op & 8) == 0){ /* LINK */
-					push32(ra[n]);
-					ra[n] = ra[7];
-					ra[7] += (s16int)fetch16();
-					tim += 16;
-				}else{ /* UNLK */
-					ra[7] = ra[n];
-					ra[n] = pop32();
-					tim += 12;
-				}
-				break;
-			}else if(v == 6){ /* MOVE USP */
-				if((rS & FLAGS) != 0){
-					if((op & 8) != 0)
-						ra[n] = asp;
-					else
-						asp = ra[n];
-					tim += 4;
-				}else
-					trap(8, curpc);
-				break;
-			}
-			if((op & 0xc0) == 0xc0){ /* JMP */
-				pc = amode(op >> 3, op, 2);
-				tim += 4;
-				break;
-			}
-			if((op & 0xc0) == 0x80){ /* JSR */
-				a = amode(op >> 3, op, 2);
-				push32(pc);
-				pc = a;
-				tim += 12;
-				break;
-			}
-			switch(op){
-			case 0x4e70: tim += 132; break; /* RESET */
-			case 0x4e71: tim += 4; break; /* NOP */
-			case 0x4e72: /* STOP */
-				if((rS & FLAGS) != 0){
-					rS = fetch16();
-					stop = 1;
-				}else
-					trap(8, curpc);
-				tim += 4;
-				break;
-			case 0x4e73: /* RTE */
-				if((rS & FLAGS) != 0){
-					v = rS;
-					rS = pop16();
-					pc = pop32();
-					if(((v ^ rS) & FLAGS) != 0){
-						v = asp;
-						asp = ra[7];
-						ra[7] = v;
-					}
-					tim += 20;
-				}else
-					trap(8, curpc);
-				break;
-			case 0x4e75: pc = pop32(); tim += 16; break; /* RTS */
-			case 0x4e76: if((rS & FLAGV) != 0) trap(7, curpc); tim += 4; break; /* TRAPV */
-			case 0x4e77: /* RTR */
-				rS = rS & 0xff00 | pop16() & 0xff;
-				pc = pop32();
-				tim += 20;
-				break;
-			default: undef();
-			}
-			break;
-		default:
-			undef();
-		}
 		break;
 	case 5:
-		if((op & 0xf8) == 0xc8){ /* DBcc */
-			n = op & 7;
-			v = (s16int)fetch16();
-			if(!cond((op >> 8) & 0xf)){
-				if((u16int)r[n] != 0){
-					r[n]--;
-					pc = pc + v - 2;
-					tim += 10;
-				}else{
-					r[n] |= 0xffff;
-					tim += 14;
-				}
-			}else
-				tim += 12;
-			break;
-		}
-		if(s == 3){ /* Scc */
-			a = amode(op >> 3, op, 0);
-			v = cond(op >> 8 & 0xf);
-			wmode(a, 0, -v);
-			if(a < 0)
-				tim += 4 + 2 * v;
-			else
-				tim += 8;
-			break;
-		} /* ADDQ, SUBQ */
-		rS |= FLAGZ;
-		if((op & 0x38) == 0x08)
-			s = 2;
-		a = amode(op >> 3, op, s);
-		v = rmode(a, s);
-		if(n == 0)
-			n = 8;
-		if((op & 0x100) == 0)
-			v = add(v, n, 0, s);
+		if((op & 0xf8) == 0xc8)
+			op_dbcc(op);
+		else if(s == 3)
+			op_scc(op);
+		else if((op & 070) == 010)
+			op_addq_subq_a(op);
 		else
-			v = sub(v, n, 0, s);
-		rS = rS & ~FLAGX | rS << 4 & FLAGX;
-		if(a < 0)
-			tim += s == 2 || (op & 0x130) == 0x110 ? 8 : 4;
-		else
-			tim += s == 2 ? 12 : 8;
-		wmode(a, s, v);
+			op_addq_subq(op);
 		break;
-	case 6: /* BRA */
-		v = (s8int)op;
-		if(v == 0)
-			v = (s16int)fetch16();
-		else if(v == (u32int)-1)
-			v = fetch32();
-		if((op & 0xf00) == 0x100){ /* BSR */
-			push32(pc);
-			pc = curpc + 2 + v;
-			tim += 18;
-			break;
-		}
-		if(cond((op >> 8) & 0xf)){
-			pc = curpc + 2 + v;
-			tim += 10;
-		}else
-			tim += (u8int)(op + 1) <= 1 ? 12 : 8;
+	case 6:
+		op_bra(op);
 		break;
-	case 7: /* MOVEQ */
-		r[n] = (s8int)op;
-		nz(r[n], 0);
-		tim += 4;
+	case 7:
+		op_moveq(op);
 		break;
 	case 8:
-		if(s == 3){ /* DIVU, DIVS */
-			a = amode(op >> 3, op, 1);
-			v = rmode(a, 1);
-			if(v == 0){
-				trap(5, curpc);
-				break;
-			}
-			if((op & 0x100) != 0){
-				w = (s32int)r[n] % (s16int)v;
-				v = (s32int)r[n] / (s16int)v;
-				if(((s16int)w ^ (s16int)v) < 0)
-					w = -w;
-				if(v != (u32int)(s16int)v){
-					rS = rS & ~FLAGC | FLAGV;
-					break;
-				}
-				tim += 158;
-			}else{
-				w = r[n] % (u16int)v;
-				v = r[n] / (u16int)v;
-				if(v >= 0x10000){
-					rS = rS & ~FLAGC | FLAGV;
-					break;
-				}
-				tim += 140;
-			}
-			r[n] = (u16int)v | w << 16;
-			nz(v, 1);
-			break;
-		}
-		if((op & 0x1f0) == 0x100){ /* SBCD */
-			n = (op >> 9) & 7;
-			m = op & 7;
-			if((op & 8) != 0){
-				a = amode(4, n, 0);
-				v = rmode(a, 0);
-				w = rmode(amode(4, m, 0), 0);
-				v = subbcd(v, w);
-				wmode(a, 0, v);
-				tim += 18;
-			}else{
-				r[n] = r[n] & 0xffffff00 | subbcd((u8int)r[n], (u8int)r[m]);
-				tim += 6;
-			}
-			break;
-		}
-	logic: /* OR, EOR, AND */
-		a = amode(op >> 3, op, s);
-		n = (op >> 9) & 7;
-		v = rmode(a, s);
-		switch(op >> 12){
-		case 8: v |= r[n]; break;
-		case 11: v ^= r[n]; break;
-		case 12: v &= r[n]; break;
-		}
-		if((op & 0x100) == 0)
-			a = ~n;
-		wmode(a, s, v);
-		nz(v, s);
-		dtime(op, s);
+		if(s == 3)
+			op_divu_divs(op);
+		else if((op & 0x1f0) == 0x100)
+			op_sbcd(op);
+		else
+			logic(op);
 		break;
 	case 11:
-		if(s == 3){ /* CMPA */
-			s = (op >> 8 & 1) + 1;
-			a = amode(op >> 3, op, s);
-			rS |= FLAGZ;
-			sub(ra[n], rmode(a, s), 0, 2);
-			tim += 6;
-			break;
-		}
-		if((op & 0x138) == 0x108){ /* CMPM */
-			m = op & 7;
-			rS |= FLAGZ;
-			sub(rmode(amode(3, n, s), s), rmode(amode(3, m, s), s), 0, s);
-			tim += s == 2 ? 20 : 12;
-			break;
-		}
-		if((op & 0x100) == 0){ /* CMP */
-			a = amode(op >> 3, op, s);
-			rS |= FLAGZ;
-			sub(r[n], rmode(a, s), 0, s);
-			tim += s == 2 ? 6 : 4;
-			break;
-		}
-		goto logic;
+		if(s == 3)
+			op_cmpa(op);
+		else if((op & 0x138) == 0x108)
+			op_cmpm(op);
+		else if((op & 0x100) == 0)
+			op_cmp(op);
+		else
+			logic(op);
+		break;
 	case 12:
-		if(s == 3){ /* MULU, MULS */
-			a = amode(op >> 3, op, 1);
-			v = rmode(a, 1);
-			if((op & 0x100) != 0)
-				v *= (s16int)r[n];
-			else
-				v = (u16int)v * (u16int)r[n];
-			r[n] = v;
-			nz(v, 1);
-			tim += 70;
-			break;
-		}
-		if((op & 0x1f0) == 0x100){ /* ABCD */
-			n = (op >> 9) & 7;
-			m = op & 7;
-			if((op & 8) != 0){
-				a = amode(4, n, 0);
-				v = rmode(a, 0);
-				w = rmode(amode(4, m, 0), 0);
-				v = addbcd(v, w);
-				wmode(a, 0, v);
-				tim += 18;
-			}else{
-				r[n] = r[n] & 0xffffff00 | addbcd((u8int)r[n], (u8int)r[m]);
-				tim += 6;
-			}
-			break;
-		
-		}
-		if((op & 0x130) == 0x100){ /* EXG */
-			m = op & 0xf;
-			if((op & 0xc8) == 0x48)
-				n |= 8;
-			v = r[n];
-			r[n] = r[m];
-			r[m] = v;
-			tim += 6;
-			break;
-		}
-		goto logic;
+		if(s == 3)
+			op_mulu_muls(op);
+		else if((op & 0x1f0) == 0x100)
+			op_abcd(op);
+		else if((op & 0x130) == 0x100)
+			op_exg(op);
+		else
+			logic(op);
+		break;
 	case 9:
 	case 13:
-		if(s == 3){ /* ADDA, SUBA */
-			if((op & 0x100) != 0){
-				s = 2;
-				tim += 6;
-			}else{
-				s = 1;
-				tim += 8;
-			}
-			a = amode(op >> 3, op, s);
-			if((op >> 12) == 13)
-				ra[n] += rmode(a, s);
-			else
-				ra[n] -= rmode(a, s);
-			break;
-		}
-		if((op & 0x130) == 0x100){ /* ADDX, SUBX */
-			m = op & 7;
-			if((op & 8) != 0){
-				a = ra[n] -= 1<<s;
-				v = rmode(a, s);
-				w = rmode(ra[m] -= 1<<s, s);
-				tim += s == 2 ? 30 : 18;
-			}else{
-				v = r[n];
-				w = r[m];
-				a = ~n;
-				tim += s == 2 ? 8 : 4;
-			}
-			if((op >> 12) == 13)
-				v = add(v, w, (rS & FLAGX) != 0, s);
-			else
-				v = sub(v, w, (rS & FLAGX) != 0, s);
-			wmode(a, s, v);
-			rS = rS & ~FLAGX | rS << 4 & FLAGX;
-			break;
-		} /* ADD, SUB */
-		a = amode(op >> 3, op, s);
-		rS |= FLAGZ;
-		d = (op & 0x100) == 0;
-		v = rmode(a, s);
-		if((op >> 12) == 13)
-			v = add(v, r[n], 0, s);
+		if(s == 3)
+			op_adda_suba(op);
+		else if((op & 0x130) == 0x100)
+			op_addx_subx(op);
 		else
-			v = sub(d ? r[n] : v, d ? v : r[n], 0, s);
-		rS = rS & ~FLAGX | rS << 4 & FLAGX;
-		if(d)
-			a = ~n;
-		wmode(a, s, v);
-		dtime(op, s);
+			op_add_sub(op);
 		break;
-	case 14: /* shifts */
-		if(s == 3){
-			m = op >> 8 & 7;
-			n = 1;
-			s = 1;
-			a = amode(op >> 3, op, s);
-		}else{
-			a = ~(uvlong)(op & 7);
-			m = op >> 2 & 6 | op >> 8 & 1;
-			n = (op >> 9) & 7;
-			if((op & 0x20) != 0)
-				n = r[n] & 63;
-			else if(n == 0)
-				n = 8;
-		}
-		wmode(a, s, rot(rmode(a, s), m, n, s));
+	case 14:
+		shifts(op);
 		break;
 	case 10:
 		trap(10, curpc);