ref: abf8c8bf2cd27541d6a102f7c0385c3fe281f578
parent: 1195ca910c393e542d6aa23035fa75719af1107e
author: qwx <devnull@localhost>
date: Sat May 12 15:21:48 EDT 2018
add port of aiju's port of games/2600
--- /dev/null
+++ b/sys/man/1/atari
@@ -1,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).
--- /dev/null
+++ b/sys/src/games/2600/2600.c
@@ -1,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);
+}
--- /dev/null
+++ b/sys/src/games/2600/aud.c
@@ -1,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;
+}
--- /dev/null
+++ b/sys/src/games/2600/cpu.c
@@ -1,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;
+ }
+}
--- /dev/null
+++ b/sys/src/games/2600/dat.h
@@ -1,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,
+};
--- /dev/null
+++ b/sys/src/games/2600/fns.h
@@ -1,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);
--- /dev/null
+++ b/sys/src/games/2600/mem.c
@@ -1,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();
+ }
+}
--- /dev/null
+++ b/sys/src/games/2600/mkfile
@@ -1,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
--- /dev/null
+++ b/sys/src/games/2600/tia.c
@@ -1,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;
+ }
+}
--- a/sys/src/games/mkfile
+++ b/sys/src/games/mkfile
@@ -24,6 +24,7 @@
BIN=/$objtype/bin/games
DIRS=\
+ 2600\
blabs\
blit\
c64\