]> git.lizzy.rs Git - plan9front.git/commitdiff
add port of aiju's port of games/2600
authorqwx <devnull@localhost>
Sat, 12 May 2018 17:21:48 +0000 (19:21 +0200)
committerqwx <devnull@localhost>
Sat, 12 May 2018 17:21:48 +0000 (19:21 +0200)
sys/man/1/atari [new file with mode: 0644]
sys/src/games/2600/2600.c [new file with mode: 0644]
sys/src/games/2600/aud.c [new file with mode: 0644]
sys/src/games/2600/cpu.c [new file with mode: 0644]
sys/src/games/2600/dat.h [new file with mode: 0644]
sys/src/games/2600/fns.h [new file with mode: 0644]
sys/src/games/2600/mem.c [new file with mode: 0644]
sys/src/games/2600/mkfile [new file with mode: 0644]
sys/src/games/2600/tia.c [new file with mode: 0644]
sys/src/games/mkfile

diff --git a/sys/man/1/atari b/sys/man/1/atari
new file mode 100644 (file)
index 0000000..63e5e81
--- /dev/null
@@ -0,0 +1,35 @@
+.SH ATARI 1
+.SH NAME
+2600 \- emulator
+.SH SYNOPSIS
+.B games/2600
+[
+.B -a
+]
+.I romfile
+.SH DESCRIPTION
+.I 2600
+is an emulator for the Atari 2600.
+It exectues the romfile given as an argument,
+and controls as if using a regular 4-direction 1-button joystick,
+using \fBspace\fR button and directional keys.
+The \fBq\fR, \fBw\fR, \fBe\fR, \fBr\fR keys correspond respectively to the reset, select, player 1 difficulty and color mode switches.
+Other keys:
+.TP
+Esc
+Pause the emulator.
+.TP
+Del
+Exit the emulator.
+.PP
+Command line options:
+.TP
+.B -a
+Enable audio output.
+.SH SOURCE
+.B /sys/src/games/2600
+.SH BUGS
+Yes.
+.SH HISTORY
+.I 2600
+first appeared in 9front (November, 2014).
diff --git a/sys/src/games/2600/2600.c b/sys/src/games/2600/2600.c
new file mode 100644 (file)
index 0000000..38d7c85
--- /dev/null
@@ -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 (file)
index 0000000..bbe7fb3
--- /dev/null
@@ -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 (file)
index 0000000..4dedfb9
--- /dev/null
@@ -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 (file)
index 0000000..304b9e0
--- /dev/null
@@ -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 (file)
index 0000000..654cb52
--- /dev/null
@@ -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 (file)
index 0000000..be24a17
--- /dev/null
@@ -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 (file)
index 0000000..df08bd2
--- /dev/null
@@ -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 (file)
index 0000000..3819fed
--- /dev/null
@@ -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;
+       }
+}
index 0c33447aaf9d9a33f999b0d136ba0865dd3c60ab..542bb4fde91e1b64865741436f8fb404f65d2db0 100644 (file)
@@ -24,6 +24,7 @@ HFILES=
 BIN=/$objtype/bin/games
 
 DIRS=\
+       2600\
        blabs\
        blit\
        c64\