mirror of
https://github.com/dborth/fceugx.git
synced 2024-11-01 06:55:05 +01:00
519 lines
13 KiB
C++
519 lines
13 KiB
C++
/* FCE Ultra - NES/Famicom Emulator
|
|
*
|
|
* Copyright notice for this file:
|
|
* Copyright (C) 2006 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
|
|
*/
|
|
|
|
#include "mapinc.h"
|
|
|
|
static uint16 latche, latcheinit;
|
|
static uint16 addrreg0, addrreg1;
|
|
static uint8 dipswitch;
|
|
static void (*WSync)(void);
|
|
static readfunc defread;
|
|
static uint8 *WRAM = NULL;
|
|
static uint32 WRAMSIZE;
|
|
|
|
static DECLFW(LatchWrite) {
|
|
latche = A;
|
|
WSync();
|
|
}
|
|
|
|
static void LatchReset(void) {
|
|
latche = latcheinit;
|
|
WSync();
|
|
}
|
|
|
|
static void LatchPower(void) {
|
|
latche = latcheinit;
|
|
WSync();
|
|
if (WRAM) {
|
|
SetReadHandler(0x6000, 0xFFFF, CartBR);
|
|
SetWriteHandler(0x6000, 0x7FFF, CartBW);
|
|
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
|
|
} else
|
|
SetReadHandler(0x6000, 0xFFFF, defread);
|
|
SetWriteHandler(addrreg0, addrreg1, LatchWrite);
|
|
}
|
|
|
|
static void LatchClose(void) {
|
|
if (WRAM)
|
|
FCEU_gfree(WRAM);
|
|
WRAM = NULL;
|
|
}
|
|
|
|
static void StateRestore(int version) {
|
|
WSync();
|
|
}
|
|
|
|
static void Latch_Init(CartInfo *info, void (*proc)(void), readfunc func, uint16 linit, uint16 adr0, uint16 adr1, uint8 wram) {
|
|
latcheinit = linit;
|
|
addrreg0 = adr0;
|
|
addrreg1 = adr1;
|
|
WSync = proc;
|
|
if (func != NULL)
|
|
defread = func;
|
|
else
|
|
defread = CartBROB;
|
|
info->Power = LatchPower;
|
|
info->Reset = LatchReset;
|
|
info->Close = LatchClose;
|
|
if (wram) {
|
|
WRAMSIZE = 8192;
|
|
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
|
|
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
|
|
if (info->battery) {
|
|
info->SaveGame[0] = WRAM;
|
|
info->SaveGameLen[0] = WRAMSIZE;
|
|
}
|
|
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
|
|
}
|
|
GameStateRestore = StateRestore;
|
|
AddExState(&latche, 2, 0, "LATC");
|
|
}
|
|
|
|
//------------------ BMCD1038 ---------------------------
|
|
|
|
static void BMCD1038Sync(void) {
|
|
if (latche & 0x80) {
|
|
setprg16(0x8000, (latche & 0x70) >> 4);
|
|
setprg16(0xC000, (latche & 0x70) >> 4);
|
|
} else
|
|
setprg32(0x8000, (latche & 0x60) >> 5);
|
|
setchr8(latche & 7);
|
|
setmirror(((latche & 8) >> 3) ^ 1);
|
|
}
|
|
|
|
static DECLFR(BMCD1038Read) {
|
|
if (latche & 0x100)
|
|
return dipswitch;
|
|
else
|
|
return CartBR(A);
|
|
}
|
|
|
|
static void BMCD1038Reset(void) {
|
|
dipswitch++;
|
|
dipswitch &= 3;
|
|
}
|
|
|
|
void BMCD1038_Init(CartInfo *info) {
|
|
Latch_Init(info, BMCD1038Sync, BMCD1038Read, 0x0000, 0x8000, 0xFFFF, 0);
|
|
info->Reset = BMCD1038Reset;
|
|
AddExState(&dipswitch, 1, 0, "DIPSW");
|
|
}
|
|
|
|
//------------------ UNL43272 ---------------------------
|
|
// mapper much complex, including 16K bankswitching
|
|
static void UNL43272Sync(void) {
|
|
if ((latche & 0x81) == 0x81) {
|
|
setprg32(0x8000, (latche & 0x38) >> 3);
|
|
} else
|
|
FCEU_printf("unrecognized command %04!\n", latche);
|
|
setchr8(0);
|
|
setmirror(0);
|
|
}
|
|
|
|
static DECLFR(UNL43272Read) {
|
|
if (latche & 0x400)
|
|
return CartBR(A & 0xFE);
|
|
else
|
|
return CartBR(A);
|
|
}
|
|
|
|
static void UNL43272Reset(void) {
|
|
latche = 0;
|
|
UNL43272Sync();
|
|
}
|
|
|
|
void UNL43272_Init(CartInfo *info) {
|
|
Latch_Init(info, UNL43272Sync, UNL43272Read, 0x0081, 0x8000, 0xFFFF, 0);
|
|
info->Reset = UNL43272Reset;
|
|
AddExState(&dipswitch, 1, 0, "DIPSW");
|
|
}
|
|
|
|
//------------------ Map 058 ---------------------------
|
|
|
|
static void BMCGK192Sync(void) {
|
|
if (latche & 0x40) {
|
|
setprg16(0x8000, latche & 7);
|
|
setprg16(0xC000, latche & 7);
|
|
} else
|
|
setprg32(0x8000, (latche >> 1) & 3);
|
|
setchr8((latche >> 3) & 7);
|
|
setmirror(((latche & 0x80) >> 7) ^ 1);
|
|
}
|
|
|
|
void BMCGK192_Init(CartInfo *info) {
|
|
Latch_Init(info, BMCGK192Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 059 ---------------------------
|
|
// One more forgotten mapper
|
|
static void M59Sync(void) {
|
|
setprg32(0x8000, (latche >> 4) & 7);
|
|
setchr8(latche & 0x7);
|
|
setmirror((latche >> 3) & 1);
|
|
}
|
|
|
|
static DECLFR(M59Read) {
|
|
if (latche & 0x100)
|
|
return 0;
|
|
else
|
|
return CartBR(A);
|
|
}
|
|
|
|
void Mapper59_Init(CartInfo *info) {
|
|
Latch_Init(info, M59Sync, M59Read, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 061 ---------------------------
|
|
static void M61Sync(void) {
|
|
if (((latche & 0x10) << 1) ^ (latche & 0x20)) {
|
|
setprg16(0x8000, ((latche & 0xF) << 1) | (((latche & 0x20) >> 4)));
|
|
setprg16(0xC000, ((latche & 0xF) << 1) | (((latche & 0x20) >> 4)));
|
|
} else
|
|
setprg32(0x8000, latche & 0xF);
|
|
setchr8(0);
|
|
setmirror(((latche >> 7) & 1) ^ 1);
|
|
}
|
|
|
|
void Mapper61_Init(CartInfo *info) {
|
|
Latch_Init(info, M61Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 092 ---------------------------
|
|
// Another two-in-one mapper, two Jaleco carts uses similar
|
|
// hardware, but with different wiring.
|
|
// Original code provided by LULU
|
|
// Additionally, PCB contains DSP extra sound chip, used for voice samples (unemulated)
|
|
|
|
static void M92Sync(void) {
|
|
uint8 reg = latche & 0xF0;
|
|
setprg16(0x8000, 0);
|
|
if (latche >= 0x9000) {
|
|
switch (reg) {
|
|
case 0xD0: setprg16(0xc000, latche & 15); break;
|
|
case 0xE0: setchr8(latche & 15); break;
|
|
}
|
|
} else {
|
|
switch (reg) {
|
|
case 0xB0: setprg16(0xc000, latche & 15); break;
|
|
case 0x70: setchr8(latche & 15); break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Mapper92_Init(CartInfo *info) {
|
|
Latch_Init(info, M92Sync, NULL, 0x80B0, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 200 ---------------------------
|
|
|
|
static void M200Sync(void) {
|
|
setprg16(0x8000, latche & 7);
|
|
setprg16(0xC000, latche & 7);
|
|
setchr8(latche & 7);
|
|
setmirror((latche & 8) >> 3);
|
|
}
|
|
|
|
void Mapper200_Init(CartInfo *info) {
|
|
Latch_Init(info, M200Sync, NULL, 0xFFFF, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 201 ---------------------------
|
|
|
|
static void M201Sync(void) {
|
|
setprg32(0x8000, latche & 3);
|
|
setchr8(latche & 3);
|
|
}
|
|
|
|
void Mapper201_Init(CartInfo *info) {
|
|
Latch_Init(info, M201Sync, NULL, 0xFFFF, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 202 ---------------------------
|
|
|
|
static void M202Sync(void) {
|
|
// According to more carefull hardware tests and PCB study
|
|
int32 mirror = latche & 1;
|
|
int32 bank = (latche >> 1) & 0x7;
|
|
int32 select = (mirror & (bank >> 2));
|
|
setprg16(0x8000, select ? (bank & 6) | 0 : bank);
|
|
setprg16(0xc000, select ? (bank & 6) | 1 : bank);
|
|
setmirror(mirror ^ 1);
|
|
setchr8(bank);
|
|
}
|
|
|
|
void Mapper202_Init(CartInfo *info) {
|
|
Latch_Init(info, M202Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 204 ---------------------------
|
|
|
|
static void M204Sync(void) {
|
|
int32 tmp2 = latche & 0x6;
|
|
int32 tmp1 = tmp2 + ((tmp2 == 0x6) ? 0 : (latche & 1));
|
|
setprg16(0x8000, tmp1);
|
|
setprg16(0xc000, tmp2 + ((tmp2 == 0x6) ? 1 : (latche & 1)));
|
|
setchr8(tmp1);
|
|
setmirror(((latche >> 4) & 1) ^ 1);
|
|
}
|
|
|
|
void Mapper204_Init(CartInfo *info) {
|
|
Latch_Init(info, M204Sync, NULL, 0xFFFF, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 212 ---------------------------
|
|
|
|
static DECLFR(M212Read) {
|
|
uint8 ret = CartBROB(A);
|
|
if ((A & 0xE010) == 0x6000)
|
|
ret |= 0x80;
|
|
return ret;
|
|
}
|
|
|
|
static void M212Sync(void) {
|
|
if (latche & 0x4000) {
|
|
setprg32(0x8000, (latche >> 1) & 3);
|
|
} else {
|
|
setprg16(0x8000, latche & 7);
|
|
setprg16(0xC000, latche & 7);
|
|
}
|
|
setchr8(latche & 7);
|
|
setmirror(((latche >> 3) & 1) ^ 1);
|
|
}
|
|
|
|
void Mapper212_Init(CartInfo *info) {
|
|
Latch_Init(info, M212Sync, M212Read, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 213 ---------------------------
|
|
|
|
static void M213Sync(void) {
|
|
if(latche & 0x40) {
|
|
setprg16(0x8000, (latche & 7));
|
|
setprg16(0xC000, (latche & 7));
|
|
} else {
|
|
setprg32(0x8000, (latche >> 1) & 3);
|
|
}
|
|
setchr8((latche >> 3) & 7);
|
|
setmirror(((latche & 1)^((latche >> 6) & 1)) ^ 1);
|
|
}
|
|
|
|
void Mapper213_Init(CartInfo *info) {
|
|
Latch_Init(info, M213Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 214 ---------------------------
|
|
|
|
static void M214Sync(void) {
|
|
setprg16(0x8000, (latche >> 2) & 3);
|
|
setprg16(0xC000, (latche >> 2) & 3);
|
|
setchr8(latche & 3);
|
|
}
|
|
|
|
void Mapper214_Init(CartInfo *info) {
|
|
Latch_Init(info, M214Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 217 ---------------------------
|
|
|
|
static void M217Sync(void) {
|
|
setprg32(0x8000, (latche >> 2) & 3);
|
|
setchr8(latche & 7);
|
|
}
|
|
|
|
void Mapper217_Init(CartInfo *info) {
|
|
Latch_Init(info, M217Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 227 ---------------------------
|
|
|
|
static void M227Sync(void) {
|
|
uint32 S = latche & 1;
|
|
uint32 p = ((latche >> 2) & 0x1F) + ((latche & 0x100) >> 3);
|
|
uint32 L = (latche >> 9) & 1;
|
|
|
|
// ok, according to nesdev wiki (refrenced to the nesdev dumping thread) there is a CHR write protection bit7.
|
|
// however, this bit clearly determined a specific PRG layout for some game but does not meant to have additional
|
|
// functionality. as I see from the menu code, it disables the chr writing before run an actual game.
|
|
// this fix here makes happy both waixing rpgs and multigame menus at once. can't veryfy it on a hardware
|
|
// but if I find some i'll definitly do this.
|
|
|
|
if ((latche & 0xF000) == 0xF000)
|
|
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
|
|
else
|
|
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1);
|
|
|
|
if ((latche >> 7) & 1) {
|
|
if (S) {
|
|
setprg32(0x8000, p >> 1);
|
|
} else {
|
|
setprg16(0x8000, p);
|
|
setprg16(0xC000, p);
|
|
}
|
|
} else {
|
|
if (S) {
|
|
if (L) {
|
|
setprg16(0x8000, p & 0x3E);
|
|
setprg16(0xC000, p | 7);
|
|
} else {
|
|
setprg16(0x8000, p & 0x3E);
|
|
setprg16(0xC000, p & 0x38);
|
|
}
|
|
} else {
|
|
if (L) {
|
|
setprg16(0x8000, p);
|
|
setprg16(0xC000, p | 7);
|
|
} else {
|
|
setprg16(0x8000, p);
|
|
setprg16(0xC000, p & 0x38);
|
|
}
|
|
}
|
|
}
|
|
|
|
setmirror(((latche >> 1) & 1) ^ 1);
|
|
setchr8(0);
|
|
setprg8r(0x10, 0x6000, 0);
|
|
}
|
|
|
|
void Mapper227_Init(CartInfo *info) {
|
|
Latch_Init(info, M227Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1);
|
|
}
|
|
|
|
//------------------ Map 229 ---------------------------
|
|
|
|
static void M229Sync(void) {
|
|
setchr8(latche);
|
|
if (!(latche & 0x1e))
|
|
setprg32(0x8000, 0);
|
|
else {
|
|
setprg16(0x8000, latche & 0x1F);
|
|
setprg16(0xC000, latche & 0x1F);
|
|
}
|
|
setmirror(((latche >> 5) & 1) ^ 1);
|
|
}
|
|
|
|
void Mapper229_Init(CartInfo *info) {
|
|
Latch_Init(info, M229Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 231 ---------------------------
|
|
|
|
static void M231Sync(void) {
|
|
setchr8(0);
|
|
if (latche & 0x20)
|
|
setprg32(0x8000, (latche >> 1) & 0x0F);
|
|
else {
|
|
setprg16(0x8000, latche & 0x1E);
|
|
setprg16(0xC000, latche & 0x1E);
|
|
}
|
|
setmirror(((latche >> 7) & 1) ^ 1);
|
|
}
|
|
|
|
void Mapper231_Init(CartInfo *info) {
|
|
Latch_Init(info, M231Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//------------------ Map 242 ---------------------------
|
|
|
|
static void M242Sync(void) {
|
|
setchr8(0);
|
|
setprg8r(0x10, 0x6000, 0);
|
|
setprg32(0x8000, (latche >> 3) & 0xf);
|
|
setmirror(((latche >> 1) & 1) ^ 1);
|
|
}
|
|
|
|
void Mapper242_Init(CartInfo *info) {
|
|
Latch_Init(info, M242Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1);
|
|
}
|
|
|
|
//------------------ 190in1 ---------------------------
|
|
|
|
static void BMC190in1Sync(void) {
|
|
setprg16(0x8000, (latche >> 2) & 7);
|
|
setprg16(0xC000, (latche >> 2) & 7);
|
|
setchr8((latche >> 2) & 7);
|
|
setmirror((latche & 1) ^ 1);
|
|
}
|
|
|
|
void BMC190in1_Init(CartInfo *info) {
|
|
Latch_Init(info, BMC190in1Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//-------------- BMC810544-C-A1 ------------------------
|
|
|
|
static void BMC810544CA1Sync(void) {
|
|
uint32 bank = latche >> 7;
|
|
if (latche & 0x40)
|
|
setprg32(0x8000, bank);
|
|
else {
|
|
setprg16(0x8000, (bank << 1) | ((latche >> 5) & 1));
|
|
setprg16(0xC000, (bank << 1) | ((latche >> 5) & 1));
|
|
}
|
|
setchr8(latche & 0x0f);
|
|
setmirror(((latche >> 4) & 1) ^ 1);
|
|
}
|
|
|
|
void BMC810544CA1_Init(CartInfo *info) {
|
|
Latch_Init(info, BMC810544CA1Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//-------------- BMCNTD-03 ------------------------
|
|
|
|
static void BMCNTD03Sync(void) {
|
|
// 1PPP Pmcc spxx xccc
|
|
// 1000 0000 0000 0000 v
|
|
// 1001 1100 0000 0100 h
|
|
// 1011 1010 1100 0100
|
|
uint32 prg = ((latche >> 10) & 0x1e);
|
|
uint32 chr = ((latche & 0x0300) >> 5) | (latche & 7);
|
|
if (latche & 0x80) {
|
|
setprg16(0x8000, prg | ((latche >> 6) & 1));
|
|
setprg16(0xC000, prg | ((latche >> 6) & 1));
|
|
} else
|
|
setprg32(0x8000, prg >> 1);
|
|
setchr8(chr);
|
|
setmirror(((latche >> 10) & 1) ^ 1);
|
|
}
|
|
|
|
void BMCNTD03_Init(CartInfo *info) {
|
|
Latch_Init(info, BMCNTD03Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|
|
|
|
//-------------- BMCG-146 ------------------------
|
|
|
|
static void BMCG146Sync(void) {
|
|
setchr8(0);
|
|
if (latche & 0x800) { // UNROM mode
|
|
setprg16(0x8000, (latche & 0x1F) | (latche & ((latche & 0x40) >> 6)));
|
|
setprg16(0xC000, (latche & 0x18) | 7);
|
|
} else {
|
|
if (latche & 0x40) { // 16K mode
|
|
setprg16(0x8000, latche & 0x1F);
|
|
setprg16(0xC000, latche & 0x1F);
|
|
} else {
|
|
setprg32(0x8000, (latche >> 1) & 0x0F);
|
|
}
|
|
}
|
|
setmirror(((latche & 0x80) >> 7) ^ 1);
|
|
}
|
|
|
|
void BMCG146_Init(CartInfo *info) {
|
|
Latch_Init(info, BMCG146Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
|
|
}
|