shithub: riscv

Download patch

ref: 93cfa1be72e18029d242ca462da3484488d1c6b3
parent: ea480e74bbd559e448c1c8afc3f2abe6888351a4
author: aiju <devnull@localhost>
date: Sun May 25 19:14:23 EDT 2014

added crude version of games/md

diff: cannot open b/sys/src/games/md//null: file does not exist: 'b/sys/src/games/md//null'
--- /dev/null
+++ b/sys/src/games/md/cpu.c
@@ -1,0 +1,1027 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "dat.h"
+#include "fns.h"
+
+enum {
+	FLAGS = 1<<13,
+	FLAGX = 16,
+	FLAGN = 8,
+	FLAGZ = 4,
+	FLAGV = 2,
+	FLAGC = 1,
+};
+
+u32int r[16], pc, curpc;
+u32int asp, irq;
+extern u32int irql[8];
+u32int irqla[8];
+u16int rS;
+static u32int op;
+int trace;
+#define ra (r+8)
+
+static void
+undef(void)
+{
+	sysfatal("undefined opcode %#o at pc=%#.6x", op, curpc);
+}
+
+static u16int
+fetch16(void)
+{
+	u16int v;
+	
+	v = memread(pc);
+	pc += 2;
+	return v;
+}
+
+static u32int
+fetch32(void)
+{
+	u32int v;
+	
+	v = fetch16() << 16;
+	return v | fetch16();
+}
+
+static void
+push16(u16int u)
+{
+	ra[7] -= 2;
+	memwrite(ra[7], u, -1);
+}
+
+static u16int
+pop16(void)
+{
+	u16int v;
+	
+	v = memread(ra[7]);
+	ra[7] += 2;
+	return v;
+}
+
+static void
+push32(u32int u)
+{
+	ra[7] -= 4;
+	memwrite(ra[7], u >> 16, -1);
+	memwrite(ra[7] + 2, u, -1);
+}
+
+static u32int
+pop32(void)
+{
+	u32int v;
+	v = memread(ra[7]) << 16;
+	v |= memread(ra[7] + 2);
+	ra[7] += 4;
+	return v;
+}
+
+static vlong
+amode(int m, int n, int s)
+{
+	u16int w;
+	u32int v;
+	
+	m &= 7;
+	n &= 7;
+	s &= 3;
+	if(n == 7 && s == 0)
+		s++;
+	switch(m){
+	case 0:
+		return ~n;
+	case 1:
+		return ~(n+8);
+	case 2:
+		return ra[n];
+	case 3:
+		v = ra[n];
+		ra[n] += 1<<s;
+		return v;
+	case 4:
+		return ra[n] -= 1<<s;
+	case 5:
+		return (u32int)(ra[n] + (s16int)fetch16());
+	case 6:
+		w = fetch16();
+		v = r[w >> 12];
+		if((w & 1<<11) == 0)
+			v = (s16int)v;
+		return (u32int)(ra[n] + v + (s8int)w);
+	case 7:
+		switch(n){
+		case 0:
+			return (u32int)(s16int)fetch16();
+		case 1:
+			return fetch32();
+		case 2:
+			v = fetch16();
+			return (u32int)(pc + (s16int)v - 2);
+		case 3:
+			w = fetch16();
+			v = r[w >> 12];
+			if((v & 1<<11) == 0)
+				v = (s16int)v;
+			return (u32int)(pc + v + (s8int)w - 2);
+		case 4:
+			v = pc;
+			pc += 1<<s;
+			if(s == 0)
+				v = pc++;
+			return v;
+		default:
+			undef();
+		}
+	default:
+		undef();
+	}
+	return 0;
+}
+
+static u32int
+rmode(vlong a, int s)
+{
+	u32int v;
+
+	if(a >= 0){
+		switch(s & 3){
+		case 0:
+			v = memread(a);
+			if((a & 1) == 0)
+				v >>= 8;
+			return (s8int) v;
+		default:
+			return (s16int) memread(a);
+		case 2:
+			v = memread(a) << 16;
+			return v | memread(a + 2);
+		}
+	}
+	v = r[~a];
+	switch(s & 3){
+	case 0: return (s8int) v;
+	case 1: return (s16int) v;
+	default: return v;
+	}
+}
+
+static void
+wmode(vlong a, int s, u32int v)
+{
+	int n;
+
+	if(a >= 0){
+		switch(s & 3){
+		case 0:
+			memwrite(a, (u8int)v | (u8int)v << 8, (a & 1) != 0 ? 0xff : 0xff00);
+			return;
+		default:
+			memwrite(a, v, -1);
+			return;
+		case 2:
+			memwrite(a, v >> 16, -1);
+			memwrite(a + 2, v, -1);
+			return;
+		}
+	}
+	n = ~a;
+	if(n < 8){
+		switch(s){
+		case 0: r[n] = r[n] & 0xffffff00 | v & 0xff; break;
+		case 1: r[n] = r[n] & 0xffff0000 | v & 0xffff; break;
+		default: r[n] = v;
+		}
+	}else{
+		if(s == 1)
+			v = (s16int) v;
+		r[n] = v;
+	}
+}
+
+static void
+nz(u32int v, int s)
+{
+	switch(s){
+	case 0: v = (s8int) v; break;
+	case 1: v = (s16int) v; break;
+	}
+	rS &= ~(FLAGC|FLAGN|FLAGV|FLAGZ);
+	if(v == 0)
+		rS |= FLAGZ;
+	if((s32int)v < 0)
+		rS |= FLAGN;
+}
+
+static u32int
+add(u32int u, u32int w, int c, int s)
+{
+	u64int v;
+
+	rS &= ~(FLAGN|FLAGV|FLAGC);
+	switch(s){
+	case 0:
+		v = (u8int)w + (u8int)u + c;
+		if(v >= 0x100)
+			rS |= FLAGC;
+		if((v & 0x80) != 0)
+			rS |= FLAGN;
+		if((~(w ^ u) & (v ^ u) & 0x80) != 0)
+			rS |= FLAGV;
+		if((u8int)v != 0)
+			rS &= ~FLAGZ;
+		break;
+	case 1:
+		v = (u16int)w + (u16int)u + c;
+		if(v >= 0x10000)
+			rS |= FLAGC;
+		if((v & 0x8000) != 0)
+			rS |= FLAGN;
+		if((~(w ^ u) & (v ^ u) & 0x8000) != 0)
+			rS |= FLAGV;
+		if((u16int)v != 0)
+			rS &= ~FLAGZ;
+		break;
+	default:
+		v = w + u + c;
+		if((v >> 32) != 0)
+			rS |= FLAGC;
+		if((v >> 31) != 0)
+			rS |= FLAGV;
+		if((~(w ^ u) & (v ^ u) & (1<<31)) != 0)
+			rS |= FLAGV;
+		if((u32int)v != 0)
+			rS &= ~FLAGZ;
+		break;
+	}
+	return v;
+} 
+
+static u32int
+sub(u32int u, u32int w, int c, int s)
+{
+	u64int v;
+
+	rS &= ~(FLAGN|FLAGV|FLAGC);
+	switch(s){
+	case 0:
+		v = (u8int)u - (u8int)w - c;
+		if(v >= 0x100)
+			rS |= FLAGC;
+		if((v & 0x80) != 0)
+			rS |= FLAGN;
+		if(((w ^ u) & (v ^ u) & 0x80) != 0)
+			rS |= FLAGV;
+		if((u8int)v != 0)
+			rS &= ~FLAGZ;
+		break;
+	case 1:
+		v = (u16int)u - (u16int)w - c;
+		if(v >= 0x10000)
+			rS |= FLAGC;
+		if((v & 0x8000) != 0)
+			rS |= FLAGN;
+		if(((w ^ u) & (v ^ u) & 0x8000) != 0)
+			rS |= FLAGV;
+		if((u16int)v != 0)
+			rS &= ~FLAGZ;
+		break;
+	default:
+		v = (u64int)u - w - c;
+		if((v >> 32) != 0)
+			rS |= FLAGC;
+		if((v & 0x80000000) != 0)
+			rS |= FLAGN;
+		if(((w ^ u) & (v ^ u) & (1<<31)) != 0)
+			rS |= FLAGV;
+		if((u32int)v != 0)
+			rS &= ~FLAGZ;
+		break;
+	}
+	return v;
+}
+
+static int
+cond(int n)
+{
+	switch(n){
+	case 0: return 1; break;
+	default: return 0; break;
+	case 2: return (rS & (FLAGC|FLAGZ)) == 0; break;
+	case 3: return (rS & (FLAGC|FLAGZ)) != 0; break;
+	case 4: return (rS & FLAGC) == 0; break;
+	case 5: return (rS & FLAGC) != 0; break;
+	case 6: return (rS & FLAGZ) == 0; break;
+	case 7: return (rS & FLAGZ) != 0; break;
+	case 8: return (rS & FLAGV) == 0; break;
+	case 9: return (rS & FLAGV) != 0; break;
+	case 10: return (rS & FLAGN) == 0; break;
+	case 11: return (rS & FLAGN) != 0; break;
+	case 12: return ((rS ^ (rS << 2)) & FLAGN) == 0; break;
+	case 13: return ((rS ^ (rS << 2)) & FLAGN) != 0; break;
+	case 14: return ((rS ^ (rS << 2)) & FLAGN) == 0 && (rS & FLAGZ) == 0; break;
+	case 15: return ((rS ^ (rS << 2)) & FLAGN) != 0 || (rS & FLAGZ) != 0; break;
+	}
+}
+
+static u32int
+rot(u32int v, int m, int n, int s)
+{
+	int l, ll, x, vf;
+	u32int msb;
+
+	msb = 1 << ((8 << s) - 1);
+	v &= (msb << 1) - 1;
+	if(m == 0)
+		x = (v & msb) != 0;
+	else
+		x = 0;
+	if((m & 6) == 4)
+		ll = l = (rS & FLAGX) != 0;
+	else
+		ll = l = 0;
+	vf = 0;
+	while(n--){
+		if((m & 1) == 0){
+			l = v & 1;
+			v >>= 1;
+		}else{
+			l = (v & msb) != 0;
+			v <<= 1;
+		}
+		rS = rS & ~FLAGX | l << 4;
+		if(m >= 6)
+			x = l;
+		else if(m >= 4){
+			x = ll;
+			ll = l;
+		}
+		if((m & 1) == 0){
+			if(x != 0)
+				v |= msb;
+		}else
+			v |= x;
+		vf |= x ^ (v & msb) != 0;
+	}
+	nz(v, s);
+	rS |= l;
+	if(m <= 1 && vf)
+		rS |= FLAGV;
+	return v;
+}
+
+static u8int
+addbcd(u8int a, u8int b)
+{
+	int r;
+	
+	r = (a & 0xf) + (b & 0xf) + (rS & FLAGX >> 4);
+	if(r > 0x09) r += 0x06;
+	if(r > 0x1f) r -= 0x10;
+	r += (a & 0xf0) + (b & 0xf0);
+	if((u8int)r != 0)
+		rS &= ~FLAGZ;
+	if(r > 0xff)
+		rS |= FLAGC|FLAGX;
+	else
+		rS &= ~(FLAGC|FLAGX);
+	return r;
+}
+
+static u8int
+subbcd(u8int a, u8int b)
+{
+	int x;
+	
+	x = (a & 0xf) + (~b & 0xf) + !(rS & FLAGX);
+	if(x < 0x10) x -= 0x06;
+	if(x < 0) x += 0x10;
+	x += (a & 0xf0) + (~b & 0xf0);
+	if((u8int)x != 0)
+		rS &= ~FLAGZ;
+	if(x <= 0xff)
+		rS |= FLAGC|FLAGX;
+	else
+		rS &= ~(FLAGC|FLAGX);
+	return x;
+}
+
+static void
+trap(int n, u32int pcv)
+{
+	int l, v;
+	u32int sr, t;
+	
+	sr = rS;
+	if(n < 0){
+		for(l = 7; l >= ((rS >> 8) & 7); l--)
+			if((irql[l] & irq) != 0)
+				break;
+		v = intack(l);
+		rS = rS & ~0x700 | l << 8;
+		irq = 0;
+	}else
+		v = n;
+	if((rS & FLAGS) == 0){
+		t = asp;
+		asp = ra[7];
+		ra[7] = t;
+	}
+	rS |= FLAGS;
+	push32(pcv);
+	push16(sr);
+	pc = memread(v * 4) << 16;
+	pc |= memread(v * 4 + 2);
+}
+
+void
+cpureset(void)
+{
+	u32int v;
+	int i;
+
+	ra[7] = memread(0) << 16 | memread(2);
+	pc = memread(4) << 16 | memread(6);
+	rS = 0x2700;
+	for(i = 7, v = 0; i >= 0; i--)
+		irqla[i] = v |= irql[i];
+}
+
+void
+step(void)
+{
+	u32int v, w;
+	vlong a;
+	int s;
+	int n, m, d;
+	static int cnt;
+
+	if(0){
+		trace++;
+		print("%x\n", curpc);
+	}
+	curpc = pc;
+	if(irq && (irqla[(rS >> 8) & 7] & irq) != 0){
+		trap(-1, curpc);
+		return;
+	}
+	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[1], ra[7]);
+	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;
+			}
+			break;
+		}
+		if((op & 0x13f) == 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;
+				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);
+				r[n] = v;
+				break;
+			case 2:
+				wmode(a, 0, r[n] >> 8);
+				wmode(a + 2, 0, r[n]);
+				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]);
+				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; break;
+			case 3: v |= w; break;
+			}
+			if(s != 0)
+				wmode(a, n, v);
+			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(n != 6)
+			wmode(a, s, v);
+		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);
+		break;
+	case 4:
+		if((op & 0x1c0) == 0x1c0){ /* LEA */
+			ra[n] = amode(op >> 3, op, 2);
+			break;
+		}
+		if((op & 0x1c0) == 0x180) /* CHK */
+			undef();
+		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;
+					}
+					w >>= 1;
+				}
+				ra[n] = a;
+				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]);
+					}
+					w >>= 1;
+				}
+				ra[n] = a;
+				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);
+					else
+						wmode(a, s, r[m]);
+					a += 1<<s;
+				}
+				w >>= 1;
+			}
+			break;
+		}
+		switch(op >> 8 & 0xf){
+		case 0:
+			if(s == 3){ /* MOVE from SR */
+				if((rS & FLAGS) != 0)
+					wmode(amode(op >> 3, op, 1), 1, rS);
+				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, v);
+			break;
+		case 2: /* CLR */
+			wmode(amode(op >> 3, op, s), s, 0);
+			nz(0, 0);
+			break;
+		case 4:
+			if(s == 3){ /* MOVE to CCR */
+				rS = rS & 0xff00 | rmode(amode(op >> 3, op, 1), 1);
+				break;
+			} /* NEG */
+			a = amode(op >> 3, op, s);
+			v = -rmode(a, s);
+			nz(v, s);
+			wmode(a, s, v);
+			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;
+					}
+				}else
+					trap(8, curpc);
+				break;
+			} /* NOT */
+			a = amode(op >> 3, op, s);
+			v = ~rmode(a, s);
+			nz(v, s);
+			wmode(a, s, v);
+			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));
+				break;
+			case 1:
+				if((op >> 3 & 7) != 0)
+					push32(amode(op >> 3, op, 0)); /* PEA */
+				else
+					nz(r[n] = r[n] >> 16 | r[n] << 16, 2); /* SWAP */
+				break;
+			case 2: /* EXT */
+				nz(r[n] = r[n] & 0xffff0000 | (u16int)(s8int)r[n], 1);
+				break;
+			case 3: /* EXT */
+				nz(r[n] = (s16int)r[n], 2);
+				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);
+				break;
+			} /* TST */
+			a = amode(op >> 3, op, s);
+			nz(rmode(a, s), s);
+			break;
+		case 14:
+			v = op >> 4 & 0xf;
+			n = op & 7;
+			if(v == 4){ /* TRAP */
+				trap(op & 0xf, curpc);
+				break;
+			}else if(v == 5){
+				if((op & 8) == 0){ /* LINK */
+					push32(ra[n]);
+					ra[n] = ra[7];
+					ra[7] += (s16int)fetch16();
+				}else{ /* UNLK */
+					ra[7] = ra[n];
+					ra[n] = pop32();
+				}
+				break;
+			}else if(v == 6){ /* MOVE USP */
+				if((rS & FLAGS) != 0){
+					if((op & 8) != 0)
+						ra[n] = asp;
+					else
+						asp = ra[n];
+				}else
+					trap(8, curpc);
+				break;
+			}
+			if((op & 0xc0) == 0xc0){ /* JMP */
+				pc = amode(op >> 3, op, 2);
+				break;
+			}
+			if((op & 0xc0) == 0x80){ /* JSR */
+				a = amode(op >> 3, op, 2);
+				push32(pc);
+				pc = a;
+				break;
+			}
+			switch(op){
+			case 0x4e70: break; /* RESET */
+			case 0x4e71: break; /* NOP */
+			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;
+					}
+				}else
+					trap(8, curpc);
+				break;
+			case 0x4e75: pc = pop32(); break; /* RTS */
+			case 0x4e76: if((rS & FLAGV) != 0) trap(7, curpc); break; /* TRAPV */
+			case 0x4e77: /* RTR */
+				rS = rS & 0xff00 | fetch16() & 0xff;
+				pc = pop32();
+				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;
+				}else
+					r[n] |= 0xffff;
+			}
+			break;
+		}
+		if(s == 3){ /* Scc */
+			a = amode(op >> 3, op, 0);
+			wmode(a, s, -cond((op >> 8) & 0xf));
+			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);
+		else
+			v = sub(v, n, 0, s);
+		wmode(a, s, v);
+		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;
+			break;
+		}
+		if(cond((op >> 8) & 0xf))
+			pc = curpc + 2 + v;
+		break;
+	case 7: /* MOVEQ */
+		r[n] = (s8int)op;
+		nz(r[n], 0);
+		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;
+				}
+			}else{
+				w = r[n] % (u16int)v;
+				v = r[n] / (u16int)v;
+				if(v >= 0x10000){
+					rS = rS & ~FLAGC | FLAGV;
+					break;
+				}
+			}
+			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(5, n, 0), 0);
+				v = subbcd(v, w);
+				wmode(a, 0, v);
+			}else
+				r[n] = r[n] & 0xffffff00 | subbcd((u8int)r[n], (u8int)r[m]);
+			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);
+		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);
+			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);
+			break;
+		}
+		if((op & 0x100) == 0){ /* CMP */
+			a = amode(op >> 3, op, s);
+			rS |= FLAGZ;
+			sub(r[n], rmode(a, s), 0, s);
+			break;
+		}
+		goto logic;
+	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);
+			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(5, n, 0), 0);
+				v = addbcd(v, w);
+				wmode(a, 0, v);
+			}else
+				r[n] = r[n] & 0xffffff00 | addbcd((u8int)r[n], (u8int)r[m]);
+			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;
+			break;
+		}
+		goto logic;
+	case 9:
+	case 13:
+		if(s == 3){ /* ADDA, SUBA */
+			s = 1;
+			if((op & 0x100) != 0)
+				s++;
+			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);
+			}else{
+				v = r[n];
+				w = r[m];
+				a = ~n;
+			}
+			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 & FLAGC << 4;
+			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);
+		else
+			v = sub(d ? r[n] : v, d ? v : r[n], 0, s);
+		rS = rS & ~FLAGX | rS & FLAGC << 4;
+		if(d)
+			a = ~n;
+		wmode(a, s, v);
+		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));
+		break;
+	case 10:
+		trap(10, curpc);
+		break;
+	case 15:
+		trap(11, curpc);
+		break;
+	default:
+		undef();
+	}
+}
--- /dev/null
+++ b/sys/src/games/md/dat.h
@@ -1,0 +1,65 @@
+typedef signed char s8int;
+typedef signed short s16int;
+typedef signed long s32int;
+
+extern u32int curpc, irq;
+
+extern u8int reg[32];
+extern u8int dma;
+
+extern u8int z80bus;
+
+extern u16int ram[32768];
+extern u16int *prg;
+extern int nprg;
+
+extern int keys, scale;
+
+extern u16int vram[32768], vsram[40];
+extern u32int cramc[64];
+extern u16int vdpstat;
+extern int vdpx, vdpy;
+
+enum {
+	MODE1   = 0x00,
+	MODE2   = 0x01,
+	PANT    = 0x02,
+	PWNT    = 0x03,
+	PBNT    = 0x04,
+	SPRTAB  = 0x05,
+	BGCOL   = 0x07,
+	HORCTR  = 0x0a,
+	MODE3   = 0x0b,
+	MODE4   = 0x0c,
+	HORSCR  = 0x0d,
+	AUTOINC = 0x0f,
+	PLSIZ   = 0x10,
+	DMACL   = 0x13,
+	DMACH   = 0x14,
+	DMASRC0 = 0x15,
+	DMASRC1 = 0x16,
+	DMASRC2 = 0x17,
+
+	IE0 = 0x20,
+	IE1 = 0x10,
+	DMAEN = 0x10,
+	
+	WIDE = 0x01,
+	
+	STATDMA = 0x02,
+	STATHBL = 0x04,
+	STATVBL = 0x08,
+	STATFR  = 0x10,
+	STATCOLL= 0x20,
+	STATOVR = 0x40,
+	STATINT = 0x80,
+};
+
+enum {
+	BUSREQ = 1,
+	BUSACK = 2,
+	RESET = 4,
+	
+	INTVBL = 1,
+	INTHOR = 2,
+};
--- /dev/null
+++ b/sys/src/games/md/fns.h
@@ -1,0 +1,12 @@
+u16int memread(u32int);
+void memwrite(u32int, u16int, u16int);
+void cpureset(void);
+void step(void);
+int z80step(void);
+u8int z80read(u16int);
+void z80write(u16int, u8int);
+int intack(int);
+void vdpstep(void);
+void flush(void);
+void dmastep(void);
+void vdpmode(void);
--- /dev/null
+++ b/sys/src/games/md/md.c
@@ -1,0 +1,200 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <keyboard.h>
+#include <mouse.h>
+#include "dat.h"
+#include "fns.h"
+
+u16int *prg;
+int nprg;
+
+int keys;
+
+int scale, paused;
+QLock pauselock;
+Mousectl *mc;
+Rectangle picr;
+Image *tmp, *bg;
+
+void
+loadrom(char *file)
+{
+	static uchar hdr[512], buf[4096];
+	u32int v;
+	u16int *p;
+	int fd, rc, i;
+	
+	fd = open(file, OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+	if(readn(fd, hdr, 512) < 512)
+		sysfatal("read: %r");
+	if(memcmp(hdr + 0x100, "SEGA MEGA DRIVE ", 16) != 0 && memcmp(hdr + 0x100, "SEGA GENESIS    ", 16) != 0)
+		sysfatal("invalid rom");
+	v = hdr[0x1a0] << 24 | hdr[0x1a1] << 16 | hdr[0x1a2] << 8 | hdr[0x1a3];
+	if(v != 0)
+		sysfatal("rom starts at nonzero address");
+	v = hdr[0x1a4] << 24 | hdr[0x1a5] << 16 | hdr[0x1a6] << 8 | hdr[0x1a7];
+	nprg = v = v+2 & ~1;
+	if(nprg == 0)
+		sysfatal("invalid rom");
+	p = prg = malloc(v);
+	if(prg == nil)
+		sysfatal("malloc: %r");
+	seek(fd, 0, 0);
+	while(v != 0){
+		rc = readn(fd, buf, sizeof buf);
+		if(rc == 0)
+			break;
+		if(rc < 0)
+			sysfatal("read: %r");
+		if(rc > v)
+			rc = v;
+		for(i = 0; i < rc; i += 2)
+			*p++ = buf[i] << 8 | buf[i+1];
+		v -= rc;
+	}
+	close(fd);
+}
+
+void
+screeninit(void)
+{
+	Point p;
+
+	originwindow(screen, Pt(0, 0), screen->r.min);
+	p = divpt(addpt(screen->r.min, screen->r.max), 2);
+	picr = (Rectangle){subpt(p, Pt(scale * 160, scale * 112)), addpt(p, Pt(scale * 160, scale * 112))};
+	tmp = allocimage(display, Rect(0, 0, scale * 320, scale > 1 ? 1 : scale * 224), XRGB32, scale > 1, 0);
+	bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
+	draw(screen, screen->r, bg, nil, ZP);	
+}
+
+void
+keyproc(void *)
+{
+	int fd, k;
+	static char buf[256];
+	char *s;
+	Rune r;
+
+	fd = open("/dev/kbd", OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+	for(;;){
+		if(read(fd, buf, sizeof(buf) - 1) <= 0)
+			sysfatal("read /dev/kbd: %r");
+		if(buf[0] == 'c'){
+			if(utfrune(buf, Kdel)){
+				close(fd);
+				threadexitsall(nil);
+			}
+		}
+		if(buf[0] != 'k' && buf[0] != 'K')
+			continue;
+		s = buf + 1;
+		k = 0;
+		while(*s != 0){
+			s += chartorune(&r, s);
+			switch(r){
+			case Kdel: close(fd); threadexitsall(nil);
+			case 'c':	k |= 0x0020; break;
+			case 'x':	k |= 0x0010; break;
+			case 'z':	k |= 0x1000; break;
+			case 10:	k |= 0x2000; break;
+			case Kup:	k |= 0x0101; break;
+			case Kdown:	k |= 0x0202; break;
+			case Kleft:	k |= 0x0004; break;
+			case Kright:	k |= 0x0008; break;
+			case Kesc:
+				if(paused)
+					qunlock(&pauselock);
+				else
+					qlock(&pauselock);
+				paused = !paused;
+				break;
+			}
+		}
+		keys = ~k;
+	}
+}
+
+void
+threadmain(int argc, char **argv)
+{
+	scale = 1;
+	ARGBEGIN{
+	case '2':
+		scale = 2;
+		break;
+	case '3':
+		scale = 3;
+		break;
+	default:
+		;
+	} ARGEND;
+	
+	if(argc != 1){
+		fprint(2, "usage: %s rom", argv0);
+		threadexitsall("usage");
+	}
+	loadrom(*argv);
+	if(initdraw(nil, nil, nil) < 0)
+		sysfatal("initdraw: %r");
+	proccreate(keyproc, nil, 8192);
+	mc = initmouse(nil, screen);
+	if(mc == nil)
+		sysfatal("initmouse: %r");
+	screeninit();
+	cpureset();
+	vdpmode();
+	for(;;){
+		if(paused != 0){
+			qlock(&pauselock);
+			qunlock(&pauselock);
+		}
+		if(dma != 1)
+			step();
+		if(dma != 0)
+			dmastep();
+		z80step();
+		vdpstep();
+	}
+}
+
+void
+flush(void)
+{
+	extern uchar pic[320*224*2*3*3];
+	Mouse m;
+	Rectangle r;
+	uchar *s;
+	int w;
+
+
+	if(nbrecvul(mc->resizec) > 0){
+		if(getwindow(display, Refnone) < 0)
+			sysfatal("resize failed: %r");
+		screeninit();
+	}
+	while(nbrecv(mc->c, &m) > 0)
+		;
+	if(scale == 1){
+		loadimage(tmp, tmp->r, pic, 320*224*4);
+		draw(screen, picr, tmp, nil, ZP);
+	}else{
+		s = pic;
+		r = picr;
+		w = 320*4*scale;
+		while(r.min.y < picr.max.y){
+			loadimage(tmp, tmp->r, s, w);
+			s += w;
+			r.max.y = r.min.y+scale;
+			draw(screen, r, tmp, nil, ZP);
+			r.min.y = r.max.y;
+		}
+	}
+	flushimage(display, 1);
+}
--- /dev/null
+++ b/sys/src/games/md/mem.c
@@ -1,0 +1,345 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "dat.h"
+#include "fns.h"
+
+u16int ram[32768], vram[32768];
+u16int cram[64], vsram[40];
+u32int cramc[64];
+u8int zram[8192];
+u8int reg[32];
+u8int ctl[15];
+
+u8int dma;
+u8int vdplatch;
+u16int vdpaddr, vdpdata;
+
+u8int z80bus = RESET;
+u16int z80bank;
+
+u8int
+regread(u16int a)
+{
+	u16int v;
+
+	switch(a | 1){
+	case 0x0001: return 0xa0;
+	case 0x0003:
+		v = keys;
+		if((ctl[0] & 0x40) == 0)
+			v >>= 8;
+		return ctl[0] & 0xc0 | v & 0x3f;
+	case 0x0005:
+		return ctl[1] & 0xc0 | 0x3f;
+	case 0x0007:
+	case 0x0009: case 0x000b: case 0x000d:
+		return ctl[a-3>>1];
+	case 0x1101: return (~z80bus & BUSACK) << 7;
+	}
+	sysfatal("read from 0xa1%.4ux (pc=%#.6ux)", a, curpc);
+	return 0;
+}
+
+void
+regwrite(u16int a, u16int v)
+{
+	switch(a | 1){
+	case 0x0003: case 0x0005: case 0x0007:
+	case 0x0009: case 0x000b: case 0x000d:
+		ctl[a-3>>1] = v;
+		return;
+	case 0x1101:
+		z80bus = z80bus & ~BUSREQ | v >> 8 & BUSREQ;
+		return;
+	case 0x1201:
+		if((v & 1<<8) == 0){
+			z80bus |= RESET;
+			z80bus &= ~BUSACK;
+		}else
+			z80bus &= ~RESET;
+		return;
+	}
+	sysfatal("write to 0xa1%.4x", a);
+}
+
+void
+vdpwrite(u16int v)
+{
+	u8int a;
+
+	if((vdplatch & 0x80) == 0){
+		if((v & 0xc000) == 0x8000){
+			a = v >> 8 & 0x1f;
+			reg[a] = v & 0xff;
+			if(a == 0x0c)
+				vdpmode();
+			vdplatch = 0;
+			return;
+		}
+		vdplatch = vdplatch & 0xfc | v >> 14 | 0x80;
+		vdpaddr = vdpaddr & 0xc000 | v & 0x3fff;
+	}else{
+		vdplatch = vdplatch & 0x03 | v >> 2 & 0x1c;
+		vdpaddr = vdpaddr & 0x3fff | v << 14 & 0xc000;
+		if((v & 0x80) != 0 && (reg[MODE2] & DMAEN) != 0){
+			dma = reg[23] >> 6 & 3;
+			if(dma == 0)
+				dma++;
+		}
+	}
+}
+
+void
+cramwrite(u16int a, u16int v)
+{
+	u32int w;
+
+	cram[a/2] = v;
+	w = v << 12 & 0xe00000 | v << 8 & 0xe000 | v << 4 & 0xe0;
+	cramc[a/2] = w;
+}
+
+u16int
+memread(u32int a)
+{
+	u16int v;
+
+	switch(a >> 21 & 7){
+	case 0: case 1: return prg[(a % nprg) / 2];
+	case 5:
+		switch(a >> 16 & 0xff){
+		case 0xa0:
+			if((z80bus & BUSACK) != 0)
+				v = z80read(a & 0x7fff);
+			else
+				v = 0;
+			return v << 8 | v;
+		case 0xa1:
+			v = regread(a);
+			return v << 8 | v;
+		}
+		goto invalid;
+	case 6:
+		if((a & 0xe700e0) != 0xc00000)
+			goto invalid;
+		switch(a & 30){
+		case 0: case 2:
+			vdplatch &= 0x7f;
+			switch(vdplatch & 0xf){
+			case 0:
+				v = vram[vdpaddr/2];
+				vdpaddr += reg[AUTOINC];
+				break;
+			case 4:
+				v = vdpaddr & 0x7f;
+				if(v < 80)
+					v = vsram[v / 2];
+				else
+					v = 0;
+				vdpaddr = (vdpaddr + reg[AUTOINC]) & 0x7f;
+				break;
+			case 8:
+				v = cram[(vdpaddr & 0x7f) / 2];
+				vdpaddr = (vdpaddr + reg[AUTOINC]) & 0x7f;
+				break;
+			default: v = 0;
+			}
+			return v;
+		case 4: case 6:
+			vdplatch &= 0x7f;
+			v = vdpstat;
+			if(dma != 0 && dma != 2)
+				v |= STATDMA;
+			if(vdpx >= 0xe4 || vdpx < 0x08)
+				v |= STATHBL;
+			return v;
+		default:
+			goto invalid;
+		}
+	case 7: return ram[((u16int)a) / 2];
+	default:
+	invalid:
+		sysfatal("read from %#.6ux (pc=%#.6ux)", a, curpc);
+		return 0;
+	}
+}
+
+void
+memwrite(u32int a, u16int v, u16int m)
+{
+	u16int *p;
+	u16int w;
+
+	switch((a >> 21) & 7){
+	case 5:
+		switch(a >> 16 & 0xff){
+		case 0xa0:
+			if((z80bus & BUSACK) != 0)
+				z80write(a & 0x7fff, v >> 8);
+			return;
+		case 0xa1:
+			regwrite(a, v >> 8);
+			return;
+		default:
+			goto invalid;
+		}
+	case 6:
+		if((a & 0xe700e0) != 0xc00000)
+			goto invalid;
+		switch(a & 30){
+		case 0: case 2:
+			if(dma == 2){
+				dma = 4;
+				vdpdata = v >> 8;
+				p = &vram[vdpaddr / 2];
+				if((vdpaddr & 1) != 0)
+					*p = *p & 0xff | v << 8;
+				else
+					*p = *p & 0xff00 | v & 0xff;
+				return;
+			}
+			vdplatch &= 0x7f;
+			switch(vdplatch & 0xf){
+			case 1:
+				if((vdpaddr & 1) != 0)
+					v = v << 8 | v >> 8;
+				p = &vram[vdpaddr / 2];
+				*p = *p & ~m | v & m;
+				vdpaddr += reg[AUTOINC];
+				return;
+			case 3:
+				cramwrite(vdpaddr & 0x7f, v);
+				vdpaddr = (vdpaddr + reg[AUTOINC]) & 0x7f;
+				return;
+			case 5:
+				w = vdpaddr & 0x7f;
+				if(w < 80)
+					vsram[w / 2] = v;
+				vdpaddr = (vdpaddr + reg[AUTOINC]) & 0x7f;
+				return;
+			default:
+				return;
+			}
+		case 4: case 6:
+			vdpwrite(v);
+			return;
+		case 16: case 18: case 20: case 22:
+			return;
+		default:
+			goto invalid;
+		}
+	case 7:
+		p = &ram[((u16int)a) / 2];
+		*p = *p & ~m | v & m;
+		break;
+	default:
+	invalid:
+		sysfatal("write to %#.6x (pc=%#.6x)", a, curpc);
+	}
+}
+
+void
+dmastep(void)
+{
+	u16int v, *p;
+	u32int a;
+	
+	switch(dma){
+	case 1:
+		a = reg[DMASRC0] << 1 | reg[DMASRC1] << 9 | reg[DMASRC2] << 17;
+		v = memread(a);
+		if(++reg[DMASRC0] == 0)
+			reg[DMASRC1]++;
+		switch(vdplatch & 0x7){
+		case 1:
+			if((vdpaddr & 1) != 0)
+				v = v >> 8 | v << 8;
+			vram[vdpaddr / 2] = v;
+			break;
+		case 3:
+			if(vdpaddr > 0x7f)
+				dma = 0;
+			else
+				cramwrite(vdpaddr, v);
+			break;
+		case 5:
+			if(vdpaddr < 80)
+				vsram[vdpaddr / 2] = v;
+			break;
+		}
+		break;
+	case 2:
+		return;
+	case 3:
+		a = reg[DMASRC0] | reg[DMASRC1] << 8;
+		v = vram[a / 2];
+		if((a & 1) == 0)
+			v = v >> 8;
+		if(++reg[DMASRC0] == 0)
+			reg[DMASRC1]++;
+		p = &vram[vdpaddr / 2];
+		if((vdpaddr & 1) != 0)
+			*p = *p & 0xff00 | v & 0xff;
+		else
+			*p = *p & 0xff | v << 8;
+		break;
+	case 4:
+		p = &vram[vdpaddr / 2];
+		if((vdpaddr & 1) == 0)
+			*p = *p & 0xff00 | vdpdata;
+		else
+			*p = *p & 0xff | vdpdata << 8;
+		break;
+	}
+	vdpaddr += reg[AUTOINC];
+	if(--reg[DMACL] == 0 && reg[DMACH]-- == 0)
+		dma = 0;
+}
+
+u8int
+z80read(u16int a)
+{
+	switch(a >> 13){
+	case 0:
+	case 1:
+		return zram[a & 0x1fff];
+	case 2:
+	case 3:
+		sysfatal("z80 read from %#.4x\n", a);
+	default:
+		return memread(z80bank << 15 | a & 0x7fff);
+	}
+}
+
+void
+z80write(u16int a, u8int v)
+{
+	switch(a >> 13){
+	case 0:
+	case 1:
+		zram[a & 0x1fff] = v;
+		return;
+	case 2:
+	case 3:
+		sysfatal("z80 write to %#.4x\n", a);
+	default:
+		memwrite(z80bank << 15 | a & 0x7ffe, v << 8 | v, (a & 1) != 0 ? 0xff : 0xff00);
+	}
+}
+
+u32int irql[8] = {[6] INTVBL};
+
+int
+intack(int l)
+{
+	switch(l){
+	case 4:
+		irq &= ~INTHOR;
+		break;
+	case 6:
+		irq &= ~INTVBL;
+		break;
+	}
+	return 24 + l;
+}
--- /dev/null
+++ b/sys/src/games/md/mkfile
@@ -1,0 +1,14 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin/games
+TARG=sega
+OFILES=\
+	cpu.$O\
+	mem.$O\
+	md.$O\
+	vdp.$O\
+	z80.$O\
+
+HFILES=dat.h fns.h
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/sys/src/games/md/vdp.c
@@ -1,0 +1,307 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "dat.h"
+#include "fns.h"
+
+u8int pic[320*224*4*3*3];
+u16int vdpstat = 0x3400;
+int vdpx, vdpy;
+u16int hctr;
+static int xmax, xdisp, ymax = 262, yvbl = 234;
+static int sx, snx, col, pri;
+
+void
+vdpmode(void)
+{
+	if((reg[MODE4] & WIDE) != 0){
+		xmax = 406;
+		xdisp = 320;
+	}else{
+		xdisp = 256;
+		xmax = 342;
+	}
+}
+
+static void
+pixeldraw(int x, int y, int v)
+{
+	u8int *p;
+	u32int *q;
+	union { u32int w; u8int b[4]; } u;
+
+	if(scale == 1){
+		p = pic + (x + y * 320) * 4;
+		p[0] = v >> 16;
+		p[1] = v >> 8;
+		p[2] = v;
+		return;
+	}
+	u.b[0] = v >> 16;
+	u.b[1] = v >> 8;
+	u.b[2] = v;
+	u.b[3] = 0;
+	if(scale == 2){
+		q = (u32int*)pic + (x + y * 320) * 2;
+		q[0] = u.w;
+		q[1] = u.w;
+	}else{
+		q = (u32int*)pic + (x + y * 320) * 3;
+		q[0] = u.w;
+		q[1] = u.w;
+		q[2] = u.w;
+	}
+}
+
+static void
+pixel(int v, int p)
+{
+	if(p >= pri){
+		col = v;
+		pri = p;
+	}
+}
+
+struct pctxt {
+	u8int ws, w, hs, h;
+	u16int tx, ty;
+	u8int tnx, tny;
+	u16int t;
+	u32int c;
+} pctxt[3];
+
+static void
+tile(struct pctxt *p)
+{
+	u16int a;
+	int y;
+	
+	switch(p - pctxt){
+	default: a = (reg[PANT] & 0x38) << 9; break;
+	case 1: a = (reg[PBNT] & 7) << 12; break;
+	case 2: a = (reg[PWNT] & 0x38) << 9; break;
+	}
+	a += p->ty << p->ws;
+	a += p->tx;
+	p->t = vram[a];
+	y = p->tny;
+	if((p->t & 0x1000) != 0)
+		y = 7 - y;
+	a = (p->t & 0x7ff) << 4 | y << 1;
+	p->c = vram[a] << 16 | vram[a+1];
+}
+
+static void
+planeinit(void)
+{
+	static int szs[] = {5, 6, 6, 7};
+	int v, a, i;
+	struct pctxt *p;
+	
+	pctxt[0].hs = pctxt[1].hs = szs[reg[PLSIZ] >> 4 & 3];
+	pctxt[0].ws = pctxt[1].ws = szs[reg[PLSIZ] & 3];
+	pctxt[2].ws = (reg[MODE4] & WIDE) != 0 ? 6 : 5;
+	pctxt[2].hs = 5;
+	for(i = 0; i < 2; i++){
+		pctxt[i].h = 1<<pctxt[i].hs;
+		pctxt[i].w = 1<<pctxt[i].ws;
+	}
+	a = reg[HORSCR] << 9 & 0x7fff;
+	switch(reg[MODE3] & 3){
+	case 1: a += vdpy << 1 & 0xe; break;
+	case 2: a += vdpy << 1 & 0xff0; break;
+	case 3: a += vdpy << 1 & 0xffe; break;
+	}
+	for(i = 0; i < 2; i++){
+		p = pctxt + i;
+		v = -(vram[a + i] & 0x3ff);
+		p->tnx = v & 7;
+		p->tx = v >> 3 & pctxt[i].w - 1;
+		v = vsram[i] + vdpy;
+		p->tny = v & 7;
+		p->ty = v >> 3 & pctxt[i].h - 1;
+		tile(pctxt + i);
+		if(p->tnx != 0)
+			if((p->t & 0x800) != 0)
+				p->c >>= p->tnx << 2;
+			else
+				p->c <<= p->tnx << 2;
+	}
+	sx = 0;
+	snx = 0;
+}
+
+static void
+plane(int n)
+{
+	struct pctxt *p;
+	u8int v, pr;
+	
+	p = pctxt + n;
+	if((p->t & 0x800) != 0){
+		v = p->c & 15;
+		p->c >>= 4;
+	}else{
+		v = p->c >> 28;
+		p->c <<= 4;
+	}
+	if(v != 0){
+		v |= p->t >> 9 & 48;
+		pr = 2 - (n & 1) + (p->t >> 13 & 4);
+		pixel(v, pr);
+	}
+	if(++p->tnx == 8){
+		p->tnx = 0;
+		if(++p->tx == p->w)
+			p->tx = 0;
+		tile(pctxt + n);
+	}
+}
+
+static void
+planes(void)
+{
+	int i;
+	u16int v;
+
+	if((reg[MODE3] & 4) != 0 && ++snx == 16){
+		snx = 0;
+		sx++;
+		for(i = 0; i < 2; i++){
+			v = vsram[sx + i] + vdpy;
+			pctxt[i].tny = v & 7;
+			pctxt[i].ty = v >> 3 & pctxt[i].h - 1;
+		}
+	}
+	plane(0);
+	plane(1);
+}
+
+static struct sprite {
+	u16int y, x;
+	u8int w, h;
+	u16int t;
+	u32int c[4];
+} spr[21], *lsp;
+
+static void
+spritesinit(void)
+{
+	u16int *t, *p, dy, *c;
+	u32int v;
+	int i, ns, np;
+	struct sprite *q;
+	
+	t = vram + (reg[SPRTAB] << 8 & 0x7f00);
+	p = t;
+	q = spr;
+	ns = (reg[MODE4] & WIDE) != 0 ? 20 : 16;
+	np = 0;
+	do{
+		q->y = (p[0] & 0x3ff) - 128;
+		q->h = (p[1] >> 8 & 3) + 1 << 3;
+		dy = vdpy - q->y;
+		if(dy >= q->h)
+			continue;
+		q->t = p[2];
+		if((q->t & 0x1000) != 0)
+			dy = q->h + ~dy;
+		q->x = (p[3] & 0x3ff) - 128;
+		q->w = (p[1] >> 10 & 3) + 1 << 3;
+		c = vram + ((q->t & 0x7ff) << 4) + (dy << 1);
+		for(i = 0; i < q->w >> 3 && np < xdisp; i++){
+			v = c[0] << 16 | c[1];
+			c += q->h << 1;
+			if((q->t & 0x800) != 0)
+				q->c[(q->w >> 3) - 1 - i] = v;
+			else
+				q->c[i] = v;
+			np += 8;
+		}
+		if(-q->x < q->w)
+			if((q->t & 0x800) != 0)
+				q->c[-q->x>>3] >>= (-q->x & 7) << 2;
+			else
+				q->c[-q->x>>3] <<= (-q->x & 7) << 2;
+		if(++q == spr + ns || np >= xdisp){
+			vdpstat |= STATOVR;
+			break;
+		}
+	}while(p = t + ((p[1] & 0x7f) << 2), p != t);
+	lsp = q;
+}
+
+static void
+sprites(void)
+{
+	struct sprite *p;
+	u16int dx;
+	int v, col, set;
+	u32int *c;
+	
+	set = 0;
+	col = 0;
+	for(p = spr; p < lsp; p++){
+		dx = vdpx - p->x;
+		if(dx >= p->w)
+			continue;
+		c = p->c + (dx >> 3);
+		if((p->t & 0x800) != 0){
+			v = *c & 15;
+			*c >>= 4;
+		}else{
+			v = *c >> 28;
+			*c <<= 4;
+		}
+		if(v != 0)
+			if(set != 0)
+				vdpstat |= STATCOLL;
+			else{
+				set = 1 | p->t & 0x8000;
+				col = p->t >> 9 & 48 | v;
+			}	
+	}
+	if(set)
+		pixel(col, set >> 13 | 2);
+}
+
+void
+vdpstep(void)
+{
+	if(vdpx == 0){
+		planeinit();
+		spritesinit();
+	}
+	if(vdpx < 320 && vdpy < 224)
+		if(vdpx < xdisp){
+			col = reg[BGCOL] & 0x3f;
+			pri = 0;
+			planes();
+			sprites();
+			pixeldraw(vdpx, vdpy, cramc[col]);
+		}else
+			pixeldraw(vdpx, vdpy, 0xcccccc);
+	if(++vdpx >= xmax){
+		vdpx = 0;
+		if(++vdpy >= ymax){
+			vdpy = 0;
+			irq &= ~INTVBL;
+			vdpstat ^= STATFR;
+			vdpstat &= ~(STATINT | STATFR | STATOVR | STATCOLL);
+			flush();
+		}
+		if(vdpy == 0 || vdpy >= 225)
+			hctr = reg[HORCTR];
+		else
+			if(--hctr == 0){
+				if((reg[MODE1] & IE1) != 0)
+					irq |= INTHOR;
+				hctr = reg[HORCTR];
+			}
+		if(vdpy == yvbl){
+			vdpstat |= STATVBL | STATINT;
+			if((reg[MODE2] & IE0) != 0)
+				irq |= INTVBL;
+		}
+	}
+}
--- /dev/null
+++ b/sys/src/games/md/z80.c
@@ -1,0 +1,23 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "dat.h"
+#include "fns.h"
+
+int
+z80step(void)
+{
+	if((z80bus & RESET) != 0){
+		return 1;
+	}
+	if((z80bus & BUSACK) != 0){
+		if((z80bus & BUSREQ) == 0)
+			z80bus &= ~BUSACK;
+		return 1;
+	}
+	if((z80bus & BUSREQ) != 0){
+		z80bus |= BUSACK;
+		return 1;
+	}
+	return 0;
+}