From 76b51dc816a4e6ad1d21b6b40b8ea32a57bd47a6 Mon Sep 17 00:00:00 2001 From: aiju Date: Mon, 24 Feb 2014 22:50:05 +0100 Subject: games/nes: added dmc, fixed envelope, added cnrom --- sys/src/games/nes/apu.c | 90 +++++++++++++++++++++++++++++++++++++---------- sys/src/games/nes/dat.h | 9 +++-- sys/src/games/nes/fns.h | 1 + sys/src/games/nes/mem.c | 50 +++++++++++++++++++++++++- sys/src/games/nes/nes.c | 10 ++++-- sys/src/games/nes/state.c | 4 +++ 6 files changed, 139 insertions(+), 25 deletions(-) (limited to 'sys/src') diff --git a/sys/src/games/nes/apu.c b/sys/src/games/nes/apu.c index 53b851d86..30d6399c7 100644 --- a/sys/src/games/nes/apu.c +++ b/sys/src/games/nes/apu.c @@ -7,7 +7,17 @@ enum { MAXBUF = 2000 }; -u8int apuseq, apuctr[10]; +enum { + LEN = 0, + ENV = 4, + TRILIN = 6, + SWEEP = 8, + RELOAD = 10, + DMCCTR = 11, + DMCSHFT = 12, +}; +u8int apuseq, apuctr[13]; +u16int dmcaddr, dmccnt; static int fd; static short sbuf[2*MAXBUF], *sbufp; @@ -41,10 +51,10 @@ declen(void) m >>= 2; if((m & 0x20) != 0) continue; - if(apuctr[i] != 0) - apuctr[i]--; + if(apuctr[LEN + i] != 0) + apuctr[LEN + i]--; } - for(i = 0, a = apuctr + 8; i < 2; i++, a++){ + for(i = 0, a = apuctr + SWEEP; i < 2; i++, a++){ m = mem[0x4001 + i * 4]; if((m & 0x80) != 0 && (m & 0x07) != 0 && (*a & 7) == 0){ p = targperiod(i); @@ -66,19 +76,23 @@ doenv(void) int i, m; u8int *a; - for(i = 0, a = apuctr + 4; i < 4; i++, a++){ + for(i = 0, a = apuctr + ENV; i < 4; i++, a++){ if(i == 2) continue; m = mem[0x4000 + 4 * i]; - if((*a & 0x80) != 0) - *a = *a & 0x70 | 0x0f; - else if(*a == 0){ - if((m & 0x20) != 0) - *a |= 0x0f; + if((apuctr[RELOAD] & (1<= f/2 || apuctr[i] == 0) + s = apuctr[ENV + i] >> 4; + if(c[i] >= f/2 || apuctr[LEN + i] == 0) s = 0; return s; } @@ -168,7 +181,7 @@ tri(void) c++; i = 32 * c / f; i ^= (i < 16) ? 0xf : 0x10; - if(apuctr[2] == 0 || (apuctr[6] & 0x7f) == 0) + if(apuctr[LEN + 2] == 0 || (apuctr[TRILIN] & 0x7f) == 0) return 0; return i; } @@ -191,18 +204,18 @@ noise(void) r >>= 1; c -= f; } - if(apuctr[3] == 0 || (r & 1) != 0) + if(apuctr[LEN + 3] == 0 || (r & 1) != 0) return 0; m = mem[0x400C]; if((m & 0x10) != 0) return m & 0xf; - return apuctr[7] & 0xf; + return apuctr[ENV + 3] >> 4; } static int dmc(void) { - return 0; + return mem[DMCBUF]; } void @@ -220,6 +233,40 @@ audiosample(void) } } +void +dmcstep(void) +{ + if((apuctr[DMCCTR] & 7) == 0){ + apuctr[DMCCTR] = 8; + if(dmccnt != 0){ + apuctr[DMCSHFT] = memread(dmcaddr); + if(dmcaddr == 0xFFFF) + dmcaddr = 0x8000; + else + dmcaddr++; + if(--dmccnt == 0){ + if((mem[DMCCTRL] & 0x40) != 0){ + dmcaddr = mem[DMCADDR] * 0x40 + 0xC000; + dmccnt = mem[DMCLEN] * 0x10 + 1; + }else if((mem[DMCCTRL] & 0x80) != 0) + irq |= IRQDMC; + } + }else + apuctr[DMCCTR] |= 0x80; + } + if((apuctr[DMCCTR] & 0x80) == 0){ + if((apuctr[DMCSHFT] & 1) != 0){ + if(mem[DMCBUF] < 126) + mem[DMCBUF] += 2; + }else{ + if(mem[DMCBUF] > 1) + mem[DMCBUF] -= 2; + } + } + apuctr[DMCSHFT] >>= 1; + apuctr[DMCCTR]--; +} + int audioout(void) { @@ -252,3 +299,8 @@ u8int apulen[32] = { 0x0C, 0x10, 0x18, 0x12, 0x30, 0x14, 0x60, 0x16, 0xC0, 0x18, 0x48, 0x1A, 0x10, 0x1C, 0x20, 0x1E, }; + +u16int dmclen[16] = { + 0x1AC, 0x17C, 0x154, 0x140, 0x11E, 0x0FE, 0x0E2, 0x0D6, + 0x0BE, 0x0A0, 0x08E, 0x080, 0x06A, 0x054, 0x048, 0x036, +}; diff --git a/sys/src/games/nes/dat.h b/sys/src/games/nes/dat.h index be58a805b..4f774dfe3 100644 --- a/sys/src/games/nes/dat.h +++ b/sys/src/games/nes/dat.h @@ -10,9 +10,10 @@ extern int map, scale, mmc3hack, oflag; extern uchar *prg, *chr; extern int nprg, nchr, map, chrram; -extern u8int apuseq, apuctr[10]; +extern u8int apuseq, apuctr[13]; +extern u16int dmcaddr, dmccnt; -extern int keys, clock, ppuclock, apuclock, saveclock, paused; +extern int keys, clock, ppuclock, apuclock, dmcclock, dmcfreq, saveclock, paused; extern void (*mapper[])(int, u8int); @@ -31,6 +32,10 @@ enum { PPUMASK = 0x2001, PPUSTATUS = 0x2002, PPUSCROLL = 0x2005, + DMCCTRL = 0x4010, + DMCBUF = 0x4011, + DMCADDR = 0x4012, + DMCLEN = 0x4013, APUSTATUS = 0x4015, APUFRAME = 0x4017, diff --git a/sys/src/games/nes/fns.h b/sys/src/games/nes/fns.h index cb82000d9..f7741f3e5 100644 --- a/sys/src/games/nes/fns.h +++ b/sys/src/games/nes/fns.h @@ -13,3 +13,4 @@ void apustep(void); void initaudio(void); void audiosample(void); int audioout(void); +void dmcstep(void); diff --git a/sys/src/games/nes/mem.c b/sys/src/games/nes/mem.c index a19725ef2..79297a977 100644 --- a/sys/src/games/nes/mem.c +++ b/sys/src/games/nes/mem.c @@ -167,6 +167,40 @@ uxrom(int p, u8int v) prgb[0] = prg + b * 0x4000; } +static void +cnrom(int p, u8int v) +{ + static u8int b; + + if(p < 0) + switch(p){ + case INIT: + prgsh = 14; + chrsh = 13; + prgb[0] = prg; + if(nprg == 1) + prgb[1] = prg; + else + prgb[1] = prg + 0x4000; + break; + case SAVE: + put8(b); + return; + case RSTR: + b = get8(); + break; + case SCAN: + return; + default: + nope(p); + return; + } + else + b = v % nchr; + chrb[0] = chr + b * 0x2000; + +} + static void mmc3(int p, u8int v) { @@ -289,6 +323,7 @@ void (*mapper[256])(int, u8int) = { [0] nrom, [1] mmc1, [2] uxrom, + [3] cnrom, [4] mmc3, [7] axrom, }; @@ -368,6 +403,7 @@ void memwrite(u16int p, u8int v) { extern u8int apulen[32]; + extern u16int dmclen[16]; int i; if(p < 0x2000){ @@ -422,9 +458,17 @@ memwrite(u16int p, u8int v) i = (p & 0xC) >> 2; if((mem[APUSTATUS] & (1<> 3]; - apuctr[i+4] |= 0x80; + apuctr[10] |= (1<= 4){ ppustep(); ppuclock -= 4; @@ -262,6 +262,10 @@ threadmain(int argc, char **argv) audiosample(); sampclock -= SAMPDIV; } + if(dmcclock >= dmcfreq){ + dmcstep(); + dmcclock -= dmcfreq; + } if(msgclock > 0){ msgclock -= t; if(msgclock <= 0){ diff --git a/sys/src/games/nes/state.c b/sys/src/games/nes/state.c index 00d0450f4..e1b37f54a 100644 --- a/sys/src/games/nes/state.c +++ b/sys/src/games/nes/state.c @@ -94,6 +94,8 @@ loadstate(char *file) ppuclock = get32(); apuclock = get32(); apuseq = get8(); + dmcaddr = get16(); + dmccnt = get16(); read(fd, apuctr, sizeof(apuctr)); mapper[map](RSTR, 0); close(fd); @@ -133,6 +135,8 @@ savestate(char *file) put32(ppuclock); put32(apuclock); put8(apuseq); + put16(dmcaddr); + put16(dmccnt); write(fd, apuctr, sizeof(apuctr)); mapper[map](SAVE, 0); close(fd); -- cgit v1.2.3