mirror of
https://github.com/dborth/fceugx.git
synced 2024-11-01 06:55:05 +01:00
544 lines
14 KiB
C++
544 lines
14 KiB
C++
/* FCE Ultra - NES/Famicom Emulator
|
|
*
|
|
* Copyright notice for this file:
|
|
* Copyright (C) 2002 Xodnizel
|
|
*
|
|
* 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"
|
|
#include "../ines.h"
|
|
|
|
static uint8 latche, latcheinit, bus_conflict;
|
|
static uint16 addrreg0, addrreg1;
|
|
static uint8 *WRAM = NULL;
|
|
static uint32 WRAMSIZE;
|
|
static void (*WSync)(void);
|
|
|
|
static DECLFW(LatchWrite) {
|
|
// FCEU_printf("bs %04x %02x\n",A,V);
|
|
if (bus_conflict)
|
|
latche = V & CartBR(A);
|
|
else
|
|
latche = V;
|
|
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(0x8000, 0xFFFF, CartBR);
|
|
}
|
|
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), uint8 init, uint16 adr0, uint16 adr1, uint8 wram, uint8 busc) {
|
|
bus_conflict = busc;
|
|
latcheinit = init;
|
|
addrreg0 = adr0;
|
|
addrreg1 = adr1;
|
|
WSync = proc;
|
|
info->Power = LatchPower;
|
|
info->Close = LatchClose;
|
|
GameStateRestore = StateRestore;
|
|
if(info->ines2)
|
|
if(info->battery_wram_size + info->wram_size > 0)
|
|
wram = 1;
|
|
if (wram)
|
|
{
|
|
if(info->ines2)
|
|
{
|
|
//I would like to do it in this way, but FCEUX is woefully inadequate
|
|
//for instance if WRAMSIZE is large, the cheat pointers may get overwritten. and it's just a giant mess.
|
|
//WRAMSIZE = info->battery_wram_size + info->wram_size;
|
|
//WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
|
|
//if(!info->wram_size && !info->battery_wram_size) {}
|
|
//else if(info->wram_size && !info->battery_wram_size)
|
|
// SetupCartPRGMapping(0x10, WRAM, info->wram_size, 1);
|
|
//else if(!info->wram_size && info->battery_wram_size)
|
|
//{
|
|
// SetupCartPRGMapping(0x10, WRAM, info->battery_wram_size, 1);
|
|
// info->SaveGame[0] = WRAM;
|
|
// info->SaveGameLen[0] = info->battery_wram_size;
|
|
//} else {
|
|
// //well, this is annoying
|
|
// SetupCartPRGMapping(0x10, WRAM, info->wram_size, 1);
|
|
// SetupCartPRGMapping(0x11, WRAM, info->battery_wram_size, 1); //? ? ? there probably isnt even a way to select this
|
|
// info->SaveGame[0] = WRAM + info->wram_size;
|
|
// info->SaveGameLen[0] = info->battery_wram_size;
|
|
//}
|
|
|
|
//this is more likely the only practical scenario
|
|
WRAMSIZE = 8192;
|
|
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
|
|
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
|
|
SetReadHandler(0x6000, 0x7FFF, CartBR);
|
|
SetWriteHandler(0x6000, 0x7FFF, CartBW);
|
|
setprg8r(0x10, 0x6000, 0);
|
|
if(info->battery_wram_size)
|
|
{
|
|
info->SaveGame[0] = WRAM;
|
|
info->SaveGameLen[0] = 8192;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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");
|
|
}
|
|
|
|
}
|
|
AddExState(&latche, 1, 0, "LATC");
|
|
}
|
|
|
|
//------------------ Map 0 ---------------------------
|
|
|
|
#ifdef DEBUG_MAPPER
|
|
static DECLFW(NROMWrite) {
|
|
FCEU_printf("bs %04x %02x\n", A, V);
|
|
CartBW(A, V);
|
|
}
|
|
#endif
|
|
|
|
static void NROMPower(void) {
|
|
setprg8r(0x10, 0x6000, 0); // Famili BASIC (v3.0) need it (uses only 4KB), FP-BASIC uses 8KB
|
|
setprg16(0x8000, ~1);
|
|
setprg16(0xC000, ~0);
|
|
setchr8(0);
|
|
|
|
SetReadHandler(0x6000, 0x7FFF, CartBR);
|
|
SetWriteHandler(0x6000, 0x7FFF, CartBW);
|
|
SetReadHandler(0x8000, 0xFFFF, CartBR);
|
|
|
|
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
|
|
|
|
#ifdef DEBUG_MAPPER
|
|
SetWriteHandler(0x4020, 0xFFFF, NROMWrite);
|
|
#endif
|
|
}
|
|
|
|
void NROM_Init(CartInfo *info) {
|
|
info->Power = NROMPower;
|
|
info->Close = LatchClose;
|
|
|
|
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");
|
|
}
|
|
|
|
//------------------ Map 2 ---------------------------
|
|
|
|
static void UNROMSync(void) {
|
|
// static uint32 mirror_in_use = 0;
|
|
// if (PRGsize[0] <= 128 * 1024) {
|
|
// setprg16(0x8000, latche & 0x7);
|
|
// if (latche & 8) mirror_in_use = 1;
|
|
// if (mirror_in_use)
|
|
// setmirror(((latche >> 3) & 1) ^ 1); // Higway Star Hacked mapper, disabled till new mapper defined
|
|
// } else
|
|
setprg16(0x8000, latche);
|
|
setprg16(0xc000, ~0);
|
|
setchr8(0);
|
|
}
|
|
|
|
void UNROM_Init(CartInfo *info) {
|
|
Latch_Init(info, UNROMSync, 0, 0x8000, 0xFFFF, 0, info->ines2 && info->submapper == 2);
|
|
}
|
|
|
|
//------------------ Map 3 ---------------------------
|
|
|
|
static void CNROMSync(void) {
|
|
setchr8(latche);
|
|
setprg32(0x8000, 0);
|
|
setprg8r(0x10, 0x6000, 0); // Hayauchy IGO uses 2Kb or RAM
|
|
}
|
|
|
|
void CNROM_Init(CartInfo *info) {
|
|
Latch_Init(info, CNROMSync, 0, 0x8000, 0xFFFF, 1, info->ines2 && info->submapper == 2);
|
|
}
|
|
|
|
//------------------ Map 7 ---------------------------
|
|
|
|
static void ANROMSync() {
|
|
setprg32(0x8000, latche & 0xF);
|
|
setmirror(MI_0 + ((latche >> 4) & 1));
|
|
setchr8(0);
|
|
}
|
|
|
|
void ANROM_Init(CartInfo *info) {
|
|
Latch_Init(info, ANROMSync, 0, 0x4020, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 8 ---------------------------
|
|
|
|
static void M8Sync() {
|
|
setprg16(0x8000, latche >> 3);
|
|
setprg16(0xc000, 1);
|
|
setchr8(latche & 3);
|
|
}
|
|
|
|
void Mapper8_Init(CartInfo *info) {
|
|
Latch_Init(info, M8Sync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 11 ---------------------------
|
|
|
|
static void M11Sync(void) {
|
|
setprg32(0x8000, latche & 0xF);
|
|
setchr8(latche >> 4);
|
|
}
|
|
|
|
void Mapper11_Init(CartInfo *info) {
|
|
Latch_Init(info, M11Sync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
void Mapper144_Init(CartInfo *info) {
|
|
Latch_Init(info, M11Sync, 0, 0x8001, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 13 ---------------------------
|
|
|
|
static void CPROMSync(void) {
|
|
setchr4(0x0000, 0);
|
|
setchr4(0x1000, latche & 3);
|
|
setprg32(0x8000, 0);
|
|
}
|
|
|
|
void CPROM_Init(CartInfo *info) {
|
|
Latch_Init(info, CPROMSync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 29 --------------------------- //Used by Glider, http://www.retrousb.com/product_info.php?cPath=30&products_id=58
|
|
|
|
static void M29Sync() {
|
|
setprg16(0x8000, (latche & 0x1C) >> 2);
|
|
setprg16(0xc000, ~0);
|
|
setchr8r(0, latche & 3);
|
|
setprg8r(0x10, 0x6000, 0);
|
|
}
|
|
|
|
void Mapper29_Init(CartInfo *info) {
|
|
Latch_Init(info, M29Sync, 0, 0x8000, 0xFFFF, 1, 0);
|
|
}
|
|
|
|
|
|
//------------------ Map 38 ---------------------------
|
|
|
|
static void M38Sync(void) {
|
|
setprg32(0x8000, latche & 3);
|
|
setchr8(latche >> 2);
|
|
}
|
|
|
|
void Mapper38_Init(CartInfo *info) {
|
|
Latch_Init(info, M38Sync, 0, 0x7000, 0x7FFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 66 ---------------------------
|
|
|
|
static void MHROMSync(void) {
|
|
setprg32(0x8000, latche >> 4);
|
|
setchr8(latche & 0xF);
|
|
}
|
|
|
|
void MHROM_Init(CartInfo *info) {
|
|
Latch_Init(info, MHROMSync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 70 ---------------------------
|
|
|
|
static void M70Sync() {
|
|
setprg16(0x8000, latche >> 4);
|
|
setprg16(0xc000, ~0);
|
|
setchr8(latche & 0xf);
|
|
}
|
|
|
|
void Mapper70_Init(CartInfo *info) {
|
|
Latch_Init(info, M70Sync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 78 ---------------------------
|
|
/* Should be two separate emulation functions for this "mapper". Sigh. URGE TO KILL RISING. */
|
|
static void M78Sync() {
|
|
setprg16(0x8000, (latche & 7));
|
|
setprg16(0xc000, ~0);
|
|
setchr8(latche >> 4);
|
|
setmirror(MI_0 + ((latche >> 3) & 1));
|
|
}
|
|
|
|
void Mapper78_Init(CartInfo *info) {
|
|
Latch_Init(info, M78Sync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 86 ---------------------------
|
|
|
|
static void M86Sync(void) {
|
|
setprg32(0x8000, (latche >> 4) & 3);
|
|
setchr8((latche & 3) | ((latche >> 4) & 4));
|
|
}
|
|
|
|
void Mapper86_Init(CartInfo *info) {
|
|
Latch_Init(info, M86Sync, ~0, 0x6000, 0x6FFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 87 ---------------------------
|
|
|
|
static void M87Sync(void) {
|
|
setprg32(0x8000, 0);
|
|
setchr8(((latche >> 1) & 1) | ((latche << 1) & 2));
|
|
}
|
|
|
|
void Mapper87_Init(CartInfo *info) {
|
|
Latch_Init(info, M87Sync, ~0, 0x6000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 89 ---------------------------
|
|
|
|
static void M89Sync(void) {
|
|
setprg16(0x8000, (latche >> 4) & 7);
|
|
setprg16(0xc000, ~0);
|
|
setchr8((latche & 7) | ((latche >> 4) & 8));
|
|
setmirror(MI_0 + ((latche >> 3) & 1));
|
|
}
|
|
|
|
void Mapper89_Init(CartInfo *info) {
|
|
Latch_Init(info, M89Sync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 93 ---------------------------
|
|
|
|
static void SSUNROMSync(void) {
|
|
setprg16(0x8000, latche >> 4);
|
|
setprg16(0xc000, ~0);
|
|
setchr8(0);
|
|
}
|
|
|
|
void SUNSOFT_UNROM_Init(CartInfo *info) {
|
|
Latch_Init(info, SSUNROMSync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 94 ---------------------------
|
|
|
|
static void M94Sync(void) {
|
|
setprg16(0x8000, latche >> 2);
|
|
setprg16(0xc000, ~0);
|
|
setchr8(0);
|
|
}
|
|
|
|
void Mapper94_Init(CartInfo *info) {
|
|
Latch_Init(info, M94Sync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 97 ---------------------------
|
|
|
|
static void M97Sync(void) {
|
|
setchr8(0);
|
|
setprg16(0x8000, ~0);
|
|
setprg16(0xc000, latche & 15);
|
|
switch (latche >> 6) {
|
|
case 0: break;
|
|
case 1: setmirror(MI_H); break;
|
|
case 2: setmirror(MI_V); break;
|
|
case 3: break;
|
|
}
|
|
setchr8(((latche >> 1) & 1) | ((latche << 1) & 2));
|
|
}
|
|
|
|
void Mapper97_Init(CartInfo *info) {
|
|
Latch_Init(info, M97Sync, ~0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 101 ---------------------------
|
|
|
|
static void M101Sync(void) {
|
|
setprg32(0x8000, 0);
|
|
setchr8(latche);
|
|
}
|
|
|
|
void Mapper101_Init(CartInfo *info) {
|
|
Latch_Init(info, M101Sync, ~0, 0x6000, 0x7FFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 107 ---------------------------
|
|
|
|
static void M107Sync(void) {
|
|
setprg32(0x8000, (latche >> 1) & 3);
|
|
setchr8(latche & 7);
|
|
}
|
|
|
|
void Mapper107_Init(CartInfo *info) {
|
|
Latch_Init(info, M107Sync, ~0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 113 ---------------------------
|
|
|
|
static void M113Sync(void) {
|
|
setprg32(0x8000, (latche >> 3) & 7);
|
|
setchr8(((latche >> 3) & 8) | (latche & 7));
|
|
// setmirror(latche>>7); // only for HES 6in1
|
|
}
|
|
|
|
void Mapper113_Init(CartInfo *info) {
|
|
Latch_Init(info, M113Sync, 0, 0x4100, 0x7FFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 140 ---------------------------
|
|
|
|
void Mapper140_Init(CartInfo *info) {
|
|
Latch_Init(info, MHROMSync, 0, 0x6000, 0x7FFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 152 ---------------------------
|
|
|
|
static void M152Sync() {
|
|
setprg16(0x8000, (latche >> 4) & 7);
|
|
setprg16(0xc000, ~0);
|
|
setchr8(latche & 0xf);
|
|
setmirror(MI_0 + ((latche >> 7) & 1)); /* Saint Seiya...hmm. */
|
|
}
|
|
|
|
void Mapper152_Init(CartInfo *info) {
|
|
Latch_Init(info, M152Sync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 180 ---------------------------
|
|
|
|
static void M180Sync(void) {
|
|
setprg16(0x8000, 0);
|
|
setprg16(0xc000, latche);
|
|
setchr8(0);
|
|
}
|
|
|
|
void Mapper180_Init(CartInfo *info) {
|
|
Latch_Init(info, M180Sync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 184 ---------------------------
|
|
|
|
static void M184Sync(void) {
|
|
setchr4(0x0000, latche);
|
|
setchr4(0x1000, latche >> 4);
|
|
setprg32(0x8000, 0);
|
|
}
|
|
|
|
void Mapper184_Init(CartInfo *info) {
|
|
Latch_Init(info, M184Sync, 0, 0x6000, 0x7FFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 203 ---------------------------
|
|
|
|
static void M203Sync(void) {
|
|
setprg16(0x8000, (latche >> 2) & 3);
|
|
setprg16(0xC000, (latche >> 2) & 3);
|
|
setchr8(latche & 3);
|
|
}
|
|
|
|
void Mapper203_Init(CartInfo *info) {
|
|
Latch_Init(info, M203Sync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ Map 240 ---------------------------
|
|
|
|
static void M240Sync(void) {
|
|
setprg8r(0x10, 0x6000, 0);
|
|
setprg32(0x8000, latche >> 4);
|
|
setchr8(latche & 0xF);
|
|
}
|
|
|
|
void Mapper240_Init(CartInfo *info) {
|
|
Latch_Init(info, M240Sync, 0, 0x4020, 0x5FFF, 1, 0);
|
|
}
|
|
|
|
//------------------ Map 241 ---------------------------
|
|
// Mapper 7 mostly, but with SRAM or maybe prot circuit
|
|
// figure out, which games do need 5xxx area reading
|
|
|
|
static void M241Sync(void) {
|
|
setchr8(0);
|
|
setprg8r(0x10, 0x6000, 0);
|
|
if (latche & 0x80)
|
|
setprg32(0x8000, latche | 8); // no 241 actually, but why not afterall?
|
|
else
|
|
setprg32(0x8000, latche);
|
|
}
|
|
|
|
void Mapper241_Init(CartInfo *info) {
|
|
Latch_Init(info, M241Sync, 0, 0x8000, 0xFFFF, 1, 0);
|
|
}
|
|
|
|
//------------------ A65AS ---------------------------
|
|
|
|
// actually, there is two cart in one... First have extra mirroring
|
|
// mode (one screen) and 32K bankswitching, second one have only
|
|
// 16 bankswitching mode and normal mirroring... But there is no any
|
|
// correlations between modes and they can be used in one mapper code.
|
|
|
|
static void BMCA65ASSync(void) {
|
|
if (latche & 0x40)
|
|
setprg32(0x8000, (latche >> 1) & 0x0F);
|
|
else {
|
|
setprg16(0x8000, ((latche & 0x30) >> 1) | (latche & 7));
|
|
setprg16(0xC000, ((latche & 0x30) >> 1) | 7);
|
|
}
|
|
setchr8(0);
|
|
if (latche & 0x80)
|
|
setmirror(MI_0 + (((latche >> 5) & 1)));
|
|
else
|
|
setmirror(((latche >> 3) & 1) ^ 1);
|
|
}
|
|
|
|
void BMCA65AS_Init(CartInfo *info) {
|
|
Latch_Init(info, BMCA65ASSync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|
|
|
|
//------------------ BMC-11160 ---------------------------
|
|
// Simple BMC discrete mapper by TXC
|
|
|
|
static void BMC11160Sync(void) {
|
|
uint32 bank = (latche >> 4) & 7;
|
|
setprg32(0x8000, bank);
|
|
setchr8((bank << 2) | (latche & 3));
|
|
setmirror((latche >> 7) & 1);
|
|
}
|
|
|
|
void BMC11160_Init(CartInfo *info) {
|
|
Latch_Init(info, BMC11160Sync, 0, 0x8000, 0xFFFF, 0, 0);
|
|
}
|