Rewrite and unify J.Y. ASIC emulation. Add multicart mappers.
This commit is contained in:
505
src/boards/90.c
505
src/boards/90.c
@@ -1,505 +0,0 @@
|
||||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2002 Xodnizel
|
||||
* Copyright (C) 2005 CaH4e3
|
||||
* Copyright (C) 2019 Libretro Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "mapinc.h"
|
||||
/* #define DEBUG90 */
|
||||
|
||||
/* Mapper 090 is simpliest mapper hardware and have not extended nametable control and latched chr banks in 4k mode
|
||||
* Mapper 209 much compicated hardware with decribed above features disabled by default and switchable by command
|
||||
* Mapper 211 the same mapper 209 but with forced nametable control
|
||||
* Mapper 281 PRG ($8000-$8FFF) and CHR ($9000-$AFFF) bank select register bits that select 256 KiB banks are masked off.
|
||||
*/
|
||||
|
||||
static int is209;
|
||||
static int is211;
|
||||
static int is281;
|
||||
|
||||
static uint8 IRQMode; /* from $c001 */
|
||||
static uint8 IRQPre; /* from $c004 */
|
||||
static uint8 IRQPreSize; /* from $c007 */
|
||||
static uint8 IRQCount; /* from $c005 */
|
||||
static uint8 IRQXOR; /* Loaded from $C006 */
|
||||
static uint8 IRQa; /* $c002, $c003, and $c000 */
|
||||
|
||||
static uint8 mul[2];
|
||||
static uint8 regie;
|
||||
|
||||
static uint8 tkcom[4];
|
||||
static uint8 prgb[4];
|
||||
static uint8 chrlow[8];
|
||||
static uint8 chrhigh[8];
|
||||
|
||||
static uint8 chr[2];
|
||||
|
||||
static uint16 names[4];
|
||||
static uint8 tekker;
|
||||
|
||||
static SFORMAT Tek_StateRegs[] = {
|
||||
{ &IRQMode, 1, "IRQM" },
|
||||
{ &IRQPre, 1, "IRQP" },
|
||||
{ &IRQPreSize, 1, "IRQR" },
|
||||
{ &IRQCount, 1, "IRQC" },
|
||||
{ &IRQXOR, 1, "IRQX" },
|
||||
{ &IRQa, 1, "IRQA" },
|
||||
{ mul, 2, "MUL" },
|
||||
{ ®ie, 1, "REGI" },
|
||||
{ tkcom, 4, "TKCO" },
|
||||
{ prgb, 4, "PRGB" },
|
||||
{ chr, 2, "CLTC" },
|
||||
{ chrlow, 4, "CHRL" },
|
||||
{ chrhigh, 8, "CHRH" },
|
||||
{ &names[0], 2 | FCEUSTATE_RLSB, "NMS0" },
|
||||
{ &names[1], 2 | FCEUSTATE_RLSB, "NMS1" },
|
||||
{ &names[2], 2 | FCEUSTATE_RLSB, "NMS2" },
|
||||
{ &names[3], 2 | FCEUSTATE_RLSB, "NMS3" },
|
||||
{ &tekker, 1, "TEKR" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static void mira(void) {
|
||||
if (((tkcom[0] & 0x20) && is209) || is211 || ((tkcom[1] & 0x08) && is281)) {
|
||||
int x;
|
||||
if (tkcom[0] & 0x40) { /* Name tables are ROM-only */
|
||||
for (x = 0; x < 4; x++)
|
||||
setntamem(CHRptr[0] + (((names[x]) & CHRmask1[0]) << 10), 0, x);
|
||||
} else { /* Name tables can be RAM or ROM. */
|
||||
for (x = 0; x < 4; x++) {
|
||||
if ((tkcom[1] & 0x80) == (names[x] & 0x80)) /* RAM selected. */
|
||||
setntamem(NTARAM + ((names[x] & 0x1) << 10), 1, x);
|
||||
else
|
||||
setntamem(CHRptr[0] + (((names[x]) & CHRmask1[0]) << 10), 0, x);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (tkcom[1] & 3) {
|
||||
case 0: setmirror(MI_V); break;
|
||||
case 1: setmirror(MI_H); break;
|
||||
case 2: setmirror(MI_0); break;
|
||||
case 3: setmirror(MI_1); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8 invertprg(uint8 bank, uint8 reverse) {
|
||||
if (reverse)
|
||||
return ((bank & 0x01) << 6 | (bank & 0x02) << 4 | (bank & 0x04) << 2 |
|
||||
(bank & 0x10) >> 2 | (bank & 0x20) >> 4 | (bank & 0x40) >> 6);
|
||||
else
|
||||
return bank;
|
||||
}
|
||||
|
||||
static void tekprom(void) {
|
||||
uint8 prgshift = 0, prgmask = 0x3F, outb_sel = 0x06, last_bank = 0x3F;
|
||||
uint8 prgmode = tkcom[0] & 0x03;
|
||||
uint8 invert = (tkcom[0] & 0x03) == 0x03 ? 1 : 0;
|
||||
uint32 bankmode = 0;
|
||||
|
||||
switch (tkcom[0] & 0x03) {
|
||||
case 0x00: prgshift = 3; prgmask = 0x0F; break;
|
||||
case 0x01: prgshift = 4; prgmask = 0x1F; break;
|
||||
default: prgshift = 5; prgmask = 0x3F; break;
|
||||
}
|
||||
|
||||
if (is281) {
|
||||
prgmask >>= 1;
|
||||
outb_sel = 0x01;
|
||||
}
|
||||
|
||||
bankmode = ((tkcom[3] & outb_sel) << prgshift);
|
||||
last_bank = (tkcom[0] & 0x04) ? prgb[3] : prgmask;
|
||||
switch (prgmode) {
|
||||
case 0x00:
|
||||
if (tkcom[0] & 0x80)
|
||||
setprg8(0x6000, (((prgb[3] << 2) + 3) & 0x3F) | bankmode);
|
||||
setprg32(0x8000, (last_bank & prgmask) | bankmode);
|
||||
break;
|
||||
case 0x01:
|
||||
if (tkcom[0] & 0x80)
|
||||
setprg8(0x6000, (((prgb[3] << 1) + 1) & 0x3F) | bankmode);
|
||||
setprg16(0x8000, (prgb[1] & prgmask) | bankmode);
|
||||
setprg16(0xC000, (last_bank & prgmask) | bankmode);
|
||||
break;
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
if (tkcom[0] & 0x80)
|
||||
setprg8(0x6000, (invertprg(prgb[3], invert) & 0x3F) | bankmode);
|
||||
setprg8(0x8000, (invertprg(prgb[0], invert) & prgmask) | bankmode);
|
||||
setprg8(0xa000, (invertprg(prgb[1], invert) & prgmask) | bankmode);
|
||||
setprg8(0xc000, (invertprg(prgb[2], invert) & prgmask) | bankmode);
|
||||
setprg8(0xe000, (invertprg(last_bank, invert) & prgmask) | bankmode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void tekvrom(void) {
|
||||
int x, bank = 0, mask = 0xFFFF;
|
||||
if (!(tkcom[3] & 0x20) || is281) {
|
||||
if (is281)
|
||||
bank = tkcom[3] & 1;
|
||||
else
|
||||
bank = (tkcom[3] & 1) | ((tkcom[3] & 0x18) >> 2);
|
||||
switch (tkcom[0] & 0x18) {
|
||||
case 0x00: bank <<= 5; mask = 0x1F; break;
|
||||
case 0x08: bank <<= 6; mask = 0x3F; break;
|
||||
case 0x10: bank <<= 7; mask = 0x7F; break;
|
||||
case 0x18: bank <<= 8; mask = 0xFF; break;
|
||||
}
|
||||
}
|
||||
switch (tkcom[0] & 0x18) {
|
||||
case 0x00: /* 8KB */
|
||||
setchr8(((chrlow[0] | (chrhigh[0] << 8)) & mask) | bank);
|
||||
break;
|
||||
case 0x08: /* 4KB */
|
||||
#if 0
|
||||
for(x=0;x<8;x+=4)
|
||||
setchr4(x<<10,((chrlow[x]|(chrhigh[x]<<8))&mask)|bank);
|
||||
#endif
|
||||
setchr4(0x0000, ((chrlow[chr[0]] | (chrhigh[chr[0]] << 8)) & mask) | bank);
|
||||
setchr4(0x1000, ((chrlow[chr[1]] | (chrhigh[chr[1]] << 8)) & mask) | bank);
|
||||
break;
|
||||
case 0x10: /* 2KB */
|
||||
for (x = 0; x < 8; x += 2)
|
||||
setchr2(x << 10, ((chrlow[x] | (chrhigh[x] << 8)) & mask) | bank);
|
||||
break;
|
||||
case 0x18: /* 1KB */
|
||||
for (x = 0; x < 8; x++)
|
||||
setchr1(x << 10, ((chrlow[x] | (chrhigh[x] << 8)) & mask) | bank);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static DECLFW(M90TekWrite) {
|
||||
switch (A & 0x5C03) {
|
||||
case 0x5800: mul[0] = V; break;
|
||||
case 0x5801: mul[1] = V; break;
|
||||
case 0x5803: regie = V; break;
|
||||
}
|
||||
}
|
||||
|
||||
static DECLFR(M90TekRead) {
|
||||
switch (A & 0x5C03) {
|
||||
case 0x5800: return(mul[0] * mul[1]);
|
||||
case 0x5801: return((mul[0] * mul[1]) >> 8);
|
||||
case 0x5803: return(regie);
|
||||
default: return tekker;
|
||||
}
|
||||
return(0xff);
|
||||
}
|
||||
|
||||
static DECLFW(M90PRGWrite) {
|
||||
/* FCEU_printf("bs %04x %02x\n",A,V); */
|
||||
prgb[A & 3] = V;
|
||||
tekprom();
|
||||
}
|
||||
|
||||
static DECLFW(M90CHRlowWrite) {
|
||||
/* FCEU_printf("bs %04x %02x\n",A,V); */
|
||||
chrlow[A & 7] = V;
|
||||
tekvrom();
|
||||
}
|
||||
|
||||
static DECLFW(M90CHRhiWrite) {
|
||||
/* FCEU_printf("bs %04x %02x\n",A,V); */
|
||||
chrhigh[A & 7] = V;
|
||||
tekvrom();
|
||||
}
|
||||
|
||||
static DECLFW(M90NTWrite) {
|
||||
/* FCEU_printf("bs %04x %02x\n",A,V); */
|
||||
if (A & 4) {
|
||||
names[A & 3] &= 0x00FF;
|
||||
names[A & 3] |= V << 8;
|
||||
} else {
|
||||
names[A & 3] &= 0xFF00;
|
||||
names[A & 3] |= V;
|
||||
}
|
||||
mira();
|
||||
}
|
||||
|
||||
static DECLFW(M90IRQWrite) {
|
||||
/* FCEU_printf("bs %04x %02x\n",A,V); */
|
||||
switch (A & 7) {
|
||||
case 00:
|
||||
/* FCEU_printf("%s IRQ (C000)\n",V&1?"Enable":"Disable"); */
|
||||
IRQa = V & 1;
|
||||
if (!(V & 1))
|
||||
X6502_IRQEnd(FCEU_IQEXT);
|
||||
break;
|
||||
case 02:
|
||||
/* FCEU_printf("Disable IRQ (C002) scanline=%d\n", scanline); */
|
||||
IRQa = 0; X6502_IRQEnd(FCEU_IQEXT);
|
||||
break;
|
||||
case 03:
|
||||
/* FCEU_printf("Enable IRQ (C003) scanline=%d\n", scanline); */
|
||||
IRQa = 1;
|
||||
break;
|
||||
case 01:
|
||||
IRQMode = V;
|
||||
#if 0
|
||||
FCEU_printf("IRQ Count method: ");
|
||||
switch (IRQMode&3)
|
||||
{
|
||||
case 00: FCEU_printf("M2 cycles\n");break;
|
||||
case 01: FCEU_printf("PPU A12 toggles\n");break;
|
||||
case 02: FCEU_printf("PPU reads\n");break;
|
||||
case 03: FCEU_printf("Writes to CPU space\n");break;
|
||||
}
|
||||
FCEU_printf("Counter prescaler size: %s\n",(IRQMode&4)?"3 bits":"8 bits");
|
||||
FCEU_printf("Counter prescaler size adjust: %s\n",(IRQMode&8)?"Used C007":"Normal Operation");
|
||||
if((IRQMode>>6)==2) FCEU_printf("Counter Down\n");
|
||||
else if((IRQMode>>6)==1) FCEU_printf("Counter Up\n");
|
||||
else FCEU_printf("Counter Stopped\n");
|
||||
#endif
|
||||
break;
|
||||
case 04:
|
||||
/* FCEU_printf("Pre Counter Loaded and Xored wiht C006: %d\n",V^IRQXOR); */
|
||||
IRQPre = V ^ IRQXOR;
|
||||
break;
|
||||
case 05:
|
||||
/* FCEU_printf("Main Counter Loaded and Xored wiht C006: %d\n",V^IRQXOR); */
|
||||
IRQCount = V ^ IRQXOR;
|
||||
break;
|
||||
case 06:
|
||||
/* FCEU_printf("Xor Value: %d\n",V); */
|
||||
IRQXOR = V;
|
||||
break;
|
||||
case 07:
|
||||
#if 0
|
||||
if(!(IRQMode&8)) FCEU_printf("C001 is clear, no effect applied\n");
|
||||
else if(V==0xFF) FCEU_printf("Prescaler is changed for 12bits\n");
|
||||
else FCEU_printf("Counter Stopped\n");
|
||||
#endif
|
||||
IRQPreSize = V;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static DECLFW(M90ModeWrite) {
|
||||
/* FCEU_printf("bs %04x %02x\n",A,V); */
|
||||
tkcom[A & 3] = V;
|
||||
tekprom();
|
||||
tekvrom();
|
||||
mira();
|
||||
|
||||
#ifdef DEBUG90
|
||||
switch (A & 3) {
|
||||
case 00:
|
||||
FCEU_printf("Main Control Register:\n");
|
||||
FCEU_printf(" PGR Banking mode: %d\n", V & 7);
|
||||
FCEU_printf(" CHR Banking mode: %d\n", (V >> 3) & 3);
|
||||
FCEU_printf(" 6000-7FFF addresses mapping: %s\n", (V & 0x80) ? "Yes" : "No");
|
||||
FCEU_printf(" Nametable control: %s\n", (V & 0x20) ? "Enabled" : "Disabled");
|
||||
if (V & 0x20)
|
||||
FCEU_printf(" Nametable can be: %s\n", (V & 0x40) ? "ROM Only" : "RAM or ROM");
|
||||
break;
|
||||
case 01:
|
||||
FCEU_printf("Mirroring mode: ");
|
||||
switch (V & 3) {
|
||||
case 0: FCEU_printf("Vertical\n"); break;
|
||||
case 1: FCEU_printf("Horizontal\n"); break;
|
||||
case 2: FCEU_printf("Nametable 0 only\n"); break;
|
||||
case 3: FCEU_printf("Nametable 1 only\n"); break;
|
||||
}
|
||||
FCEU_printf("Mirroring flag: %s\n", (V & 0x80) ? "On" : "Off");
|
||||
break;
|
||||
case 02:
|
||||
if ((((tkcom[0]) >> 5) & 3) == 1)
|
||||
FCEU_printf("Nametable ROM/RAM select mode: %d\n", V >> 7);
|
||||
break;
|
||||
case 03:
|
||||
FCEU_printf("CHR Banking mode: %s\n", (V & 0x20) ? "Entire CHR ROM" : "256Kb Switching mode");
|
||||
if (!(V & 0x20)) FCEU_printf("256K CHR bank number: %02x\n", (V & 1) | ((V & 0x18) >> 2));
|
||||
FCEU_printf("512K PRG bank number: %d\n", (V & 6) >> 1);
|
||||
FCEU_printf("CHR Bank mirroring: %s\n", (V & 0x80) ? "Swapped" : "Normal operate");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static DECLFW(M90DummyWrite) {
|
||||
/* FCEU_printf("bs %04x %02x\n",A,V); */
|
||||
}
|
||||
|
||||
static void CCL(void) {
|
||||
if ((IRQMode >> 6) == 1) { /* Count Up */
|
||||
IRQCount++;
|
||||
if ((IRQCount == 0) && IRQa) {
|
||||
X6502_IRQBegin(FCEU_IQEXT);
|
||||
}
|
||||
} else if ((IRQMode >> 6) == 2) { /* Count down */
|
||||
IRQCount--;
|
||||
if ((IRQCount == 0xFF) && IRQa) {
|
||||
X6502_IRQBegin(FCEU_IQEXT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ClockCounter(void) {
|
||||
uint8 premask;
|
||||
|
||||
if (IRQMode & 0x4)
|
||||
premask = 0x7;
|
||||
else
|
||||
premask = 0xFF;
|
||||
if ((IRQMode >> 6) == 1) { /* Count up */
|
||||
IRQPre++;
|
||||
if ((IRQPre & premask) == 0) CCL();
|
||||
} else if ((IRQMode >> 6) == 2) { /* Count down */
|
||||
IRQPre--;
|
||||
if ((IRQPre & premask) == premask) CCL();
|
||||
}
|
||||
}
|
||||
|
||||
void FP_FASTAPASS(1) CPUWrap(int a) {
|
||||
int x;
|
||||
if ((IRQMode & 3) == 0) for (x = 0; x < a; x++) ClockCounter();
|
||||
}
|
||||
|
||||
static void SLWrap(void) {
|
||||
int x;
|
||||
if ((IRQMode & 3) == 1) for (x = 0; x < 8; x++) ClockCounter();
|
||||
}
|
||||
|
||||
static uint32 lastread;
|
||||
static void FP_FASTAPASS(1) M90PPU(uint32 A) {
|
||||
if ((IRQMode & 3) == 2) {
|
||||
if (lastread != A) {
|
||||
ClockCounter();
|
||||
ClockCounter();
|
||||
}
|
||||
lastread = A;
|
||||
}
|
||||
|
||||
if (is209) {
|
||||
uint8 l, h;
|
||||
h = A >> 8;
|
||||
if (h < 0x20 && ((h & 0x0F) == 0xF)) {
|
||||
l = A & 0xF0;
|
||||
if (l == 0xD0) {
|
||||
chr[(h & 0x10) >> 4] = ((h & 0x10) >> 2);
|
||||
tekvrom();
|
||||
} else if (l == 0xE0) {
|
||||
chr[(h & 0x10) >> 4] = ((h & 0x10) >> 2) | 2;
|
||||
tekvrom();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
chr[0] = 0;
|
||||
chr[1] = 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void togglie(void) {
|
||||
tekker += 0x40;
|
||||
tekker &= 0xC0;
|
||||
FCEU_printf("tekker=%02x\n", tekker);
|
||||
memset(tkcom, 0x00, sizeof(tkcom));
|
||||
memset(prgb, 0xff, sizeof(prgb));
|
||||
tekprom();
|
||||
tekvrom();
|
||||
}
|
||||
|
||||
static void M90Restore(int version) {
|
||||
tekprom();
|
||||
tekvrom();
|
||||
mira();
|
||||
}
|
||||
|
||||
static void M90Power(void) {
|
||||
SetWriteHandler(0x5000, 0x5fff, M90TekWrite);
|
||||
SetWriteHandler(0x8000, 0x8ff0, M90PRGWrite);
|
||||
SetWriteHandler(0x9000, 0x9fff, M90CHRlowWrite);
|
||||
SetWriteHandler(0xA000, 0xAfff, M90CHRhiWrite);
|
||||
SetWriteHandler(0xB000, 0xBfff, M90NTWrite);
|
||||
SetWriteHandler(0xC000, 0xCfff, M90IRQWrite);
|
||||
SetWriteHandler(0xD000, 0xD5ff, M90ModeWrite);
|
||||
SetWriteHandler(0xE000, 0xFfff, M90DummyWrite);
|
||||
|
||||
SetReadHandler(0x5000, 0x5fff, M90TekRead);
|
||||
SetReadHandler(0x6000, 0xffff, CartBR);
|
||||
|
||||
mul[0] = mul[1] = regie = 0xFF;
|
||||
|
||||
memset(tkcom, 0x00, sizeof(tkcom));
|
||||
memset(prgb, 0xff, sizeof(prgb));
|
||||
memset(chrlow, 0xff, sizeof(chrlow));
|
||||
memset(chrhigh, 0xff, sizeof(chrhigh));
|
||||
memset(names, 0x00, sizeof(names));
|
||||
|
||||
if (is211)
|
||||
tekker = 0xC0;
|
||||
else
|
||||
tekker = 0x00;
|
||||
|
||||
tekprom();
|
||||
tekvrom();
|
||||
}
|
||||
|
||||
void Mapper90_Init(CartInfo *info) {
|
||||
is211 = 0;
|
||||
is209 = 0;
|
||||
is281 = 0;
|
||||
info->Reset = togglie;
|
||||
info->Power = M90Power;
|
||||
PPU_hook = M90PPU;
|
||||
MapIRQHook = CPUWrap;
|
||||
GameHBIRQHook2 = SLWrap;
|
||||
GameStateRestore = M90Restore;
|
||||
AddExState(Tek_StateRegs, ~0, 0, 0);
|
||||
}
|
||||
|
||||
void Mapper209_Init(CartInfo *info) {
|
||||
is211 = 0;
|
||||
is209 = 1;
|
||||
is281 = 0;
|
||||
info->Reset = togglie;
|
||||
info->Power = M90Power;
|
||||
PPU_hook = M90PPU;
|
||||
MapIRQHook = CPUWrap;
|
||||
GameHBIRQHook2 = SLWrap;
|
||||
GameStateRestore = M90Restore;
|
||||
AddExState(Tek_StateRegs, ~0, 0, 0);
|
||||
}
|
||||
|
||||
void Mapper211_Init(CartInfo *info) {
|
||||
is211 = 1;
|
||||
is281 = 0;
|
||||
info->Reset = togglie;
|
||||
info->Power = M90Power;
|
||||
PPU_hook = M90PPU;
|
||||
MapIRQHook = CPUWrap;
|
||||
GameHBIRQHook2 = SLWrap;
|
||||
GameStateRestore = M90Restore;
|
||||
AddExState(Tek_StateRegs, ~0, 0, 0);
|
||||
}
|
||||
|
||||
void Mapper281_Init(CartInfo *info) {
|
||||
is211 = 0;
|
||||
is209 = 0;
|
||||
is281 = 1;
|
||||
info->Reset = togglie;
|
||||
info->Power = M90Power;
|
||||
PPU_hook = M90PPU;
|
||||
MapIRQHook = CPUWrap;
|
||||
GameHBIRQHook2 = SLWrap;
|
||||
GameStateRestore = M90Restore;
|
||||
AddExState(Tek_StateRegs, ~0, 0, 0);
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2005 CaH4e3
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* BMC 42-in-1 "reset switch" type
|
||||
*/
|
||||
|
||||
#include "mapinc.h"
|
||||
|
||||
static uint8 bank_mode;
|
||||
static uint8 bank_value;
|
||||
static uint8 prgb[4];
|
||||
static SFORMAT StateRegs[] =
|
||||
{
|
||||
{ &bank_mode, 1, "BNM" },
|
||||
{ &bank_value, 1, "BMV" },
|
||||
{ prgb, 4, "PRGB" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static void Sync(void) {
|
||||
/* FCEU_printf("%02x: %02x %02x\n", bank_mode, bank_value, prgb[0]); */
|
||||
switch (bank_mode & 7) {
|
||||
case 0:
|
||||
setprg32(0x8000, bank_value & 7); break;
|
||||
case 1:
|
||||
setprg16(0x8000, ((8 + (bank_value & 7)) >> 1) + prgb[1]);
|
||||
setprg16(0xC000, (bank_value & 7) >> 1);
|
||||
break;
|
||||
case 4:
|
||||
setprg32(0x8000, 8 + (bank_value & 7)); break;
|
||||
case 5:
|
||||
setprg16(0x8000, ((8 + (bank_value & 7)) >> 1) + prgb[1]);
|
||||
setprg16(0xC000, ((8 + (bank_value & 7)) >> 1) + prgb[3]);
|
||||
break;
|
||||
case 2:
|
||||
setprg8(0x8000, prgb[0] >> 2);
|
||||
setprg8(0xa000, prgb[1]);
|
||||
setprg8(0xc000, prgb[2]);
|
||||
setprg8(0xe000, ~0);
|
||||
break;
|
||||
case 3:
|
||||
setprg8(0x8000, prgb[0]);
|
||||
setprg8(0xa000, prgb[1]);
|
||||
setprg8(0xc000, prgb[2]);
|
||||
setprg8(0xe000, prgb[3]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static DECLFW(BMC13in1JY110Write) {
|
||||
/* FCEU_printf("%04x:%04x\n",A,V); */
|
||||
switch (A) {
|
||||
case 0x8000:
|
||||
case 0x8001:
|
||||
case 0x8002:
|
||||
case 0x8003: prgb[A & 3] = V; break;
|
||||
case 0xD000: bank_mode = V; break;
|
||||
case 0xD001: setmirror(V & 3);
|
||||
case 0xD002: break;
|
||||
case 0xD003: bank_value = V; break;
|
||||
}
|
||||
Sync();
|
||||
}
|
||||
|
||||
static void BMC13in1JY110Power(void) {
|
||||
prgb[0] = prgb[1] = prgb[2] = prgb[3] = 0;
|
||||
bank_mode = 0;
|
||||
bank_value = 0;
|
||||
setprg32(0x8000, 0);
|
||||
setchr8(0);
|
||||
SetWriteHandler(0x8000, 0xFFFF, BMC13in1JY110Write);
|
||||
SetReadHandler(0x8000, 0xFFFF, CartBR);
|
||||
}
|
||||
|
||||
static void StateRestore(int version) {
|
||||
Sync();
|
||||
}
|
||||
|
||||
void BMC13in1JY110_Init(CartInfo *info) {
|
||||
info->Power = BMC13in1JY110Power;
|
||||
AddExState(&StateRegs, ~0, 0, 0);
|
||||
GameStateRestore = StateRestore;
|
||||
}
|
||||
483
src/boards/jyasic.c
Normal file
483
src/boards/jyasic.c
Normal file
@@ -0,0 +1,483 @@
|
||||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2002 Xodnizel
|
||||
* Copyright (C) 2005 CaH4e3
|
||||
* Copyright (C) 2019 Libretro Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "mapinc.h"
|
||||
|
||||
void (*sync)(void);
|
||||
static uint8 allowExtendedMirroring;
|
||||
|
||||
static uint8 mode[4];
|
||||
static uint8* WRAM = NULL;
|
||||
static uint32 WRAMSIZE;
|
||||
|
||||
static uint8 irqControl;
|
||||
static uint8 irqEnabled;
|
||||
static uint8 irqPrescaler;
|
||||
static uint8 irqCounter;
|
||||
static uint8 irqXor;
|
||||
static uint32 lastPPUAddress;
|
||||
|
||||
static uint8 prg[4];
|
||||
static uint16 chr[8];
|
||||
static uint16 nt[4];
|
||||
static uint8 latch[2];
|
||||
static uint8 mul[2];
|
||||
static uint8 adder;
|
||||
static uint8 test;
|
||||
static uint8 dipSwitch;
|
||||
|
||||
static writefunc cpuWriteHandlers[0x10000]; // Actual write handlers for CPU write trapping as a method fo IRQ clocking
|
||||
|
||||
static SFORMAT JYASIC_stateRegs[] = {
|
||||
{ &irqControl, 1, "IRQM" },
|
||||
{ &irqPrescaler, 1, "IRQP" },
|
||||
{ &irqCounter, 1, "IRQC" },
|
||||
{ &irqXor, 1, "IRQX" },
|
||||
{ &irqEnabled, 1, "IRQA" },
|
||||
{ mul, 2, "MUL" },
|
||||
{ &test, 1, "REGI" },
|
||||
{ mode , 4, "TKCO" },
|
||||
{ prg, 4, "PRGB" },
|
||||
{ latch, 2, "CLTC" },
|
||||
{ chr, 8*2, "CHRB" },
|
||||
{ &nt[0], 2 | FCEUSTATE_RLSB, "NMS0" },
|
||||
{ &nt[1], 2 | FCEUSTATE_RLSB, "NMS1" },
|
||||
{ &nt[2], 2 | FCEUSTATE_RLSB, "NMS2" },
|
||||
{ &nt[3], 2 | FCEUSTATE_RLSB, "NMS3" },
|
||||
{ &dipSwitch, 1, "TEKR" },
|
||||
{ &adder, 1, "ADDE" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static uint8 rev (uint8_t val) {
|
||||
return ((val <<6) &0x40) | ((val <<4) &0x20) | ((val <<2) &0x10) | (val &0x08) | ((val >>2) &0x04) | ((val >>4) &0x02) | ((val >>6) &0x01);
|
||||
}
|
||||
|
||||
static void syncPRG (int AND, int OR) {
|
||||
uint8_t prgLast =mode[0] &0x04? prg[3]: 0xFF;
|
||||
uint8_t prg6000 =0;
|
||||
switch (mode[0] &0x03) {
|
||||
case 0: setprg32(0x8000, prgLast &AND >>2 |OR >>2);
|
||||
prg6000 =prg[3] <<2 |3;
|
||||
break;
|
||||
case 1: setprg16(0x8000, prg[1] &AND >>1 |OR >>1);
|
||||
setprg16(0xC000, prgLast &AND >>1 |OR >>1);
|
||||
prg6000 =prg[3] <<1 |1;
|
||||
break;
|
||||
case 2: setprg8(0x8000, prg[0] &AND |OR);
|
||||
setprg8(0xA000, prg[1] &AND |OR);
|
||||
setprg8(0xC000, prg[2] &AND |OR);
|
||||
setprg8(0xE000, prgLast &AND |OR);
|
||||
prg6000 =prg[3];
|
||||
break;
|
||||
case 3: setprg8(0x8000, rev(prg[0]) &AND |OR);
|
||||
setprg8(0xA000, rev(prg[1]) &AND |OR);
|
||||
setprg8(0xC000, rev(prg[2]) &AND |OR);
|
||||
setprg8(0xE000, rev( prgLast) &AND |OR);
|
||||
prg6000 =rev(prg[3]);
|
||||
break;
|
||||
}
|
||||
if (mode[0] &0x80) // Map ROM
|
||||
setprg8 (0x6000, prg6000 &AND |OR);
|
||||
else
|
||||
if (WRAMSIZE) // Otherwise map WRAM if it exists
|
||||
setprg8r(0x10, 0x6000, 0);
|
||||
}
|
||||
|
||||
static void syncCHR (int AND, int OR) {
|
||||
if (mode[3] &0x80 && (mode[0] &0x18) ==0x08) // MMC4 mode[0] with 4 KiB CHR mode[0]
|
||||
for (int chrBank =0; chrBank <8; chrBank +=4) setchr4(0x400 *chrBank, chr[latch[chrBank /4]&2 | chrBank] &AND >>2 | OR >>2);
|
||||
else
|
||||
switch(mode[0] &0x18) {
|
||||
case 0x00: // 8 KiB CHR mode[0]
|
||||
setchr8(chr[0] &AND >>3 | OR >>3);
|
||||
break;
|
||||
case 0x08: // 4 KiB CHR mode[0]
|
||||
for (int chrBank =0; chrBank <8; chrBank +=4) setchr4(0x400 *chrBank, chr[chrBank] &AND >>2 | OR >>2);
|
||||
break;
|
||||
case 0x10:
|
||||
for (int chrBank =0; chrBank <8; chrBank +=2) setchr2(0x400 *chrBank, chr[chrBank] &AND >>1 | OR >>1);
|
||||
break;
|
||||
case 0x18:
|
||||
for (int chrBank =0; chrBank <8; chrBank +=1) setchr1(0x400 *chrBank, chr[chrBank] &AND | OR );
|
||||
break;
|
||||
}
|
||||
PPUCHRRAM =mode[2] &0x40? 0xFF: 0x00; // Write-protect or write-enable CHR-RAM
|
||||
}
|
||||
|
||||
static void syncNT (int AND, int OR) {
|
||||
if (mode[0] &0x20 || mode[1] &0x08) { // ROM nametables or extended mirroring
|
||||
// First, set normal CIRAM pages using extended registers ...
|
||||
setmirrorw(nt[0] &1, nt[1] &1, nt[2] &1, nt[3] &1);
|
||||
|
||||
if (mode[0] &0x20) for (int ntBank =0; ntBank <4; ntBank++) { // Then replace with ROM nametables if such are generally enabled
|
||||
int vromHere =(nt[ntBank] &0x80) ^(mode[2] &0x80) |(mode[0] &0x40); // ROM nametables are used either when globally enabled via D000.6 or per-bank via B00x.7 vs. D002.7
|
||||
if (vromHere) setntamem(CHRptr[0] +0x400*((nt[ntBank] &AND | OR) & CHRmask1[0]), 0, ntBank);
|
||||
}
|
||||
} else
|
||||
switch (mode[1] &0x03) { // Regularly mirrored CIRAM
|
||||
case 0: setmirror(MI_V); break;
|
||||
case 1: setmirror(MI_H); break;
|
||||
case 2: setmirror(MI_0); break;
|
||||
case 3: setmirror(MI_1); break;
|
||||
}
|
||||
}
|
||||
|
||||
static void clockIRQ (void) {
|
||||
uint8_t mask =irqControl &0x04? 0x07: 0xFF;
|
||||
if (irqEnabled) switch (irqControl &0xC0) {
|
||||
case 0x40:
|
||||
irqPrescaler =(irqPrescaler &~mask) | (++irqPrescaler &mask);
|
||||
if ((irqPrescaler &mask) ==0x00 && (irqControl &0x08? irqCounter: ++irqCounter) ==0x00) X6502_IRQBegin(FCEU_IQEXT);
|
||||
break;
|
||||
case 0x80:
|
||||
irqPrescaler =(irqPrescaler &~mask) | (--irqPrescaler &mask);
|
||||
if ((irqPrescaler &mask) ==mask && (irqControl &0x08? irqCounter: --irqCounter) ==0xFF) X6502_IRQBegin(FCEU_IQEXT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static DECLFW(trapCPUWrite) {
|
||||
if ((irqControl &0x03) ==0x03) clockIRQ(); // Clock IRQ counter on CPU writes
|
||||
cpuWriteHandlers[A](A, V);
|
||||
}
|
||||
|
||||
static void FP_FASTAPASS(1) trapPPUAddressChange (uint32 A) {
|
||||
if ((irqControl &0x03) ==0x02 && lastPPUAddress !=A) for (int i =0; i <2; i++) clockIRQ(); // Clock IRQ counter on PPU "reads"
|
||||
if (mode[3] &0x80 && (mode[0] &0x18) ==0x08 && ((A &0x2FF0) ==0xFD0 || (A &0x2FF0) ==0xFE0)) { // If MMC4 mode[0] is enabled, and CHR mode[0] is 4 KiB, and tile FD or FE is being fetched ...
|
||||
latch[A >>12 &1] =(A >>10 &4) | (A >>4 &2); // ... switch the left or right pattern table's latch to 0 (FD) or 2 (FE), being used as an offset for the CHR register index.
|
||||
sync();
|
||||
}
|
||||
lastPPUAddress =A;
|
||||
}
|
||||
|
||||
static void ppuScanline(void) {
|
||||
if ((irqControl &0x03) ==0x01) for (int i =0; i <8; i++) clockIRQ(); // Clock IRQ counter on A12 rises (eight per scanline). This should be done in trapPPUAddressChange, but would require more accurate PPU emulation for that.
|
||||
}
|
||||
|
||||
void FP_FASTAPASS(1) cpuCycle(int a) {
|
||||
if ((irqControl &0x03) ==0x00) while (a--) clockIRQ(); // Clock IRQ counter on M2 cycles
|
||||
}
|
||||
|
||||
static DECLFR(readALU_DIP) {
|
||||
if ((A &0x3FF) ==0 && A !=0x5800) // 5000, 5400, 5C00: read solder pad setting
|
||||
return dipSwitch | X.DB &0x3F;
|
||||
else
|
||||
if (A &0x800) switch (A &3) { // 5800-5FFF: read ALU
|
||||
case 0: return (mul[0] *mul[1]) &0xFF;
|
||||
case 1: return (mul[0] *mul[1]) >>8;
|
||||
case 2: return adder;
|
||||
case 3: return test;
|
||||
} else // all others
|
||||
return X.DB;
|
||||
}
|
||||
|
||||
static DECLFW(writeALU) {
|
||||
switch (A &3) {
|
||||
case 0: mul[0] =V; break;
|
||||
case 1: mul[1] =V; break;
|
||||
case 2: adder +=V; break;
|
||||
case 3: test =V;
|
||||
adder =0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static DECLFW(writePRG) {
|
||||
prg[A &3] = V;
|
||||
sync();
|
||||
}
|
||||
|
||||
static DECLFW(writeCHRLow) {
|
||||
chr[A &7] =chr[A &7] &0xFF00 | V;
|
||||
sync();
|
||||
}
|
||||
|
||||
static DECLFW(writeCHRHigh) {
|
||||
chr[A &7] =chr[A &7] &0x00FF | V <<8;
|
||||
sync();
|
||||
}
|
||||
|
||||
static DECLFW(writeNT) {
|
||||
if (~A &4)
|
||||
nt[A &3] =nt[A &3] &0xFF00 | V;
|
||||
else
|
||||
nt[A &3] =nt[A &3] &0x00FF | V <<8;
|
||||
sync();
|
||||
}
|
||||
|
||||
static DECLFW(writeIRQ) {
|
||||
switch (A &7) {
|
||||
case 0: irqEnabled =!!(V &1);
|
||||
if (!irqEnabled) {
|
||||
irqPrescaler =0;
|
||||
X6502_IRQEnd(FCEU_IQEXT);
|
||||
}
|
||||
break;
|
||||
case 1: irqControl =V;
|
||||
break;
|
||||
case 2: irqEnabled =0;
|
||||
irqPrescaler =0;
|
||||
X6502_IRQEnd(FCEU_IQEXT);
|
||||
break;
|
||||
case 3: irqEnabled =1;
|
||||
break;
|
||||
case 4: irqPrescaler =V ^irqXor;
|
||||
break;
|
||||
case 5: irqCounter =V ^irqXor;
|
||||
break;
|
||||
case 6: irqXor =V;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static DECLFW(writeMode) {
|
||||
switch (A &3) {
|
||||
case 0: mode[0] =V;
|
||||
if (!allowExtendedMirroring) mode[0] &=~0x20;
|
||||
break;
|
||||
case 1: mode[1] =V;
|
||||
if (!allowExtendedMirroring) mode[1] &=~0x08;
|
||||
break;
|
||||
case 2: mode[2] =V;
|
||||
break;
|
||||
case 3: mode[3] =V;
|
||||
break;
|
||||
}
|
||||
sync();
|
||||
}
|
||||
|
||||
static void JYASIC_power(void) {
|
||||
SetWriteHandler(0x5000, 0x5FFF, writeALU);
|
||||
SetWriteHandler(0x6000, 0x7fff, CartBW);
|
||||
SetWriteHandler(0x8000, 0x87FF, writePRG); // 8800-8FFF ignored
|
||||
SetWriteHandler(0x9000, 0x97FF, writeCHRLow); // 9800-9FFF ignored
|
||||
SetWriteHandler(0xA000, 0xA7FF, writeCHRHigh); // A800-AFFF ignored
|
||||
SetWriteHandler(0xB000, 0xB7FF, writeNT); // B800-BFFF ignored
|
||||
SetWriteHandler(0xC000, 0xCFFF, writeIRQ);
|
||||
SetWriteHandler(0xD000, 0xD7FF, writeMode); // D800-DFFF ignored
|
||||
|
||||
for (unsigned int i =0; i <0x10000; i++) cpuWriteHandlers[i] =GetWriteHandler(i);
|
||||
SetWriteHandler(0x0000, 0xFFFF, trapCPUWrite); // Trap all CPU writes for IRQ clocking purposes
|
||||
|
||||
SetReadHandler(0x5000, 0x5FFF, readALU_DIP);
|
||||
SetReadHandler(0x6000, 0xFFFF, CartBR);
|
||||
|
||||
mul[0] = mul[1] = adder = test = dipSwitch = 0;
|
||||
mode[0] = mode[1] = mode[2] = mode[3] =0;
|
||||
irqControl =irqEnabled = irqPrescaler =irqCounter = irqXor = lastPPUAddress = 0;
|
||||
memset(prg, 0, sizeof(prg));
|
||||
memset(chr, 0, sizeof(chr));
|
||||
memset(nt, 0, sizeof(nt));
|
||||
latch[0] =0;
|
||||
latch[1] =4;
|
||||
|
||||
sync();
|
||||
}
|
||||
|
||||
static void JYASIC_reset (void) {
|
||||
dipSwitch = (dipSwitch +0x40) &0xC0;
|
||||
}
|
||||
|
||||
static void JYASIC_restore (int version) {
|
||||
sync();
|
||||
}
|
||||
|
||||
void JYASIC_init (CartInfo *info) {
|
||||
info->Reset = JYASIC_reset;
|
||||
info->Power = JYASIC_power;
|
||||
PPU_hook = trapPPUAddressChange;
|
||||
MapIRQHook = cpuCycle;
|
||||
GameHBIRQHook2 = ppuScanline;
|
||||
AddExState(JYASIC_stateRegs, ~0, 0, 0);
|
||||
GameStateRestore = JYASIC_restore;
|
||||
|
||||
// WRAM is present only in iNES mapper 35, or in mappers with numbers above 255 that require NES 2.0, which explicitly denotes WRAM size
|
||||
if (info->iNES2)
|
||||
WRAMSIZE =info->PRGRamSize + info->PRGRamSaveSize;
|
||||
else
|
||||
WRAMSIZE =info->mapper ==35? 8192: 0;
|
||||
|
||||
if (WRAMSIZE) {
|
||||
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
|
||||
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
|
||||
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
|
||||
}
|
||||
}
|
||||
|
||||
static void syncSingleCart (void) {
|
||||
syncPRG(0x3F, mode[3] <<5 &~0x3F);
|
||||
if (mode[3] &0x20) {
|
||||
syncCHR(0x1FF, mode[3] <<6 &0x600);
|
||||
syncNT (0x1FF, mode[3] <<6 &0x600);
|
||||
} else {
|
||||
syncCHR(0x0FF, mode[3] <<8 &0x100 | mode[3] <<6 &0x600);
|
||||
syncNT (0x0FF, mode[3] <<8 &0x100 | mode[3] <<6 &0x600);
|
||||
}
|
||||
}
|
||||
void Mapper35_Init(CartInfo *info) { // Basically mapper 90/209/211 with WRAM
|
||||
allowExtendedMirroring =1;
|
||||
sync =syncSingleCart;
|
||||
JYASIC_init(info);
|
||||
}
|
||||
void Mapper90_Init(CartInfo *info) { // Single cart, extended mirroring and ROM nametables disabled
|
||||
allowExtendedMirroring =0;
|
||||
sync =syncSingleCart;
|
||||
JYASIC_init(info);
|
||||
}
|
||||
void Mapper209_Init(CartInfo *info) { // Single cart, extended mirroring and ROM nametables enabled
|
||||
allowExtendedMirroring =1;
|
||||
sync =syncSingleCart;
|
||||
JYASIC_init(info);
|
||||
}
|
||||
void Mapper211_Init(CartInfo *info) { // Duplicate of mapper 209
|
||||
allowExtendedMirroring =1;
|
||||
sync =syncSingleCart;
|
||||
JYASIC_init(info);
|
||||
}
|
||||
|
||||
static void sync281 (void) {
|
||||
syncPRG(0x1F, mode[3] <<5);
|
||||
syncCHR(0xFF, mode[3] <<8);
|
||||
syncNT (0xFF, mode[3] <<8);
|
||||
}
|
||||
void Mapper281_Init(CartInfo *info) { // Multicart
|
||||
allowExtendedMirroring =1;
|
||||
sync =sync281;
|
||||
JYASIC_init(info);
|
||||
}
|
||||
|
||||
static void sync282 (void) {
|
||||
syncPRG(0x1F, mode[3] <<4 &~0x1F);
|
||||
if (mode[3] &0x20) {
|
||||
syncCHR(0x1FF, mode[3] <<6 &0x600);
|
||||
syncNT (0x1FF, mode[3] <<6 &0x600);
|
||||
} else {
|
||||
syncCHR(0x0FF, mode[3] <<8 &0x100 | mode[3] <<6 &0x600);
|
||||
syncNT (0x0FF, mode[3] <<8 &0x100 | mode[3] <<6 &0x600);
|
||||
}
|
||||
}
|
||||
void Mapper282_Init(CartInfo *info) { // Multicart
|
||||
allowExtendedMirroring =1;
|
||||
sync =sync282;
|
||||
JYASIC_init(info);
|
||||
}
|
||||
|
||||
void sync295 (void) {
|
||||
syncPRG(0x0F, mode[3] <<4);
|
||||
syncCHR(0x7F, mode[3] <<7);
|
||||
syncNT (0x7F, mode[3] <<7);
|
||||
}
|
||||
void Mapper295_Init(CartInfo *info) { // Multicart
|
||||
allowExtendedMirroring =1;
|
||||
sync =sync295;
|
||||
JYASIC_init(info);
|
||||
}
|
||||
|
||||
void sync358 (void) {
|
||||
syncPRG(0x1F, mode[3] <<4 &~0x1F);
|
||||
if (mode[3] &0x20) {
|
||||
syncCHR(0x1FF, mode[3] <<7 &0x600);
|
||||
syncNT (0x1FF, mode[3] <<7 &0x600);
|
||||
} else {
|
||||
syncCHR(0x0FF, mode[3] <<8 &0x100 | mode[3] <<7 &0x600);
|
||||
syncNT (0x0FF, mode[3] <<8 &0x100 | mode[3] <<7 &0x600);
|
||||
}
|
||||
}
|
||||
void Mapper358_Init(CartInfo *info) { // Multicart
|
||||
allowExtendedMirroring =1;
|
||||
sync =sync358;
|
||||
JYASIC_init(info);
|
||||
}
|
||||
|
||||
void sync386 (void) {
|
||||
syncPRG(0x1F, mode[3] <<4 &0x20 | mode[3] <<3 &0x40);
|
||||
if (mode[3] &0x20) {
|
||||
syncCHR(0x1FF, mode[3] <<7 &0x600);
|
||||
syncNT (0x1FF, mode[3] <<7 &0x600);
|
||||
} else {
|
||||
syncCHR(0x0FF, mode[3] <<8 &0x100 | mode[3] <<7 &0x600);
|
||||
syncNT (0x0FF, mode[3] <<8 &0x100 | mode[3] <<7 &0x600);
|
||||
}
|
||||
}
|
||||
void Mapper386_Init(CartInfo *info) { // Multicart
|
||||
allowExtendedMirroring =1;
|
||||
sync =sync386;
|
||||
JYASIC_init(info);
|
||||
}
|
||||
|
||||
void sync387 (void) {
|
||||
syncPRG(0x0F, mode[3] <<3 &0x10 | mode[3] <<2 &0x20);
|
||||
if (mode[3] &0x20) {
|
||||
syncCHR(0x1FF, mode[3] <<7 &0x600);
|
||||
syncNT (0x1FF, mode[3] <<7 &0x600);
|
||||
} else {
|
||||
syncCHR(0x0FF, mode[3] <<8 &0x100 | mode[3] <<7 &0x600);
|
||||
syncNT (0x0FF, mode[3] <<8 &0x100 | mode[3] <<7 &0x600);
|
||||
}
|
||||
}
|
||||
void Mapper387_Init(CartInfo *info) { // Multicart
|
||||
allowExtendedMirroring =1;
|
||||
sync =sync387;
|
||||
JYASIC_init(info);
|
||||
}
|
||||
|
||||
void sync388 (void) {
|
||||
syncPRG(0x1F, mode[3] <<3 &0x60);
|
||||
if (mode[3] &0x20) {
|
||||
syncCHR(0x1FF, mode[3] <<8 &0x200);
|
||||
syncNT (0x1FF, mode[3] <<8 &0x200);
|
||||
} else {
|
||||
syncCHR(0x0FF, mode[3] <<8 &0x100 | mode[3] <<8 &0x200);
|
||||
syncNT (0x0FF, mode[3] <<8 &0x100 | mode[3] <<8 &0x200);
|
||||
}
|
||||
}
|
||||
void Mapper388_Init(CartInfo *info) { // Multicart
|
||||
allowExtendedMirroring =0;
|
||||
sync =sync388;
|
||||
JYASIC_init(info);
|
||||
}
|
||||
|
||||
void sync397 (void) {
|
||||
syncPRG(0x1F, mode[3] <<4 &~0x1F);
|
||||
syncCHR(0x7F, mode[3] <<7);
|
||||
syncNT (0x7F, mode[3] <<7);
|
||||
}
|
||||
void Mapper397_Init(CartInfo *info) { // Multicart
|
||||
allowExtendedMirroring =1;
|
||||
sync =sync397;
|
||||
JYASIC_init(info);
|
||||
}
|
||||
|
||||
void sync421 (void) {
|
||||
if (mode[3] &0x04)
|
||||
syncPRG(0x3F, mode[3] <<4 &~0x3F);
|
||||
else
|
||||
syncPRG(0x1F, mode[3] <<4 &~0x1F);
|
||||
syncCHR(0x1FF, mode[3] <<8 &0x300);
|
||||
syncNT (0x1FF, mode[3] <<8 &0x300);
|
||||
}
|
||||
void Mapper421_Init(CartInfo *info) { // Multicart
|
||||
allowExtendedMirroring =1;
|
||||
sync =sync421;
|
||||
JYASIC_init(info);
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2009 CaH4e3
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Wario Land II (Kirby hack)
|
||||
*/
|
||||
|
||||
#include "mapinc.h"
|
||||
|
||||
static uint8 reg[8], chr[8];
|
||||
static uint8 *WRAM = NULL;
|
||||
static uint32 WRAMSIZE;
|
||||
static uint16 IRQCount, IRQa;
|
||||
|
||||
static SFORMAT StateRegs[] =
|
||||
{
|
||||
{ reg, 8, "REGS" },
|
||||
{ chr, 8, "CHRS" },
|
||||
{ &IRQCount, 2, "IRQc" },
|
||||
{ &IRQa, 2, "IRQa" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static void Sync(void) {
|
||||
int i;
|
||||
setprg8r(0x10, 0x6000, 0);
|
||||
setprg8(0x8000, reg[0]);
|
||||
setprg8(0xA000, reg[1]);
|
||||
setprg8(0xC000, reg[2]);
|
||||
setprg8(0xE000, ~0);
|
||||
for (i = 0; i < 8; i++)
|
||||
setchr1(i << 10, chr[i]);
|
||||
setmirror(reg[3] ^ 1);
|
||||
}
|
||||
|
||||
static DECLFW(UNLSC127Write) {
|
||||
switch (A) {
|
||||
case 0x8000: reg[0] = V; break;
|
||||
case 0x8001: reg[1] = V; break;
|
||||
case 0x8002: reg[2] = V; break;
|
||||
case 0x9000: chr[0] = V; break;
|
||||
case 0x9001: chr[1] = V; break;
|
||||
case 0x9002: chr[2] = V; break;
|
||||
case 0x9003: chr[3] = V; break;
|
||||
case 0x9004: chr[4] = V; break;
|
||||
case 0x9005: chr[5] = V; break;
|
||||
case 0x9006: chr[6] = V; break;
|
||||
case 0x9007: chr[7] = V; break;
|
||||
case 0xC002: IRQa = 0; X6502_IRQEnd(FCEU_IQEXT); break;
|
||||
case 0xC005: IRQCount = V; break;
|
||||
case 0xC003: IRQa = 1; break;
|
||||
case 0xD001: reg[3] = V; break;
|
||||
}
|
||||
Sync();
|
||||
}
|
||||
|
||||
static DECLFR(UNLSC127ProtRead) {
|
||||
return 0x20;
|
||||
}
|
||||
|
||||
static void UNLSC127Power(void) {
|
||||
IRQCount = IRQa = 0;
|
||||
Sync();
|
||||
SetReadHandler(0x5800, 0x5800, UNLSC127ProtRead);
|
||||
SetReadHandler(0x6000, 0x7fff, CartBR);
|
||||
SetWriteHandler(0x6000, 0x7fff, CartBW);
|
||||
SetReadHandler(0x8000, 0xFFFF, CartBR);
|
||||
SetWriteHandler(0x8000, 0xFFFF, UNLSC127Write);
|
||||
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
|
||||
}
|
||||
|
||||
static void UNLSC127IRQ(void) {
|
||||
if (IRQa) {
|
||||
if(IRQCount > 0)
|
||||
IRQCount--;
|
||||
if (!IRQCount) {
|
||||
X6502_IRQBegin(FCEU_IQEXT);
|
||||
IRQa = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void UNLSC127Reset(void) {
|
||||
IRQCount = IRQa = 0;
|
||||
}
|
||||
|
||||
static void UNLSC127Close(void) {
|
||||
if (WRAM)
|
||||
FCEU_gfree(WRAM);
|
||||
WRAM = NULL;
|
||||
}
|
||||
|
||||
static void StateRestore(int version) {
|
||||
Sync();
|
||||
}
|
||||
|
||||
void UNLSC127_Init(CartInfo *info) {
|
||||
info->Reset = UNLSC127Reset;
|
||||
info->Power = UNLSC127Power;
|
||||
info->Close = UNLSC127Close;
|
||||
GameHBIRQHook = UNLSC127IRQ;
|
||||
GameStateRestore = StateRestore;
|
||||
WRAMSIZE = 8192;
|
||||
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
|
||||
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
|
||||
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
|
||||
AddExState(&StateRegs, ~0, 0, 0);
|
||||
}
|
||||
13
src/ines.c
13
src/ines.c
@@ -448,7 +448,7 @@ INES_BOARD_BEGIN()
|
||||
INES_BOARD( "IREM G-101", 32, Mapper32_Init )
|
||||
INES_BOARD( "TC0190FMC/TC0350FMR", 33, Mapper33_Init )
|
||||
INES_BOARD( "IREM I-IM/BNROM", 34, Mapper34_Init )
|
||||
INES_BOARD( "Wario Land 2", 35, UNLSC127_Init )
|
||||
INES_BOARD( "EL870914C", 35, Mapper35_Init )
|
||||
INES_BOARD( "TXC Policeman", 36, Mapper36_Init )
|
||||
INES_BOARD( "PAL-ZZ SMB/TETRIS/NWC", 37, Mapper37_Init )
|
||||
INES_BOARD( "Bit Corp.", 38, Mapper38_Init ) /* Crime Busters */
|
||||
@@ -676,7 +676,8 @@ INES_BOARD_BEGIN()
|
||||
|
||||
INES_BOARD( "8-in-1 JY-119", 267, Mapper267_Init )
|
||||
INES_BOARD( "Games Xplosion 121-in-1", 269, Mapper269_Init )
|
||||
INES_BOARD( "HUMMER/JY-052", 281, Mapper281_Init )
|
||||
INES_BOARD( "YY860417C", 281, Mapper281_Init )
|
||||
INES_BOARD( "860224C", 282, Mapper282_Init )
|
||||
INES_BOARD( "GKCX1", 288, Mapper288_Init )
|
||||
INES_BOARD( "MMC3 BMC PIRATE", 294, Bs5652_Init ) /* nesdev redirects this as mapper 134 */
|
||||
INES_BOARD( "TXC 01-22110-000", 297, Mapper297_Init )
|
||||
@@ -735,7 +736,7 @@ INES_BOARD_BEGIN()
|
||||
INES_BOARD( "60311C", 289, BMC60311C_Init )
|
||||
INES_BOARD( "NTD-03", 290, BMCNTD03_Init )
|
||||
INES_BOARD( "DRAGONFIGHTER", 292, UNLBMW8544_Init )
|
||||
INES_BOARD( "13in1JY110", 295, BMC13in1JY110_Init )
|
||||
INES_BOARD( "YY860216C", 295, Mapper295_Init )
|
||||
INES_BOARD( "TF1201", 298, UNLTF1201_Init )
|
||||
INES_BOARD( "11160", 299, BMC11160_Init )
|
||||
INES_BOARD( "190in1", 300, BMC190in1_Init )
|
||||
@@ -779,9 +780,15 @@ INES_BOARD_BEGIN()
|
||||
INES_BOARD( "G-146", 349, BMCG146_Init )
|
||||
INES_BOARD( "891227", 350, BMC891227_Init )
|
||||
INES_BOARD( "3D-BLOCK", 355, UNL3DBlock_Init )
|
||||
INES_BOARD( "YY860606C", 358, Mapper358_Init )
|
||||
INES_BOARD( "N49C-300", 369, Mapper369_Init )
|
||||
INES_BOARD( "YY860729C", 386, Mapper386_Init )
|
||||
INES_BOARD( "YY850735C", 387, Mapper387_Init )
|
||||
INES_BOARD( "YY850835C", 388, Mapper388_Init )
|
||||
INES_BOARD( "NC7000M", 391, NC7000M_Init )
|
||||
INES_BOARD( "YY850439C", 397, Mapper397_Init )
|
||||
INES_BOARD( "831019C J-2282", 402, J2282_Init )
|
||||
INES_BOARD( "SC871115C", 421, Mapper421_Init )
|
||||
INES_BOARD( "SA-9602B", 513, SA9602B_Init )
|
||||
INES_BOARD( "DANCE2000", 518, UNLD2000_Init )
|
||||
INES_BOARD( "EH8813A", 519, UNLEH8813A_Init )
|
||||
|
||||
@@ -76,6 +76,7 @@ void Mapper31_Init(CartInfo *);
|
||||
void Mapper32_Init(CartInfo *);
|
||||
void Mapper33_Init(CartInfo *);
|
||||
void Mapper34_Init(CartInfo *);
|
||||
void Mapper35_Init(CartInfo *);
|
||||
void Mapper36_Init(CartInfo *);
|
||||
void Mapper37_Init(CartInfo *);
|
||||
void Mapper38_Init(CartInfo *);
|
||||
@@ -244,6 +245,8 @@ void Mapper255_Init(CartInfo *);
|
||||
|
||||
void GN45_Init(CartInfo *info); /* m361, m366 */
|
||||
void Mapper281_Init(CartInfo *);
|
||||
void Mapper282_Init(CartInfo *);
|
||||
void Mapper295_Init(CartInfo *);
|
||||
|
||||
void Bs5652_Init(CartInfo *);
|
||||
void NC7000M_Init(CartInfo *);
|
||||
@@ -257,6 +260,7 @@ void Mapper297_Init(CartInfo *);
|
||||
void Mapper353_Init(CartInfo *);
|
||||
void Mapper356_Init(CartInfo *);
|
||||
void Mapper357_Init(CartInfo *);
|
||||
void Mapper358_Init(CartInfo *);
|
||||
void Mapper359_Init(CartInfo *);
|
||||
void Mapper360_Init(CartInfo *);
|
||||
void Mapper369_Init(CartInfo *);
|
||||
@@ -266,11 +270,16 @@ void Mapper374_Init(CartInfo *);
|
||||
void Mapper380_Init(CartInfo *);
|
||||
void Mapper381_Init(CartInfo *);
|
||||
void Mapper382_Init(CartInfo *);
|
||||
void Mapper386_Init(CartInfo *);
|
||||
void Mapper387_Init(CartInfo *);
|
||||
void Mapper388_Init(CartInfo *);
|
||||
void Mapper389_Init(CartInfo *);
|
||||
void Mapper390_Init(CartInfo *);
|
||||
void Mapper395_Init(CartInfo *);
|
||||
void Mapper397_Init(CartInfo *);
|
||||
void Mapper401_Init(CartInfo *);
|
||||
void Mapper411_Init(CartInfo *);
|
||||
void Mapper421_Init(CartInfo *);
|
||||
void Mapper422_Init(CartInfo *);
|
||||
void Mapper516_Init(CartInfo *);
|
||||
void Mapper533_Init(CartInfo *);
|
||||
|
||||
@@ -421,7 +421,7 @@ static void CheckHashInfo(void) {
|
||||
static BMAPPING bmap[] = {
|
||||
{ "11160", 299, BMC11160_Init, 0 },
|
||||
{ "12-IN-1", 331, BMC12IN1_Init, 0 },
|
||||
{ "13in1JY110", 295, BMC13in1JY110_Init, 0 },
|
||||
{ "13in1JY110", 295, Mapper295_Init, 0 },
|
||||
{ "190in1", 300, BMC190in1_Init, 0 },
|
||||
{ "22211", 132, Mapper132_Init, 0 },
|
||||
{ "3D-BLOCK", 355, UNL3DBlock_Init, 0 },
|
||||
@@ -510,7 +510,7 @@ static BMAPPING bmap[] = {
|
||||
{ "SA-NROM", 143, TCA01_Init, 0 },
|
||||
{ "SAROM", 1, SAROM_Init, 0 },
|
||||
{ "SBROM", 1, SBROM_Init, 0 },
|
||||
{ "SC-127", 35, UNLSC127_Init, 0 },
|
||||
{ "SC-127", 35, Mapper35_Init, 0 },
|
||||
{ "SCROM", 1, SCROM_Init, 0 },
|
||||
{ "SEROM", 1, SEROM_Init, 0 },
|
||||
{ "SGROM", 1, SGROM_Init, 0 },
|
||||
|
||||
@@ -25,7 +25,6 @@ void AC08_Init(CartInfo *info);
|
||||
void ANROM_Init(CartInfo *info);
|
||||
void BMC11160_Init(CartInfo *info);
|
||||
void BMC12IN1_Init(CartInfo *info);
|
||||
void BMC13in1JY110_Init(CartInfo *info);
|
||||
void BMC190in1_Init(CartInfo *info);
|
||||
void BMC411120C_Init(CartInfo *info);
|
||||
void BMC64in1nr_Init(CartInfo *info);
|
||||
@@ -135,7 +134,6 @@ void UNLN625092_Init(CartInfo *info);
|
||||
void UNLMaliSB_Init(CartInfo *info);
|
||||
void UNLOneBus_Init(CartInfo *info);
|
||||
void UNLPEC586Init(CartInfo *info);
|
||||
void UNLSC127_Init(CartInfo *info);
|
||||
void UNLSHeroes_Init(CartInfo *info);
|
||||
void UNLSL12_Init(CartInfo *info);
|
||||
void UNLSL1632_Init(CartInfo *info);
|
||||
|
||||
Reference in New Issue
Block a user