#include <libc.h>
#include <thread.h>
#include <draw.h>
+#include "../eui.h"
#include "dat.h"
#include "fns.h"
uchar mem[32768];
uchar ppuram[16384];
uchar oam[256];
-uchar *prgb[2], *chrb[2];
-extern uchar *prg, *chr;
-extern int nprg, nchr;
+uchar *prgb[16], *chrb[16];
u16int pput, ppuv;
-u8int ppusx;
-static int vramlatch = 1, keylatch = 0xFF;
-extern int keys, nmi, map, mirr;
+u8int ppusx, vrambuf;
+int vramlatch = 1, keylatch = 0xFF, keylatch2 = 0xFF;
+int prgsh, chrsh, mmc3hack;
+
+static void
+nope(int p)
+{
+ print("unimplemented mapper function %d (mapper %d)\n", p, map);
+}
static void
nrom(int p, u8int)
{
- if(p < 0){
+ if(p >= 0)
+ return;
+ switch(p){
+ case INIT:
+ case RSTR:
prgb[0] = prg;
if(nprg == 1)
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);
}
- return;
}
static void
mmc1(int v, u8int p)
{
static u8int n, s, mode, c0, c1, pr;
- int wchr, wprg;
static int mirrs[] = {MSINGB, MSINGA, MVERT, MHORZ};
if(v < 0){
- wchr = 1;
- wprg = 1;
- mode = 0x0C;
- goto t;
+ switch(v){
+ case INIT:
+ if(nprg > 32)
+ sysfatal("bad rom, too much prg rom for mmc1");
+ mode = 0x0C;
+ prgsh = 14;
+ chrsh = 12;
+ goto t;
+ case RSTR:
+ mode = get8();
+ c0 = get8();
+ c1 = get8();
+ pr = get8();
+ n = get8();
+ s = get8();
+ goto t;
+ case SAVE:
+ put8(mode);
+ put8(c0);
+ put8(c1);
+ put8(pr);
+ put8(n);
+ put8(s);
+ break;
+ default:
+ nope(v);
+ case SCAN:
+ break;
+ }
+ return;
}
if((p & 0x80) != 0){
n = 0;
s >>= 1;
return;
}
- wchr = wprg = 1;
switch(v & 0xE000){
case 0x8000:
mode = s;
mirr = mirrs[mode & 3];
- wchr = wprg = 1;
break;
case 0xA000:
+ if(nprg > 16){
+ pr = s & 0x10 | pr & 0x0f;
+ pr %= nprg;
+ }
c0 = s & 0x1f;
c0 %= 2*nchr;
- wchr = 1;
break;
case 0xC000:
c1 = s & 0x1f;
c1 %= 2*nchr;
- if((mode & 0x10) != 0)
- wchr = 1;
break;
case 0xE000:
- pr = s & 0x0f;
+ pr = pr & 0x10 | s & 0x0f;
pr %= nprg;
- wprg = 1;
break;
}
+ s = 0;
+ n = 0;
t:
- if(wprg)
- switch(mode & 0x0c){
- case 0x08:
- prgb[0] = prg;
- prgb[1] = prg + pr * 0x4000;
+ switch(mode & 0x0c){
+ case 0x08:
+ prgb[0] = prg;
+ prgb[1] = prg + pr * 0x4000;
+ break;
+ case 0x0C:
+ prgb[0] = prg + pr * 0x4000;
+ prgb[1] = prg + ((pr & 0x10 | 0x0f) % nprg) * 0x4000;
+ break;
+ default:
+ prgb[0] = prg + (pr & 0xfe) * 0x4000;
+ prgb[1] = prg + (pr | 1) * 0x4000;
+ break;
+ }
+ if((mode & 0x10) != 0){
+ chrb[0] = chr + c0 * 0x1000;
+ chrb[1] = chr + c1 * 0x1000;
+ }else{
+ chrb[0] = chr + (c0 & 0xfe) * 0x1000;
+ chrb[1] = chr + (c0 | 1) * 0x1000;
+ }
+}
+
+static void
+uxrom(int p, u8int v)
+{
+ static u8int b;
+
+ if(p < 0)
+ switch(p){
+ case INIT:
+ prgsh = 14;
+ chrsh = 13;
+ prgb[1] = prg + (nprg - 1) * 0x4000;
+ chrb[0] = chr;
break;
- case 0x0C:
- prgb[0] = prg + pr * 0x4000;
- prgb[1] = prg + (0x0f % nprg) * 0x4000;
+ case SAVE:
+ put8(b);
+ return;
+ case RSTR:
+ b = get8();
break;
+ case SCAN:
+ return;
default:
- prgb[0] = prg + (pr & 0xfe) * 0x4000;
- prgb[1] = prg + (pr | 1) * 0x4000;
- break;
+ nope(p);
+ return;
}
- if(wchr)
- if((mode & 0x10) != 0){
- chrb[0] = chr + c0 * 0x1000;
- chrb[1] = chr + c1 * 0x1000;
- }else{
- chrb[0] = chr + (c0 & 0xfe) * 0x1000;
- chrb[1] = chr + (c0 | 1) * 0x1000;
+ else
+ b = v % nprg;
+ 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;
}
- s = 0;
- n = 0;
+ else
+ b = v % nchr;
+ chrb[0] = chr + b * 0x2000;
+
}
static void
-mmc7(int v, u8int p)
+mmc3(int p, u8int v)
{
- if(v < 0){
- nrom(-1, 0);
- p = 0;
+ 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 |= IRQMMC;
+ 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 &= ~IRQMMC; break;
+ case 0xE001: en = 1; break;
}
- prgb[0] = prg + (p & 3) * 0x8000;
+ 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) >> 5;
+ 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
+axrom(int p, u8int v)
+{
+ static int b;
+
+ if(p >= 0)
+ b = v;
+ else
+ switch(p){
+ case INIT:
+ nrom(INIT, 0);
+ b = 0;
+ break;
+ case SAVE:
+ put8(b);
+ return;
+ case RSTR:
+ b = get8();
+ break;
+ case SCAN:
+ return;
+ default:
+ nope(p);
+ return;
+ }
+ prgb[0] = prg + (b & 3) * 0x8000;
prgb[1] = prgb[0] + 0x4000;
}
void (*mapper[256])(int, u8int) = {
[0] nrom,
[1] mmc1,
- [7] mmc7,
+ [2] uxrom,
+ [3] cnrom,
+ [4] mmc3,
+ [7] axrom,
};
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
memread(u16int p)
{
- static u8int vrambuf;
u8int v;
+ int i;
if(p < 0x2000){
p &= 0x7FF;
vrambuf = ppuread(ppuv);
incvram();
return vrambuf;
+ case APUSTATUS:
+ v = (irq & 3) << 6;
+ for(i = 0; i < 4; i++){
+ if(apuctr[i] != 0)
+ v |= (1<<i);
+ }
+ if(mem[0x4013] != 0)
+ v |= (1<<4);
+ irq &= ~IRQFRAME;
+ return v;
case 0x4016:
if((mem[p] & 1) != 0)
return keys & 1;
keylatch = (keylatch >> 1) | 0x80;
return v | 0x40;
case 0x4017:
- return 0x40;
+ if((mem[p] & 1) != 0)
+ return keys2 & 1;
+ v = keylatch2 & 1;
+ keylatch2 = (keylatch2 >> 1) | 0x80;
+ return v | 0x40;
}
}
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];
}
void
memwrite(u16int p, u8int v)
{
+ extern u8int apulen[32];
+ extern u16int dmclen[16];
+ int i;
+
if(p < 0x2000){
p &= 0x7FF;
}else if(p < 0x6000){
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;
ppuwrite(ppuv, v);
incvram();
return;
+ case 0x4001:
+ case 0x4005:
+ i = (p & 0xC) >> 2;
+ apuctr[i+8] |= 0x80;
+ break;
+ case 0x4003:
+ case 0x4007:
+ case 0x400B:
+ case 0x400F:
+ i = (p & 0xC) >> 2;
+ if((mem[APUSTATUS] & (1<<i)) != 0){
+ apuctr[i] = apulen[v >> 3];
+ 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;
+ case APUSTATUS:
+ 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:
- if((mem[p] & 1) != 0 && (v & 1) == 0)
+ if((mem[p] & 1) != 0 && (v & 1) == 0){
keylatch = keys;
+ keylatch2 = keys2;
+ }
+ break;
+ case APUFRAME:
+ apuseq = 0;
+ if((v & 0x80) != 0)
+ apuclock = APUDIV;
+ else
+ apuclock = 0;
+ if((v & 0x40) != 0)
+ irq &= ~IRQFRAME;
break;
}
- }else if(p >= 0x8000){
+ }else if(p < 0x8000){
+ if(saveclock == 0)
+ saveclock = SAVEFREQ;
+ }else{
if(mapper[map] != nil)
mapper[map](p, v);
return;
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;
}