From af8c91cf6d30628c17c7d7cb9733dee9e7488ab0 Mon Sep 17 00:00:00 2001 From: aiju Date: Sat, 22 Feb 2014 17:43:15 +0100 Subject: [PATCH] games/nes: mmc3 and bugfixes --- sys/src/games/nes/cpu.c | 6 +- sys/src/games/nes/dat.h | 8 ++- sys/src/games/nes/mem.c | 130 +++++++++++++++++++++++++++++++++++----- sys/src/games/nes/ppu.c | 26 +++++--- 4 files changed, 142 insertions(+), 28 deletions(-) diff --git a/sys/src/games/nes/cpu.c b/sys/src/games/nes/cpu.c index f0469db8c..e21c2e88c 100644 --- a/sys/src/games/nes/cpu.c +++ b/sys/src/games/nes/cpu.c @@ -5,7 +5,7 @@ u16int pc, curpc; u8int rA, rX, rY, rS, rP; -int nmi; +u8int irq, nmi; static u8int fetch8(void) @@ -249,6 +249,10 @@ step(void) nmi = 0; return 7; } + if(irq && (rP & 4) == 0){ + interrupt(0, 0); + return 7; + } curpc = pc; op = fetch8(); if(trace) diff --git a/sys/src/games/nes/dat.h b/sys/src/games/nes/dat.h index 502c91f79..0dee8f83b 100644 --- a/sys/src/games/nes/dat.h +++ b/sys/src/games/nes/dat.h @@ -1,13 +1,14 @@ extern u16int pc, curpc; extern u8int rA, rX, rY, rS, rP; +extern u8int irq, nmi; extern uchar mem[32768], ppuram[16384], oam[256]; extern u16int pput, ppuv; extern u8int ppusx, vrambuf; extern int mirr, ppux, ppuy, odd, vramlatch, keylatch; -extern int map, scale; +extern int map, scale, mmc3hack; extern uchar *prg, *chr; -extern int nprg, nchr, nmi, map, chrram; +extern int nprg, nchr, map, chrram; extern int keys, clock, ppuclock; @@ -37,7 +38,7 @@ enum { GRAYSCALE = 1<<0, BG8DISP = 1<<1, - BG8SPRITE = 1<<2, + SPRITE8DISP = 1<<2, BGDISP = 1<<3, SPRITEDISP = 1<<4, @@ -84,4 +85,5 @@ enum { INIT = -1, SAVE = -2, RSTR = -3, + SCAN = -4, }; diff --git a/sys/src/games/nes/mem.c b/sys/src/games/nes/mem.c index 7b0395edd..9787f021e 100644 --- a/sys/src/games/nes/mem.c +++ b/sys/src/games/nes/mem.c @@ -8,10 +8,11 @@ uchar mem[32768]; uchar ppuram[16384]; uchar oam[256]; -uchar *prgb[2], *chrb[2]; +uchar *prgb[16], *chrb[16]; u16int pput, ppuv; u8int ppusx, vrambuf; int vramlatch = 1, keylatch = 0xFF; +int prgsh, chrsh, mmc3hack; static void nope(int p) @@ -32,10 +33,12 @@ nrom(int p, u8int) prgb[1] = prg; else prgb[1] = prg + 0x4000; + prgsh = 14; chrb[0] = chr; - chrb[1] = chr + 0x1000; + chrsh = 13; break; case SAVE: + case SCAN: break; default: nope(p); @@ -52,6 +55,8 @@ mmc1(int v, u8int p) switch(v){ case INIT: mode = 0x0C; + prgsh = 14; + chrsh = 12; goto t; case RSTR: mode = get8(); @@ -71,6 +76,8 @@ mmc1(int v, u8int p) break; default: nope(v); + case SCAN: + break; } return; } @@ -131,14 +138,103 @@ t: } static void -mmc7(int v, u8int p) +mmc3(int p, u8int v) +{ + static u8int m, b[8], l, n, en; + int i, j, c; + + if(p < 0){ + switch(p){ + case INIT: + prgsh = 13; + chrsh = 10; + mmc3hack = 1; + prgb[2] = prg + (2 * nprg - 2) * 0x2000; + prgb[3] = prgb[2] + 0x2000; + goto t; + case SCAN: + if(n == 0) + n = l; + else + n--; + if(n == 0 && en) + irq |= 2; + return; + case SAVE: + put8(m); + for(i = 0; i < 8; i++) + put8(b[i]); + put8(l); + put8(n); + put8(en); + return; + case RSTR: + m = get8(); + for(i = 0; i < 8; i++) + b[i] = get8(); + l = get8(); + n = get8(); + en = get8(); + goto t; + } + } + switch(p & 0xE001){ + case 0x8000: + if(((m ^ v) & 0xc0) != 0){ + m = v; + goto t; + } + m = v; + break; + case 0x8001: + i = m & 7; + if(i < 6) + v %= 8 * nchr; + else + v %= 2 * nprg; + b[i] = v; + goto t; + case 0xA000: + if(mirr == MFOUR) + break; + if(v & 1) + mirr = MHORZ; + else + mirr = MVERT; + break; + case 0xC000: l = v; break; + case 0xC001: n = 0; break; + case 0xE000: en = 0; irq &= ~2; break; + case 0xE001: en = 1; break; + } + return; +t: + if((m & 0x40) != 0){ + prgb[0] = prg + (2 * nprg - 2) * 0x2000; + prgb[2] = prg + b[6] * 0x2000; + }else{ + prgb[0] = prg + b[6] * 0x2000; + prgb[2] = prg + (2 * nprg - 2) * 0x2000; + } + prgb[1] = prg + b[7] * 0x2000; + c = (m & 0x80) >> 6; + for(i = 0; i < 2; i++){ + chrb[j = (i << 1) ^ c] = chr + (b[i] >> 1) * 0x800; + chrb[j+1] = chrb[j] + 0x400; + } + for(i = 2; i < 6; i++) + chrb[(i + 2) ^ c] = chr + b[i] * 0x400; +} + +static void +mmc7(int p, u8int v) { static int b; - if(v >= 0) - b = p; + if(p >= 0) + b = v; else - switch(v){ + switch(p){ case INIT: nrom(INIT, 0); b = 0; @@ -150,7 +246,7 @@ mmc7(int v, u8int p) b = get8(); break; default: - nope(v); + nope(p); return; } prgb[0] = prg + (b & 3) * 0x8000; @@ -160,17 +256,23 @@ mmc7(int v, u8int p) void (*mapper[256])(int, u8int) = { [0] nrom, [1] mmc1, + [4] mmc3, [7] mmc7, }; static void incvram(void) { + int old; + + old = ppuv; if((mem[PPUCTRL] & VRAMINC) != 0) ppuv += 32; else ppuv += 1; ppuv &= 0x3FFF; + if(mmc3hack && (old & (1<<12)) == 0 && (ppuv & (1<<12)) != 0) + mapper[map](SCAN, 0); } u8int @@ -212,10 +314,8 @@ memread(u16int p) } } if(p >= 0x8000){ - if((p & 0x4000) != 0) - return prgb[1][p - 0xC000]; - else - return prgb[0][p - 0x8000]; + p -= 0x8000; + return prgb[p >> prgsh][p & ((1 << prgsh) - 1)]; } return mem[p]; } @@ -253,6 +353,8 @@ memwrite(u16int p, u8int v) pput = (pput & 0xFF) | (v << 8) & 0x3F00; else{ pput = (pput & 0xFF00) | v; + if(mmc3hack && (ppuv & (1<<12)) == 0 && (pput & (1<<12)) != 0) + mapper[map](SCAN, 0); ppuv = pput; } vramlatch ^= 1; @@ -295,10 +397,8 @@ ppumap(u16int p) case MSINGA: p &= ~0xC00; break; case MSINGB: p |= 0xC00; break; } - if(p < 0x1000) - return chrb[0] + p; - else if(p < 0x2000) - return chrb[1] + p - 0x1000; + if(p < 0x2000) + return chrb[p >> chrsh] + (p & ((1 << chrsh) - 1)); else return ppuram + p; } diff --git a/sys/src/games/nes/ppu.c b/sys/src/games/nes/ppu.c index 2301d5565..77a759034 100644 --- a/sys/src/games/nes/ppu.c +++ b/sys/src/games/nes/ppu.c @@ -167,7 +167,7 @@ static void drawsprites(void) { uchar *p; - int big, dx, dy, i, x; + int big, dx, dy, i, x, cc, pri; u8int r1, r2, c; static int n, m, nz, s0, t0; static struct { u8int x, a; u16int t; } s[8], *sp; @@ -212,18 +212,22 @@ drawsprites(void) mem[PPUSTATUS] |= SPRITE0HIT; nz >>= 1; } + cc = -1; + pri = 0; for(i = m - 1; i >= 0; i--){ dx = x - t[i].x; if(dx < 0 || dx > 7) continue; c = (t[i].r1 & 1) | (t[i].r2 & 1) << 1; if(c != 0){ - if((t[i].a & (1<<5)) == 0 || !iscolor(x, ppuy)) - pixel(x, ppuy, pal(c, t[i].a & 3, 1), 0); + cc = pal(c, t[i].a & 3, 1); + pri = (t[i].a & (1<<5)) == 0; } t[i].r1 >>= 1; t[i].r2 >>= 1; } + if(cc != -1 && (pri || !iscolor(x, ppuy))) + pixel(x, ppuy, cc, 0); } if(ppux == 257){ for(i = 0; i < n; i++){ @@ -276,18 +280,22 @@ void ppustep(void) { extern int nmi; - int bg; + int mask; if(ppuy < 240 || ppuy == 261){ - bg = (mem[PPUMASK] & BGDISP) != 0; - if(bg) + mask = mem[PPUMASK]; + if((mask & BGDISP) != 0) drawbg(); - if((mem[PPUMASK] & SPRITEDISP) != 0 && ppuy != 261) + if(((mask & BGDISP) == 0 && ppux <= 257 || ppux <= 10 && (mask & BG8DISP) == 0) && ppux >= 2) + pixel(ppux - 2, ppuy, ppuread(0x3F00), 1); + if((mask & SPRITEDISP) != 0 && ppuy != 261 && (ppux > 10 || (mask & SPRITE8DISP) != 0)) drawsprites(); + if(ppux == 240 && (mask & SPRITEDISP) != 0) + mapper[map](SCAN, 0); if(ppuy == 261){ if(ppux == 1) mem[PPUSTATUS] &= ~(PPUVBLANK|SPRITE0HIT); - else if(ppux >= 280 && ppux <= 304 && bg) + else if(ppux >= 280 && ppux <= 304 && (mask & BGDISP) != 0) ppuv = (pput & 0x7BE0) | (ppuv & 0x041F); } }else if(ppuy == 241){ @@ -304,7 +312,7 @@ ppustep(void) ppuy++; if(ppuy > 261){ ppuy = 0; - if(odd && (mem[PPUCTRL] & (BGDISP | SPRITEDISP)) != 0) + if(odd && (mem[PPUMASK] & (BGDISP | SPRITEDISP)) != 0) ppux++; odd ^= 1; } -- 2.44.0