ref: 93cfa1be72e18029d242ca462da3484488d1c6b3
parent: ea480e74bbd559e448c1c8afc3f2abe6888351a4
author: aiju <devnull@localhost>
date: Sun May 25 19:14:23 EDT 2014
added crude version of games/md
--- /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;
+}