diff options
author | qwx <devnull@localhost> | 2018-05-12 19:21:48 +0200 |
---|---|---|
committer | qwx <devnull@localhost> | 2018-05-12 19:21:48 +0200 |
commit | abf8c8bf2cd27541d6a102f7c0385c3fe281f578 (patch) | |
tree | b22231a6b8e46fb335e067fb3cb89b35303c6902 /sys/src/games | |
parent | 1195ca910c393e542d6aa23035fa75719af1107e (diff) |
add port of aiju's port of games/2600
Diffstat (limited to 'sys/src/games')
-rw-r--r-- | sys/src/games/2600/2600.c | 96 | ||||
-rw-r--r-- | sys/src/games/2600/aud.c | 81 | ||||
-rw-r--r-- | sys/src/games/2600/cpu.c | 501 | ||||
-rw-r--r-- | sys/src/games/2600/dat.h | 80 | ||||
-rw-r--r-- | sys/src/games/2600/fns.h | 9 | ||||
-rw-r--r-- | sys/src/games/2600/mem.c | 195 | ||||
-rw-r--r-- | sys/src/games/2600/mkfile | 14 | ||||
-rw-r--r-- | sys/src/games/2600/tia.c | 212 | ||||
-rw-r--r-- | sys/src/games/mkfile | 1 |
9 files changed, 1189 insertions, 0 deletions
diff --git a/sys/src/games/2600/2600.c b/sys/src/games/2600/2600.c new file mode 100644 index 000000000..38d7c856f --- /dev/null +++ b/sys/src/games/2600/2600.c @@ -0,0 +1,96 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <draw.h> +#include <keyboard.h> +#include <emu.h> +#include "dat.h" +#include "fns.h" + +u8int *rom, *rop; +u16int bnk[8]; +int mask = 0xfff; + +void +togdifc(void) +{ + p0difc ^= 1<<6; +} + +void +togbw(void) +{ + bwmod ^= 1<<3; +} + +static void +loadrom(char *name) +{ + int i, sz, fd; + + fd = open(name, OREAD); + if(fd < 0) + sysfatal("open: %r"); + sz = seek(fd, 0, 2); + switch(sz){ + case 0x800: mask = 0x7ff; + case 0x1000: break; + case 0x3000: bnk[6] = 2<<12; + case 0x2000: bnk[5] = 1<<12; break; + case 0x4000: for(i=1; i<4; bnk[i+2] = i<<12, i++); break; + case 0x8000: for(i=1; i<8; bnk[i] = i<<12, i++); break; + default: sysfatal("unsupported ROM size"); + } + rom = malloc(sz); + if(rom == nil) + sysfatal("malloc: %r"); + rop = rom; + pread(fd, rom, sz, 0); + close(fd); +} + +void +threadmain(int argc, char **argv) +{ + ARGBEGIN { + case 'a': + initaudio(); + break; + default: + goto usage; + } ARGEND; + if(argc != 1){ + usage: + fprint(2, "usage: %s [ -23a ] rom\n", argv0); + exits("usage"); + } + loadrom(argv[0]); + initemu(PICW, PICH, 4, XRGB32, 1, nil); + regkey("a", ' ', 1<<4); + regkey("start", 'q', 1<<5); + regkey("control", 'w', 1<<6); + regkey("up", Kup, 1<<0); + regkey("down", Kdown, 1<<1); + regkey("left", Kleft, 1<<2); + regkey("right", Kright, 1<<3); + regkeyfn('e', togdifc); + regkeyfn('r', togbw); + + pc = memread(0xFFFC) | memread(0xFFFD) << 8; + rP = FLAGI; + for(;;){ + if(paused){ + qlock(&pauselock); + qunlock(&pauselock); + } + step(); + } +} + +void +flush(void) +{ + flushmouse(1); + flushscreen(); + flushaudio(audioout); +} diff --git a/sys/src/games/2600/aud.c b/sys/src/games/2600/aud.c new file mode 100644 index 000000000..bbe7fb32c --- /dev/null +++ b/sys/src/games/2600/aud.c @@ -0,0 +1,81 @@ +#include <u.h> +#include <libc.h> +#include "dat.h" +#include "fns.h" + +static int sdiv[2], fdiv[2], cdiv[2], ch[2], sr[2] = {-1,-1}; +static short sbuf[2000*2], *sbufp; +static int audfd; + +#define div(n) if(++cdiv[i] < n) break; cdiv[i] = 0 + +static void +channel(int i) +{ + sdiv[i] += HZ/114; + for(; sdiv[i] >= RATE; sdiv[i] -= RATE) + if(fdiv[i] >= (reg[AUDF0 + i] & 31)){ + fdiv[i] = 0; + switch(reg[AUDC0 + i] & 15){ + case 0: ch[i] = 1; break; + case 2: div(15); + case 1: ch[i] = sr[i] & 1; sr[i] = sr[i] >> 1 & 7 | (sr[i] << 2 ^ sr[i] << 3) & 8; break; + case 4: case 5: ch[i] ^= 1; break; + case 12: case 13: div(3); ch[i] ^= 1; break; + case 6: case 10: div(16); ch[i] ^= 1; break; + case 14: div(46); ch[i] ^= 1; break; + case 15: div(3); + case 7: case 9: ch[i] = sr[i] & 1; sr[i] = sr[i] >> 1 & 15 | (sr[i] << 2 ^ sr[i] << 4) & 16; break; + case 8: ch[i] = sr[i] & 1; sr[i] = sr[i] >> 1 & 255 | (sr[i] << 4 ^ sr[i] << 8) & 256; break; + case 3: + ch[i] = sr[i] & 1; + sr[i] = sr[i] & 15 | sr[i] >> 1 & 240 | (sr[i] << 2 ^ sr[i] << 3) & 256; + if((sr[i] & 256) != 0) + sr[i] = sr[i] & 496 | sr[i] >> 1 & 7 | (sr[i] << 2 ^ sr[i]) << 3 & 8; + break; + } + }else + fdiv[i]++; +} + +void +sample(void) +{ + int d; + + if(sbufp == nil) + return; + channel(0); + channel(1); + d = ch[0] * (reg[AUDV0] & 15) + ch[1] * (reg[AUDV1] & 15); + if(sbufp < sbuf + nelem(sbuf) - 1){ + *sbufp++ = d * 1000; + *sbufp++ = d * 1000; + } +} + +int +audioout(void) +{ + int rc; + + if(sbufp == nil) + return -1; + if(sbufp == sbuf) + return 0; + rc = write(audfd, sbuf, (sbufp - sbuf) * 2); + if(rc > 0) + sbufp -= (rc+1)/2; + if(sbufp < sbuf) + sbufp = sbuf; + return 0; +} + +void +initaudio(void) +{ + audfd = open("/dev/audio", OWRITE); + if(audfd < 0) + return; + sbufp = sbuf; +} diff --git a/sys/src/games/2600/cpu.c b/sys/src/games/2600/cpu.c new file mode 100644 index 000000000..4dedfb9eb --- /dev/null +++ b/sys/src/games/2600/cpu.c @@ -0,0 +1,501 @@ +#include <u.h> +#include <libc.h> +#include <emu.h> +#include "dat.h" +#include "fns.h" + +u16int pc, curpc; +u8int rA, rX, rY, rS, rP; +int nrdy; + +static u8int +fetch8(void) +{ + return memread(pc++); +} + +static u16int +fetch16(void) +{ + u16int r; + + r = memread(pc++); + r |= memread(pc++) << 8; + return r; +} + +static void +push8(u8int v) +{ + memwrite(0x100 | rS--, v); +} + +static void +push16(u16int v) +{ + memwrite(0x100 | rS--, v >> 8); + memwrite(0x100 | rS--, v); +} + +static u8int +pop8(void) +{ + return memread(0x100 | ++rS); +} + +static u16int +pop16(void) +{ + u16int v; + + v = memread(0x100 | ++rS); + v |= memread(0x100 | ++rS) << 8; + return v; +} + +#define imm() fetch8() +#define zp() memread(fetch8()) +#define zpX() memread(azpX(rX)) +#define zpY() memread(azpX(rY)) +#define abso() memread(fetch16()) +#define absX() memread(aabsX(rX, 0)) +#define absY() memread(aabsX(rY, 0)) +#define indX() memread(aindX()) +#define indY() memread(aindY(0)) + +static u16int +azpX(u8int a) +{ + u8int v; + + v = fetch8(); + memread(v); + return v + a; +} + +static u16int +aabsX(u8int a, int wr) +{ + u16int v, c; + + v = fetch16(); + c = (u8int)v + a & 0x100; + v += a; + if(c != 0 || wr) + memread(v - c); + return v; +} + +static u16int +aindX(void) +{ + u8int r; + u16int a; + + r = fetch8(); + memread(r); + r += rX; + a = memread(r++); + a |= memread(r) << 8; + return a; +} + +static u16int +aindY(int wr) +{ + u8int r; + u16int a, c; + + r = fetch8(); + a = memread(r++) + rY; + c = a & 0x100; + a += memread(r) << 8; + if(c != 0 || wr) + memread(a - c); + return a; +} + +static void +adc(u8int d) +{ + int r; + + if((rP & FLAGD) != 0){ + r = (rA & 0xf) + (d & 0xf) + (rP & FLAGC); + if(r > 0x09) + r += 0x06; + if(r > 0x1f) + r -= 0x10; + r += (rA & 0xf0) + (d & 0xf0); + }else + r = rA + d + (rP & FLAGC); + rP &= ~(FLAGN | FLAGZ | FLAGV | FLAGC); + if((~(rA ^ d) & (rA ^ r)) & 0x80) rP |= FLAGV; + if((rP & FLAGD) != 0 && r > 0x9f) + r += 0x60; + if(r > 0xFF) rP |= FLAGC; + if(r & 0x80) rP |= FLAGN; + rA = r; + if(rA == 0) rP |= FLAGZ; +} + +static u8int +nz(u8int d) +{ + rP &= ~(FLAGN | FLAGZ); + if(d & 0x80) rP |= FLAGN; + if(d == 0) rP |= FLAGZ; + return d; +} + +static void +asl(u16int a) +{ + u8int v; + + rP &= ~(FLAGN | FLAGZ | FLAGC); + v = memread(a); + memwrite(a, v); + if(v & 0x80) rP |= FLAGC; + v <<= 1; + if(v == 0) rP |= FLAGZ; + if(v & 0x80) rP |= FLAGN; + memwrite(a, v); +} + +static void +lsr(u16int a) +{ + u8int v; + + rP &= ~(FLAGN | FLAGZ | FLAGC); + v = memread(a); + memwrite(a, v); + rP |= v & 1; + v >>= 1; + if(v == 0) rP |= FLAGZ; + if(v & 0x80) rP |= FLAGN; + memwrite(a, v); +} + +static void +branch(void) +{ + s8int t; + u16int npc; + + t = fetch8(); + memread(pc); + npc = pc + t; + if((npc ^ pc) >> 8) + memread(pc & 0xff00 | npc & 0xff); + pc = npc; +} + +static void +cmp(u8int a, u8int d) +{ + rP &= ~(FLAGN | FLAGZ | FLAGC); + if(a == d) rP |= FLAGZ; + if(a >= d) rP |= FLAGC; + if((a - d) & 0x80) rP |= FLAGN; +} + +static void +dec(u16int a) +{ + u8int v; + + v = memread(a); + memwrite(a, v); + memwrite(a, nz(v - 1)); +} + +static void +inc(u16int a) +{ + u8int v; + + v = memread(a); + memwrite(a, v); + v = nz(v + 1); + memwrite(a, v); +} + +static void +rol(u16int a) +{ + u8int v, b; + + v = memread(a); + memwrite(a, v); + b = rP & FLAGC; + rP &= ~(FLAGC | FLAGN | FLAGZ); + if(v & 0x80) rP |= FLAGC; + v = (v << 1) | b; + if(v & 0x80) rP |= FLAGN; + if(v == 0) rP |= FLAGZ; + memwrite(a, v); +} + +static void +ror(u16int a) +{ + u8int v, b; + + v = memread(a); + memwrite(a, v); + b = rP & FLAGC; + rP &= ~(FLAGC | FLAGN | FLAGZ); + rP |= v & 1; + v = (v >> 1) | (b << 7); + if(v & 0x80) rP |= FLAGN; + if(v == 0) rP |= FLAGZ; + memwrite(a, v); +} + +static void +sbc(u8int d) +{ + int r; + + if((rP & FLAGD) != 0){ + d = ~d; + r = (rA & 0xf) + (d & 0xf) + (rP & FLAGC); + if(r < 0x10) r -= 0x06; + if(r < 0) r += 0x10; + r += (rA & 0xf0) + (d & 0xf0); + }else + r = rA + (u8int)~d + (rP & FLAGC); + rP &= ~(FLAGZ | FLAGV | FLAGC | FLAGN); + if(((rA ^ d) & (rA ^ r)) & 0x80) rP |= FLAGV; + if(r > 0xFF) rP |= FLAGC; + else if((rP & FLAGD) != 0) + r -= 0x60; + rA = r; + if(rA == 0) rP |= FLAGZ; + if(rA & 0x80) rP |= FLAGN; +} + +static void +interrupt(int nmi, int brk) +{ + fetch8(); + push16(pc); + push8(rP | 0x20 | (brk << 4)); + pc = memread(0xFFFA | (!nmi << 2)); + pc |= memread(0xFFFB | (!nmi << 2)) << 8; + rP |= FLAGI; +} + +void +step(void) +{ + u8int op; + u16int a, v; + + if(nrdy){ + io(); + return; + } + curpc = pc; + op = fetch8(); + if(trace) + print("%.4x %.2x | %.2x %.2x %.2x | %.2x %.2x | %3d %3d\n", curpc, op, rA, rX, rY, rS, rP, ppux-3, ppuy); + switch(op){ + case 0x00: fetch8(); interrupt(0, 1); return; + case 0x01: nz(rA |= indX()); return; + case 0x05: nz(rA |= zp()); return; + case 0x06: asl(fetch8()); return; + case 0x08: memread(pc); push8(rP | 0x30); return; + case 0x09: nz(rA |= imm()); return; + case 0x0A: + rP &= ~(FLAGN | FLAGZ | FLAGC); + if(rA & 0x80) rP |= FLAGC; + rA <<= 1; + if(rA == 0) rP |= FLAGZ; + if(rA & 0x80) rP |= FLAGN; + memread(pc); + return; + case 0x0D: nz(rA |= abso()); return; + case 0x0E: asl(fetch16()); return; + case 0x10: if((rP & FLAGN) == 0) branch(); else fetch8(); return; + case 0x11: nz(rA |= indY()); return; + case 0x15: nz(rA |= zpX()); return; + case 0x16: asl(azpX(rX)); return; + case 0x18: rP &= ~FLAGC; memread(pc); return; + case 0x19: nz(rA |= absY()); return; + case 0x1D: nz(rA |= absX()); return; + case 0x1E: asl(aabsX(rX, 1)); return; + case 0x20: v = fetch8(); memread(rS|0x100); push16(pc); pc = fetch8() << 8 | v; return; + case 0x21: nz(rA &= indX()); return; + case 0x24: + a = memread(fetch8()); + rP &= ~(FLAGN | FLAGZ | FLAGV); + rP |= a & 0xC0; + if((a & rA) == 0) rP |= FLAGZ; + return; + case 0x25: nz(rA &= zp()); return; + case 0x26: rol(fetch8()); return; + case 0x28: memread(pc); memread(0x100|rS); rP = pop8() & 0xcf; return; + case 0x29: nz(rA &= imm()); return; + case 0x2A: + a = rP & FLAGC; + rP &= ~(FLAGC | FLAGZ | FLAGN); + if(rA & 0x80) rP |= FLAGC; + rA = (rA << 1) | a; + if(rA & 0x80) rP |= FLAGN; + if(rA == 0) rP |= FLAGZ; + memread(pc); + return; + case 0x2C: + a = memread(fetch16()); + rP &= ~(FLAGN | FLAGZ | FLAGV); + rP |= a & 0xC0; + if((a & rA) == 0) rP |= FLAGZ; + return; + case 0x2D: nz(rA &= abso()); return; + case 0x2E: rol(fetch16()); return; + case 0x30: if((rP & FLAGN) != 0) branch(); else fetch8(); return; + case 0x31: nz(rA &= indY()); return; + case 0x35: nz(rA &= zpX()); return; + case 0x36: rol(azpX(rX)); return; + case 0x38: rP |= FLAGC; memread(pc); return; + case 0x39: nz(rA &= absY()); return; + case 0x3E: rol(aabsX(rX, 1)); return; + case 0x3D: nz(rA &= absX()); return; + case 0x40: fetch8(); memread(rS|0x100); rP = pop8() & 0xcf; pc = pop16(); return; + case 0x41: nz(rA ^= indX()); return; + case 0x45: nz(rA ^= zp()); return; + case 0x46: lsr(fetch8()); return; + case 0x48: memread(pc); push8(rA); return; + case 0x49: nz(rA ^= imm()); return; + case 0x4A: + rP &= ~(FLAGN | FLAGZ | FLAGC); + rP |= rA & 1; + rA >>= 1; + if(rA == 0) rP |= FLAGZ; + if(rA & 0x80) rP |= FLAGN; + memread(pc); + return; + case 0x4C: pc = fetch16(); return; + case 0x4D: nz(rA ^= abso()); return; + case 0x4E: lsr(fetch16()); return; + case 0x51: nz(rA ^= indY()); return; + case 0x56: lsr(azpX(rX)); return; + case 0x58: rP &= ~FLAGI; memread(pc); return; + case 0x50: if((rP & FLAGV) == 0) branch(); else fetch8(); return; + case 0x55: nz(rA ^= zpX()); return; + case 0x59: nz(rA ^= absY()); return; + case 0x5D: nz(rA ^= absX()); return; + case 0x5E: lsr(aabsX(rX, 1)); return; + case 0x60: fetch8(); memread(rS | 0x100); pc = pop16(); fetch8(); return; + case 0x61: adc(indX()); return; + case 0x65: adc(zp()); return; + case 0x66: ror(fetch8()); return; + case 0x68: memread(pc); memread(0x100|rS); nz(rA = pop8()); return; + case 0x69: adc(imm()); return; + case 0x6A: + a = rP & FLAGC; + rP &= ~(FLAGC | FLAGN | FLAGZ); + rP |= rA & 1; + rA = (rA >> 1) | (a << 7); + if(rA & 0x80) rP |= FLAGN; + if(rA == 0) rP |= FLAGZ; + memread(pc); + return; + case 0x6C: v = fetch16(); pc = memread(v) | (memread((v & 0xFF00) | (u8int)(v+1)) << 8); return; + case 0x6D: adc(abso()); return; + case 0x6E: ror(fetch16()); return; + case 0x70: if((rP & FLAGV) != 0) branch(); else fetch8(); return; + case 0x71: adc(indY()); return; + case 0x75: adc(zpX()); return; + case 0x76: ror(azpX(rX)); return; + case 0x78: rP |= FLAGI; memread(pc); return; + case 0x79: adc(absY()); return; + case 0x7D: adc(absX()); return; + case 0x7E: ror(aabsX(rX, 1)); return; + case 0x81: memwrite(aindX(), rA); return; + case 0x84: memwrite(fetch8(), rY); return; + case 0x85: memwrite(fetch8(), rA); return; + case 0x86: memwrite(fetch8(), rX); return; + case 0x88: nz(--rY); memread(pc); return; + case 0x8A: nz(rA = rX); memread(pc); return; + case 0x8C: memwrite(fetch16(), rY); return; + case 0x8D: memwrite(fetch16(), rA); return; + case 0x8E: memwrite(fetch16(), rX); return; + case 0x90: if((rP & FLAGC) == 0) branch(); else fetch8(); return; + case 0x91: memwrite(aindY(1), rA); return; + case 0x94: memwrite(azpX(rX), rY); return; + case 0x95: memwrite(azpX(rX), rA); return; + case 0x96: memwrite(azpX(rY), rX); return; + case 0x98: nz(rA = rY); memread(pc); return; + case 0x99: memwrite(aabsX(rY, 1), rA); return; + case 0x9A: rS = rX; memread(pc); return; + case 0x9D: memwrite(aabsX(rX, 1), rA); return; + case 0xA0: nz(rY = imm()); return; + case 0xA1: nz(rA = indX()); return; + case 0xA2: nz(rX = imm()); return; + case 0xA4: nz(rY = zp()); return; + case 0xA5: nz(rA = zp()); return; + case 0xA6: nz(rX = zp()); return; + case 0xA8: nz(rY = rA); memread(pc); return; + case 0xA9: nz(rA = imm()); return; + case 0xAA: nz(rX = rA); memread(pc); return; + case 0xAC: nz(rY = abso()); return; + case 0xAE: nz(rX = abso()); return; + case 0xAD: nz(rA = abso()); return; + case 0xB0: if((rP & FLAGC) != 0) branch(); else fetch8(); return; + case 0xB1: nz(rA = indY()); return; + case 0xB4: nz(rY = zpX()); return; + case 0xB5: nz(rA = zpX()); return; + case 0xB6: nz(rX = zpY()); return; + case 0xB8: rP &= ~FLAGV; memread(pc); return; + case 0xB9: nz(rA = absY()); return; + case 0xBA: nz(rX = rS); memread(pc); return; + case 0xBC: nz(rY = absX()); return; + case 0xBD: nz(rA = absX()); return; + case 0xBE: nz(rX = absY()); return; + case 0xC1: cmp(rA, indX()); return; + case 0xC5: cmp(rA, zp()); return; + case 0xC9: cmp(rA, imm()); return; + case 0xCD: cmp(rA, abso()); return; + case 0xD0: if((rP & FLAGZ) == 0) branch(); else fetch8(); return; + case 0xD1: cmp(rA, indY()); return; + case 0xD5: cmp(rA, zpX()); return; + case 0xD8: rP &= ~FLAGD; memread(pc); return; + case 0xD9: cmp(rA, absY()); return; + case 0xDD: cmp(rA, absX()); return; + case 0xC0: cmp(rY, imm()); return; + case 0xC4: cmp(rY, zp()); return; + case 0xC6: dec(fetch8()); return; + case 0xC8: nz(++rY); memread(pc); return; + case 0xCA: nz(--rX); memread(pc); return; + case 0xCC: cmp(rY, abso()); return; + case 0xCE: dec(fetch16()); return; + case 0xD6: dec(azpX(rX)); return; + case 0xDE: dec(aabsX(rX, 1)); return; + case 0xE0: cmp(rX, imm()); return; + case 0xE1: sbc(indX()); return; + case 0xE4: cmp(rX, zp()); return; + case 0xE5: sbc(zp()); return; + case 0xE6: inc(fetch8()); return; + case 0xE8: nz(++rX); memread(pc); return; + case 0xE9: sbc(imm()); return; + case 0xEA: memread(pc); return; + case 0xEC: cmp(rX, abso()); return; + case 0xED: sbc(abso()); return; + case 0xEE: inc(fetch16()); return; + case 0xF0: if((rP & FLAGZ) != 0) branch(); else fetch8(); return; + case 0xF1: sbc(indY()); return; + case 0xF5: sbc(zpX()); return; + case 0xF6: inc(azpX(rX)); return; + case 0xF8: rP |= FLAGD; memread(pc); return; + case 0xF9: sbc(absY()); return; + case 0xFD: sbc(absX()); return; + case 0xFE: inc(aabsX(rX, 1)); return; + default: + fprint(2, "undefined %#x (pc %#x)\n", op, curpc); + return; + } +} diff --git a/sys/src/games/2600/dat.h b/sys/src/games/2600/dat.h new file mode 100644 index 000000000..304b9e025 --- /dev/null +++ b/sys/src/games/2600/dat.h @@ -0,0 +1,80 @@ +extern u16int pc, curpc; +extern u8int rP; +extern int nrdy; +extern int p0difc; +extern int bwmod; + +extern int ppux, ppuy; +extern u8int p0x, p1x, m0x, m1x, blx; +extern u16int coll; + +extern u8int *rom, *rop; +extern u16int bnk[]; +extern int mask; +extern u8int reg[64]; + +enum { + FLAGC = 1<<0, + FLAGZ = 1<<1, + FLAGI = 1<<2, + FLAGD = 1<<3, + FLAGB = 1<<4, + FLAGV = 1<<6, + FLAGN = 1<<7, +}; + +enum { + VSYNC, + VBLANK, + WSYNC, + RSYNC, + NUSIZ0, + NUSIZ1, + COLUP0, + COLUP1, + COLUPF, + COLUBK, + CTRLPF, + REFP0, + REFP1, + PF0, + PF1, + PF2, + RESP0, + RESP1, + RESM0, + RESM1, + RESBL, + AUDC0, + AUDC1, + AUDF0, + AUDF1, + AUDV0, + AUDV1, + GRP0, + GRP1, + ENAM0, + ENAM1, + ENABL, + HMP0, + HMP1, + HMM0, + HMM1, + HMBL, + VDELP0, + VDELP1, + VDELBL, + RESMP0, + RESMP1, + HMOVE, + HMCLR, + CXCLR, +}; + +enum { + PICW = 320, + PICH = 222, + HZ = 3579545, + RATE = 44100, + SAMPDIV = HZ / 3 / RATE, +}; diff --git a/sys/src/games/2600/fns.h b/sys/src/games/2600/fns.h new file mode 100644 index 000000000..654cb5252 --- /dev/null +++ b/sys/src/games/2600/fns.h @@ -0,0 +1,9 @@ +u8int memread(u16int); +void memwrite(u16int, u8int); +void step(void); +void tiastep(void); +void flush(void); +void io(void); +void initaudio(void); +void sample(void); +int audioout(void); diff --git a/sys/src/games/2600/mem.c b/sys/src/games/2600/mem.c new file mode 100644 index 000000000..be24a17e1 --- /dev/null +++ b/sys/src/games/2600/mem.c @@ -0,0 +1,195 @@ +#include <u.h> +#include <libc.h> +#include <emu.h> +#include "dat.h" +#include "fns.h" + +u8int ram[128], reg[64]; +static u8int timer, timerun, timerspeed; +static u16int timerpre; +static u8int grp0d, grp1d, enabld; + +static u8int +tiaread(u8int a) +{ + if(a < 8) + return coll >> (a << 1 & 14) << 6; + if(a == 0xc) + return ~keys << 3 & 0x80; + return 0x80; +} + +static void +tiawrite(u8int a, u8int v) +{ + switch(a){ + case VSYNC: + if((v & 2) != 0) + flush(); + return; + case VBLANK: + if((v & 2) == 0) + ppuy = 0; + break; + case WSYNC: nrdy = 1; break; + case RESP0: p0x = ppux >= 160 ? 3 : ppux+5; break; + case RESP1: p1x = ppux >= 160 ? 3 : ppux+5; break; + case RESM0: m0x = ppux >= 160 ? 2 : ppux+4; break; + case RESM1: m1x = ppux >= 160 ? 2 : ppux+4; break; + case RESBL: blx = ppux >= 160 ? 2 : ppux+4; break; + case HMOVE: + p0x = (p0x - ((s8int) reg[HMP0] >> 4)) % 160; + p1x = (p1x - ((s8int) reg[HMP1] >> 4)) % 160; + m0x = (m0x - ((s8int) reg[HMM0] >> 4)) % 160; + m1x = (m1x - ((s8int) reg[HMM1] >> 4)) % 160; + blx = (blx - ((s8int) reg[HMBL] >> 4)) % 160; + break; + case HMCLR: reg[HMP0] = reg[HMP1] = reg[HMM0] = reg[HMM1] = reg[HMBL] = 0; break; + case VDELP0: + if((v & 1) == 0) + reg[GRP0] = grp0d; + break; + case VDELP1: + if((v & 1) == 0) + reg[GRP1] = grp1d; + break; + case VDELBL: + if((v & 1) == 0) + reg[ENABL] = enabld; + break; + case GRP0: + if((reg[VDELP1] & 1) != 0) + reg[GRP1] = grp1d; + if((reg[VDELP0] & 1) != 0){ + grp0d = v; + return; + } + break; + case GRP1: + if((reg[VDELP0] & 1) != 0) + reg[GRP0] = grp0d; + if((reg[VDELBL] & 1) != 0) + reg[ENABL] = enabld; + if((reg[VDELP1] & 1) != 0){ + grp1d = v; + return; + } + break; + case ENABL: + if((reg[VDELBL] & 1) != 0){ + enabld = v; + return; + } + break; + case CXCLR: + coll = 0; + break; + } + reg[a] = v; +} + +static u8int +ioread(u8int a) +{ + u8int v; + + switch(a){ + case 0: + return ~(keys << 4); + case 2: + return keys >> 5 ^ 3 | bwmod | p0difc; + case 4: + timerspeed = 0; + return timer; + case 5: + v = timerun; + timerun &= ~(1<<6); + return v; + } + return 0; +} + +static void +iowrite(u8int a, u8int v) +{ + switch(a){ + case 4: + timerpre = 1; + goto timer; + case 5: + timerpre = 8; + goto timer; + case 6: + timerpre = 64; + goto timer; + case 7: + timerpre = 1024; + timer: + timerun &= ~(1<<7); + timerspeed = v == 0; + timer = v - 1; + break; + } +} + +u8int +memread(u16int a) +{ + u8int v; + + if((a & 0x1000) != 0) + v = rop[a & mask]; + else if((a & 1<<7) == 0) + v = tiaread(a & 0xf); + else if((a & 1<<9) == 0) + v = ram[a & 0x7f]; + else + v = ioread(a & 7); + if(a > 0xfff3 && a < 0xfffc) + rop = rom + bnk[a - 0xfff4]; + io(); + return v; +} + +void +memwrite(u16int a, u8int v) +{ + if((a & 0x1000) != 0){ + ;} + else if((a & 1<<7) == 0) + tiawrite(a & 0x3f, v); + else if((a & 1<<9) == 0) + ram[a & 0x7f] = v; + else + iowrite(a & 7, v); + if(a > 0xfff3 && a < 0xfffc) + rop = rom + bnk[a - 0xfff4]; + io(); +} + +static void +timerstep(void) +{ + static int cl; + + cl++; + if((timerspeed || (cl & timerpre - 1) == 0) && timer-- == 0){ + timerspeed = 1; + timerun |= 3<<6; + } +} + +void +io(void) +{ + static int snddiv; + + timerstep(); + tiastep(); + tiastep(); + tiastep(); + if(++snddiv == SAMPDIV){ + snddiv = 0; + sample(); + } +} diff --git a/sys/src/games/2600/mkfile b/sys/src/games/2600/mkfile new file mode 100644 index 000000000..df08bd2d8 --- /dev/null +++ b/sys/src/games/2600/mkfile @@ -0,0 +1,14 @@ +</$objtype/mkfile + +BIN=/$objtype/bin/games +TARG=2600 +OFILES=\ + 2600.$O\ + aud.$O\ + cpu.$O\ + mem.$O\ + tia.$O\ + +HFILES=dat.h fns.h + +</sys/src/cmd/mkone diff --git a/sys/src/games/2600/tia.c b/sys/src/games/2600/tia.c new file mode 100644 index 000000000..3819fedaa --- /dev/null +++ b/sys/src/games/2600/tia.c @@ -0,0 +1,212 @@ +#include <u.h> +#include <libc.h> +#include <emu.h> +#include "dat.h" +#include "fns.h" + +int ppux=1, ppuy; +int col, pri; +u8int p0x, p1x, m0x, m1x, blx; +u16int coll; +u8int disp; +int p0difc; +int bwmod = 1<<3; + +enum { + SRCPF, + SRCP0, + SRCP1, + SRCM0, + SRCM1, + SRCBL, +}; + +static void +pixeldraw(u8int v) +{ + u32int c; + union { u32int l; u8int c[4]; } u; + u32int *p; + static u32int col[] = { + 0x000000, 0x404040, 0x6C6C6C, 0x909090, 0xB0B0B0, 0xC8C8C8, 0xDCDCDC, 0xECECEC, + 0x444400, 0x646410, 0x848424, 0xA0A034, 0xB8B840, 0xD0D050, 0xE8E85C, 0xFCFC68, + 0x702800, 0x844414, 0x985C28, 0xAC783C, 0xBC8C4C, 0xCCA05C, 0xDCB468, 0xECC878, + 0x841800, 0x983418, 0xAC5030, 0xC06848, 0xD0805C, 0xE09470, 0xECA880, 0xFCBC94, + 0x880000, 0x9C2020, 0xB03C3C, 0xC05858, 0xD07070, 0xE08888, 0xECA0A0, 0xFCB4B4, + 0x78005C, 0x8C2074, 0xA03C88, 0xB0589C, 0xC070B0, 0xD084C0, 0xDC9CD0, 0xECB0E0, + 0x480078, 0x602090, 0x783CA4, 0x8C58B8, 0xA070CC, 0xB484DC, 0xC49CEC, 0xD4B0FC, + 0x140084, 0x302098, 0x4C3CAC, 0x6858C0, 0x7C70D0, 0x9488E0, 0xA8A0EC, 0xBCB4FC, + 0x000088, 0x1C209C, 0x3840B0, 0x505CC0, 0x6874D0, 0x7C8CE0, 0x90A4EC, 0xA4B8FC, + 0x00187C, 0x1C3890, 0x3854A8, 0x5070BC, 0x6888CC, 0x7C9CDC, 0x90B4EC, 0xA4C8FC, + 0x002C5C, 0x1C4C78, 0x386890, 0x5084AC, 0x689CC0, 0x7CB4D4, 0x90CCE8, 0xA4E0FC, + 0x003C2C, 0x1C5C48, 0x387C64, 0x509C80, 0x68B494, 0x7CD0AC, 0x90E4C0, 0xA4FCD4, + 0x003C00, 0x205C20, 0x407C40, 0x5C9C5C, 0x74B474, 0x8CD08C, 0xA4E4A4, 0xB8FCB8, + 0x143800, 0x345C1C, 0x507C38, 0x6C9850, 0x84B468, 0x9CCC7C, 0xB4E490, 0xC8FCA4, + 0x2C3000, 0x4C501C, 0x687034, 0x848C4C, 0x9CA864, 0xB4C078, 0xCCD488, 0xE0EC9C, + 0x442800, 0x644818, 0x846830, 0xA08444, 0xB89C58, 0xD0B46C, 0xE8CC7C, 0xFCE08C, + }; + + c = col[v >> 1]; + u.c[0] = c; + u.c[1] = c >> 8; + u.c[2] = c >> 16; + u.c[3] = 0xff; + p = (u32int *)pic + ppuy * PICW * scale + ppux * 2 * scale; + switch(scale){ + case 16: *p++ = u.l; *p++ = u.l; + case 15: *p++ = u.l; *p++ = u.l; + case 14: *p++ = u.l; *p++ = u.l; + case 13: *p++ = u.l; *p++ = u.l; + case 12: *p++ = u.l; *p++ = u.l; + case 11: *p++ = u.l; *p++ = u.l; + case 10: *p++ = u.l; *p++ = u.l; + case 9: *p++ = u.l; *p++ = u.l; + case 8: *p++ = u.l; *p++ = u.l; + case 7: *p++ = u.l; *p++ = u.l; + case 6: *p++ = u.l; *p++ = u.l; + case 5: *p++ = u.l; *p++ = u.l; + case 4: *p++ = u.l; *p++ = u.l; + case 3: *p++ = u.l; *p++ = u.l; + case 2: *p++ = u.l; *p++ = u.l; + default: *p++ = u.l; *p = u.l; + } +} + +static void +pixel(u8int v, int p, int s) +{ + if(p > pri){ + col = v; + pri = p; + } + disp |= 1<<s; +} + +static void +playfield(void) +{ + int x, p; + u8int c; + + x = ppux / 4; + if(x >= 20) + if((reg[CTRLPF] & 1) != 0) + x = 39 - x; + else + x = x - 20; + if(x < 4){ + if((reg[PF0] & 0x10<<x) == 0) + return; + }else if(x < 12){ + if((reg[PF1] & 0x800>>x) == 0) + return; + }else + if((reg[PF2] & 1<<x-12) == 0) + return; + if((reg[CTRLPF] & 6) == 2) + if(ppux < 80){ + c = reg[COLUP0]; + p = 3; + }else{ + c = reg[COLUP1]; + p = 2; + } + else{ + c = reg[COLUPF]; + p = (reg[CTRLPF] & 4) + 1; + } + pixel(c, p, SRCPF); +} + +static void +player(int n) +{ + u8int c; + int x; + + c = reg[GRP0 + n]; + x = ppux - (n ? p1x : p0x); + if(x < 0) + return; + switch(reg[NUSIZ0 + n] & 7){ + default: if(x >= 8) return; break; + case 1: if(x >= 8 && (x < 16 || x >= 24)) return; break; + case 2: if(x >= 8 && (x < 32 || x >= 40)) return; break; + case 3: if(x >= 40 || ((x & 15) >= 8)) return; break; + case 4: if(x >= 8 && (x < 64 || x >= 72)) return; break; + case 5: if(x >= 16) return; x >>= 1; break; + case 6: if(x >= 72 || ((x & 31) >= 8)) return; break; + case 7: if(x >= 32) return; x >>= 2; break; + } + x &= 7; + if((reg[REFP0 + n] & 8) == 0) + x ^= 7; + if((c & 1<<x) == 0) + return; + c = reg[COLUP0 + n]; + pixel(c, 3 - n, SRCP0 + n); +} + +static void +missile(int n) +{ + int x; + + x = ppux - (n ? m1x : m0x); + if((reg[RESMP0 + n] & 2) != 0){ + if(n) + m1x = p1x; + else + m0x = p0x; + return; + } + if(x < 0 || x >= 1<<(reg[NUSIZ0] >> 4 & 3) || (reg[ENAM0 + n] & 2) == 0) + return; + pixel(reg[COLUP0 + n], 3 - n, SRCM0 + n); +} + +static void +ball(void) +{ + int x; + + x = ppux - blx; + if(x < 0 || x >= 1<<(reg[CTRLPF] >> 4 & 3) || (reg[ENABL] & 2) == 0) + return; + pixel(reg[COLUPF], (reg[CTRLPF] & 4) + 1, SRCBL); +} + +void +tiastep(void) +{ + static u16int colltab[64] = { + 0x0000, 0x0000, 0x0000, 0x0020, 0x0000, 0x0080, 0x8000, 0x80a0, + 0x0000, 0x0200, 0x0001, 0x0221, 0x0002, 0x0282, 0x8003, 0x82a3, + 0x0000, 0x0800, 0x0008, 0x0828, 0x0004, 0x0884, 0x800c, 0x88ac, + 0x4000, 0x4a00, 0x4009, 0x4a29, 0x4006, 0x4a86, 0xc00f, 0xcaaf, + 0x0000, 0x2000, 0x0010, 0x2030, 0x0040, 0x20c0, 0x8050, 0xa0f0, + 0x0100, 0x2300, 0x0111, 0x2331, 0x0142, 0x23c2, 0x8153, 0xa3f3, + 0x0400, 0x2c00, 0x0418, 0x2c38, 0x0444, 0x2cc4, 0x845c, 0xacfc, + 0x4500, 0x6f00, 0x4519, 0x6f39, 0x4546, 0x6fc6, 0xc55f, 0xefff, + }; + + if(ppuy < PICH && ppux < 160){ + col = reg[COLUBK]; + pri = 0; + disp = 0; + playfield(); + player(0); + player(1); + missile(0); + missile(1); + ball(); + coll |= colltab[disp]; + pixeldraw(col); + } + if(ppux == 160) + nrdy = 0; + if(++ppux == 228){ + ppuy++; + ppux = 0; + } +} diff --git a/sys/src/games/mkfile b/sys/src/games/mkfile index 0c33447aa..542bb4fde 100644 --- a/sys/src/games/mkfile +++ b/sys/src/games/mkfile @@ -24,6 +24,7 @@ HFILES= BIN=/$objtype/bin/games DIRS=\ + 2600\ blabs\ blit\ c64\ |