add port of aiju's port of games/2600

This commit is contained in:
qwx 2018-05-12 19:21:48 +02:00
parent 1195ca910c
commit abf8c8bf2c
10 changed files with 1224 additions and 0 deletions

35
sys/man/1/atari Normal file
View file

@ -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).

96
sys/src/games/2600/2600.c Normal file
View file

@ -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);
}

81
sys/src/games/2600/aud.c Normal file
View file

@ -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;
}

501
sys/src/games/2600/cpu.c Normal file
View file

@ -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;
}
}

80
sys/src/games/2600/dat.h Normal file
View file

@ -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,
};

9
sys/src/games/2600/fns.h Normal file
View file

@ -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);

195
sys/src/games/2600/mem.c Normal file
View file

@ -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();
}
}

14
sys/src/games/2600/mkfile Normal file
View file

@ -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

212
sys/src/games/2600/tia.c Normal file
View file

@ -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;
}
}

View file

@ -24,6 +24,7 @@ HFILES=
BIN=/$objtype/bin/games
DIRS=\
2600\
blabs\
blit\
c64\