2009-07-17 19:27:04 +02:00
/* 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
2012-12-14 18:18:20 +01:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2009-07-17 19:27:04 +02:00
*/
/* None of this code should use any of the iNES bank switching wrappers. */
# include "mapinc.h"
2018-08-13 17:04:20 +02:00
# define ABANKS MMC5SPRVPage
# define BBANKS MMC5BGVPage
# define SpriteON (PPU[1] & 0x10) //Show Sprite
# define ScreenON (PPU[1] & 0x08) //Show screen
# define PPUON (PPU[1] & 0x18) //PPU should operate
# define Sprite16 (PPU[0] & 0x20) //Sprites 8x16/8x8
2009-07-17 19:27:04 +02:00
static void ( * sfun ) ( int P ) ;
static void ( * psfun ) ( void ) ;
void MMC5RunSound ( int Count ) ;
void MMC5RunSoundHQ ( void ) ;
2012-12-14 18:43:51 +01:00
static INLINE void MMC5SPRVROM_BANK1 ( uint32 A , uint32 V ) {
if ( CHRptr [ 0 ] ) {
V & = CHRmask1 [ 0 ] ;
MMC5SPRVPage [ ( A ) > > 10 ] = & CHRptr [ 0 ] [ ( V ) < < 10 ] - ( A ) ;
}
2009-07-17 19:27:04 +02:00
}
2012-12-14 18:43:51 +01:00
static INLINE void MMC5BGVROM_BANK1 ( uint32 A , uint32 V ) {
if ( CHRptr [ 0 ] ) {
V & = CHRmask1 [ 0 ] ; MMC5BGVPage [ ( A ) > > 10 ] = & CHRptr [ 0 ] [ ( V ) < < 10 ] - ( A ) ;
}
}
2009-07-17 19:27:04 +02:00
2012-12-14 18:43:51 +01:00
static INLINE void MMC5SPRVROM_BANK2 ( uint32 A , uint32 V ) {
if ( CHRptr [ 0 ] ) {
V & = CHRmask2 [ 0 ] ; MMC5SPRVPage [ ( A ) > > 10 ] = MMC5SPRVPage [ ( ( A ) > > 10 ) + 1 ] = & CHRptr [ 0 ] [ ( V ) < < 11 ] - ( A ) ;
}
}
static INLINE void MMC5BGVROM_BANK2 ( uint32 A , uint32 V ) {
if ( CHRptr [ 0 ] ) {
V & = CHRmask2 [ 0 ] ; MMC5BGVPage [ ( A ) > > 10 ] = MMC5BGVPage [ ( ( A ) > > 10 ) + 1 ] = & CHRptr [ 0 ] [ ( V ) < < 11 ] - ( A ) ;
}
}
2009-07-17 19:27:04 +02:00
2012-12-14 18:43:51 +01:00
static INLINE void MMC5SPRVROM_BANK4 ( uint32 A , uint32 V ) {
if ( CHRptr [ 0 ] ) {
V & = CHRmask4 [ 0 ] ; MMC5SPRVPage [ ( A ) > > 10 ] = MMC5SPRVPage [ ( ( A ) > > 10 ) + 1 ] = MMC5SPRVPage [ ( ( A ) > > 10 ) + 2 ] = MMC5SPRVPage [ ( ( A ) > > 10 ) + 3 ] = & CHRptr [ 0 ] [ ( V ) < < 12 ] - ( A ) ;
}
}
static INLINE void MMC5BGVROM_BANK4 ( uint32 A , uint32 V ) {
if ( CHRptr [ 0 ] ) {
V & = CHRmask4 [ 0 ] ; MMC5BGVPage [ ( A ) > > 10 ] = MMC5BGVPage [ ( ( A ) > > 10 ) + 1 ] = MMC5BGVPage [ ( ( A ) > > 10 ) + 2 ] = MMC5BGVPage [ ( ( A ) > > 10 ) + 3 ] = & CHRptr [ 0 ] [ ( V ) < < 12 ] - ( A ) ;
}
}
2009-07-17 19:27:04 +02:00
2012-12-14 18:43:51 +01:00
static INLINE void MMC5SPRVROM_BANK8 ( uint32 V ) {
if ( CHRptr [ 0 ] ) {
V & = CHRmask8 [ 0 ] ; MMC5SPRVPage [ 0 ] = MMC5SPRVPage [ 1 ] = MMC5SPRVPage [ 2 ] = MMC5SPRVPage [ 3 ] = MMC5SPRVPage [ 4 ] = MMC5SPRVPage [ 5 ] = MMC5SPRVPage [ 6 ] = MMC5SPRVPage [ 7 ] = & CHRptr [ 0 ] [ ( V ) < < 13 ] ;
}
}
static INLINE void MMC5BGVROM_BANK8 ( uint32 V ) {
if ( CHRptr [ 0 ] ) {
V & = CHRmask8 [ 0 ] ; MMC5BGVPage [ 0 ] = MMC5BGVPage [ 1 ] = MMC5BGVPage [ 2 ] = MMC5BGVPage [ 3 ] = MMC5BGVPage [ 4 ] = MMC5BGVPage [ 5 ] = MMC5BGVPage [ 6 ] = MMC5BGVPage [ 7 ] = & CHRptr [ 0 ] [ ( V ) < < 13 ] ;
}
}
2009-07-17 19:27:04 +02:00
static uint8 PRGBanks [ 4 ] ;
static uint8 WRAMPage ;
2009-07-18 00:54:58 +02:00
static uint16 CHRBanksA [ 8 ] , CHRBanksB [ 4 ] ;
2009-07-17 19:27:04 +02:00
static uint8 WRAMMaskEnable [ 2 ] ;
uint8 mmc5ABMode ; /* A=0, B=1 */
2012-12-14 18:43:51 +01:00
static uint8 IRQScanline , IRQEnable ;
2009-07-17 19:27:04 +02:00
static uint8 CHRMode , NTAMirroring , NTFill , ATFill ;
static uint8 MMC5IRQR ;
static uint8 MMC5LineCounter ;
static uint8 mmc5psize , mmc5vsize ;
static uint8 mul [ 2 ] ;
2016-09-18 05:43:24 +02:00
static uint32 WRAMSIZE = 0 ;
2012-12-14 18:43:51 +01:00
static uint8 * WRAM = NULL ;
static uint8 * MMC5fill = NULL ;
static uint8 * ExRAM = NULL ;
2009-07-17 19:27:04 +02:00
2016-09-18 05:43:24 +02:00
static uint8 MMC5WRAMsize ; //configuration, not state
static uint8 MMC5WRAMIndex [ 8 ] ; //configuration, not state
2009-07-17 19:27:04 +02:00
static uint8 MMC5ROMWrProtect [ 4 ] ;
static uint8 MMC5MemIn [ 5 ] ;
static void MMC5CHRA ( void ) ;
static void MMC5CHRB ( void ) ;
typedef struct __cartdata {
2012-12-14 18:43:51 +01:00
uint32 crc32 ;
uint8 size ;
2009-07-17 19:27:04 +02:00
} cartdata ;
2018-08-13 17:04:20 +02:00
# define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V) >> 10][(V)]
uint8 * MMC5BGVRAMADR ( uint32 A )
{
if ( newppu )
{
if ( Sprite16 )
{
bool isPattern = PPUON ! = 0 ;
if ( ppuphase = = PPUPHASE_OBJ & & isPattern )
return & ABANKS [ ( A ) > > 10 ] [ ( A ) ] ;
if ( ppuphase = = PPUPHASE_BG & & isPattern )
return & BBANKS [ ( A ) > > 10 ] [ ( A ) ] ;
else if ( mmc5ABMode = = 0 )
return & ABANKS [ ( A ) > > 10 ] [ ( A ) ] ;
else
return & BBANKS [ ( A ) > > 10 ] [ ( A ) ] ;
}
else return & ABANKS [ ( A ) > > 10 ] [ ( A ) ] ; ;
}
2012-12-14 18:43:51 +01:00
if ( ! Sprite16 ) {
if ( mmc5ABMode = = 0 )
2018-08-13 17:04:20 +02:00
return & ABANKS [ ( A ) > > 10 ] [ ( A ) ] ;
2012-12-14 18:18:20 +01:00
else
2018-08-13 17:04:20 +02:00
return & BBANKS [ ( A ) > > 10 ] [ ( A ) ] ;
} else return & BBANKS [ ( A ) > > 10 ] [ ( A ) ] ;
2009-07-17 19:27:04 +02:00
}
static void mmc5_PPUWrite ( uint32 A , uint8 V ) {
uint32 tmp = A ;
extern uint8 PALRAM [ 0x20 ] ;
2012-12-14 18:43:51 +01:00
if ( tmp > = 0x3F00 ) {
// hmmm....
if ( ! ( tmp & 0xf ) )
PALRAM [ 0x00 ] = PALRAM [ 0x04 ] = PALRAM [ 0x08 ] = PALRAM [ 0x0C ] = V & 0x3F ;
else if ( tmp & 3 ) PALRAM [ ( tmp & 0x1f ) ] = V & 0x3f ;
} else if ( tmp < 0x2000 ) {
if ( PPUCHRRAM & ( 1 < < ( tmp > > 10 ) ) )
VPage [ tmp > > 10 ] [ tmp ] = V ;
} else {
if ( PPUNTARAM & ( 1 < < ( ( tmp & 0xF00 ) > > 10 ) ) )
vnapage [ ( ( tmp & 0xF00 ) > > 10 ) ] [ tmp & 0x3FF ] = V ;
}
2009-07-17 19:27:04 +02:00
}
2018-08-13 17:04:20 +02:00
extern uint32 NTRefreshAddr ;
uint8 FASTCALL mmc5_PPURead ( uint32 A )
{
bool split = false ;
if ( newppu )
{
if ( ( MMC5HackSPMode & 0x80 ) & & ! ( MMC5HackCHRMode & 2 ) )
{
int target = MMC5HackSPMode & 0x1f ;
int side = MMC5HackSPMode & 0x40 ;
int ht = NTRefreshAddr & 31 ;
if ( side = = 0 )
{
if ( ht < target ) split = true ;
}
else
{
if ( ht > = target ) split = true ;
}
}
}
if ( A < 0x2000 )
{
if ( Sprite16 )
{
bool isPattern = ! ! PPUON ;
if ( ppuphase = = PPUPHASE_OBJ & & isPattern )
return ABANKS [ ( A ) > > 10 ] [ ( A ) ] ;
if ( ppuphase = = PPUPHASE_BG & & isPattern )
{
if ( split )
return MMC5HackVROMPTR [ MMC5HackSPPage * 0x1000 + ( A & 0xFFF ) ] ;
//uhhh call through to this more sophisticated function, only if it's really needed?
//we should probably reuse it completely, if we can
if ( MMC5HackCHRMode = = 1 )
return * FCEUPPU_GetCHR ( A , NTRefreshAddr ) ;
return BBANKS [ ( A ) > > 10 ] [ ( A ) ] ;
}
else if ( mmc5ABMode = = 0 )
return ABANKS [ ( A ) > > 10 ] [ ( A ) ] ;
else
return BBANKS [ ( A ) > > 10 ] [ ( A ) ] ;
}
else
{
if ( ppuphase = = PPUPHASE_BG & & ScreenON )
{
if ( split )
return MMC5HackVROMPTR [ MMC5HackSPPage * 0x1000 + ( A & 0xFFF ) ] ;
//uhhh call through to this more sophisticated function, only if it's really needed?
//we should probably reuse it completely, if we can
if ( MMC5HackCHRMode = = 1 )
return * FCEUPPU_GetCHR ( A , NTRefreshAddr ) ;
}
return ABANKS [ ( A ) > > 10 ] [ ( A ) ] ;
}
}
else
{
if ( split )
{
static const int kHack = - 1 ; //dunno if theres science to this or if it just fixes SDF (cant be bothered to think about it)
int linetile = ( newppu_get_scanline ( ) + kHack ) / 8 + MMC5HackSPScroll ;
//REF NT: return 0x2000 | (v << 0xB) | (h << 0xA) | (vt << 5) | ht;
//REF AT: return 0x2000 | (v << 0xB) | (h << 0xA) | 0x3C0 | ((vt & 0x1C) << 1) | ((ht & 0x1C) >> 2);
if ( ( A & 0x3FF ) > = 0x3C0 )
{
A & = ~ ( 0x1C < < 1 ) ; //mask off VT
A | = ( linetile & 0x1C ) < < 1 ; //mask on adjusted VT
return ExRAM [ A & 0x3FF ] ;
}
else
{
A & = ~ ( ( 0x1F < < 5 ) | ( 1 < < 0xB ) ) ; //mask off VT and V
A | = ( linetile & 31 ) < < 5 ; //mask on adjusted VT (V doesnt make any sense, I think)
return ExRAM [ A & 0x3FF ] ;
}
}
if ( MMC5HackCHRMode = = 1 )
{
if ( ( A & 0x3FF ) > = 0x3C0 )
{
uint8 byte = ExRAM [ NTRefreshAddr & 0x3ff ] ;
//get attribute part and paste it 4x across the byte
byte > > = 6 ;
byte * = 0x55 ;
return byte ;
}
}
2012-12-14 18:43:51 +01:00
return vnapage [ ( A > > 10 ) & 0x3 ] [ A & 0x3FF ] ;
2009-07-17 19:27:04 +02:00
}
}
2012-12-14 18:43:51 +01:00
cartdata MMC5CartList [ ] =
{
2016-09-18 05:43:24 +02:00
{ 0x6f4e4312 , 4 } , /* Aoki Ookami to Shiroki Mejika - Genchou Hishi */
{ 0x15fe6d0f , 2 } , /* Bandit Kings of Ancient China */
{ 0x671f23a8 , 0 } , /* Castlevania III - Dracula's Curse (E) */
{ 0xcd4e7430 , 0 } , /* Castlevania III - Dracula's Curse (KC) */
{ 0xed2465be , 0 } , /* Castlevania III - Dracula's Curse (U) */
{ 0xfe3488d1 , 2 } , /* Daikoukai Jidai */
{ 0x0ec6c023 , 1 } , /* Gemfire */
{ 0x0afb395e , 0 } , /* Gun Sight */
2012-12-14 18:43:51 +01:00
{ 0x1ced086f , 2 } , /* Ishin no Arashi */
2016-09-18 05:43:24 +02:00
{ 0x9cbadc25 , 1 } , /* Just Breed */
{ 0x6396b988 , 2 } , /* L'Empereur (J) */
{ 0x9c18762b , 2 } , /* L'Empereur (U) */
{ 0xb0480ae9 , 0 } , /* Laser Invasion */
{ 0xb4735fac , 0 } , /* Metal Slader Glory */
{ 0xf540677b , 4 } , /* Nobunaga no Yabou - Bushou Fuuun Roku */
{ 0xeee9a682 , 2 } , /* Nobunaga no Yabou - Sengoku Gunyuu Den (J) (PRG0) */
{ 0xf9b4240f , 2 } , /* Nobunaga no Yabou - Sengoku Gunyuu Den (J) (PRG1) */
{ 0x8ce478db , 2 } , /* Nobunaga's Ambition 2 */
{ 0xf011e490 , 4 } , /* Romance of The Three Kingdoms II */
{ 0xbc80fb52 , 1 } , /* Royal Blood */
{ 0x184c2124 , 4 } , /* Sangokushi II (J) (PRG0) */
{ 0xee8e6553 , 4 } , /* Sangokushi II (J) (PRG1) */
{ 0xd532e98f , 1 } , /* Shin 4 Nin Uchi Mahjong - Yakuman Tengoku */
{ 0x39f2ce4b , 2 } , /* Suikoden - Tenmei no Chikai */
{ 0xbb7f829a , 0 } , /* Uchuu Keibitai SDF */
{ 0xaca15643 , 2 } , /* Uncharted Waters */
2009-07-17 19:27:04 +02:00
} ;
2016-09-18 05:43:24 +02:00
# define MMC5_NOCARTS (sizeof(MMC5CartList) / sizeof(MMC5CartList[0]))
2012-12-14 18:43:51 +01:00
int DetectMMC5WRAMSize ( uint32 crc32 ) {
2009-07-17 19:27:04 +02:00
int x ;
2012-12-14 18:43:51 +01:00
for ( x = 0 ; x < MMC5_NOCARTS ; x + + ) {
if ( crc32 = = MMC5CartList [ x ] . crc32 ) {
2016-09-18 05:43:24 +02:00
if ( MMC5CartList [ x ] . size > 1 )
FCEU_printf ( " >8KB external WRAM present. Use UNIF if you hack the ROM image. \n " ) ;
2012-12-14 18:43:51 +01:00
return ( MMC5CartList [ x ] . size * 8 ) ;
2009-07-17 19:27:04 +02:00
}
}
return 64 ;
}
2012-12-14 18:43:51 +01:00
static void BuildWRAMSizeTable ( void ) {
2009-07-17 19:27:04 +02:00
int x ;
2012-12-14 18:43:51 +01:00
for ( x = 0 ; x < 8 ; x + + ) {
switch ( MMC5WRAMsize ) {
2016-09-18 05:43:24 +02:00
case 0 : MMC5WRAMIndex [ x ] = 255 ; break ; //X,X,X,X,X,X,X,X
case 1 : MMC5WRAMIndex [ x ] = ( x > 3 ) ? 255 : 0 ; break ; //0,0,0,0,X,X,X,X
case 2 : MMC5WRAMIndex [ x ] = ( x & 4 ) > > 2 ; break ; //0,0,0,0,1,1,1,1
case 4 : MMC5WRAMIndex [ x ] = ( x > 3 ) ? 255 : ( x & 3 ) ; break ; //0,1,2,3,X,X,X,X
case 8 : MMC5WRAMIndex [ x ] = x ; break ; //0,1,2,3,4,5,6,7
2009-07-17 19:27:04 +02:00
}
}
}
2012-12-14 18:43:51 +01:00
static void MMC5CHRA ( void ) {
int x ;
switch ( mmc5vsize & 3 ) {
case 0 :
setchr8 ( CHRBanksA [ 7 ] ) ;
MMC5SPRVROM_BANK8 ( CHRBanksA [ 7 ] ) ;
break ;
case 1 :
setchr4 ( 0x0000 , CHRBanksA [ 3 ] ) ;
setchr4 ( 0x1000 , CHRBanksA [ 7 ] ) ;
MMC5SPRVROM_BANK4 ( 0x0000 , CHRBanksA [ 3 ] ) ;
MMC5SPRVROM_BANK4 ( 0x1000 , CHRBanksA [ 7 ] ) ;
break ;
case 2 :
setchr2 ( 0x0000 , CHRBanksA [ 1 ] ) ;
setchr2 ( 0x0800 , CHRBanksA [ 3 ] ) ;
setchr2 ( 0x1000 , CHRBanksA [ 5 ] ) ;
setchr2 ( 0x1800 , CHRBanksA [ 7 ] ) ;
MMC5SPRVROM_BANK2 ( 0x0000 , CHRBanksA [ 1 ] ) ;
MMC5SPRVROM_BANK2 ( 0x0800 , CHRBanksA [ 3 ] ) ;
MMC5SPRVROM_BANK2 ( 0x1000 , CHRBanksA [ 5 ] ) ;
MMC5SPRVROM_BANK2 ( 0x1800 , CHRBanksA [ 7 ] ) ;
break ;
case 3 :
for ( x = 0 ; x < 8 ; x + + ) {
setchr1 ( x < < 10 , CHRBanksA [ x ] ) ;
MMC5SPRVROM_BANK1 ( x < < 10 , CHRBanksA [ x ] ) ;
}
break ;
}
2009-07-17 19:27:04 +02:00
}
2012-12-14 18:43:51 +01:00
static void MMC5CHRB ( void ) {
int x ;
switch ( mmc5vsize & 3 ) {
case 0 :
setchr8 ( CHRBanksB [ 3 ] ) ;
MMC5BGVROM_BANK8 ( CHRBanksB [ 3 ] ) ;
break ;
case 1 :
setchr4 ( 0x0000 , CHRBanksB [ 3 ] ) ;
setchr4 ( 0x1000 , CHRBanksB [ 3 ] ) ;
MMC5BGVROM_BANK4 ( 0x0000 , CHRBanksB [ 3 ] ) ;
MMC5BGVROM_BANK4 ( 0x1000 , CHRBanksB [ 3 ] ) ;
break ;
case 2 :
setchr2 ( 0x0000 , CHRBanksB [ 1 ] ) ;
setchr2 ( 0x0800 , CHRBanksB [ 3 ] ) ;
setchr2 ( 0x1000 , CHRBanksB [ 1 ] ) ;
setchr2 ( 0x1800 , CHRBanksB [ 3 ] ) ;
MMC5BGVROM_BANK2 ( 0x0000 , CHRBanksB [ 1 ] ) ;
MMC5BGVROM_BANK2 ( 0x0800 , CHRBanksB [ 3 ] ) ;
MMC5BGVROM_BANK2 ( 0x1000 , CHRBanksB [ 1 ] ) ;
MMC5BGVROM_BANK2 ( 0x1800 , CHRBanksB [ 3 ] ) ;
break ;
case 3 :
for ( x = 0 ; x < 8 ; x + + ) {
setchr1 ( x < < 10 , CHRBanksB [ x & 3 ] ) ;
MMC5BGVROM_BANK1 ( x < < 10 , CHRBanksB [ x & 3 ] ) ;
}
break ;
}
2009-07-17 19:27:04 +02:00
}
2012-12-14 18:43:51 +01:00
static void MMC5WRAM ( uint32 A , uint32 V ) {
V = MMC5WRAMIndex [ V & 7 ] ;
if ( V ! = 255 ) {
setprg8r ( 0x10 , A , V ) ;
2016-09-18 05:43:24 +02:00
FCEU_CheatAddRAM ( 8 , 0x6000 , ( WRAM + ( ( V * 8192 ) & ( WRAMSIZE - 1 ) ) ) ) ;
2012-12-14 18:43:51 +01:00
MMC5MemIn [ ( A - 0x6000 ) > > 13 ] = 1 ;
} else
MMC5MemIn [ ( A - 0x6000 ) > > 13 ] = 0 ;
2009-07-17 19:27:04 +02:00
}
2012-12-14 18:43:51 +01:00
static void MMC5PRG ( void ) {
int x ;
switch ( mmc5psize & 3 ) {
case 0 :
MMC5ROMWrProtect [ 0 ] = MMC5ROMWrProtect [ 1 ] = MMC5ROMWrProtect [ 2 ] = MMC5ROMWrProtect [ 3 ] = 1 ;
setprg32 ( 0x8000 , ( ( PRGBanks [ 1 ] & 0x7F ) > > 2 ) ) ;
for ( x = 0 ; x < 4 ; x + + )
MMC5MemIn [ 1 + x ] = 1 ;
break ;
case 1 :
if ( PRGBanks [ 1 ] & 0x80 ) {
MMC5ROMWrProtect [ 0 ] = MMC5ROMWrProtect [ 1 ] = 1 ;
setprg16 ( 0x8000 , ( PRGBanks [ 1 ] > > 1 ) ) ;
MMC5MemIn [ 1 ] = MMC5MemIn [ 2 ] = 1 ;
} else {
MMC5ROMWrProtect [ 0 ] = MMC5ROMWrProtect [ 1 ] = 0 ;
MMC5WRAM ( 0x8000 , PRGBanks [ 1 ] & 7 & 0xFE ) ;
MMC5WRAM ( 0xA000 , ( PRGBanks [ 1 ] & 7 & 0xFE ) + 1 ) ;
}
MMC5MemIn [ 3 ] = MMC5MemIn [ 4 ] = 1 ;
MMC5ROMWrProtect [ 2 ] = MMC5ROMWrProtect [ 3 ] = 1 ;
setprg16 ( 0xC000 , ( PRGBanks [ 3 ] & 0x7F ) > > 1 ) ;
break ;
case 2 :
if ( PRGBanks [ 1 ] & 0x80 ) {
MMC5MemIn [ 1 ] = MMC5MemIn [ 2 ] = 1 ;
MMC5ROMWrProtect [ 0 ] = MMC5ROMWrProtect [ 1 ] = 1 ;
setprg16 ( 0x8000 , ( PRGBanks [ 1 ] & 0x7F ) > > 1 ) ;
} else {
MMC5ROMWrProtect [ 0 ] = MMC5ROMWrProtect [ 1 ] = 0 ;
MMC5WRAM ( 0x8000 , PRGBanks [ 1 ] & 7 & 0xFE ) ;
MMC5WRAM ( 0xA000 , ( PRGBanks [ 1 ] & 7 & 0xFE ) + 1 ) ;
}
if ( PRGBanks [ 2 ] & 0x80 ) {
MMC5ROMWrProtect [ 2 ] = 1 ;
MMC5MemIn [ 3 ] = 1 ;
setprg8 ( 0xC000 , PRGBanks [ 2 ] & 0x7F ) ;
} else {
MMC5ROMWrProtect [ 2 ] = 0 ;
MMC5WRAM ( 0xC000 , PRGBanks [ 2 ] & 7 ) ;
}
MMC5MemIn [ 4 ] = 1 ;
MMC5ROMWrProtect [ 3 ] = 1 ;
setprg8 ( 0xE000 , PRGBanks [ 3 ] & 0x7F ) ;
break ;
case 3 :
for ( x = 0 ; x < 3 ; x + + )
if ( PRGBanks [ x ] & 0x80 ) {
MMC5ROMWrProtect [ x ] = 1 ;
setprg8 ( 0x8000 + ( x < < 13 ) , PRGBanks [ x ] & 0x7F ) ;
MMC5MemIn [ 1 + x ] = 1 ;
} else {
MMC5ROMWrProtect [ x ] = 0 ;
MMC5WRAM ( 0x8000 + ( x < < 13 ) , PRGBanks [ x ] & 7 ) ;
}
MMC5MemIn [ 4 ] = 1 ;
MMC5ROMWrProtect [ 3 ] = 1 ;
setprg8 ( 0xE000 , PRGBanks [ 3 ] & 0x7F ) ;
break ;
}
2009-07-17 19:27:04 +02:00
}
2012-12-14 18:43:51 +01:00
static DECLFW ( Mapper5_write ) {
2016-09-18 05:43:24 +02:00
switch ( A ) {
case 0x5100 :
mmc5psize = V ;
MMC5PRG ( ) ;
break ;
case 0x5101 :
mmc5vsize = V ;
if ( ! mmc5ABMode ) {
MMC5CHRB ( ) ;
MMC5CHRA ( ) ;
} else {
MMC5CHRA ( ) ;
MMC5CHRB ( ) ;
}
break ;
case 0x5102 :
WRAMMaskEnable [ 0 ] = V ;
break ;
case 0x5103 :
WRAMMaskEnable [ 1 ] = V ;
break ;
case 0x5104 :
CHRMode = V ;
MMC5HackCHRMode = V & 3 ;
break ;
2012-12-14 18:43:51 +01:00
case 0x5105 :
{
int x ;
for ( x = 0 ; x < 4 ; x + + ) {
switch ( ( V > > ( x < < 1 ) ) & 3 ) {
case 0 : PPUNTARAM | = 1 < < x ; vnapage [ x ] = NTARAM ; break ;
case 1 : PPUNTARAM | = 1 < < x ; vnapage [ x ] = NTARAM + 0x400 ; break ;
case 2 : PPUNTARAM | = 1 < < x ; vnapage [ x ] = ExRAM ; break ;
case 3 : PPUNTARAM & = ~ ( 1 < < x ) ; vnapage [ x ] = MMC5fill ; break ;
}
}
NTAMirroring = V ;
break ;
}
2016-09-18 05:43:24 +02:00
case 0x5106 :
if ( V ! = NTFill )
FCEU_dwmemset ( MMC5fill , ( V | ( V < < 8 ) | ( V < < 16 ) | ( V < < 24 ) ) , 0x3c0 ) ;
NTFill = V ;
break ;
case 0x5107 :
if ( V ! = ATFill ) {
unsigned char moop = V | ( V < < 2 ) | ( V < < 4 ) | ( V < < 6 ) ;
FCEU_dwmemset ( MMC5fill + 0x3c0 , moop | ( moop < < 8 ) | ( moop < < 16 ) | ( moop < < 24 ) , 0x40 ) ;
2012-12-14 18:43:51 +01:00
}
2016-09-18 05:43:24 +02:00
ATFill = V ;
break ;
case 0x5113 :
WRAMPage = V ;
MMC5WRAM ( 0x6000 , V & 7 ) ;
2012-12-14 18:43:51 +01:00
break ;
case 0x5114 :
case 0x5115 :
case 0x5116 :
2016-09-18 05:43:24 +02:00
case 0x5117 :
PRGBanks [ A & 3 ] = V ;
MMC5PRG ( ) ;
break ;
case 0x5120 :
case 0x5121 :
case 0x5122 :
case 0x5123 :
case 0x5124 :
case 0x5125 :
case 0x5126 :
case 0x5127 :
mmc5ABMode = 0 ;
CHRBanksA [ A & 7 ] = V | ( ( MMC50x5130 & 0x3 ) < < 8 ) ;
MMC5CHRA ( ) ;
break ;
2012-12-14 18:43:51 +01:00
case 0x5128 :
case 0x5129 :
case 0x512a :
case 0x512b :
mmc5ABMode = 1 ;
2016-09-18 05:43:24 +02:00
CHRBanksB [ A & 3 ] = V | ( ( MMC50x5130 & 0x3 ) < < 8 ) ;
2012-12-14 18:43:51 +01:00
MMC5CHRB ( ) ;
break ;
case 0x5130 : MMC50x5130 = V ; break ;
case 0x5200 : MMC5HackSPMode = V ; break ;
case 0x5201 : MMC5HackSPScroll = ( V > > 3 ) & 0x1F ; break ;
case 0x5202 : MMC5HackSPPage = V & 0x3F ; break ;
case 0x5203 : X6502_IRQEnd ( FCEU_IQEXT ) ; IRQScanline = V ; break ;
case 0x5204 : X6502_IRQEnd ( FCEU_IQEXT ) ; IRQEnable = V & 0x80 ; break ;
case 0x5205 : mul [ 0 ] = V ; break ;
case 0x5206 : mul [ 1 ] = V ; break ;
}
}
static DECLFR ( MMC5_ReadROMRAM ) {
if ( MMC5MemIn [ ( A - 0x6000 ) > > 13 ] )
return Page [ A > > 11 ] [ A ] ;
else
return X . DB ;
}
static DECLFW ( MMC5_WriteROMRAM ) {
2016-09-18 05:43:24 +02:00
if ( ( A > = 0x8000 ) & & ( MMC5ROMWrProtect [ ( A - 0x8000 ) > > 13 ] ) )
return ;
2012-12-14 18:43:51 +01:00
if ( MMC5MemIn [ ( A - 0x6000 ) > > 13 ] )
2016-09-18 05:43:24 +02:00
if ( ( ( WRAMMaskEnable [ 0 ] & 3 ) | ( ( WRAMMaskEnable [ 1 ] & 3 ) < < 2 ) ) = = 6 )
Page [ A > > 11 ] [ A ] = V ;
2012-12-14 18:43:51 +01:00
}
static DECLFW ( MMC5_ExRAMWr ) {
if ( MMC5HackCHRMode ! = 3 )
ExRAM [ A & 0x3ff ] = V ;
}
static DECLFR ( MMC5_ExRAMRd ) {
2016-09-18 05:43:24 +02:00
return ExRAM [ A & 0x3ff ] ;
2012-12-14 18:43:51 +01:00
}
static DECLFR ( MMC5_read ) {
switch ( A ) {
2016-09-18 05:43:24 +02:00
case 0x5204 : {
2012-12-14 18:43:51 +01:00
uint8 x ;
X6502_IRQEnd ( FCEU_IQEXT ) ;
x = MMC5IRQR ;
# ifdef FCEUDEF_DEBUGGER
if ( ! fceuindbg )
# endif
MMC5IRQR & = 0x40 ;
return x ;
}
2016-09-18 05:43:24 +02:00
case 0x5205 :
return ( mul [ 0 ] * mul [ 1 ] ) ;
case 0x5206 :
return ( ( mul [ 0 ] * mul [ 1 ] ) > > 8 ) ;
2012-12-14 18:43:51 +01:00
}
return ( X . DB ) ;
}
void MMC5Synco ( void ) {
int x ;
MMC5PRG ( ) ;
for ( x = 0 ; x < 4 ; x + + ) {
switch ( ( NTAMirroring > > ( x < < 1 ) ) & 3 ) {
case 0 : PPUNTARAM | = 1 < < x ; vnapage [ x ] = NTARAM ; break ;
case 1 : PPUNTARAM | = 1 < < x ; vnapage [ x ] = NTARAM + 0x400 ; break ;
case 2 : PPUNTARAM | = 1 < < x ; vnapage [ x ] = ExRAM ; break ;
case 3 : PPUNTARAM & = ~ ( 1 < < x ) ; vnapage [ x ] = MMC5fill ; break ;
}
}
MMC5WRAM ( 0x6000 , WRAMPage & 7 ) ;
if ( ! mmc5ABMode ) {
MMC5CHRB ( ) ;
MMC5CHRA ( ) ;
} else {
MMC5CHRA ( ) ;
MMC5CHRB ( ) ;
}
2016-09-18 05:43:24 +02:00
//in case the fill register changed, we need to overwrite the fill buffer
FCEU_dwmemset ( MMC5fill , NTFill | ( NTFill < < 8 ) | ( NTFill < < 16 ) | ( NTFill < < 24 ) , 0x3c0 ) ;
2012-12-14 18:43:51 +01:00
{
2016-09-18 05:43:24 +02:00
unsigned char moop = ATFill | ( ATFill < < 2 ) | ( ATFill < < 4 ) | ( ATFill < < 6 ) ;
FCEU_dwmemset ( MMC5fill + 0x3c0 , moop | ( moop < < 8 ) | ( moop < < 16 ) | ( moop < < 24 ) , 0x40 ) ;
2012-12-14 18:43:51 +01:00
}
2016-09-18 05:43:24 +02:00
2012-12-14 18:43:51 +01:00
MMC5HackCHRMode = CHRMode & 3 ;
2016-09-18 05:43:24 +02:00
//zero 17-apr-2013 - why the heck should this happen here? anything in a `synco` should be depending on the state.
//im going to leave it commented out to see what happens
//X6502_IRQEnd(FCEU_IQEXT);
2012-12-14 18:43:51 +01:00
}
void MMC5_hb ( int scanline ) {
2016-09-18 05:43:24 +02:00
//zero 24-jul-2014 - revised for newer understanding, to fix metal slader glory credits. see r7371 in bizhawk
int sl = scanline + 1 ;
int ppuon = ( PPU [ 1 ] & 0x18 ) ;
if ( ! ppuon | | sl > = 241 )
{
// whenever rendering is off for any reason (vblank or forced disable
// the irq counter resets, as well as the inframe flag (easily verifiable from software)
MMC5IRQR & = ~ 0x40 ;
MMC5IRQR & = ~ 0x80 ;
2012-12-14 18:43:51 +01:00
MMC5LineCounter = 0 ;
2016-09-18 05:43:24 +02:00
X6502_IRQEnd ( FCEU_IQEXT ) ;
2012-12-14 18:43:51 +01:00
return ;
}
2016-09-18 05:43:24 +02:00
if ( ! ( MMC5IRQR & 0x40 ) )
{
MMC5IRQR | = 0x40 ;
MMC5IRQR & = ~ 0x80 ;
MMC5LineCounter = 0 ;
X6502_IRQEnd ( FCEU_IQEXT ) ;
}
else
{
MMC5LineCounter + + ;
if ( MMC5LineCounter = = IRQScanline )
{
2012-12-14 18:43:51 +01:00
MMC5IRQR | = 0x80 ;
if ( IRQEnable & 0x80 )
X6502_IRQBegin ( FCEU_IQEXT ) ;
}
}
2016-09-18 05:43:24 +02:00
2012-12-14 18:43:51 +01:00
}
void MMC5_StateRestore ( int version ) {
MMC5Synco ( ) ;
2009-07-17 19:27:04 +02:00
}
typedef struct {
2012-12-14 18:43:51 +01:00
uint16 wl [ 2 ] ;
uint8 env [ 2 ] ;
uint8 enable ;
uint8 running ;
uint8 raw ;
uint8 rawcontrol ;
int32 dcount [ 2 ] ;
int32 BC [ 3 ] ;
int32 vcount [ 2 ] ;
2009-07-17 19:27:04 +02:00
} MMC5APU ;
static MMC5APU MMC5Sound ;
2012-12-14 18:43:51 +01:00
static void Do5PCM ( ) {
int32 V ;
int32 start , end ;
start = MMC5Sound . BC [ 2 ] ;
end = ( SOUNDTS < < 16 ) / soundtsinc ;
if ( end < = start ) return ;
MMC5Sound . BC [ 2 ] = end ;
if ( ! ( MMC5Sound . rawcontrol & 0x40 ) & & MMC5Sound . raw )
for ( V = start ; V < end ; V + + )
Wave [ V > > 4 ] + = MMC5Sound . raw < < 1 ;
}
static void Do5PCMHQ ( ) {
2016-09-18 05:43:24 +02:00
uint32 V ;
2012-12-14 18:43:51 +01:00
if ( ! ( MMC5Sound . rawcontrol & 0x40 ) & & MMC5Sound . raw )
for ( V = MMC5Sound . BC [ 2 ] ; V < SOUNDTS ; V + + )
WaveHi [ V ] + = MMC5Sound . raw < < 5 ;
MMC5Sound . BC [ 2 ] = SOUNDTS ;
}
static DECLFW ( Mapper5_SW ) {
A & = 0x1F ;
GameExpSound . Fill = MMC5RunSound ;
GameExpSound . HiFill = MMC5RunSoundHQ ;
switch ( A ) {
case 0x10 : if ( psfun ) psfun ( ) ; MMC5Sound . rawcontrol = V ; break ;
case 0x11 : if ( psfun ) psfun ( ) ; MMC5Sound . raw = V ; break ;
case 0x0 :
case 0x4 :
if ( sfun ) sfun ( A > > 2 ) ;
MMC5Sound . env [ A > > 2 ] = V ;
break ;
case 0x2 :
case 0x6 :
if ( sfun ) sfun ( A > > 2 ) ;
MMC5Sound . wl [ A > > 2 ] & = ~ 0x00FF ;
MMC5Sound . wl [ A > > 2 ] | = V & 0xFF ;
break ;
case 0x3 :
case 0x7 :
MMC5Sound . wl [ A > > 2 ] & = ~ 0x0700 ;
MMC5Sound . wl [ A > > 2 ] | = ( V & 0x07 ) < < 8 ;
MMC5Sound . running | = 1 < < ( A > > 2 ) ;
break ;
case 0x15 :
if ( sfun ) {
sfun ( 0 ) ;
sfun ( 1 ) ;
}
MMC5Sound . running & = V ;
MMC5Sound . enable = V ;
break ;
}
}
2009-07-17 19:27:04 +02:00
2012-12-14 18:43:51 +01:00
static void Do5SQ ( int P ) {
static int tal [ 4 ] = { 1 , 2 , 4 , 6 } ;
int32 V , amp , rthresh , wl ;
int32 start , end ;
2009-07-17 19:27:04 +02:00
2012-12-14 18:43:51 +01:00
start = MMC5Sound . BC [ P ] ;
end = ( SOUNDTS < < 16 ) / soundtsinc ;
if ( end < = start ) return ;
MMC5Sound . BC [ P ] = end ;
wl = MMC5Sound . wl [ P ] + 1 ;
amp = ( MMC5Sound . env [ P ] & 0xF ) < < 4 ;
rthresh = tal [ ( MMC5Sound . env [ P ] & 0xC0 ) > > 6 ] ;
if ( wl > = 8 & & ( MMC5Sound . running & ( P + 1 ) ) ) {
int dc , vc ;
wl < < = 18 ;
dc = MMC5Sound . dcount [ P ] ;
vc = MMC5Sound . vcount [ P ] ;
for ( V = start ; V < end ; V + + ) {
if ( dc < rthresh )
Wave [ V > > 4 ] + = amp ;
vc - = nesincsize ;
while ( vc < = 0 ) {
vc + = wl ;
dc = ( dc + 1 ) & 7 ;
}
}
MMC5Sound . dcount [ P ] = dc ;
MMC5Sound . vcount [ P ] = vc ;
}
2009-07-17 19:27:04 +02:00
}
2012-12-14 18:43:51 +01:00
static void Do5SQHQ ( int P ) {
static int tal [ 4 ] = { 1 , 2 , 4 , 6 } ;
2016-09-18 05:43:24 +02:00
uint32 V ;
2012-12-14 18:43:51 +01:00
int32 amp , rthresh , wl ;
wl = MMC5Sound . wl [ P ] + 1 ;
amp = ( ( MMC5Sound . env [ P ] & 0xF ) < < 8 ) ;
rthresh = tal [ ( MMC5Sound . env [ P ] & 0xC0 ) > > 6 ] ;
if ( wl > = 8 & & ( MMC5Sound . running & ( P + 1 ) ) ) {
int dc , vc ;
wl < < = 1 ;
dc = MMC5Sound . dcount [ P ] ;
vc = MMC5Sound . vcount [ P ] ;
for ( V = MMC5Sound . BC [ P ] ; V < SOUNDTS ; V + + ) {
if ( dc < rthresh )
WaveHi [ V ] + = amp ;
vc - - ;
if ( vc < = 0 ) { /* Less than zero when first started. */
vc = wl ;
dc = ( dc + 1 ) & 7 ;
}
}
MMC5Sound . dcount [ P ] = dc ;
MMC5Sound . vcount [ P ] = vc ;
}
MMC5Sound . BC [ P ] = SOUNDTS ;
2009-07-17 19:27:04 +02:00
}
2012-12-14 18:43:51 +01:00
void MMC5RunSoundHQ ( void ) {
Do5SQHQ ( 0 ) ;
Do5SQHQ ( 1 ) ;
Do5PCMHQ ( ) ;
}
2009-07-17 19:27:04 +02:00
2012-12-14 18:43:51 +01:00
void MMC5HiSync ( int32 ts ) {
int x ;
for ( x = 0 ; x < 3 ; x + + )
MMC5Sound . BC [ x ] = ts ;
2009-07-17 19:27:04 +02:00
}
2012-12-14 18:43:51 +01:00
void MMC5RunSound ( int Count ) {
int x ;
Do5SQ ( 0 ) ;
Do5SQ ( 1 ) ;
Do5PCM ( ) ;
for ( x = 0 ; x < 3 ; x + + )
MMC5Sound . BC [ x ] = Count ;
}
void Mapper5_ESI ( void ) {
GameExpSound . RChange = Mapper5_ESI ;
if ( FSettings . SndRate ) {
if ( FSettings . soundq > = 1 ) {
sfun = Do5SQHQ ;
psfun = Do5PCMHQ ;
} else {
sfun = Do5SQ ;
psfun = Do5PCM ;
}
} else {
sfun = 0 ;
psfun = 0 ;
}
memset ( MMC5Sound . BC , 0 , sizeof ( MMC5Sound . BC ) ) ;
memset ( MMC5Sound . vcount , 0 , sizeof ( MMC5Sound . vcount ) ) ;
GameExpSound . HiSync = MMC5HiSync ;
2009-07-17 19:27:04 +02:00
}
2012-12-14 18:43:51 +01:00
void NSFMMC5_Init ( void ) {
memset ( & MMC5Sound , 0 , sizeof ( MMC5Sound ) ) ;
mul [ 0 ] = mul [ 1 ] = 0 ;
ExRAM = ( uint8 * ) FCEU_gmalloc ( 1024 ) ;
Mapper5_ESI ( ) ;
SetWriteHandler ( 0x5c00 , 0x5fef , MMC5_ExRAMWr ) ;
SetReadHandler ( 0x5c00 , 0x5fef , MMC5_ExRAMRd ) ;
MMC5HackCHRMode = 2 ;
SetWriteHandler ( 0x5000 , 0x5015 , Mapper5_SW ) ;
SetWriteHandler ( 0x5205 , 0x5206 , Mapper5_write ) ;
SetReadHandler ( 0x5205 , 0x5206 , MMC5_read ) ;
2009-07-17 19:27:04 +02:00
}
2012-12-14 18:43:51 +01:00
void NSFMMC5_Close ( void ) {
2016-09-18 05:43:24 +02:00
if ( WRAM )
FCEU_gfree ( WRAM ) ;
WRAM = NULL ;
2012-12-14 18:43:51 +01:00
FCEU_gfree ( ExRAM ) ;
2016-09-18 05:43:24 +02:00
ExRAM = NULL ;
2009-07-17 19:27:04 +02:00
}
2012-12-14 18:43:51 +01:00
static void GenMMC5Reset ( void ) {
int x ;
for ( x = 0 ; x < 4 ; x + + ) PRGBanks [ x ] = ~ 0 ;
for ( x = 0 ; x < 8 ; x + + ) CHRBanksA [ x ] = ~ 0 ;
for ( x = 0 ; x < 4 ; x + + ) CHRBanksB [ x ] = ~ 0 ;
WRAMMaskEnable [ 0 ] = WRAMMaskEnable [ 1 ] = ~ 0 ;
mmc5psize = mmc5vsize = 3 ;
CHRMode = 0 ;
NTAMirroring = NTFill = ATFill = 0xFF ;
MMC5Synco ( ) ;
SetWriteHandler ( 0x4020 , 0x5bff , Mapper5_write ) ;
SetReadHandler ( 0x4020 , 0x5bff , MMC5_read ) ;
SetWriteHandler ( 0x5c00 , 0x5fff , MMC5_ExRAMWr ) ;
SetReadHandler ( 0x5c00 , 0x5fff , MMC5_ExRAMRd ) ;
SetWriteHandler ( 0x6000 , 0xFFFF , MMC5_WriteROMRAM ) ;
SetReadHandler ( 0x6000 , 0xFFFF , MMC5_ReadROMRAM ) ;
SetWriteHandler ( 0x5000 , 0x5015 , Mapper5_SW ) ;
SetWriteHandler ( 0x5205 , 0x5206 , Mapper5_write ) ;
SetReadHandler ( 0x5205 , 0x5206 , MMC5_read ) ;
// GameHBIRQHook=MMC5_hb;
2016-09-18 05:43:24 +02:00
// FCEU_CheatAddRAM(8, 0x6000, WRAM);
2012-12-14 18:43:51 +01:00
FCEU_CheatAddRAM ( 1 , 0x5c00 , ExRAM ) ;
}
static SFORMAT MMC5_StateRegs [ ] = {
{ PRGBanks , 4 , " PRGB " } ,
{ CHRBanksA , 16 , " CHRA " } ,
{ CHRBanksB , 8 , " CHRB " } ,
{ & WRAMPage , 1 , " WRMP " } ,
{ WRAMMaskEnable , 2 , " WRME " } ,
{ & mmc5ABMode , 1 , " ABMD " } ,
{ & IRQScanline , 1 , " IRQS " } ,
{ & IRQEnable , 1 , " IRQE " } ,
{ & CHRMode , 1 , " CHRM " } ,
{ & NTAMirroring , 1 , " NTAM " } ,
{ & NTFill , 1 , " NTFL " } ,
{ & ATFill , 1 , " ATFL " } ,
2016-09-18 05:43:24 +02:00
//zero 17-apr-2013 - added
{ & MMC5IRQR , 1 , " IRQR " } ,
{ & MMC5LineCounter , 1 , " LCTR " } ,
{ & mmc5psize , 1 , " PSIZ " } ,
{ & mmc5vsize , 1 , " VSIZ " } ,
{ mul , 2 , " MUL2 " } ,
{ MMC5ROMWrProtect , 4 , " WRPR " } ,
{ MMC5MemIn , 5 , " MEMI " } ,
2012-12-14 18:43:51 +01:00
{ & MMC5Sound . wl [ 0 ] , 2 | FCEUSTATE_RLSB , " SDW0 " } ,
{ & MMC5Sound . wl [ 1 ] , 2 | FCEUSTATE_RLSB , " SDW1 " } ,
{ MMC5Sound . env , 2 , " SDEV " } ,
{ & MMC5Sound . enable , 1 , " SDEN " } ,
{ & MMC5Sound . running , 1 , " SDRU " } ,
{ & MMC5Sound . raw , 1 , " SDRW " } ,
{ & MMC5Sound . rawcontrol , 1 , " SDRC " } ,
2016-09-18 05:43:24 +02:00
//zero 17-apr-2013 - added
{ & MMC5Sound . dcount [ 0 ] , 4 | FCEUSTATE_RLSB , " DCT0 " } ,
{ & MMC5Sound . dcount [ 1 ] , 4 | FCEUSTATE_RLSB , " DCT1 " } ,
{ & MMC5Sound . BC [ 0 ] , 4 | FCEUSTATE_RLSB , " BC00 " } ,
{ & MMC5Sound . BC [ 1 ] , 4 | FCEUSTATE_RLSB , " BC01 " } ,
{ & MMC5Sound . BC [ 2 ] , 4 | FCEUSTATE_RLSB , " BC02 " } ,
{ & MMC5Sound . vcount [ 0 ] , 4 | FCEUSTATE_RLSB , " VCT0 " } ,
{ & MMC5Sound . vcount [ 1 ] , 4 | FCEUSTATE_RLSB , " VCT1 " } ,
2012-12-14 18:43:51 +01:00
{ 0 }
2009-07-17 19:27:04 +02:00
} ;
2012-12-14 18:43:51 +01:00
static void GenMMC5_Init ( CartInfo * info , int wsize , int battery ) {
if ( wsize ) {
WRAM = ( uint8 * ) FCEU_gmalloc ( wsize * 1024 ) ;
SetupCartPRGMapping ( 0x10 , WRAM , wsize * 1024 , 1 ) ;
AddExState ( WRAM , wsize * 1024 , 0 , " WRAM " ) ;
}
MMC5fill = ( uint8 * ) FCEU_gmalloc ( 1024 ) ;
ExRAM = ( uint8 * ) FCEU_gmalloc ( 1024 ) ;
2018-08-13 17:04:20 +02:00
// MMC5fill is and 8-bit tile index, and a 2-bit attribute implented as a mirrored nametable
u8 nval = MMC5fill [ 0x000 ] ;
u8 aval = MMC5fill [ 0x3C0 ] & 3 ; aval = aval | ( aval < < 2 ) | ( aval < < 4 ) | ( aval < < 6 ) ;
FCEU_dwmemset ( MMC5fill + 0x000 , nval | ( nval < < 8 ) | ( nval < < 16 ) | ( nval < < 24 ) , 0x3C0 ) ;
FCEU_dwmemset ( MMC5fill + 0x3C0 , aval | ( aval < < 8 ) | ( aval < < 16 ) | ( aval < < 24 ) , 0x040 ) ;
2012-12-14 18:43:51 +01:00
AddExState ( ExRAM , 1024 , 0 , " ERAM " ) ;
AddExState ( & MMC5HackSPMode , 1 , 0 , " SPLM " ) ;
AddExState ( & MMC5HackSPScroll , 1 , 0 , " SPLS " ) ;
AddExState ( & MMC5HackSPPage , 1 , 0 , " SPLP " ) ;
AddExState ( & MMC50x5130 , 1 , 0 , " 5130 " ) ;
2016-09-18 05:43:24 +02:00
AddExState ( MMC5_StateRegs , ~ 0 , 0 , 0 ) ;
2012-12-14 18:43:51 +01:00
MMC5WRAMsize = wsize / 8 ;
BuildWRAMSizeTable ( ) ;
GameStateRestore = MMC5_StateRestore ;
info - > Power = GenMMC5Reset ;
if ( battery ) {
info - > SaveGame [ 0 ] = WRAM ;
2018-08-13 17:04:20 +02:00
//this is more complex than it looks because it MUST BE, I guess. is there an assumption that only 8KB of 16KB is battery backed? That's NES mappers for you
//I added 64KB for the new 64KB homebrews
2012-12-14 18:43:51 +01:00
if ( wsize < = 16 )
info - > SaveGameLen [ 0 ] = 8192 ;
2018-08-13 17:04:20 +02:00
else if ( wsize = = 64 )
info - > SaveGameLen [ 0 ] = 64 * 1024 ;
2012-12-14 18:43:51 +01:00
else
info - > SaveGameLen [ 0 ] = 32768 ;
}
MMC5HackVROMMask = CHRmask4 [ 0 ] ;
MMC5HackExNTARAMPtr = ExRAM ;
MMC5Hack = 1 ;
MMC5HackVROMPTR = CHRptr [ 0 ] ;
MMC5HackCHRMode = 0 ;
MMC5HackSPMode = MMC5HackSPScroll = MMC5HackSPPage = 0 ;
Mapper5_ESI ( ) ;
FFCEUX_PPURead = mmc5_PPURead ;
FFCEUX_PPUWrite = mmc5_PPUWrite ;
}
void Mapper5_Init ( CartInfo * info ) {
2016-09-18 05:43:24 +02:00
WRAMSIZE = DetectMMC5WRAMSize ( info - > CRC32 ) ;
GenMMC5_Init ( info , WRAMSIZE , info - > battery ) ;
2009-07-17 19:27:04 +02:00
}
// ELROM seems to have 0KB of WRAM
2016-09-18 05:43:24 +02:00
// EKROM seems to have 8KB of WRAM, battery-backed
// ETROM seems to have 16KB of WRAM, battery-backed
// EWROM seems to have 32KB of WRAM, battery-backed
2009-07-17 19:27:04 +02:00
2016-09-18 05:43:24 +02:00
void ELROM_Init ( CartInfo * info ) {
GenMMC5_Init ( info , 0 , 0 ) ;
}
2009-07-17 19:27:04 +02:00
2016-09-18 05:43:24 +02:00
void EKROM_Init ( CartInfo * info ) {
GenMMC5_Init ( info , 8 , info - > battery ) ;
2009-07-17 19:27:04 +02:00
}
2016-09-18 05:43:24 +02:00
void ETROM_Init ( CartInfo * info ) {
GenMMC5_Init ( info , 16 , info - > battery ) ;
2009-07-17 19:27:04 +02:00
}
2012-12-14 18:43:51 +01:00
void EWROM_Init ( CartInfo * info ) {
GenMMC5_Init ( info , 32 , info - > battery ) ;
2009-07-17 19:27:04 +02:00
}