From f6eacf471e61b188607690e4cdc28a2d94f7db14 Mon Sep 17 00:00:00 2001 From: aiju Date: Sat, 7 Feb 2015 18:03:17 +0100 Subject: [PATCH] added games/c64 --- sys/lib/c64/basic.bin | Bin 0 -> 8192 bytes sys/lib/c64/crom.bin | Bin 0 -> 4096 bytes sys/lib/c64/kernal.bin | Bin 0 -> 8192 bytes sys/src/games/c64/c64.c | 373 ++++++++++++++++++++++++++++ sys/src/games/c64/cpu.c | 514 +++++++++++++++++++++++++++++++++++++++ sys/src/games/c64/dat.h | 95 ++++++++ sys/src/games/c64/fns.h | 11 + sys/src/games/c64/mem.c | 304 +++++++++++++++++++++++ sys/src/games/c64/mkfile | 13 + sys/src/games/c64/vic.c | 366 ++++++++++++++++++++++++++++ 10 files changed, 1676 insertions(+) create mode 100644 sys/lib/c64/basic.bin create mode 100644 sys/lib/c64/crom.bin create mode 100644 sys/lib/c64/kernal.bin create mode 100644 sys/src/games/c64/c64.c create mode 100644 sys/src/games/c64/cpu.c create mode 100644 sys/src/games/c64/dat.h create mode 100644 sys/src/games/c64/fns.h create mode 100644 sys/src/games/c64/mem.c create mode 100644 sys/src/games/c64/mkfile create mode 100644 sys/src/games/c64/vic.c diff --git a/sys/lib/c64/basic.bin b/sys/lib/c64/basic.bin new file mode 100644 index 0000000000000000000000000000000000000000..9e06923a0f04494a071ca9b5da1dd1796ef8e597 GIT binary patch literal 8192 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 literal 0 HcmV?d00001 diff --git a/sys/lib/c64/crom.bin b/sys/lib/c64/crom.bin new file mode 100644 index 0000000000000000000000000000000000000000..191ac46020700b54be928ced7772b053d794fa72 GIT binary patch literal 4096 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 eo0Y +#include +#include +#include +#include +#include +#include "dat.h" +#include "fns.h" + +char *bindir = "/sys/lib/c64"; +Image *tmp, *bg, *red; +Rectangle picr, progr; +Mousectl *mc; +QLock pauselock; +int paused, scale; +u8int *rom; +int nrom; +u64int keys; +u16int joys; +uchar *tape, tapever, tapeplay; +ulong tapelen; +int joymode; + +void +progress(int a, int b) +{ + static int cur; + int w; + + if(b == 0 || a == 0){ + if(cur != 0){ + draw(screen, progr, bg, nil, ZP); + cur = 0; + } + return; + } + w = a * Dx(progr) / b; + if(cur == w) + return; + draw(screen, Rect(progr.min.x, progr.min.y, progr.min.x + w, progr.max.y), red, nil, ZP); + cur = w; +} + +static void +loadsys(char *name, u8int *p, int n) +{ + static char buf[256]; + int fd; + + snprint(buf, sizeof(buf), "%s/%s", bindir, name); + fd = open(buf, OREAD); + if(fd < 0) + sysfatal("open: %r"); + if(readn(fd, p, n) < n) + sysfatal("readn: %r"); + close(fd); +} + +static void +loadrom(char *name) +{ + int fd; + + fd = open(name, OREAD); + if(fd < 0) + sysfatal("open: %r"); + nrom = seek(fd, 0, 2); + if(nrom > 4096) + sysfatal("large ROM not supported"); + if((nrom & nrom-1) != 0) + sysfatal("non-power-of-two ROM size"); + rom = malloc(nrom); + if(rom == nil) + sysfatal("malloc: %r"); + pread(fd, rom, nrom, 0); + close(fd); +} + +static void +loadcart(char *name) +{ + int fd; + u16int t, l; + u8int buf[80]; + + fd = open(name, OREAD); + if(fd < 0) + sysfatal("open: %r"); + read(fd, buf, 80); + if(memcmp(buf, "C64 CARTRIDGE ", 16) != 0) + sysfatal("not a c64 cartridge"); + t = buf[0x16] << 8 | buf[0x17]; + if(t != 0) + sysfatal("unsupported type %d", t); + if(buf[0x18] == 0) pla &= ~EXROM; + if(buf[0x19] == 0) pla &= ~GAME; + t = buf[0x4c] << 8 | buf[0x4d]; + if(t < 0x8000 || t >= 0xc000 && t < 0xe000) + sysfatal("odd starting address %x", t); + if(t >= 0xe000) + t -= 0x4000; + t -= 0x8000; + l = buf[0x4e] << 8 | buf[0x4f]; + if(l + t > 16384) + sysfatal("cart too large"); + read(fd, cart + t, l); + close(fd); +} + +static void +loadtape(char *name) +{ + int fd; + uchar buf[20]; + + fd = open(name, OREAD); + if(fd < 0) + sysfatal("open: %r"); + read(fd, buf, 20); + if(memcmp(buf, "C64-TAPE-RAW", 12) != 0) + sysfatal("not a c64 raw tape"); + tapever = buf[12]; + if(tapever > 1) + sysfatal("unsupported tape version %d", tapever); + tapelen = buf[16] | buf[17] << 8 | buf[18] << 16 | buf[19] << 24; + tape = malloc(tapelen); + readn(fd, tape, tapelen); + close(fd); +} + +static void +keyproc(void *) +{ + int fd, i, setnmi; + u16int j; + u64int k; + static Rune keymap[64] = { + Kbs, '\n', Kleft, KF|7, KF|1, KF|3, KF|5, Kup, + '3', 'w', 'a', '4', 'z', 's', 'e', Kshift, + '5', 'r', 'd', '6', 'c', 'f', 't', 'x', + '7', 'y', 'g', '8', 'b', 'h', 'u', 'v', + '9', 'i', 'j', '0', 'm', 'k', 'o', 'n', + '\'', 'p', 'l', '-', '.', ':', '@', ',', + '[', '*', ';', Khome, Kalt, '=', ']', '/', + '1', Kins, '\t', '2', ' ', Kctl, 'q', Kdel + }; + static char buf[256]; + char *s; + Rune r; + + fd = open("/dev/kbd", OREAD); + if(fd < 0) + sysfatal("open: %r"); + for(;;){ + if(read(fd, buf, sizeof(buf) - 1) <= 0) + sysfatal("read /dev/kbd: %r"); + if(buf[0] == 'c'){ + if(utfrune(buf, Kend)){ + close(fd); + threadexitsall(nil); + } + if(utfrune(buf, KF|12)) + trace ^= 1; + } + if(buf[0] != 'k' && buf[0] != 'K') + continue; + s = buf + 1; + j = 0; + k = 0; + setnmi = 0; + while(*s != 0){ + s += chartorune(&r, s); + switch(r){ + case Kend: close(fd); threadexitsall(nil); + case Kesc: + if(paused) + qunlock(&pauselock); + else + qlock(&pauselock); + paused = !paused; + break; + case '`': + setnmi = 1; + break; + case Kleft: if(joymode) j |= 1<<2+5*(joymode-1); break; + case Kright: if(joymode) j |= 1<<3+5*(joymode-1); break; + case Kup: if(joymode) j |= 1<<0+5*(joymode-1); break; + case Kdown: if(joymode) j |= 1<<1+5*(joymode-1); break; + case Kctl: if(joymode) j |= 1<<4+5*(joymode-1); break; + } + for(i = 0; i < 64; i++) + if(keymap[i] == r) + k |= 1ULL<r.min, screen->r.max), 2); + picr = (Rectangle){subpt(p, Pt(picw/2*scale, pich/2*scale)), addpt(p, Pt(picw/2*scale, pich/2*scale))}; + p.y += pich*scale*3/4; + q = Pt(Dx(screen->r) * 2/5, 8); + progr = (Rectangle){subpt(p, q), addpt(p, q)}; + tmp = allocimage(display, Rect(0, 0, picw*scale, scale > 1 ? 1 : pich), XRGB32, 1, 0); + bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF); + red = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xFF0000FF); + draw(screen, screen->r, bg, nil, ZP); +} + +static void +usage(void) +{ + fprint(2, "usage: %s [ -23a ] [ rom ]\n", argv0); + exits("usage"); +} + +void +threadmain(int argc, char **argv) +{ + scale = 1; + + memreset(); + + ARGBEGIN { + case '2': + scale = 2; + break; + case '3': + scale = 3; + break; + case 'c': + loadcart(EARGF(usage())); + break; + case 't': + loadtape(EARGF(usage())); + break; + case 'N': + region = NTSC0; + break; + case 'p': + region = PAL; + break; + case 'd': + bindir = strdup(EARGF(usage())); + break; + default: + usage(); + } ARGEND; + if(argc >= 2) + usage(); + loadsys("kernal.bin", krom, 8192); + loadsys("basic.bin", brom, 8192); + loadsys("crom.bin", crom, 4096); + + vicreset(); + + if(initdraw(nil, nil, nil) < 0) + sysfatal("initdraw: %r"); + mc = initmouse(nil, screen); + if(mc == nil) + sysfatal("initmouse: %r"); + screeninit(); + proccreate(keyproc, nil, mainstacksize); + + nmien = IRQRESTORE; + pc = memread(0xFFFC) | memread(0xFFFD) << 8; + rP = FLAGI; + for(;;){ + if(paused){ + qlock(&pauselock); + qunlock(&pauselock); + } + step(); + } +} + +static void +menu(void) +{ + enum { JOY, TAPE }; + static char joystr[32] = "joy: none"; + static char tapestr[32] = "tape: play"; + static char *items[] = { + [JOY] joystr, + [TAPE] tapestr, + nil + }; + static Menu m = { + items, nil, 0 + }; + + switch(menuhit(3, mc, &m, nil)){ + case JOY: + joymode = (joymode + 1) % 3; + if(joymode == 0) + strcpy(joystr, "joy: none"); + else + sprint(joystr, "joy: %d", joymode); + break; + case TAPE: + tapeplay ^= 1; + if(tapeplay == 0){ + strcpy(tapestr, "tape: play"); + progress(0, 0); + }else + strcpy(tapestr, "tape: stop"); + break; + } +} + +void +flush(void) +{ + extern u8int pic[]; +// vlong new, diff; +// static vlong old, delta; + + if(nbrecvul(mc->resizec) > 0){ + if(getwindow(display, Refnone) < 0) + sysfatal("resize failed: %r"); + screeninit(); + } + while(nbrecv(mc->c, &mc->Mouse) > 0) + if((mc->buttons & 4) != 0) + menu(); + if(scale == 1){ + loadimage(tmp, tmp->r, pic, picw*pich*4); + draw(screen, picr, tmp, nil, ZP); + }else{ + Rectangle r; + uchar *s; + int w; + + s = pic; + r = picr; + w = picw*4*scale; + while(r.min.y < picr.max.y){ + loadimage(tmp, tmp->r, s, w); + s += w; + r.max.y = r.min.y+scale; + draw(screen, r, tmp, nil, ZP); + r.min.y = r.max.y; + } + } + flushimage(display, 1); +/* + if(audioout() < 0){ + new = nsec(); + diff = 0; + if(old != 0){ + diff = BILLION/60 - (new - old) - delta; + if(diff >= MILLION) + sleep(diff/MILLION); + } + old = nsec(); + if(diff != 0){ + diff = (old - new) - (diff / MILLION) * MILLION; + delta += (diff - delta) / 100; + } + } +*/ +} diff --git a/sys/src/games/c64/cpu.c b/sys/src/games/c64/cpu.c new file mode 100644 index 000000000..5f77ff92f --- /dev/null +++ b/sys/src/games/c64/cpu.c @@ -0,0 +1,514 @@ +#include +#include +#include "dat.h" +#include "fns.h" + +u16int pc, curpc; +u8int rA, rX, rY, rS, rP; +int nrdy, irq, nmi, nmi0, irqen, nmien; + +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) +{ + memread(pc); + if(brk) + pc++; + push16(pc); + push8(rP | 0x20 | (brk << 4)); + pc = memread(0xFFFA | (!nmi << 2)); + pc |= memread(0xFFFB | (!nmi << 2)) << 8; + rP |= FLAGI; +} + +int trace; + +void +step(void) +{ + u8int op; + u16int a, v; + + if(nrdy){ + io(); + return; + } + if((nmi & nmien) != 0 && (nmi0 & nmien) == 0){ + nmi0 = nmi; + interrupt(1, 0); + return; + } + nmi0 = nmi; + if((irq & irqen) != 0 && (rP & FLAGI) == 0){ + interrupt(0, 0); + return; + } + curpc = pc; + op = fetch8(); + if(trace) + print("%.4x %.2x | %.2x %.2x %.2x | %.2x %.2x | %3d %3d %.6x %.6x\n", curpc, op, rA, rX, rY, rS, rP, ppux-3, ppuy, irq, nmi); + 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: + print("undefined %#x (pc %#x)\n", op, curpc); + return; + } +} diff --git a/sys/src/games/c64/dat.h b/sys/src/games/c64/dat.h new file mode 100644 index 000000000..f8f1de1ce --- /dev/null +++ b/sys/src/games/c64/dat.h @@ -0,0 +1,95 @@ +typedef char s8int; + +extern u8int reg[47], crom[4096], krom[8192], brom[8192], cram[1024], cart[16384]; + +extern u16int pc, curpc; +extern u8int rP; +extern int nrdy, irq, nmi, irqen, nmien, trace; + +extern u8int pla; + +extern uchar *tape, tapever, tapeplay; +extern ulong tapelen; + +extern u16int ppux, ppuy, picw, pich; +extern u64int keys; +extern u16int joys; +extern int scale, region; + +enum { + FLAGC = 1<<0, + FLAGZ = 1<<1, + FLAGI = 1<<2, + FLAGD = 1<<3, + FLAGB = 1<<4, + FLAGV = 1<<6, + FLAGN = 1<<7, +}; + +enum { + IRQRASTER = 1<<0, + IRQBGCOLL = 1<<1, + IRQSPRCOLL = 1<<2, + IRQLIGHT = 1<<3, + IRQTIMERA = 1<<4, + IRQTIMERB = 1<<5, + IRQTOD = 1<<6, + IRQSDR = 1<<7, + IRQFLAG = 1<<8, + IRQRESTORE = 1<<9, +}; + +enum{ + MSBX = 0x10, + CTRL1 = 0x11, + RASTER = 0x12, + SPREN = 0x15, + CTRL2 = 0x16, + SPRYE = 0x17, + MEMP = 0x18, + IRQLATCH = 0x19, + IRQEN = 0x1a, + SPRDP = 0x1b, + SPRMC = 0x1c, + SPRXE = 0x1d, + SPRSPR = 0x1e, + SPRBG = 0x1f, + EC = 0x20, + BG0 = 0x21, + BG1 = 0x22, + BG2 = 0x23, + BG3 = 0x24, + SPRMC0 = 0x25, + SPRMC1 = 0x26, + SPRCOL = 0x27 +}; + +enum { + LORAM = 1, + HIRAM = 2, + CHAREN = 4, + GAME = 8, + EXROM = 16, + + ECM = 0x40, + BMM = 0x20, + DEN = 0x10, + RSEL = 0x08, + CSEL = 0x08, + + MCM = 0x10, +}; + +enum { + BILLION = 1000*1000*1000, + MILLION = 1000*1000, + HZ = 3579545, + RATE = 44100, + SAMPDIV = HZ / 3 / RATE, +}; + +enum { + NTSC, + NTSC0, + PAL +}; diff --git a/sys/src/games/c64/fns.h b/sys/src/games/c64/fns.h new file mode 100644 index 000000000..9ef05a102 --- /dev/null +++ b/sys/src/games/c64/fns.h @@ -0,0 +1,11 @@ +u8int memread(u16int); +void memwrite(u16int, u8int); +void step(void); +void vicstep(void); +void flush(void); +u8int vmemread(u16int); +void io(void); +void memreset(void); +void vicreset(void); +void bordset(void); +void progress(int, int); diff --git a/sys/src/games/c64/mem.c b/sys/src/games/c64/mem.c new file mode 100644 index 000000000..1b13f2465 --- /dev/null +++ b/sys/src/games/c64/mem.c @@ -0,0 +1,304 @@ +#include +#include +#include +#include "dat.h" +#include "fns.h" + +u8int pla; +u8int ram[65536], krom[8192], brom[8192], crom[4096], cart[16384], cram[1024]; +u8int reg[47]; +u16int vicbank; +u8int cia[32]; +u16int timer[4], timrel[4]; + +enum { + TIMEREN = 1, + TIMERUND = 2, + TIMERSTOP = 8, + TIMERASRC = 0x20, + TIMERBSRC = 0x60, + TIMERBSYS = 0, + TIMERBA = 0x40, +}; + +u8int +ciaread(int n, u8int a) +{ + u8int r; + int i; + + switch(a){ + case 0: + return (cia[0] | ~cia[2]) & (~joys >> 5 | 0xe0); + case 1: + if(!n){ + r = 0; + for(i = 0; i < 8; i++) + if((cia[0] & 1<> 8 * i; + return (cia[1] | ~cia[3]) & ~r & (~joys | 0xe0); + } + break; + case 4: return timer[n*2]; + case 5: return timer[n*2] >> 8; + case 6: return timer[n*2+1]; + case 7: return timer[n*2+1] >> 8; + case 13: + if(n){ + r = nmi >> 4 & 0x1f | ((nmi & nmien & 0x1f0) != 0) << 7; + nmi &= ~0x1f0; + return r; + }else{ + r = irq >> 4 & 0x1f | ((irq & irqen & 0x1f0) != 0) << 7; + irq &= ~0x1f0; + return r; + } + } + return cia[n * 16 + a]; +} + +void +ciawrite(int n, u8int a, u8int v) +{ + switch(a){ + case 0: + if(n) + vicbank = (~v & 3) << 14; + break; + case 4: timrel[n*2] = v | timrel[n*2] & 0xff00; break; + case 5: timrel[n*2] = v << 8 | timrel[n*2] & 0xff; break; + case 6: timrel[n*2+1] = v | timrel[n*2+1] & 0xff00; break; + case 7: timrel[n*2+1] = v << 8 | timrel[n*2+1] & 0xff; break; + case 13: + if(n) + if((v & 0x80) != 0) + nmien |= v << 4 & 0x1f0; + else + nmien &= ~(v << 4 & 0x1f0); + else + if((v & 0x80) != 0) + irqen |= v << 4 & 0x1f0; + else + irqen &= ~(v << 4 & 0x1f0); + break; + case 14: case 15: + if((v & 0x10) != 0){ + timer[n * 2 + (a & 1)] = timrel[n * 2 + (a & 1)]; + v &= ~0x10; + } + break; + } + cia[n * 16 + a] = v; +} + +u8int +mioread(u16int a) +{ + u8int b, v; + + switch(a & 0xc00){ + case 0: + b = a & 63; + switch(b){ + case CTRL1: + return reg[b] & 0x7f | ppuy >> 1 & 0x80; + case RASTER: + return ppuy; + case IRQLATCH: + return irq & 0xf | (irq & irqen & 0xf) + 0x7f & 0x80; + case IRQEN: + return irqen & 0xf; + case SPRSPR: + case SPRBG: + v = reg[b]; + reg[b] = 0; + return v; + } + if(b >= 0x20) + return reg[b] | 0xf0; + if(b >= 47) + return 0xff; + return reg[b]; + case 0x800: + return cram[a & 0x3ff]; + case 0xc00: + if((a & 0x200) == 0) + return ciaread(a >> 8 & 1, a & 0xf); + default: + return 0xff; + } +} + +void +miowrite(u16int a, u8int v) +{ + u8int b; + + switch(a & 0xc00){ + case 0: + b = a & 63; + if(b >= 0x20) + v &= 0xf; + switch(b){ + case CTRL2: v |= 0xc0; break; + case IRQLATCH: + v |= 0xf0; + irq &= ~(v & 0xf); + break; + case IRQEN: + irqen = irqen & ~0xf | v & 0xf; + v |= 0xf0; + break; + } + if(b < 47) + reg[b] = v; + if(b == CTRL1 || b == CTRL2) + bordset(); + return; + case 0x800: + cram[a & 0x3ff] = v & 0xf; + return; + case 0xc00: + if((a & 0x200) == 0) + ciawrite(a >> 8 & 1, a & 0xf, v); + return; + } +} + +void +tapestep(void) +{ + static int tapectr; + static int idx; + + if((ram[1] & 1<<5) != 0) + return; + if(tapectr == 0){ + if(idx >= tapelen){ + progress(0, 0); + tapeplay = 0; + idx = 0; + return; + } + tapectr = tape[idx++] << 3; + if(tapever == 1 && tapectr == 0){ + tapectr = tape[idx++]; + tapectr |= tape[idx++] << 8; + tapectr |= tape[idx++] << 16; + } + progress(idx, tapelen); + }else{ + tapectr--; + if(tapectr == 0) + irq |= IRQFLAG; + } +} + +void +timerstep(void) +{ + int i, at; + u8int a, b; + u16int *t; + + for(i = 0; i < 2; i++){ + a = cia[i * 16 + 14]; + b = cia[i * 16 + 15]; + at = 0; + t = &timer[2 * i]; + if((a & (TIMEREN|TIMERASRC)) == TIMEREN){ + t[0]--; + if(t[0] == 0){ + at = 1; + if(i) + nmi |= IRQTIMERA; + else + irq |= IRQTIMERA; + if((a & TIMERSTOP) != 0) + cia[i * 16 + 14] &= ~TIMEREN; + t[0] = timrel[2 * i]; + } + } + if((b & TIMEREN) != 0 && ((b & TIMERBSRC) == TIMERBSYS || (b & TIMERBSRC) == TIMERBA && at)){ + t[1]--; + if(t[1] == 0){ + if(i) + nmi |= IRQTIMERB; + else + irq |= IRQTIMERB; + if((b & TIMERSTOP) == 0) + cia[i * 16 + 15] &= ~TIMEREN; + t[1] = timrel[2 * i + 1]; + } + } + } + if(tapeplay) + tapestep(); +} + +void +io(void) +{ + vicstep(); + timerstep(); +} + +u8int +memread(u16int a) +{ + io(); + if(a == 1) + return ram[1] & ~(1<<4) | (tapeplay ^ 1) << 4; + switch(a >> 12){ + case 8: case 9: + if((pla & (EXROM|GAME)) == EXROM || (pla & (EXROM|HIRAM|LORAM)) == (HIRAM|LORAM)) + return cart[a & 0x1fff]; + goto def; + case 10: case 11: + if((pla & (GAME|HIRAM|LORAM)) == (GAME|HIRAM|LORAM)) + return brom[a & 0x1fff]; + if((pla & (EXROM|GAME|HIRAM)) == HIRAM) + return cart[8192 + (a & 0x1fff)]; + goto def; + case 13: + if((pla & (HIRAM|LORAM)) == 0 || pla == 1) + goto def; + if((pla & CHAREN) == 0 && (pla & (EXROM|GAME)) != EXROM) + return crom[a & 0xfff]; + return mioread(a & 0xfff); + case 14: case 15: + if((pla & (EXROM|GAME)) == EXROM) + return cart[8192 + (a & 0x1fff)]; + if((pla & HIRAM) == HIRAM) + return krom[a & 0x1fff]; + def: + default: + return ram[a]; + } +} + +void +memwrite(u16int a, u8int v) +{ + if(a >> 12 == 13 && !((pla & (HIRAM|LORAM)) == 0 || pla == 1 || (pla & CHAREN) == 0 && (pla & (EXROM|GAME)) != EXROM)) + miowrite(a & 0xfff, v); + ram[a] = v; + if(a == 1) + pla = pla & ~7 | v & 7; + io(); +} + +u8int +vmemread(u16int a) +{ + a |= vicbank; + if((a & 0x7000) == 0x1000) + return crom[a & 0xfff]; + return ram[a]; +} + +void +memreset(void) +{ + pla = 0x1f; +} diff --git a/sys/src/games/c64/mkfile b/sys/src/games/c64/mkfile new file mode 100644 index 000000000..09f954bef --- /dev/null +++ b/sys/src/games/c64/mkfile @@ -0,0 +1,13 @@ + +#include +#include +#include "dat.h" +#include "fns.h" + +int region, picidx; +u16int ppux, ppuy, lastx, wrapx, maxy, lvis, rvis, uvis, dvis, picw, pich, lbord, rbord, ubord, dbord, spr0; +u16int vc, vcbase, vmli; +u8int badln, rc, displ, fract, visreg, hbord, vbord, rbord0, lbord0; +u16int chrp[40]; +u8int pic[400*300*3*3]; +u64int pxs, npxs, npxs0, opxs; +u8int fg; + +typedef struct spr spr; +enum { + SPRFDMA = 1, + SPRFYEX = 2, + SPRFDISP = 4, +}; +struct spr { + u8int flags; + u32int data; + u8int mc, mcbase, dp; + u16int x; +} sp[8]; + +void +bordset(void) +{ + int r, c; + + r = (reg[CTRL1] & RSEL) != 0; + c = (reg[CTRL2] & CSEL) != 0; + lbord = c ? 0x14 : 0x1c; + lbord0 = c ? 0xf0 : 0xe0; + rbord = c ? 0x154 : 0x14c; + rbord0 = c ? 0x0f : 0x3f; + ubord = r ? 0x33 : 0x37; + dbord = r ? 0xfb : 0xf7; + if((reg[CTRL1] & DEN) == 0) + ubord = -1; +} + +void +vicreset(void) +{ + switch(region){ + case NTSC0: + lastx = 0x1fc; + wrapx = 0x19c; + maxy = 262; + picw = 412; + pich = 234; + spr0 = 0x16c; + lvis = 0x1e4; + rvis = 0x184; + uvis = 41; + dvis = 13; + break; + case NTSC: + lastx = 0x1fc; + wrapx = 0x19c; + maxy = 263; + picw = 419; + pich = 235; + spr0 = 0x174; + lvis = 0x1e4; + rvis = 0x18c; + uvis = 41; + dvis = 13; + break; + case PAL: + lastx = 0x1f4; + wrapx = 0x194; + maxy = 312; + picw = 404; + pich = 284; + spr0 = 0x164; + lvis = 0x1dc; + rvis = 0x17c; + uvis = 16; + dvis = 300; + break; + } + ppux = 4; + ppuy = 0; + bordset(); +} + +void +pixeldraw(u64int p, int n) +{ + int i; + static u8int cr[] = {0, 255, 136, 170, 204, 0, 0, 238, 221, 102, 255, 51, 119, 170, 0, 187}; + static u8int cg[] = {0, 255, 0, 255, 68, 204, 0, 238, 136, 68, 119, 51, 119, 255, 136, 187}; + static u8int cb[] = {0, 255, 0, 238, 204, 85, 170, 119, 85, 0, 119, 51, 119, 102, 255, 187}; + u8int *q, c; + + q = pic + picidx * 4; + for(i = 0; i < n; i++){ + c = p >> 56; + p <<= 8; + + q[4 * i] = cb[c]; + q[4 * i + 1] = cg[c]; + q[4 * i + 2] = cr[c]; + } + picidx += n; +} + +void +pixels(u8int d, u16int c) +{ + u8int c0, c1, c2, n; + int i; + + npxs0 = npxs; + npxs = 0; + switch((reg[CTRL1] & (ECM|BMM) | reg[CTRL2] & MCM) >> 4){ + case 0: + c0 = c >> 8; + normal: + fg = d; + for(i = 0; i < 8; i++){ + npxs = npxs << 8 | ((d & 0x80) != 0 ? c0 : reg[BG0]); + d <<= 1; + } + break; + case 1: + c0 = c >> 8 & 7; + if((c & 0x800) == 0) + goto normal; + fg = d & 0xaa | d >> 1 & 0x55; + for(i = 0; i < 8; i += 2){ + n = d >> 6; + npxs = npxs << 16 | (n == 3 ? c0 : reg[BG0 + n]) * 0x101; + d <<= 2; + } + break; + case 2: + c0 = c & 15; + c1 = c >> 4 & 15; + fg = d; + for(i = 0; i < 8; i++){ + npxs = npxs << 8 | ((d & 0x80) != 0 ? c1 : c0); + d <<= 1; + } + break; + case 3: + c0 = c & 15; + c1 = c >> 4 & 15; + c2 = c >> 8; + fg = d & 0xaa | d >> 1 & 0x55; + for(i = 0; i < 8; i += 2){ + n = d >> 6; + switch(n){ + default: n = reg[BG0]; break; + case 1: n = c1; break; + case 2: n = c0; break; + case 3: n = c2; + } + npxs = npxs << 16 | n * 0x101; + d <<= 2; + } + break; + case 4: + c0 = c >> 8; + fg = d; + for(i = 0; i < 8; i++){ + npxs = npxs << 8 | ((d & 0x80) != 0 ? c0 : reg[BG0 + (d >> 6 & 3)]); + d <<= 1; + } + break; + default: + fg = 0; + break; + } +} + +void +bgpixels(void) +{ + int i, j, x; + u8int h; + u8int spract, s, o; + + h = hbord; + opxs = 0; + for(i = 0; i < 8; i++){ + if((reg[CTRL2] + 4 & 7) == i) + pxs = i >= 4 ? npxs : npxs0; + o = pxs >> 56; + pxs <<= 8; + + x = ppux + i; + spract = 0; + for(j = 0; j < 8; j++) + if((sp[j].flags & SPRFDISP) != 0 && (u16int)(x-sp[j].x) < 48 && (sp[j].data & ((reg[SPRMC]&1<> 7); + if(s != 0) + for(j = 0; j < 8; j++) + if((s & 1<> 22 & 3){ + case 1: o = reg[SPRMC0]; break; + case 2: o = reg[SPRCOL+j]; break; + case 3: o = reg[SPRMC1]; break; + } + else + o = reg[SPRCOL+j]; + break; + } + if((h & 0x80) != 0) + o = reg[EC]; + opxs = opxs << 8 | o; + h <<= 1; + fg <<= 1; + for(j = 0; j < 8; j++) + if((u16int)(x-sp[j].x) < 48 && ((reg[SPRXE] & 1<> 7; + if(ppux == rbord && hbord == 0) + hbord = rbord0; + else if(ppux == lbord){ + if(ppuy == dbord) + vbord = 1; + if(ppuy == ubord) + vbord = 0; + if(!vbord) + hbord = lbord0; + } + if(badln) + displ = 1; + if(ppux == 4){ + vc = vcbase; + vmli = 0; + if(badln) + rc = 0; + } + if(ppux == 12) + for(i = 0; i < 8; i++){ + if((sp[i].flags & SPRFDISP) == 0 || (reg[SPRYE] & 1<= 0x14 && ppux <= 0x14c){ + if((reg[CTRL1] & BMM) != 0) + gaddr = (reg[MEMP] & 0x08) << 10 | vc << 3 | rc; + else + gaddr = (reg[MEMP] & 0x0e) << 10 | (chrp[vmli] & 0xff) << 3 | rc; + if(!displ) + gaddr = 0x3fff; + if((reg[CTRL1] & ECM) != 0) + gaddr &= ~0x600; + pixels(vmemread(gaddr) & -displ, chrp[vmli] & -displ); + vmli++; + vc = vc + 1 & 0x3ff; + } + if(visreg && (ppux >= lvis || ppux < rvis)){ + bgpixels(); + pixeldraw(opxs, ppux == lvis ? region == NTSC ? 3 : 4 : 8); + } + if(ppux == 0x14c){ + for(i = 0; i < 8; i++){ + if((reg[SPRYE] & 1<= 0xc && ppux <= 0x144) + chrp[vmli] = vmemread(vc | (reg[MEMP] & 0xf0) << 6) | cram[vc] << 8; + else if(ppux == 0x154) + nrdy = 0; + } + if(ppux == 0x164){ + if(displ && rc == 7){ + displ = badln; + vcbase = vc; + } + if(displ) + rc = rc + 1 & 7; + for(i = 0; i < 8; i++){ + sp[i].mc = sp[i].mcbase; + if((sp[i].flags & SPRFDMA) != 0 && reg[2*i+1] == (u8int)ppuy) + sp[i].flags |= SPRFDISP; + } + } + if((u16int)(ppux - spr0) < 128){ + i = ppux - spr0 >> 4; + nrdy = (sp[i].flags & SPRFDMA) != 0; + if((ppux & 8) == 0){ + sp[i].dp = vmemread((reg[MEMP] & 0xf0) << 6 | 0x3f8 | i); + sp[i].x = nrdy ? reg[2 * i] | reg[MSBX] << 8 - i & 0x100 : -1; + if(nrdy) + sp[i].data = vmemread(sp[i].dp << 6 | sp[i].mc++) << 16; + }else if(nrdy){ + sp[i].data = sp[i].data & 0xff00ff | vmemread(sp[i].dp << 6 | sp[i].mc++) << 8; + sp[i].data = sp[i].data & 0xffff00 | vmemread(sp[i].dp << 6 | sp[i].mc++); + } + }else if(ppux - spr0 == 128) + nrdy = 0; + if(ppux == wrapx){ + ppuy++; + if(ppuy == maxy){ + flush(); + ppuy = 0; + vcbase = 0; + } + if((ppuy & 0xff) == reg[RASTER] && ((ppuy ^ reg[CTRL1] << 1) & 0x100) == 0) + irq |= IRQRASTER; + if(ppuy == dbord) + vbord = 1; + else if(ppuy == ubord) + vbord = 0; + else if(ppuy == dvis) + visreg = 0; + if(ppuy == uvis){ + picidx = 0; + visreg = 1; + } + if(ppuy == 0xf7) + fract = 0; + } + if(ppux == lastx) + ppux = 4; + else + ppux += 8; +}