diff options
author | aiju <devnull@localhost> | 2014-05-25 23:14:23 +0200 |
---|---|---|
committer | aiju <devnull@localhost> | 2014-05-25 23:14:23 +0200 |
commit | 93cfa1be72e18029d242ca462da3484488d1c6b3 (patch) | |
tree | c00c99b5fa52fef255a5c382aa9bb35861469345 /sys/src | |
parent | ea480e74bbd559e448c1c8afc3f2abe6888351a4 (diff) |
added crude version of games/md
Diffstat (limited to 'sys/src')
-rw-r--r-- | sys/src/games/md/cpu.c | 1027 | ||||
-rw-r--r-- | sys/src/games/md/dat.h | 65 | ||||
-rw-r--r-- | sys/src/games/md/fns.h | 12 | ||||
-rw-r--r-- | sys/src/games/md/md.c | 200 | ||||
-rw-r--r-- | sys/src/games/md/mem.c | 345 | ||||
-rw-r--r-- | sys/src/games/md/mkfile | 14 | ||||
-rw-r--r-- | sys/src/games/md/vdp.c | 307 | ||||
-rw-r--r-- | sys/src/games/md/z80.c | 23 |
8 files changed, 1993 insertions, 0 deletions
diff --git a/sys/src/games/md/cpu.c b/sys/src/games/md/cpu.c new file mode 100644 index 000000000..092e21fc0 --- /dev/null +++ b/sys/src/games/md/cpu.c @@ -0,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(); + } +} diff --git a/sys/src/games/md/dat.h b/sys/src/games/md/dat.h new file mode 100644 index 000000000..f82098827 --- /dev/null +++ b/sys/src/games/md/dat.h @@ -0,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, +}; diff --git a/sys/src/games/md/fns.h b/sys/src/games/md/fns.h new file mode 100644 index 000000000..514f4fa9e --- /dev/null +++ b/sys/src/games/md/fns.h @@ -0,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); diff --git a/sys/src/games/md/md.c b/sys/src/games/md/md.c new file mode 100644 index 000000000..d762a8b6a --- /dev/null +++ b/sys/src/games/md/md.c @@ -0,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); +} diff --git a/sys/src/games/md/mem.c b/sys/src/games/md/mem.c new file mode 100644 index 000000000..b0353b6da --- /dev/null +++ b/sys/src/games/md/mem.c @@ -0,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; +} diff --git a/sys/src/games/md/mkfile b/sys/src/games/md/mkfile new file mode 100644 index 000000000..6a0868a05 --- /dev/null +++ b/sys/src/games/md/mkfile @@ -0,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 diff --git a/sys/src/games/md/vdp.c b/sys/src/games/md/vdp.c new file mode 100644 index 000000000..c6100fc12 --- /dev/null +++ b/sys/src/games/md/vdp.c @@ -0,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; + } + } +} diff --git a/sys/src/games/md/z80.c b/sys/src/games/md/z80.c new file mode 100644 index 000000000..4d990a0fc --- /dev/null +++ b/sys/src/games/md/z80.c @@ -0,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; +} |