2020-03-12 23:56:55 +08:00
/* FCEUmm - NES/Famicom Emulator
2017-04-27 00:45:40 +08:00
*
* Copyright notice for this file :
* Copyright ( C ) 2006 CaH4e3
2020-03-12 23:56:55 +08:00
* Copyright ( C ) 2020 negativeExponent
2017-04-27 00:45:40 +08:00
*
* 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
*/
2021-05-26 20:19:25 +02:00
/* Mappers:
176 - Standard
2021-05-26 20:36:06 +02:00
523 - Jncota KT - xxx , re - release of 封 神 榜 ꞉ 伏 魔 三 太 子 : 1 KiB - > 2 KiB , 2 KiB - > 4 KiB CHR , hard - wired nametable mirroring )
2021-05-26 20:19:25 +02:00
Submappers :
0 - Standard
1 - FK - xxx
2 - 外 星 FS005 / FS006
3 - JX9003B
4 - GameStar Smart Genius Deluxe
Verified on real hardware :
" Legend of Kage " sets CNROM latch 1 and switches between CHR bank 0 and 1 using 5FF 2 , causing the wrong bank ( 1 instead of 0 ) during gameplay .
Heuristics for NES 1.0 :
- 1 MiB PRG + 1 MiB CHR = > Submapper 1
- 256 KiB PRG + 128 KiB CHR = > Submapper 1
- 128 KiB PRG + 64 KiB CHR = > Submapper 1
- A001 .5 ever set = > Submapper 2
- 5FF 5 / 5FF 6 written - to = > Submapper 3
Heuristic for detecting whether the DIP switch should be changed on every soft reset :
The first write to the $ 5 xxx range is to $ 501 x = > ROM always addresses $ 501 x ; changing the DIP switch on reset would break the emulation after reset , so don ' t do it .
The first write to the $ 5 xxx range is to $ 5020 or higher = > ROM either uses a DIP switch or writes to $ 5FF x for safety ; changing the DIP switch on reset is possible .
2020-10-19 09:17:45 +08:00
*/
2020-03-12 23:56:55 +08:00
# include "mapinc.h"
# include "../ines.h"
static uint8 * WRAM = NULL ;
static uint8 * CHRRAM = NULL ;
static uint32 WRAMSIZE = 0 ;
static uint32 CHRRAMSIZE = 0 ;
2021-05-26 20:19:25 +02:00
static uint8 fk23_regs [ 8 ] = { 0 } ; /* JX9003B has eight registers, all others have four */
2020-03-12 23:56:55 +08:00
static uint8 mmc3_regs [ 12 ] = { 0 } ;
static uint8 mmc3_ctrl = 0 ;
static uint8 mmc3_mirr = 0 ;
static uint8 mmc3_wram = 0 ;
static uint8 irq_count = 0 ;
static uint8 irq_latch = 0 ;
static uint8 irq_enabled = 0 ;
static uint8 irq_reload = 0 ;
2021-05-26 20:19:25 +02:00
static uint8 latch = 0 ;
2020-03-12 23:56:55 +08:00
static uint8 dipswitch = 0 ;
2021-05-26 20:19:25 +02:00
static uint8 subType = 0 ; /* NES 2.0 Submapper, denoting PCB variants */
static uint8 jncota523 = 0 ; /* Jncota board with unusual wiring that turns 1 KiB CHR banks into 2 KiB banks, and has hard-wired nametable mirroring. */
static uint8 dipsw_enable = 0 ; /* Change the address mask on every reset? */
static uint8 after_power = 0 ; /* Used for detecting whether a DIP switch is used or not (see above) */
2020-03-12 23:56:55 +08:00
static SFORMAT StateRegs [ ] = {
2021-05-26 20:19:25 +02:00
{ fk23_regs , 8 , " EXPR " } ,
2020-03-19 21:58:59 +08:00
{ mmc3_regs , 12 , " M3RG " } ,
2021-05-26 20:19:25 +02:00
{ & latch , 1 , " LATC " } ,
2020-03-19 21:58:59 +08:00
{ & dipswitch , 1 , " DPSW " } ,
{ & mmc3_ctrl , 1 , " M3CT " } ,
{ & mmc3_mirr , 1 , " M3MR " } ,
{ & mmc3_wram , 1 , " M3WR " } ,
{ & irq_reload , 1 , " IRQR " } ,
{ & irq_count , 1 , " IRQC " } ,
{ & irq_latch , 1 , " IRQL " } ,
{ & irq_enabled , 1 , " IRQA " } ,
{ & subType , 1 , " SUBT " } ,
2020-03-12 23:56:55 +08:00
{ 0 }
2017-04-27 00:45:40 +08:00
} ;
2021-05-26 20:19:25 +02:00
# define INVERT_PRG !!(mmc3_ctrl & 0x40)
# define INVERT_CHR !!(mmc3_ctrl & 0x80)
# define WRAM_ENABLED !!(mmc3_wram & 0x80)
# define WRAM_EXTENDED (!!(mmc3_wram & 0x20) && subType == 2) /* Extended A001 register. Only available on FS005 PCB. */
# define FK23_ENABLED (!!(mmc3_wram & 0x40) || !WRAM_EXTENDED) /* Enable or disable registers in the $5xxx range. Only available on FS005 PCB. */
# define PRG_MODE ( fk23_regs[0] & 0x07)
# define MMC3_EXTENDED !!( fk23_regs[3] & 0x02) /* Extended MMC3 mode, adding extra registers for switching the normally-fixed PRG banks C and E and for eight independent 1 KiB CHR banks. Only available on FK- and FS005 PCBs. */
# define CHR_8K_MODE !!( fk23_regs[0] & 0x40) /* MMC3 CHR registers are ignored, apply outer bank only, and CNROM latch if it exists */
# define CHR_CNROM_MODE (~fk23_regs[0] & 0x20 && subType == 1) /* Only subtype 1 has a CNROM latch, which can be disabled */
# define CHR_OUTER_BANK_SIZE !!( fk23_regs[0] & 0x10) /* Switch between 256 and 128 KiB CHR, or 32 and 16 KiB CHR in CNROM mode */
# define CHR_MIXED !!(WRAM_EXTENDED && mmc3_wram &0x04) /* First 8 KiB of CHR address space are RAM, then ROM */
2020-03-12 23:56:55 +08:00
2020-10-20 21:12:32 +08:00
static void cwrap ( uint32 A , uint32 V )
2020-03-12 23:56:55 +08:00
{
2020-04-26 08:19:45 +08:00
int bank = 0 ;
2021-05-26 20:36:06 +02:00
if ( jncota523 )
{
if ( ~ A & 0x0400 ) setchr2r ( bank , A , V ) ;
}
else
{
/* some workaround for chr rom / ram access */
if ( ! VROM_size )
bank = 0 ;
else if ( CHRRAMSIZE & & fk23_regs [ 0 ] & 0x20 )
bank = 0x10 ;
if ( CHR_MIXED & & V < 8 ) bank = 0x10 ; /* first 8K of chr bank is RAM */
setchr1r ( bank , A , V ) ;
}
2017-04-27 00:45:40 +08:00
}
2020-03-12 23:56:55 +08:00
static void SyncCHR ( void )
{
2021-05-26 20:19:25 +02:00
uint32 outer = fk23_regs [ 2 ] | ( subType = = 3 ? ( fk23_regs [ 6 ] < < 8 ) : 0 ) ; /* Outer 8 KiB CHR bank. Subtype 3 has an MSB register providing more bits. */
if ( CHR_8K_MODE )
2020-03-12 23:56:55 +08:00
{
2021-05-26 20:19:25 +02:00
uint32 mask = ( CHR_CNROM_MODE ? ( CHR_OUTER_BANK_SIZE ? 0x01 : 0x03 ) : 0x00 ) ;
uint32 bank = ( ( outer & ~ mask ) | ( latch & mask ) ) < < 3 ; /* Address bits are never OR'd; they either come from the outer bank or from the CNROM latch. */
2020-03-12 23:56:55 +08:00
2020-10-20 21:12:32 +08:00
cwrap ( 0x0000 , bank + 0 ) ;
2020-03-12 23:56:55 +08:00
cwrap ( 0x0400 , bank + 1 ) ;
cwrap ( 0x0800 , bank + 2 ) ;
cwrap ( 0x0C00 , bank + 3 ) ;
cwrap ( 0x1000 , bank + 4 ) ;
cwrap ( 0x1400 , bank + 5 ) ;
cwrap ( 0x1800 , bank + 6 ) ;
cwrap ( 0x1C00 , bank + 7 ) ;
}
else
{
2021-05-26 20:19:25 +02:00
uint32 cbase = ( INVERT_CHR ? 0x1000 : 0 ) ;
uint32 mask = ( CHR_OUTER_BANK_SIZE ? 0x7F : 0xFF ) ;
outer = ( outer < < 3 ) & ~ mask ; /* From 8 KiB to 1 KiB banks. Address bits are never OR'd; they either come from the outer bank or from the MMC3. */
2020-10-20 21:12:32 +08:00
2020-03-12 23:56:55 +08:00
if ( MMC3_EXTENDED )
{
2021-05-26 20:19:25 +02:00
cwrap ( cbase ^ 0x0000 , mmc3_regs [ 0 ] & mask | outer ) ;
cwrap ( cbase ^ 0x0400 , mmc3_regs [ 10 ] & mask | outer ) ;
cwrap ( cbase ^ 0x0800 , mmc3_regs [ 1 ] & mask | outer ) ;
cwrap ( cbase ^ 0x0c00 , mmc3_regs [ 11 ] & mask | outer ) ;
cwrap ( cbase ^ 0x1000 , mmc3_regs [ 2 ] & mask | outer ) ;
cwrap ( cbase ^ 0x1400 , mmc3_regs [ 3 ] & mask | outer ) ;
cwrap ( cbase ^ 0x1800 , mmc3_regs [ 4 ] & mask | outer ) ;
cwrap ( cbase ^ 0x1c00 , mmc3_regs [ 5 ] & mask | outer ) ;
2020-03-12 23:56:55 +08:00
}
else
{
2021-05-26 20:19:25 +02:00
cwrap ( cbase ^ 0x0000 , ( mmc3_regs [ 0 ] & 0xFE ) & mask | outer ) ;
cwrap ( cbase ^ 0x0400 , ( mmc3_regs [ 0 ] | 0x01 ) & mask | outer ) ;
cwrap ( cbase ^ 0x0800 , ( mmc3_regs [ 1 ] & 0xFE ) & mask | outer ) ;
cwrap ( cbase ^ 0x0C00 , ( mmc3_regs [ 1 ] | 0x01 ) & mask | outer ) ;
cwrap ( cbase ^ 0x1000 , mmc3_regs [ 2 ] & mask | outer ) ;
cwrap ( cbase ^ 0x1400 , mmc3_regs [ 3 ] & mask | outer ) ;
cwrap ( cbase ^ 0x1800 , mmc3_regs [ 4 ] & mask | outer ) ;
cwrap ( cbase ^ 0x1c00 , mmc3_regs [ 5 ] & mask | outer ) ;
2020-03-12 23:56:55 +08:00
}
}
2017-04-27 00:45:40 +08:00
}
2020-03-12 23:56:55 +08:00
static void SyncPRG ( void )
{
2021-05-26 20:19:25 +02:00
uint32 mask = 0x3F > > PRG_MODE ; /* For PRG modes 0-2, the mode# decides how many bits of the inner 8 KiB bank are used. This is greatly relevant to map the correct bank that contains the reset vectors. */
uint32 prg_base = fk23_regs [ 1 ] & 0x7F ; /* The bits for the first 2 MiB are the same between all the variants. */
switch ( subType )
2020-03-12 23:56:55 +08:00
{
2021-05-26 20:19:25 +02:00
case 1 : /* FK-xxx */
if ( PRG_MODE = = 0 ) mask = 0xFF ; /* Mode 0 allows the MMC3 to address 2 MiB rather than the usual 512 KiB. */
break ;
case 2 : /* FS005 */
prg_base | = fk23_regs [ 0 ] < < 4 & 0x080 | fk23_regs [ 0 ] < < 1 & 0x100 | fk23_regs [ 2 ] < < 3 & 0x600 | fk23_regs [ 2 ] < < 6 & 0x800 ;
break ;
case 3 : /* JX9003B */
if ( PRG_MODE = = 0 ) mask = 0xFF ; /* Mode 0 allows the MMC3 to address 2 MiB rather than the usual 512 KiB. */
prg_base | = fk23_regs [ 5 ] < < 7 ;
break ;
case 4 : /* GameStar Smart Genius Deluxe */
prg_base | = fk23_regs [ 2 ] & 0x80 ;
break ;
}
2020-10-20 21:12:32 +08:00
2021-05-26 20:19:25 +02:00
switch ( PRG_MODE )
{
case 0 : /* MMC3 with 512 KiB or 2 MiB addressable */
case 1 : /* MMC3 with 256 KiB addressable */
case 2 : /* MMC3 with 128 KiB addressable */
2020-03-12 23:56:55 +08:00
{
2021-05-26 20:19:25 +02:00
uint32 cbase = ( INVERT_PRG ? 0x4000 : 0 ) ;
prg_base = ( prg_base < < 1 ) & ~ mask ; /* from 16 to 8 KiB. Address bits are never OR'd; they either come from the outer bank or from the MMC3. */
if ( MMC3_EXTENDED )
{
setprg8 ( 0x8000 ^ cbase , mmc3_regs [ 6 ] & mask | prg_base ) ;
setprg8 ( 0xA000 , mmc3_regs [ 7 ] & mask | prg_base ) ;
setprg8 ( 0xC000 ^ cbase , mmc3_regs [ 8 ] & mask | prg_base ) ;
setprg8 ( 0xE000 , mmc3_regs [ 9 ] & mask | prg_base ) ;
}
else
{
setprg8 ( 0x8000 ^ cbase , ( mmc3_regs [ 6 ] & mask ) | prg_base ) ;
setprg8 ( 0xA000 , ( mmc3_regs [ 7 ] & mask ) | prg_base ) ;
setprg8 ( 0xC000 ^ cbase , ( 0xFE & mask ) | prg_base ) ;
setprg8 ( 0xE000 , ( 0xFF & mask ) | prg_base ) ;
}
break ;
2020-03-12 23:56:55 +08:00
}
2021-05-26 20:19:25 +02:00
case 3 : /* NROM-128 */
setprg16 ( 0x8000 , prg_base ) ;
setprg16 ( 0xC000 , prg_base ) ;
break ;
case 4 : /* NROM-256 */
setprg32 ( 0x8000 , ( prg_base > > 1 ) ) ;
break ;
case 5 : /* UNROM */
setprg16 ( 0x8000 , latch & 0x07 | prg_base & ~ 0x07 ) ;
setprg16 ( 0xC000 , 0x07 | prg_base ) ;
break ;
2020-10-20 21:12:32 +08:00
}
2017-04-27 00:45:40 +08:00
}
2020-03-12 23:56:55 +08:00
static void SyncWRAM ( void )
{
/* TODO: WRAM Protected mode when not in extended mode */
if ( WRAM_ENABLED | | WRAM_EXTENDED )
{
if ( WRAM_EXTENDED )
{
setprg8r ( 0x10 , 0x4000 , ( mmc3_wram & 0x03 ) + 1 ) ;
setprg8r ( 0x10 , 0x6000 , mmc3_wram & 0x03 ) ;
}
else
setprg8r ( 0x10 , 0x6000 , 0 ) ;
}
2017-04-27 00:45:40 +08:00
}
2020-03-12 23:56:55 +08:00
static void SyncMIR ( void )
{
2021-05-26 20:36:06 +02:00
if ( jncota523 ) /* Jncota board has hard-wired mirroring */
return ;
else
2021-05-26 20:19:25 +02:00
switch ( mmc3_mirr & ( subType = = 2 ? 0x03 : 0x01 ) )
2020-03-12 23:56:55 +08:00
{
2021-05-26 20:36:06 +02:00
case 0 : setmirror ( MI_V ) ; break ;
case 1 : setmirror ( MI_H ) ; break ;
case 2 : setmirror ( MI_0 ) ; break ;
case 3 : setmirror ( MI_1 ) ; break ;
2020-03-12 23:56:55 +08:00
}
2017-04-27 00:45:40 +08:00
}
2020-03-12 23:56:55 +08:00
static void Sync ( void )
{
SyncPRG ( ) ;
SyncCHR ( ) ;
SyncWRAM ( ) ;
SyncMIR ( ) ;
2017-04-27 00:45:40 +08:00
}
2020-10-20 21:12:32 +08:00
static DECLFW ( Write5000 )
2020-03-12 23:56:55 +08:00
{
2021-05-26 20:19:25 +02:00
if ( after_power & & A > 0x5010 & & A ! = 0x5FF3 ) /* Ignore writes from $5000-$500F, in particular to $5008, but not $5FF3 */
{
after_power = 0 ;
dipsw_enable = A > = 0x5020 ; /* The DIP switch change on soft-reset is enabled if the first write after power-on is not to $501x */
}
if ( FK23_ENABLED & & ( A & ( 0x10 < < dipswitch ) ) )
2020-03-12 23:56:55 +08:00
{
2021-05-26 20:19:25 +02:00
fk23_regs [ A & ( subType = = 3 ? 7 : 3 ) ] = V ;
2020-10-20 21:12:32 +08:00
SyncPRG ( ) ;
SyncCHR ( ) ;
2020-03-12 23:56:55 +08:00
}
else
/* FK23C Registers disabled, $5000-$5FFF maps to the second 4 KiB of the 8 KiB WRAM bank 2 */
CartBW ( A , V ) ;
2017-04-27 00:45:40 +08:00
}
2020-10-20 21:12:32 +08:00
static DECLFW ( Write8000 )
2020-03-12 23:56:55 +08:00
{
2021-05-26 20:19:25 +02:00
latch = V ;
if ( CHR_8K_MODE & & CHR_CNROM_MODE ) SyncCHR ( ) ; /* CNROM latch updated */
if ( PRG_MODE = = 5 ) SyncPRG ( ) ; /* UNROM latch has been updated */
switch ( A & 0xE001 )
2020-03-12 23:56:55 +08:00
{
2021-05-26 20:19:25 +02:00
case 0x8000 :
2020-03-12 23:56:55 +08:00
{
2021-05-26 20:19:25 +02:00
if ( A & 2 ) return ; /* Confirmed on real hardware: writes to 8002 and 8003, or 9FFE and 9FFF, are ignored. Needed for Dr. Mario on some of the "bouncing ball" multis. */
uint8 old_ctrl = mmc3_ctrl ;
/* Subtype 2, 8192 or more KiB PRG-ROM, no CHR-ROM: Like Subtype 0,
* but MMC3 registers $ 46 and $ 47 swapped . */
if ( subType = = 2 )
{
if ( V = = 0x46 )
V = 0x47 ;
else if ( V = = 0x47 )
V = 0x46 ;
}
mmc3_ctrl = V ;
if ( INVERT_PRG ! = ( old_ctrl & 0x40 ) )
SyncPRG ( ) ;
if ( INVERT_CHR ! = ( old_ctrl & 0x80 ) )
SyncCHR ( ) ;
break ;
2020-03-12 23:56:55 +08:00
}
2021-05-26 20:19:25 +02:00
case 0x8001 :
2020-03-12 23:56:55 +08:00
{
2021-05-26 20:19:25 +02:00
if ( A & 2 ) return ; /* Confirmed on real hardware: writes to 8002 and 8003, or 9FFE and 9FFF, are ignored. Needed for Dr. Mario on some of the "bouncing ball" multis. */
uint8 ctrl_mask = MMC3_EXTENDED ? 0x0F : 0x07 ;
if ( ( mmc3_ctrl & ctrl_mask ) < 12 )
{
mmc3_regs [ mmc3_ctrl & ctrl_mask ] = V ;
if ( ( ( mmc3_ctrl & ctrl_mask ) < 6 ) | | ( ( mmc3_ctrl & ctrl_mask ) > = 10 ) )
SyncCHR ( ) ;
else
SyncPRG ( ) ;
}
break ;
2020-03-12 23:56:55 +08:00
}
2021-05-26 20:19:25 +02:00
case 0xA000 :
mmc3_mirr = V ;
SyncMIR ( ) ;
break ;
case 0xA001 :
/* ignore bits when ram config register is disabled */
if ( ( V & 0x20 ) = = 0 )
V & = 0xC0 ;
mmc3_wram = V ;
Sync ( ) ;
break ;
case 0xC000 :
irq_latch = V ;
break ;
case 0xC001 :
irq_reload = 1 ;
break ;
case 0xE000 :
X6502_IRQEnd ( FCEU_IQEXT ) ;
irq_enabled = 0 ;
break ;
case 0xE001 :
irq_enabled = 1 ;
break ;
default :
break ;
2020-03-12 23:56:55 +08:00
}
2017-04-27 00:45:40 +08:00
}
2020-03-12 23:56:55 +08:00
static void IRQHook ( void )
{
if ( ! irq_count | | irq_reload )
irq_count = irq_latch ;
else
irq_count - - ;
2017-04-27 00:45:40 +08:00
2020-03-12 23:56:55 +08:00
if ( ! irq_count & & irq_enabled )
X6502_IRQBegin ( FCEU_IQEXT ) ;
2017-05-01 21:17:28 +08:00
2020-03-12 23:56:55 +08:00
irq_reload = 0 ;
}
2017-04-27 00:45:40 +08:00
2020-03-12 23:56:55 +08:00
static void Reset ( void )
{
/* this little hack makes sure that we try all the dip switch settings eventually, if we reset enough */
2020-10-19 09:17:45 +08:00
if ( dipsw_enable ) {
2020-03-12 23:56:55 +08:00
dipswitch = ( dipswitch + 1 ) & 7 ;
2020-10-19 09:17:45 +08:00
FCEU_printf ( " BMCFK23C dipswitch set to $%04x \n " , 0x5000 | 0x10 < < dipswitch ) ;
}
2020-03-12 23:56:55 +08:00
fk23_regs [ 0 ] = fk23_regs [ 1 ] = fk23_regs [ 2 ] = fk23_regs [ 3 ] = 0 ;
mmc3_regs [ 0 ] = 0 ;
mmc3_regs [ 1 ] = 2 ;
mmc3_regs [ 2 ] = 4 ;
mmc3_regs [ 3 ] = 5 ;
mmc3_regs [ 4 ] = 6 ;
mmc3_regs [ 5 ] = 7 ;
mmc3_regs [ 6 ] = 0 ;
mmc3_regs [ 7 ] = 1 ;
mmc3_regs [ 8 ] = ~ 1 ;
mmc3_regs [ 9 ] = ~ 0 ;
mmc3_regs [ 10 ] = ~ 0 ;
mmc3_regs [ 11 ] = ~ 0 ;
mmc3_wram = 0x80 ;
mmc3_ctrl = mmc3_mirr = irq_count = irq_latch = irq_enabled = 0 ;
Sync ( ) ;
2017-04-27 00:45:40 +08:00
}
2020-03-12 23:56:55 +08:00
static void Power ( void )
{
fk23_regs [ 0 ] = fk23_regs [ 1 ] = fk23_regs [ 2 ] = fk23_regs [ 3 ] = 0 ;
mmc3_regs [ 0 ] = 0 ;
mmc3_regs [ 1 ] = 2 ;
mmc3_regs [ 2 ] = 4 ;
mmc3_regs [ 3 ] = 5 ;
mmc3_regs [ 4 ] = 6 ;
mmc3_regs [ 5 ] = 7 ;
mmc3_regs [ 6 ] = 0 ;
mmc3_regs [ 7 ] = 1 ;
mmc3_regs [ 8 ] = ~ 1 ;
mmc3_regs [ 9 ] = ~ 0 ;
mmc3_regs [ 10 ] = ~ 0 ;
mmc3_regs [ 11 ] = ~ 0 ;
mmc3_wram = 0x80 ;
mmc3_ctrl = mmc3_mirr = irq_count = irq_latch = irq_enabled = 0 ;
Sync ( ) ;
SetReadHandler ( 0x8000 , 0xFFFF , CartBR ) ;
2021-05-26 20:19:25 +02:00
SetWriteHandler ( 0x5000 , 0x5FFF , Write5000 ) ;
2020-10-20 21:12:32 +08:00
SetWriteHandler ( 0x8000 , 0xFFFF , Write8000 ) ;
2020-03-12 23:56:55 +08:00
if ( WRAMSIZE )
{
SetReadHandler ( 0x6000 , 0x7FFF , CartBR ) ;
SetWriteHandler ( 0x6000 , 0x7FFF , CartBW ) ;
FCEU_CheatAddRAM ( WRAMSIZE > > 10 , 0x6000 , WRAM ) ;
}
}
2017-04-27 00:45:40 +08:00
2020-03-12 23:56:55 +08:00
static void Close ( void )
{
if ( WRAM )
FCEU_gfree ( WRAM ) ;
WRAM = NULL ;
2017-04-27 00:45:40 +08:00
2020-03-12 23:56:55 +08:00
if ( CHRRAM )
FCEU_gfree ( CHRRAM ) ;
CHRRAM = NULL ;
}
2017-04-27 00:45:40 +08:00
2020-03-19 09:18:02 +08:00
static void StateRestore ( int version )
2020-03-12 23:56:55 +08:00
{
Sync ( ) ;
}
2021-05-28 21:22:18 +02:00
void Init ( CartInfo * info )
2020-03-12 23:56:55 +08:00
{
2021-05-28 21:22:18 +02:00
/* Initialization for iNES and UNIF. subType and dipsw_enable must have been set. */
2020-03-19 21:58:59 +08:00
info - > Power = Power ;
info - > Reset = Reset ;
info - > Close = Close ;
GameHBIRQHook = IRQHook ;
GameStateRestore = StateRestore ;
2020-03-12 23:56:55 +08:00
AddExState ( StateRegs , ~ 0 , 0 , 0 ) ;
if ( CHRRAMSIZE )
{
CHRRAM = ( uint8 * ) FCEU_gmalloc ( CHRRAMSIZE ) ;
SetupCartCHRMapping ( 0x10 , CHRRAM , CHRRAMSIZE , 1 ) ;
AddExState ( CHRRAM , CHRRAMSIZE , 0 , " CRAM " ) ;
}
if ( WRAMSIZE )
{
WRAM = ( uint8 * ) FCEU_gmalloc ( WRAMSIZE ) ;
SetupCartPRGMapping ( 0x10 , WRAM , WRAMSIZE , 1 ) ;
AddExState ( WRAM , WRAMSIZE , 0 , " WRAM " ) ;
if ( info - > battery )
{
info - > SaveGame [ 0 ] = WRAM ;
2020-10-21 21:03:36 +08:00
if ( info - > iNES2 & & info - > PRGRamSaveSize )
2020-10-21 21:07:13 +08:00
info - > SaveGameLen [ 0 ] = info - > PRGRamSaveSize ;
2020-10-21 21:03:36 +08:00
else
info - > SaveGameLen [ 0 ] = WRAMSIZE ;
2020-03-12 23:56:55 +08:00
}
}
2020-03-19 21:58:59 +08:00
2020-03-12 23:56:55 +08:00
}
2017-04-27 00:45:40 +08:00
2021-05-28 21:22:18 +02:00
void Mapper176_Init ( CartInfo * info ) { /* .NES file */
dipsw_enable = 0 ;
jncota523 = 0 ;
2020-03-19 21:58:59 +08:00
if ( info - > iNES2 )
{
2021-05-28 21:22:18 +02:00
subType = info - > submapper ;
after_power = subType ! = 2 ; /* FS005 never has DIP switches, the others may have one, so use the heuristic. */
CHRRAMSIZE = info - > CHRRamSize + info - > CHRRamSaveSize ;
2020-03-19 21:58:59 +08:00
WRAMSIZE = info - > PRGRamSize + info - > PRGRamSaveSize ;
}
else
{
2021-05-28 21:22:18 +02:00
/* Waixing boards have 32K battery backed wram */
2020-03-19 21:58:59 +08:00
if ( info - > battery )
2021-05-28 21:22:18 +02:00
{
subType = 2 ;
after_power = 0 ;
2020-03-19 21:58:59 +08:00
WRAMSIZE = 32 * 1024 ;
2021-05-28 21:22:18 +02:00
}
2020-10-12 11:12:07 +08:00
else
2021-05-28 21:22:18 +02:00
{
/* Always enable WRAM for iNES-headered files */
2020-10-12 11:12:07 +08:00
WRAMSIZE = 8 * 1024 ;
2021-05-28 21:22:18 +02:00
/* Distinguishing subType 1 from subType 0 is important for the correct reset vector location.
It is safe to assume subType 1 except for 1024 + 512 KiB ROMs . */
subType = ( ROM_size = = 128 & & VROM_size = = 256 | | /* 2048+2048 */
ROM_size = = 128 & & VROM_size = = 128 | | /* 2048+1024 */
ROM_size = = 128 & & VROM_size = = 64 | | /* 2048+512 */
ROM_size = = 128 & & VROM_size = = 0 | | /* 2048+0 */
ROM_size = = 64 & & VROM_size = = 64 ) ? /* 1024+512 */
0 : 1 ;
/* Detect heuristically whether the address mask should be changed on every soft reset */
after_power = 1 ;
}
2020-03-19 21:58:59 +08:00
}
2021-05-28 21:22:18 +02:00
Init ( info ) ;
2020-03-19 21:58:59 +08:00
}
2021-05-28 21:22:18 +02:00
void BMCFK23C_Init ( CartInfo * info ) /* UNIF FK23C */
2020-03-12 23:56:55 +08:00
{
2020-03-19 21:58:59 +08:00
if ( ! UNIFchrrama )
2021-05-28 21:22:18 +02:00
{
/* Rockman I-VI uses mixed chr rom/ram */
if ( ( ROM_size * 16 ) = = 2048 & & ( VROM_size * 8 ) = = 512 )
CHRRAMSIZE = 8 * 1024 ;
}
2020-10-13 04:27:33 +08:00
WRAMSIZE = 8 * 1024 ;
2021-05-28 21:22:18 +02:00
/* UNIF FK23C differs from UNIF FK23CA explicitly by the absence of a DIP switch */
dipsw_enable = 0 ;
after_power = 0 ;
2021-05-26 20:36:06 +02:00
jncota523 = 0 ;
2021-05-28 21:22:18 +02:00
/* The UNIF MAPR tells us nothing about whether it is subtype 0 or 1 */
subType = ( ROM_size = = 128 & & VROM_size = = 256 | | /* 2048+2048 */
ROM_size = = 128 & & VROM_size = = 128 | | /* 2048+1024 */
ROM_size = = 128 & & VROM_size = = 64 | | /* 2048+512 */
ROM_size = = 128 & & VROM_size = = 0 | | /* 2048+0 */
ROM_size = = 64 & & VROM_size = = 64 ) ? /* 1024+512 */
0 : 1 ;
Init ( info ) ;
2017-04-27 00:45:40 +08:00
}
2020-03-19 21:58:59 +08:00
2021-05-28 21:22:18 +02:00
void BMCFK23CA_Init ( CartInfo * info ) /* UNIF FK23CA */
{
WRAMSIZE = 8 * 1024 ;
2020-03-19 21:58:59 +08:00
2021-05-28 21:22:18 +02:00
/* UNIF FK23CA differs from UNIF FK23C explicitly by the presence of a DIP switch */
dipsw_enable = 1 ;
after_power = 0 ;
2021-05-26 20:36:06 +02:00
jncota523 = 0 ;
2021-05-28 21:22:18 +02:00
/* The UNIF MAPR tells us nothing about whether it is subtype 0 or 1 */
subType = ( ROM_size = = 128 & & VROM_size = = 256 | | /* 2048+2048 */
ROM_size = = 128 & & VROM_size = = 128 | | /* 2048+1024 */
ROM_size = = 128 & & VROM_size = = 64 | | /* 2048+512 */
ROM_size = = 128 & & VROM_size = = 0 | | /* 2048+0 */
ROM_size = = 64 & & VROM_size = = 64 ) ? /* 1024+512 */
0 : 1 ;
Init ( info ) ;
2020-03-19 21:58:59 +08:00
}
2021-05-28 21:22:18 +02:00
void Super24_Init ( CartInfo * info ) /* UNIF BMC-Super24in1SC03 */
2020-03-19 21:58:59 +08:00
{
2021-05-28 21:22:18 +02:00
CHRRAMSIZE = 8 * 1024 ;
dipsw_enable = 0 ;
after_power = 0 ;
jncota523 = 0 ;
subType = 0 ;
Init ( info ) ;
}
2020-03-19 21:58:59 +08:00
2021-05-28 21:22:18 +02:00
void WAIXINGFS005_Init ( CartInfo * info ) /* UNIF WAIXING-FS005 */
{
CHRRAMSIZE = 8 * 1024 ;
2020-03-19 21:58:59 +08:00
WRAMSIZE = 32 * 1024 ;
2021-05-28 21:22:18 +02:00
dipsw_enable = 0 ;
after_power = 0 ;
2021-05-26 20:36:06 +02:00
jncota523 = 0 ;
2021-05-28 21:22:18 +02:00
subType = 2 ;
Init ( info ) ;
2021-05-26 20:36:06 +02:00
}
2021-05-28 21:22:18 +02:00
void Mapper523_Init ( CartInfo * info ) /* Jncota Fengshengban */
2021-05-26 20:36:06 +02:00
{
WRAMSIZE = 8 * 1024 ;
2021-05-28 21:22:18 +02:00
dipsw_enable = 0 ;
after_power = 0 ;
jncota523 = 1 ;
subType = 1 ;
Init ( info ) ;
2020-03-19 21:58:59 +08:00
}