diff options
author | aiju <devnull@localhost> | 2015-02-07 18:03:17 +0100 |
---|---|---|
committer | aiju <devnull@localhost> | 2015-02-07 18:03:17 +0100 |
commit | f6eacf471e61b188607690e4cdc28a2d94f7db14 (patch) | |
tree | c97e1e616cbcb9052e77de624e78905c81a51c40 /sys/src/games | |
parent | 8ac5227a3626dd70a51d2c091b8730ce0f2d8403 (diff) |
added games/c64
Diffstat (limited to 'sys/src/games')
-rw-r--r-- | sys/src/games/c64/c64.c | 373 | ||||
-rw-r--r-- | sys/src/games/c64/cpu.c | 514 | ||||
-rw-r--r-- | sys/src/games/c64/dat.h | 95 | ||||
-rw-r--r-- | sys/src/games/c64/fns.h | 11 | ||||
-rw-r--r-- | sys/src/games/c64/mem.c | 304 | ||||
-rw-r--r-- | sys/src/games/c64/mkfile | 13 | ||||
-rw-r--r-- | sys/src/games/c64/vic.c | 366 |
7 files changed, 1676 insertions, 0 deletions
diff --git a/sys/src/games/c64/c64.c b/sys/src/games/c64/c64.c new file mode 100644 index 000000000..b81de50e5 --- /dev/null +++ b/sys/src/games/c64/c64.c @@ -0,0 +1,373 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <draw.h> +#include <mouse.h> +#include <keyboard.h> +#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<<i; + } + if(setnmi) + nmi |= IRQRESTORE; + else + nmi &= ~IRQRESTORE; + keys = k; + joys = j; + } + +} + +static void +screeninit(void) +{ + Point p, q; + + p = divpt(addpt(screen->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 <u.h> +#include <libc.h> +#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 <u.h> +#include <libc.h> +#include <thread.h> +#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<<i) == 0) + r |= keys >> 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 @@ +</$objtype/mkfile + +BIN=/$objtype/bin/games +TARG=2600 +OFILES=\ + c64.$O\ + cpu.$O\ + mem.$O\ + vic.$O\ + +HFILES=dat.h fns.h + +</sys/src/cmd/mkone diff --git a/sys/src/games/c64/vic.c b/sys/src/games/c64/vic.c new file mode 100644 index 000000000..27c9d3674 --- /dev/null +++ b/sys/src/games/c64/vic.c @@ -0,0 +1,366 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#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<<j)?3:2)<<22) != 0) + spract |= 1<<j; + if((spract & spract - 1) != 0 && vbord == 0){ + reg[SPRSPR] |= spract; + irq |= IRQSPRCOLL; + } + if(fg != 0 && spract != 0 && vbord == 0){ + reg[SPRBG] |= spract; + irq |= IRQBGCOLL; + } + s = spract & ~(reg[SPRDP] & ((s8int)fg) >> 7); + if(s != 0) + for(j = 0; j < 8; j++) + if((s & 1<<j) != 0){ + if((reg[SPRMC] & 1<<j) != 0) + switch(sp[j].data >> 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<<j) == 0 || (x-sp[j].x & 1) != 0)) + if((reg[SPRMC] & 1<<j) != 0){ + if((x-sp[j].x & 1) != 0) + sp[j].data <<= 2; + }else + sp[j].data <<= 1; + } +} + +void +vicstep(void) +{ + u16int gaddr; + int i; + + if(ppuy == 0x30 && (reg[CTRL1] & DEN) != 0) + fract = 1; + badln = ((ppuy ^ reg[CTRL1]) & 7) == 0 && fract; + hbord = ((s8int)(hbord << 7)) >> 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<<i) != 0 && (sp[i].flags & SPRFYEX) == 0) + continue; + sp[i].mcbase += 3; + if(sp[i].mcbase == 63) + sp[i].flags &= ~(SPRFDMA|SPRFDISP); + } + if(ppux >= 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<<i) != 0) + sp[i].flags ^= SPRFYEX; + if((reg[SPREN] & 1<<i) == 0 || reg[2*i+1] != (u8int)ppuy) + continue; + sp[i].flags |= SPRFDMA; + sp[i].mcbase = 0; + if((reg[SPRYE] & 1<<i) != 0) + sp[i].flags &= ~SPRFYEX; + } + }else if(ppux == 0x154) + npxs = reg[BG0] * 0x0101010101010101ULL; + if(badln){ + if(ppux == lastx - 8) + nrdy = 1; + else if(ppux >= 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; +} |