Files
ci-libretro-fceumm/src/boards/datalatch.c

675 lines
16 KiB
C
Raw Normal View History

/* 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 "../fds_apu.h"
static uint8 latche, latcheinit, bus_conflict;
static uint16 addrreg0, addrreg1;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static void (*WSync)(void);
2025-04-01 16:30:51 +02:00
static uint8 submapper;
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 (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");
}
AddExState(&latche, 1, 0, "LATC");
AddExState(&bus_conflict, 1, 0, "BUSC");
}
/*------------------ 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, 0);
2019-05-31 20:18:48 +08:00
setprg16(0xC000, 1);
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) {
setprg8r(0x10, 0x6000, 0);
setprg16(0x8000, latche);
setprg16(0xc000, ~0);
setchr8(0);
}
void UNROM_Init(CartInfo *info) {
/* By default, do not emulate bus conflicts except when explicitly told by a NES 2.0 header to do so. */
Latch_Init(info, UNROMSync, 0, 0x8000, 0xFFFF, 1, 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) {
/* By default, do not emulate bus conflicts except when explicitly told by a NES 2.0 header to do so. */
Latch_Init(info, CNROMSync, 0, 0x8000, 0xFFFF, 1, info->iNES2 && info->submapper == 2);
}
/*------------------ Map 7 ---------------------------*/
2018-02-21 14:46:01 +01:00
static void ANROMSync(void) {
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 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 ---------------------------*/
/* added 2019-5-23
* Mapper 28, used by homebrew game Glider
* https://wiki.nesdev.com/w/index.php/INES_Mapper_029 */
static void M29Sync(void) {
setprg16(0x8000, (latche >> 2) & 7);
setprg16(0xc000, ~0);
setchr8r(0, latche & 3);
setprg8r(0x10, 0x6000, 0);
}
void Mapper29_Init(CartInfo *info) {
Latch_Init(info, M29Sync, 0x0000, 0x6000, 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 ---------------------------*/
2018-02-21 14:46:01 +01:00
static void M70Sync(void) {
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. */
2018-02-21 14:46:01 +01:00
static void M78Sync(void) {
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 ---------------------------*/
2018-02-21 14:46:01 +01:00
static void M152Sync(void) {
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);
}
2022-02-18 21:05:50 +08:00
/*------------------ Map 271 ---------------------------*/
static void M271Sync(void) {
setchr8(latche & 0x0F);
setprg32(0x8000, latche >> 4);
setmirror((latche >> 5) & 1);
}
void Mapper271_Init(CartInfo *info) {
Latch_Init(info, M271Sync, 0, 0x8000, 0xFFFF, 0, 0);
}
2020-01-28 12:07:47 +08:00
/*------------------ Map 381 ---------------------------*/
/* 2-in-1 High Standard Game (BC-019), reset-based */
static uint8 reset = 0;
static void M381Sync(void) {
setprg16(0x8000, ((latche & 0x10) >> 4) | ((latche & 7) << 1) | (reset << 4));
setprg16(0xC000, 15 | (reset << 4));
setchr8(0);
}
static void M381Reset(void) {
reset ^= 1;
M381Sync();
}
void Mapper381_Init(CartInfo *info) {
info->Reset = M381Reset;
Latch_Init(info, M381Sync, 0, 0x8000, 0xFFFF, 1, 0);
AddExState(&reset, 1, 0, "RST0");
}
2020-01-28 11:42:04 +08:00
/*------------------ Map 538 ---------------------------*/
/* NES 2.0 Mapper 538 denotes the 60-1064-16L PCB, used for a
* bootleg cartridge conversion named Super Soccer Champion
* of the Konami FDS game Exciting Soccer.
*/
static uint8 M538Banks[16] = { 0, 1, 2, 1, 3, 1, 4, 1, 5, 5, 1, 1, 6, 6, 7, 7 };
static void M538Sync(void) {
setprg8(0x6000, (latche >> 1) | 8);
setprg8(0x8000, M538Banks[latche & 15]);
setprg8(0xA000, 14);
setprg8(0xC000, 7);
setprg8(0xE000, 15);
setchr8(0);
setmirror(1);
}
static void M538Power(void) {
FDSSoundPower();
LatchPower();
}
2020-01-28 11:42:04 +08:00
void Mapper538_Init(CartInfo *info) {
Latch_Init(info, M538Sync, 0, 0xC000, 0xCFFF, 1, 0);
info->Power = M538Power;
2020-01-28 11:42:04 +08:00
}
/*------------------ 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);
}
/*------------------ BMC-K-3046 ---------------------------*/
/* NES 2.0 mapper 336 is used for an 11-in-1 multicart
* http://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_336 */
static void BMCK3046Sync(void) {
setprg16(0x8000, latche);
setprg16(0xC000, latche | 0x07);
setchr8(0);
2025-04-01 16:30:51 +02:00
setmirror(latche &(submapper ==2? 0x08: 0x20)? MI_H: MI_V);
}
static DECLFW(BMCK3046_Write1) { /* Special bus conflict: 300 Ohm resistor placed so that for D3, ROM always wins. */
latche = CartBR(A) &0x08 | V &CartBR(A) &~0x08;
WSync();
}
static void BMCK3046_Power(void) {
LatchPower();
if (submapper ==1) SetWriteHandler(0x8000, 0xFFFF, BMCK3046_Write1);
}
static void BMCK3046_Reset(void) {
latche = 0;
WSync();
}
void BMCK3046_Init(CartInfo *info) {
2025-04-01 16:30:51 +02:00
submapper =info->submapper;
Latch_Init(info, BMCK3046Sync, 0, 0x8000, 0xFFFF, 0, 0);
2025-04-01 16:30:51 +02:00
info->Reset = BMCK3046_Reset;
info->Power = BMCK3046_Power;
}
/* Mapper 429: LIKO BBG-235-8-1B/Milowork FCFC1 */
static void Mapper429_Sync(void) {
setprg32(0x8000, latche >>2);
2022-07-27 13:28:57 +02:00
setchr8(latche);
}
static void Mapper429_Reset(void) {
latche = 4; /* Initial CHR bank 0, initial PRG bank 1 */
Mapper429_Sync();
}
void Mapper429_Init(CartInfo *info) {
info->Reset = Mapper429_Reset;
Latch_Init(info, Mapper429_Sync, 0, 0x8000, 0xFFFF, 0, 0);
}
2022-02-07 13:17:21 +08:00
/*------------------ Mapper 415 ---------------------------*/
static void Mapper415_Sync(void) {
setprg8(0x6000, latche & 0x0F);
setprg32(0x8000, ~0);
setchr8(0);
setmirror(((latche >> 4) & 1) ^ 1);
}
static void M415Power(void) {
LatchPower();
SetReadHandler(0x6000, 0x7FFF, CartBR);
}
void Mapper415_Init(CartInfo *info) {
Latch_Init(info, Mapper415_Sync, 0, 0x8000, 0xFFFF, 0, 0);
info->Power = M415Power;
}
2025-03-31 20:35:43 +02:00
2025-04-05 22:15:36 +02:00
/*------------------ Mapper 462 ---------------------------*/
static uint8 M462OuterBank;
static void Mapper462_Sync(void) {
if (M462OuterBank &0x40) {
setprg32(0x8000, latche &7 | M462OuterBank >>3 &~7);
setmirror(latche &0x10? MI_1: MI_0);
} else {
setprg16(0x8000, latche &7 | M462OuterBank >>2 &~7);
setprg16(0xC000, 7 | M462OuterBank >>2 &~7);
setmirror(M462OuterBank &0x10? MI_V: MI_H);
}
setchr8(0);
}
static DECLFW(M462_WriteExtra) {
M462OuterBank =V;
Mapper462_Sync();
}
static void M462Power(void) {
M462OuterBank =0;
LatchPower();
SetWriteHandler(0xA000, 0xBFFF, M462_WriteExtra);
}
static void M462Reset(void) {
M462OuterBank =0;
Mapper462_Sync();
}
void Mapper462_Init(CartInfo *info) {
Latch_Init(info, Mapper462_Sync, 0, 0x8000, 0xFFFF, 0, 0);
info->Power = M462Power;
info->Reset = M462Reset;
AddExState(&M462OuterBank, 1, 0, "EXP0");
}
2025-04-25 02:06:01 +02:00
/*------------------ Mapper 477 ---------------------------*/
static void Mapper477_Sync(void) {
if (latche &0xE) {
setprg16(0x8000, 0xFF);
setprg16(0xC000, latche);
} else
setprg32(0x8000, latche >>1);
setchr8(latche);
}
static DECLFW(Mapper477_Write) { /* Resistors placed on the first 128 KiB PRG ROM chip (banks 8-15) cause ROM to always win D0..D3. Otherwise, normal AND-type bus conflicts. */
latche = latche &8? (CartBR(A) &0x0F | V &CartBR(A) &~0x0F): (CartBR(A) &V);
WSync();
}
static void Mapper477_Power(void) {
LatchPower();
SetWriteHandler(0x8000, 0xFFFF, Mapper477_Write);
}
static void Mapper477_Reset(void) {
latche = 0;
WSync();
}
void Mapper477_Init(CartInfo *info) {
submapper =info->submapper;
Latch_Init(info, Mapper477_Sync, 0, 0x8000, 0xFFFF, 0, 0);
info->Reset = Mapper477_Reset;
info->Power = Mapper477_Power;
}
2025-04-05 22:15:36 +02:00
/*------------------ Mapper 481 ---------------------------*/
2025-03-31 20:35:43 +02:00
static void Mapper481_Sync(void) {
setprg16(0x8000, latche >>4 &~7 | latche &7);
setprg16(0xc000, latche >>4 | 7);
setchr8(0);
}
void Mapper481_Init(CartInfo *info) {
Latch_Init(info, Mapper481_Sync, 0, 0x8000, 0xFFFF, 1, 0);
}