diff options
author | aiju <aiju@phicode.de> | 2014-02-24 22:50:29 +0100 |
---|---|---|
committer | aiju <aiju@phicode.de> | 2014-02-24 22:50:29 +0100 |
commit | d8489586ecaa1c80a93537f20dcf2a28757f4340 (patch) | |
tree | 21dc6f8202c48b010e6804893ccb3b9d16d2618c /sys | |
parent | 5e353e17c6d4410487bc33aaa07fdb3121962c16 (diff) | |
parent | 76b51dc816a4e6ad1d21b6b40b8ea32a57bd47a6 (diff) |
merge
Diffstat (limited to 'sys')
-rw-r--r-- | sys/src/games/nes/apu.c | 90 | ||||
-rw-r--r-- | sys/src/games/nes/dat.h | 9 | ||||
-rw-r--r-- | sys/src/games/nes/fns.h | 1 | ||||
-rw-r--r-- | sys/src/games/nes/mem.c | 50 | ||||
-rw-r--r-- | sys/src/games/nes/nes.c | 10 | ||||
-rw-r--r-- | sys/src/games/nes/state.c | 4 |
6 files changed, 139 insertions, 25 deletions
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<<i)) != 0) + *a = 0xf0 | m & 0x0f; + else if((*a & 0x0f) == 0){ + *a |= m & 0x0f; + if((*a & 0xf0) == 0){ + if((m & 0x20) != 0) + *a |= 0xf0; + }else + *a -= 0x10; }else (*a)--; } - a = apuctr + 6; + a = apuctr + TRILIN; if((*a & 0x80) != 0) *a = mem[0x4008]; else if(*a != 0) @@ -143,11 +157,10 @@ pulse(int i) c[i]++; m = mem[0x4000 + 4 * i]; if((m & 0x10) != 0) - s = m; + s = m & 0x0f; else - s = apuctr[i+4]; - s &= 0x0f; - if(c[i] >= 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 @@ -168,6 +168,40 @@ uxrom(int p, u8int v) } 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) { static u8int m, b[8], l, n, en; @@ -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<<i)) != 0){ apuctr[i] = apulen[v >> 3]; - apuctr[i+4] |= 0x80; + apuctr[10] |= (1<<i); } break; + case DMCCTRL: + if((v & 0x80) == 0) + irq &= ~IRQDMC; + dmcfreq = 12 * dmclen[v & 0xf]; + break; + case DMCBUF: + v &= ~0x80; + break; case 0x4014: memcpy(oam, mem + (v<<8), sizeof(oam)); return; @@ -432,6 +476,10 @@ memwrite(u16int p, u8int v) for(i = 0; i < 4; i++) if((v & (1<<i)) == 0) apuctr[i] = 0; + if((v & 0x10) != 0 && dmccnt == 0){ + dmcaddr = mem[DMCADDR] * 0x40 + 0xC000; + dmccnt = mem[DMCLEN] * 0x10 + 1; + } irq &= ~IRQDMC; break; case 0x4016: diff --git a/sys/src/games/nes/nes.c b/sys/src/games/nes/nes.c index a283825ce..96b05084f 100644 --- a/sys/src/games/nes/nes.c +++ b/sys/src/games/nes/nes.c @@ -13,7 +13,7 @@ uchar *prg, *chr; int scale; Rectangle picr; Image *tmp, *bg; -int clock, ppuclock, apuclock, sampclock, msgclock, saveclock; +int clock, ppuclock, apuclock, dmcclock, dmcfreq, sampclock, msgclock, saveclock; Mousectl *mc; int keys, paused, savereq, loadreq, oflag, savefd = -1; int mirr; @@ -230,6 +230,7 @@ threadmain(int argc, char **argv) pc = memread(0xFFFC) | memread(0xFFFD) << 8; rP = FLAGI; + dmcfreq = 12 * 428; for(;;){ if(savereq){ savestate("nes.save"); @@ -248,8 +249,7 @@ threadmain(int argc, char **argv) ppuclock += t; apuclock += t; sampclock += t; - //syncclock += t; - //checkclock += t; + dmcclock += t; while(ppuclock >= 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); |