2016-01-24 11:18:50 -05:00
# include "stdafx.h"
2016-08-24 20:48:14 -04:00
# include <random>
2016-01-24 11:18:50 -05:00
# include <assert.h>
# include "../Utilities/FolderUtilities.h"
2017-08-19 19:40:02 -04:00
# include "../Utilities/IpsPatcher.h"
# include "BaseMapper.h"
# include "Console.h"
2016-01-24 11:18:50 -05:00
# include "CheatManager.h"
2016-09-05 09:05:34 -04:00
# include "Debugger.h"
2017-03-31 22:14:16 -04:00
# include "MemoryManager.h"
2017-11-19 23:08:23 -05:00
# include "BatteryManager.h"
2018-07-01 15:21:05 -04:00
# include "MessageManager.h"
# include "EmulationSettings.h"
2021-03-19 15:16:36 +01:00
# include "CPU.h"
2016-01-24 11:18:50 -05:00
2016-06-02 23:56:11 -04:00
void BaseMapper : : WriteRegister ( uint16_t addr , uint8_t value ) { }
2021-08-26 15:03:02 +02:00
void BaseMapper : : WriteEPSM ( uint16_t addr , uint8_t value ) { _epsmaudio - > WriteRegister ( addr , value ) ; }
2016-06-02 23:56:11 -04:00
uint8_t BaseMapper : : ReadRegister ( uint16_t addr ) { return 0 ; }
void BaseMapper : : InitMapper ( RomData & romData ) { }
void BaseMapper : : Reset ( bool softReset ) { }
2016-08-18 23:41:58 -04:00
//Make sure the page size is no bigger than the size of the ROM itself
//Otherwise we will end up reading from unallocated memory
uint16_t BaseMapper : : InternalGetPrgPageSize ( ) { return std : : min ( ( uint32_t ) GetPRGPageSize ( ) , _prgSize ) ; }
uint16_t BaseMapper : : InternalGetSaveRamPageSize ( ) { return std : : min ( ( uint32_t ) GetSaveRamPageSize ( ) , _saveRamSize ) ; }
uint16_t BaseMapper : : InternalGetWorkRamPageSize ( ) { return std : : min ( ( uint32_t ) GetWorkRamPageSize ( ) , _workRamSize ) ; }
uint16_t BaseMapper : : InternalGetChrPageSize ( ) { return std : : min ( ( uint32_t ) GetCHRPageSize ( ) , _chrRomSize ) ; }
uint16_t BaseMapper : : InternalGetChrRamPageSize ( ) { return std : : min ( ( uint32_t ) GetChrRamPageSize ( ) , _chrRamSize ) ; }
2016-01-24 11:18:50 -05:00
2018-08-07 18:29:09 -04:00
bool BaseMapper : : ValidateAddressRange ( uint16_t startAddr , uint16_t endAddr )
2016-01-24 11:18:50 -05:00
{
if ( ( startAddr & 0xFF ) | | ( endAddr & 0xFF ) ! = 0xFF ) {
2018-08-07 18:29:09 -04:00
# ifdef _DEBUG
throw new std : : runtime_error ( " Start/End address must be multiples of 256/0x100 " ) ;
# else
//Ignore this request in release mode - granularity smaller than 256 bytes is not supported
return false ;
# endif
}
return true ;
}
void BaseMapper : : SetCpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr , int16_t pageNumber , PrgMemoryType type , int8_t accessType )
{
2018-08-19 13:53:20 -04:00
if ( ! ValidateAddressRange ( startAddr , endAddr ) | | startAddr > 0xFF00 | | endAddr < = startAddr ) {
2018-08-07 18:29:09 -04:00
return ;
2016-01-24 11:18:50 -05:00
}
uint32_t pageCount ;
uint32_t pageSize ;
uint8_t defaultAccessType = MemoryAccessType : : Read ;
switch ( type ) {
case PrgMemoryType : : PrgRom :
pageCount = GetPRGPageCount ( ) ;
pageSize = InternalGetPrgPageSize ( ) ;
break ;
case PrgMemoryType : : SaveRam :
2016-08-18 23:41:58 -04:00
pageSize = InternalGetSaveRamPageSize ( ) ;
2016-08-18 23:59:38 -04:00
if ( pageSize = = 0 ) {
# ifdef _DEBUG
MessageManager : : DisplayMessage ( " Debug " , " Tried to map undefined save ram. " ) ;
# endif
return ;
}
pageCount = _saveRamSize / pageSize ;
2016-01-24 11:18:50 -05:00
defaultAccessType | = MemoryAccessType : : Write ;
break ;
case PrgMemoryType : : WorkRam :
2016-08-18 23:41:58 -04:00
pageSize = InternalGetWorkRamPageSize ( ) ;
2016-08-18 23:59:38 -04:00
if ( pageSize = = 0 ) {
# ifdef _DEBUG
MessageManager : : DisplayMessage ( " Debug " , " Tried to map undefined work ram. " ) ;
# endif
return ;
}
pageCount = _workRamSize / pageSize ;
2016-01-24 11:18:50 -05:00
defaultAccessType | = MemoryAccessType : : Write ;
break ;
default :
throw new std : : runtime_error ( " Invalid parameter " ) ;
}
2016-07-26 19:19:28 -04:00
if ( pageCount = = 0 ) {
# ifdef _DEBUG
MessageManager : : DisplayMessage ( " Debug " , " Tried to map undefined save/work ram. " ) ;
# endif
return ;
}
2017-04-09 15:10:04 -04:00
auto wrapPageNumber = [ = ] ( int16_t & page ) - > void {
if ( page < 0 ) {
//Can't use modulo for negative number because pageCount is sometimes not a power of 2. (Fixes some Mapper 191 games)
page = pageCount + page ;
} else {
page = page % pageCount ;
}
} ;
wrapPageNumber ( pageNumber ) ;
2016-06-25 20:46:54 -04:00
accessType = accessType ! = - 1 ? accessType : defaultAccessType ;
2018-08-19 13:53:20 -04:00
2016-08-18 23:41:58 -04:00
if ( ( uint16_t ) ( endAddr - startAddr ) > = pageSize ) {
# ifdef _DEBUG
MessageManager : : DisplayMessage ( " Debug " , " Tried to map undefined prg - page size too small for selected range. " ) ;
# endif
2016-08-26 21:50:52 -04:00
//If range is bigger than a single page, keep going until we reach the last page
2017-04-09 15:10:04 -04:00
uint32_t addr = startAddr ;
while ( addr < = endAddr - pageSize + 1 ) {
2018-08-19 13:53:20 -04:00
SetCpuMemoryMapping ( addr , addr + pageSize - 1 , type , pageNumber * pageSize , accessType ) ;
2017-04-09 15:10:04 -04:00
addr + = pageSize ;
pageNumber + + ;
wrapPageNumber ( pageNumber ) ;
2016-08-26 21:50:52 -04:00
}
} else {
2018-08-19 13:53:20 -04:00
SetCpuMemoryMapping ( startAddr , endAddr , type , pageNumber * pageSize , accessType ) ;
}
}
void BaseMapper : : SetCpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr , PrgMemoryType type , uint32_t sourceOffset , int8_t accessType )
{
uint8_t * source = nullptr ;
switch ( type ) {
default :
case PrgMemoryType : : PrgRom : source = _prgRom ; break ;
case PrgMemoryType : : SaveRam : source = _saveRam ; break ;
case PrgMemoryType : : WorkRam : source = _workRam ; break ;
}
int firstSlot = startAddr > > 8 ;
int slotCount = ( endAddr - startAddr + 1 ) > > 8 ;
for ( int i = 0 ; i < slotCount ; i + + ) {
_prgMemoryOffset [ firstSlot + i ] = sourceOffset + i * 0x100 ;
_prgMemoryType [ firstSlot + i ] = type ;
_prgMemoryAccess [ firstSlot + i ] = ( MemoryAccessType ) accessType ;
2016-08-18 23:41:58 -04:00
}
2018-08-19 13:53:20 -04:00
SetCpuMemoryMapping ( startAddr , endAddr , source + sourceOffset , accessType ) ;
2016-06-25 20:46:54 -04:00
}
void BaseMapper : : SetCpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr , uint8_t * source , int8_t accessType )
{
2018-08-07 18:29:09 -04:00
if ( ! ValidateAddressRange ( startAddr , endAddr ) ) {
return ;
2016-06-25 20:46:54 -04:00
}
2016-01-24 11:18:50 -05:00
startAddr > > = 8 ;
endAddr > > = 8 ;
for ( uint16_t i = startAddr ; i < = endAddr ; i + + ) {
_prgPages [ i ] = source ;
2019-01-09 20:19:16 -05:00
_prgMemoryAccess [ i ] = accessType ! = - 1 ? ( MemoryAccessType ) accessType : MemoryAccessType : : Read ;
2016-01-24 11:18:50 -05:00
source + = 0x100 ;
}
}
2016-07-20 21:06:36 -04:00
void BaseMapper : : RemoveCpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr )
{
//Unmap this section of memory (causing open bus behavior)
2018-09-07 17:17:35 -04:00
int firstSlot = startAddr > > 8 ;
int slotCount = ( endAddr - startAddr + 1 ) > > 8 ;
for ( int i = 0 ; i < slotCount ; i + + ) {
_prgMemoryOffset [ firstSlot + i ] = - 1 ;
_prgMemoryType [ firstSlot + i ] = PrgMemoryType : : PrgRom ;
_prgMemoryAccess [ firstSlot + i ] = MemoryAccessType : : NoAccess ;
}
2016-07-20 21:06:36 -04:00
SetCpuMemoryMapping ( startAddr , endAddr , nullptr , MemoryAccessType : : NoAccess ) ;
}
2016-01-24 11:18:50 -05:00
void BaseMapper : : SetPpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr , uint16_t pageNumber , ChrMemoryType type , int8_t accessType )
{
2018-08-19 13:53:20 -04:00
if ( ! ValidateAddressRange ( startAddr , endAddr ) | | startAddr > 0x3F00 | | endAddr > 0x3FFF | | endAddr < = startAddr ) {
2018-08-07 18:29:09 -04:00
return ;
}
2016-06-02 23:56:11 -04:00
uint32_t pageCount = 0 ;
uint32_t pageSize = 0 ;
2016-01-24 11:18:50 -05:00
uint8_t defaultAccessType = MemoryAccessType : : Read ;
switch ( type ) {
case ChrMemoryType : : Default :
pageSize = InternalGetChrPageSize ( ) ;
2017-01-06 19:31:36 -05:00
if ( pageSize = = 0 ) {
# ifdef _DEBUG
MessageManager : : DisplayMessage ( " Debug " , " Tried to map undefined chr rom/ram. " ) ;
# endif
return ;
}
pageCount = GetCHRPageCount ( ) ;
2016-01-24 11:18:50 -05:00
if ( _onlyChrRam ) {
defaultAccessType | = MemoryAccessType : : Write ;
}
break ;
case ChrMemoryType : : ChrRom :
pageSize = InternalGetChrPageSize ( ) ;
2017-01-06 19:31:36 -05:00
if ( pageSize = = 0 ) {
# ifdef _DEBUG
MessageManager : : DisplayMessage ( " Debug " , " Tried to map undefined chr rom. " ) ;
# endif
return ;
}
pageCount = GetCHRPageCount ( ) ;
2016-01-24 11:18:50 -05:00
break ;
case ChrMemoryType : : ChrRam :
2016-08-18 23:41:58 -04:00
pageSize = InternalGetChrRamPageSize ( ) ;
2016-08-18 23:59:38 -04:00
if ( pageSize = = 0 ) {
# ifdef _DEBUG
MessageManager : : DisplayMessage ( " Debug " , " Tried to map undefined chr ram. " ) ;
# endif
return ;
}
2016-01-24 11:18:50 -05:00
pageCount = _chrRamSize / pageSize ;
defaultAccessType | = MemoryAccessType : : Write ;
break ;
2019-01-09 20:19:16 -05:00
case ChrMemoryType : : NametableRam :
pageSize = BaseMapper : : NametableSize ;
pageCount = BaseMapper : : NametableCount ;
defaultAccessType | = MemoryAccessType : : Write ;
break ;
2016-01-24 11:18:50 -05:00
}
2017-01-06 19:31:36 -05:00
if ( pageCount = = 0 ) {
# ifdef _DEBUG
MessageManager : : DisplayMessage ( " Debug " , " Tried to map undefined chr ram. " ) ;
# endif
return ;
}
2017-04-09 15:10:04 -04:00
pageNumber = pageNumber % pageCount ;
2017-02-23 19:58:46 -05:00
if ( ( uint16_t ) ( endAddr - startAddr ) > = pageSize ) {
# ifdef _DEBUG
MessageManager : : DisplayMessage ( " Debug " , " Tried to map undefined chr - page size too small for selected range. " ) ;
# endif
2017-04-09 15:10:04 -04:00
uint32_t addr = startAddr ;
while ( addr < = endAddr - pageSize + 1 ) {
2018-08-19 13:53:20 -04:00
SetPpuMemoryMapping ( addr , addr + pageSize - 1 , type , pageNumber * pageSize , accessType ) ;
2017-04-09 15:10:04 -04:00
addr + = pageSize ;
pageNumber = ( pageNumber + 1 ) % pageCount ;
2017-02-23 19:58:46 -05:00
}
} else {
2018-08-19 13:53:20 -04:00
SetPpuMemoryMapping ( startAddr , endAddr , type , pageNumber * pageSize , accessType = = - 1 ? defaultAccessType : accessType ) ;
}
}
void BaseMapper : : SetPpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr , ChrMemoryType type , uint32_t sourceOffset , int8_t accessType )
{
uint8_t * sourceMemory = nullptr ;
switch ( type ) {
default :
2019-12-06 20:29:58 -05:00
case ChrMemoryType : : Default :
sourceMemory = _onlyChrRam ? _chrRam : _chrRom ;
type = _onlyChrRam ? ChrMemoryType : : ChrRam : ChrMemoryType : : ChrRom ;
break ;
2018-08-19 13:53:20 -04:00
case ChrMemoryType : : ChrRom : sourceMemory = _chrRom ; break ;
case ChrMemoryType : : ChrRam : sourceMemory = _chrRam ; break ;
2019-01-09 20:19:16 -05:00
case ChrMemoryType : : NametableRam : sourceMemory = _nametableRam ; break ;
2018-08-19 13:53:20 -04:00
}
int firstSlot = startAddr > > 8 ;
int slotCount = ( endAddr - startAddr + 1 ) > > 8 ;
for ( int i = 0 ; i < slotCount ; i + + ) {
_chrMemoryOffset [ firstSlot + i ] = sourceOffset + i * 256 ;
_chrMemoryType [ firstSlot + i ] = type ;
_chrMemoryAccess [ firstSlot + i ] = ( MemoryAccessType ) accessType ;
2017-02-23 19:58:46 -05:00
}
2018-08-19 13:53:20 -04:00
SetPpuMemoryMapping ( startAddr , endAddr , sourceMemory + sourceOffset , accessType ) ;
2016-01-24 11:18:50 -05:00
}
void BaseMapper : : SetPpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr , uint8_t * sourceMemory , int8_t accessType )
{
2018-08-07 18:29:09 -04:00
if ( ! ValidateAddressRange ( startAddr , endAddr ) ) {
return ;
2016-01-24 11:18:50 -05:00
}
startAddr > > = 8 ;
endAddr > > = 8 ;
for ( uint16_t i = startAddr ; i < = endAddr ; i + + ) {
_chrPages [ i ] = sourceMemory ;
2019-01-09 20:19:16 -05:00
_chrMemoryAccess [ i ] = accessType ! = - 1 ? ( MemoryAccessType ) accessType : MemoryAccessType : : ReadWrite ;
2016-01-24 11:18:50 -05:00
if ( sourceMemory ! = nullptr ) {
sourceMemory + = 0x100 ;
}
}
}
void BaseMapper : : RemovePpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr )
{
//Unmap this section of memory (causing open bus behavior)
2018-09-07 17:17:35 -04:00
int firstSlot = startAddr > > 8 ;
int slotCount = ( endAddr - startAddr + 1 ) > > 8 ;
for ( int i = 0 ; i < slotCount ; i + + ) {
_chrMemoryOffset [ firstSlot + i ] = - 1 ;
_chrMemoryType [ firstSlot + i ] = ChrMemoryType : : Default ;
_chrMemoryAccess [ firstSlot + i ] = MemoryAccessType : : NoAccess ;
}
2016-01-24 11:18:50 -05:00
SetPpuMemoryMapping ( startAddr , endAddr , nullptr , MemoryAccessType : : NoAccess ) ;
}
uint8_t BaseMapper : : InternalReadRam ( uint16_t addr )
{
2017-03-31 22:14:16 -04:00
return _prgPages [ addr > > 8 ] ? _prgPages [ addr > > 8 ] [ ( uint8_t ) addr ] : 0 ;
2016-01-24 11:18:50 -05:00
}
2016-01-24 14:20:35 -05:00
void BaseMapper : : SelectPrgPage4x ( uint16_t slot , uint16_t page , PrgMemoryType memoryType )
{
2016-11-12 11:42:04 -05:00
BaseMapper : : SelectPrgPage2x ( slot * 2 , page , memoryType ) ;
BaseMapper : : SelectPrgPage2x ( slot * 2 + 1 , page + 2 , memoryType ) ;
2016-01-24 14:20:35 -05:00
}
void BaseMapper : : SelectPrgPage2x ( uint16_t slot , uint16_t page , PrgMemoryType memoryType )
{
2016-11-12 11:42:04 -05:00
BaseMapper : : SelectPRGPage ( slot * 2 , page , memoryType ) ;
BaseMapper : : SelectPRGPage ( slot * 2 + 1 , page + 1 , memoryType ) ;
2016-01-24 14:20:35 -05:00
}
2016-01-24 11:18:50 -05:00
void BaseMapper : : SelectPRGPage ( uint16_t slot , uint16_t page , PrgMemoryType memoryType )
{
2016-12-17 23:14:47 -05:00
if ( _prgSize < 0x8000 & & GetPRGPageSize ( ) > _prgSize ) {
2016-01-24 11:18:50 -05:00
//Total PRG size is smaller than available memory range, map the entire PRG to all slots
//i.e same logic as NROM (mapper 0) when PRG is 16kb
//Needed by "Pyramid" (mapper 79)
# ifdef _DEBUG
2016-02-19 13:05:04 -05:00
MessageManager : : DisplayMessage ( " Debug " , " PrgSizeWarning " ) ;
2016-01-24 11:18:50 -05:00
# endif
2016-12-17 23:14:47 -05:00
for ( slot = 0 ; slot < 0x8000 / _prgSize ; slot + + ) {
2016-01-24 11:18:50 -05:00
uint16_t startAddr = 0x8000 + slot * _prgSize ;
uint16_t endAddr = startAddr + _prgSize - 1 ;
SetCpuMemoryMapping ( startAddr , endAddr , 0 , memoryType ) ;
}
} else {
uint16_t startAddr = 0x8000 + slot * InternalGetPrgPageSize ( ) ;
uint16_t endAddr = startAddr + InternalGetPrgPageSize ( ) - 1 ;
SetCpuMemoryMapping ( startAddr , endAddr , page , memoryType ) ;
}
}
void BaseMapper : : SelectChrPage8x ( uint16_t slot , uint16_t page , ChrMemoryType memoryType )
{
2016-11-12 11:42:04 -05:00
BaseMapper : : SelectChrPage4x ( slot , page , memoryType ) ;
BaseMapper : : SelectChrPage4x ( slot * 2 + 1 , page + 4 , memoryType ) ;
2016-01-24 11:18:50 -05:00
}
void BaseMapper : : SelectChrPage4x ( uint16_t slot , uint16_t page , ChrMemoryType memoryType )
{
2016-11-12 11:42:04 -05:00
BaseMapper : : SelectChrPage2x ( slot * 2 , page , memoryType ) ;
BaseMapper : : SelectChrPage2x ( slot * 2 + 1 , page + 2 , memoryType ) ;
2016-01-24 11:18:50 -05:00
}
void BaseMapper : : SelectChrPage2x ( uint16_t slot , uint16_t page , ChrMemoryType memoryType )
{
2016-11-12 11:42:04 -05:00
BaseMapper : : SelectCHRPage ( slot * 2 , page , memoryType ) ;
BaseMapper : : SelectCHRPage ( slot * 2 + 1 , page + 1 , memoryType ) ;
2016-01-24 11:18:50 -05:00
}
void BaseMapper : : SelectCHRPage ( uint16_t slot , uint16_t page , ChrMemoryType memoryType )
{
2019-01-09 20:19:16 -05:00
uint16_t pageSize ;
if ( memoryType = = ChrMemoryType : : NametableRam ) {
pageSize = BaseMapper : : NametableSize ;
2016-06-11 13:18:47 -04:00
} else {
2019-01-09 20:19:16 -05:00
pageSize = memoryType = = ChrMemoryType : : ChrRam ? InternalGetChrRamPageSize ( ) : InternalGetChrPageSize ( ) ;
2016-06-11 13:18:47 -04:00
}
2019-01-09 20:19:16 -05:00
uint16_t startAddr = slot * pageSize ;
uint16_t endAddr = startAddr + pageSize - 1 ;
SetPpuMemoryMapping ( startAddr , endAddr , page , memoryType ) ;
2016-01-24 11:18:50 -05:00
}
2016-08-24 20:48:14 -04:00
2018-04-14 22:12:05 -04:00
uint8_t BaseMapper : : GetPowerOnByte ( uint8_t defaultValue )
{
2018-07-13 22:19:26 -04:00
if ( _console - > GetSettings ( ) - > CheckFlag ( EmulationFlags : : RandomizeMapperPowerOnState ) ) {
2018-04-14 22:12:05 -04:00
std : : random_device rd ;
std : : mt19937 mt ( rd ( ) ) ;
std : : uniform_int_distribution < > dist ( 0 , 255 ) ;
return dist ( mt ) ;
} else {
return defaultValue ;
}
}
2019-02-08 19:39:35 -05:00
uint32_t BaseMapper : : GetDipSwitches ( )
{
uint32_t mask = ( 1 < < GetDipSwitchCount ( ) ) - 1 ;
return _console - > GetSettings ( ) - > GetDipSwitches ( ) & mask ;
}
2016-01-24 11:18:50 -05:00
bool BaseMapper : : HasBattery ( )
{
2018-07-07 14:52:51 -04:00
return _romInfo . HasBattery ;
2016-01-24 11:18:50 -05:00
}
void BaseMapper : : LoadBattery ( )
{
2018-03-15 23:57:35 -04:00
if ( HasBattery ( ) & & _saveRamSize > 0 ) {
2018-07-22 17:31:50 -04:00
_console - > GetBatteryManager ( ) - > LoadBattery ( " .sav " , _saveRam , _saveRamSize ) ;
2016-01-24 11:18:50 -05:00
}
2018-03-15 23:57:35 -04:00
if ( _hasChrBattery & & _chrRamSize > 0 ) {
2018-07-22 17:31:50 -04:00
_console - > GetBatteryManager ( ) - > LoadBattery ( " .sav.chr " , _chrRam , _chrRamSize ) ;
2016-07-29 17:28:01 -04:00
}
2016-01-24 11:18:50 -05:00
}
void BaseMapper : : SaveBattery ( )
{
2018-03-15 23:57:35 -04:00
if ( HasBattery ( ) & & _saveRamSize > 0 ) {
2018-07-22 17:31:50 -04:00
_console - > GetBatteryManager ( ) - > SaveBattery ( " .sav " , _saveRam , _saveRamSize ) ;
2016-01-24 11:18:50 -05:00
}
2016-07-29 17:28:01 -04:00
2018-03-15 23:57:35 -04:00
if ( _hasChrBattery & & _chrRamSize > 0 ) {
2018-07-22 17:31:50 -04:00
_console - > GetBatteryManager ( ) - > SaveBattery ( " .sav.chr " , _chrRam , _chrRamSize ) ;
2016-07-29 17:28:01 -04:00
}
2016-01-24 11:18:50 -05:00
}
uint32_t BaseMapper : : GetPRGPageCount ( )
{
2018-08-22 18:30:13 -04:00
uint16_t pageSize = InternalGetPrgPageSize ( ) ;
return pageSize ? ( _prgSize / pageSize ) : 0 ;
2016-01-24 11:18:50 -05:00
}
uint32_t BaseMapper : : GetCHRPageCount ( )
{
2018-08-22 18:30:13 -04:00
uint16_t pageSize = InternalGetChrPageSize ( ) ;
return pageSize ? ( _chrRomSize / pageSize ) : 0 ;
2016-01-24 11:18:50 -05:00
}
string BaseMapper : : GetBatteryFilename ( )
{
2018-07-07 14:52:51 -04:00
return FolderUtilities : : CombinePath ( FolderUtilities : : GetSaveFolder ( ) , FolderUtilities : : GetFilename ( _romInfo . RomName , false ) + " .sav " ) ;
2016-01-24 11:18:50 -05:00
}
2016-06-12 13:53:41 -04:00
void BaseMapper : : InitializeChrRam ( int32_t chrRamSize )
2016-01-24 11:18:50 -05:00
{
2016-07-23 09:21:43 -04:00
uint32_t defaultRamSize = GetChrRamSize ( ) ? GetChrRamSize ( ) : 0x2000 ;
_chrRamSize = chrRamSize > = 0 ? chrRamSize : defaultRamSize ;
2016-01-28 22:34:23 -05:00
if ( _chrRamSize > 0 ) {
_chrRam = new uint8_t [ _chrRamSize ] ;
2019-06-22 16:33:59 -04:00
_console - > InitializeRam ( _chrRam , _chrRamSize ) ;
2016-01-28 22:34:23 -05:00
}
2016-01-24 11:18:50 -05:00
}
2018-06-17 11:28:41 -04:00
void BaseMapper : : SetupDefaultWorkRam ( )
{
//Setup a default work/save ram in 0x6000-0x7FFF space
if ( HasBattery ( ) & & _saveRamSize > 0 ) {
SetCpuMemoryMapping ( 0x6000 , 0x7FFF , 0 , PrgMemoryType : : SaveRam ) ;
} else if ( _workRamSize > 0 ) {
SetCpuMemoryMapping ( 0x6000 , 0x7FFF , 0 , PrgMemoryType : : WorkRam ) ;
}
}
2016-06-13 22:46:01 -04:00
bool BaseMapper : : HasChrRam ( )
{
return _chrRamSize > 0 ;
}
2016-11-07 19:09:08 -05:00
bool BaseMapper : : HasChrRom ( )
{
return ! _onlyChrRam ;
}
2016-06-11 13:18:47 -04:00
void BaseMapper : : AddRegisterRange ( uint16_t startAddr , uint16_t endAddr , MemoryOperation operation )
2016-01-24 11:18:50 -05:00
{
for ( int i = startAddr ; i < = endAddr ; i + + ) {
2016-06-11 13:18:47 -04:00
if ( ( int ) operation & ( int ) MemoryOperation : : Read ) {
_isReadRegisterAddr [ i ] = true ;
}
if ( ( int ) operation & ( int ) MemoryOperation : : Write ) {
_isWriteRegisterAddr [ i ] = true ;
}
2016-01-24 11:18:50 -05:00
}
}
2016-06-11 13:18:47 -04:00
void BaseMapper : : RemoveRegisterRange ( uint16_t startAddr , uint16_t endAddr , MemoryOperation operation )
2016-01-24 11:18:50 -05:00
{
for ( int i = startAddr ; i < = endAddr ; i + + ) {
2016-06-11 13:18:47 -04:00
if ( ( int ) operation & ( int ) MemoryOperation : : Read ) {
_isReadRegisterAddr [ i ] = false ;
}
if ( ( int ) operation & ( int ) MemoryOperation : : Write ) {
_isWriteRegisterAddr [ i ] = false ;
}
2016-01-24 11:18:50 -05:00
}
}
void BaseMapper : : StreamState ( bool saving )
{
2019-01-09 20:19:16 -05:00
//Need to get the number of nametables in the state first, before we try to stream the nametable ram array
Stream ( _nametableCount ) ;
2016-06-02 23:56:11 -04:00
ArrayInfo < uint8_t > chrRam = { _chrRam , _chrRamSize } ;
2016-07-26 19:19:28 -04:00
ArrayInfo < uint8_t > workRam = { _workRam , _workRamSize } ;
2016-06-02 23:56:11 -04:00
ArrayInfo < uint8_t > saveRam = { _saveRam , _saveRamSize } ;
2019-01-09 20:19:16 -05:00
ArrayInfo < uint8_t > nametableRam = { _nametableRam , _nametableCount * BaseMapper : : NametableSize } ;
2018-08-19 13:53:20 -04:00
2019-01-09 20:19:16 -05:00
ArrayInfo < int32_t > prgMemoryOffset = { _prgMemoryOffset , 0x100 } ;
ArrayInfo < int32_t > chrMemoryOffset = { _chrMemoryOffset , 0x40 } ;
ArrayInfo < PrgMemoryType > prgMemoryType = { _prgMemoryType , 0x100 } ;
ArrayInfo < ChrMemoryType > chrMemoryType = { _chrMemoryType , 0x40 } ;
ArrayInfo < MemoryAccessType > prgMemoryAccess = { _prgMemoryAccess , 0x100 } ;
ArrayInfo < MemoryAccessType > chrMemoryAccess = { _chrMemoryAccess , 0x40 } ;
2021-07-30 14:21:56 +02:00
SnapshotInfo epsmaudio { _epsmaudio . get ( ) } ;
2021-08-11 17:55:56 +08:00
SnapshotInfo invA13Audio { _invA13Audio . get ( ) } ;
SnapshotInfo invOE1Audio { _invOE1Audio . get ( ) } ;
2017-11-19 23:08:23 -05:00
2021-08-11 17:55:56 +08:00
Stream ( _mirroringType , chrRam , workRam , saveRam , nametableRam , prgMemoryOffset , chrMemoryOffset , prgMemoryType , chrMemoryType , prgMemoryAccess , chrMemoryAccess , epsmaudio , invA13Audio , invOE1Audio ) ;
2017-10-07 20:32:55 -04:00
2016-01-24 11:18:50 -05:00
if ( ! saving ) {
2019-01-09 20:19:16 -05:00
RestorePrgChrState ( ) ;
2018-08-19 13:53:20 -04:00
}
}
2019-01-09 20:19:16 -05:00
void BaseMapper : : RestorePrgChrState ( )
2018-08-19 13:53:20 -04:00
{
2019-01-09 20:19:16 -05:00
for ( uint16_t i = 0 ; i < 0x100 ; i + + ) {
uint16_t startAddr = i < < 8 ;
if ( _prgMemoryAccess [ i ] ! = MemoryAccessType : : NoAccess ) {
SetCpuMemoryMapping ( startAddr , startAddr + 0xFF , _prgMemoryType [ i ] , _prgMemoryOffset [ i ] , _prgMemoryAccess [ i ] ) ;
} else {
RemoveCpuMemoryMapping ( startAddr , startAddr + 0xFF ) ;
2016-01-24 11:18:50 -05:00
}
2019-01-09 20:19:16 -05:00
}
2016-01-24 11:18:50 -05:00
2019-01-09 20:19:16 -05:00
for ( uint16_t i = 0 ; i < 0x40 ; i + + ) {
uint16_t startAddr = i < < 8 ;
if ( _chrMemoryAccess [ i ] ! = MemoryAccessType : : NoAccess ) {
SetPpuMemoryMapping ( startAddr , startAddr + 0xFF , _chrMemoryType [ i ] , _chrMemoryOffset [ i ] , _chrMemoryAccess [ i ] ) ;
} else {
RemovePpuMemoryMapping ( startAddr , startAddr + 0xFF ) ;
2016-01-24 11:18:50 -05:00
}
}
}
2016-01-28 20:47:16 -05:00
void BaseMapper : : Initialize ( RomData & romData )
2016-01-24 11:18:50 -05:00
{
2018-07-07 14:52:51 -04:00
_romInfo = romData . Info ;
2016-06-03 19:16:31 -04:00
2016-01-24 11:18:50 -05:00
_batteryFilename = GetBatteryFilename ( ) ;
2016-07-26 19:19:28 -04:00
2019-01-26 16:49:26 -05:00
if ( romData . SaveRamSize = = - 1 | | ForceSaveRamSize ( ) ) {
2017-11-19 23:08:23 -05:00
_saveRamSize = GetSaveRamSize ( ) ;
2019-01-26 16:49:26 -05:00
} else {
_saveRamSize = romData . SaveRamSize ;
2016-07-26 19:19:28 -04:00
}
2019-01-26 16:49:26 -05:00
if ( romData . WorkRamSize = = - 1 | | ForceWorkRamSize ( ) ) {
2016-07-26 19:19:28 -04:00
_workRamSize = GetWorkRamSize ( ) ;
2019-01-26 16:49:26 -05:00
} else {
_workRamSize = romData . WorkRamSize ;
2016-07-26 19:19:28 -04:00
}
2016-01-24 11:18:50 -05:00
_allowRegisterRead = AllowRegisterRead ( ) ;
2016-06-11 13:18:47 -04:00
memset ( _isReadRegisterAddr , 0 , sizeof ( _isReadRegisterAddr ) ) ;
memset ( _isWriteRegisterAddr , 0 , sizeof ( _isWriteRegisterAddr ) ) ;
AddRegisterRange ( RegisterStartAddress ( ) , RegisterEndAddress ( ) , MemoryOperation : : Any ) ;
2016-01-24 11:18:50 -05:00
2016-01-28 20:47:16 -05:00
_prgSize = ( uint32_t ) romData . PrgRom . size ( ) ;
_chrRomSize = ( uint32_t ) romData . ChrRom . size ( ) ;
_originalPrgRom = romData . PrgRom ;
2017-08-12 16:52:45 -04:00
_originalChrRom = romData . ChrRom ;
2016-01-28 20:47:16 -05:00
_prgRom = new uint8_t [ _prgSize ] ;
_chrRom = new uint8_t [ _chrRomSize ] ;
memcpy ( _prgRom , romData . PrgRom . data ( ) , _prgSize ) ;
if ( _chrRomSize > 0 ) {
memcpy ( _chrRom , romData . ChrRom . data ( ) , _chrRomSize ) ;
}
2016-07-29 17:28:01 -04:00
_hasChrBattery = romData . SaveChrRamSize > 0 | | ForceChrBattery ( ) ;
2018-07-07 14:52:51 -04:00
switch ( romData . Info . BusConflicts ) {
2017-04-01 15:47:43 -04:00
case BusConflictType : : Default : _hasBusConflicts = HasBusConflicts ( ) ; break ;
case BusConflictType : : Yes : _hasBusConflicts = true ; break ;
case BusConflictType : : No : _hasBusConflicts = false ; break ;
}
2016-01-24 11:18:50 -05:00
2020-02-23 13:00:39 -05:00
if ( _hasBusConflicts ) {
MessageManager : : Log ( " [iNes] Bus conflicts enabled " ) ;
}
2016-01-24 11:18:50 -05:00
_saveRam = new uint8_t [ _saveRamSize ] ;
2016-07-26 19:19:28 -04:00
_workRam = new uint8_t [ _workRamSize ] ;
2016-01-24 11:18:50 -05:00
2019-06-22 16:33:59 -04:00
_console - > InitializeRam ( _saveRam , _saveRamSize ) ;
_console - > InitializeRam ( _workRam , _workRamSize ) ;
2016-01-24 11:18:50 -05:00
2019-01-09 20:19:16 -05:00
_nametableCount = 2 ;
_nametableRam = new uint8_t [ BaseMapper : : NametableSize * BaseMapper : : NametableCount ] ;
2019-06-22 16:33:59 -04:00
_console - > InitializeRam ( _nametableRam , BaseMapper : : NametableSize * BaseMapper : : NametableCount ) ;
2016-01-24 11:18:50 -05:00
2019-01-09 20:19:16 -05:00
for ( int i = 0 ; i < 0x100 ; i + + ) {
2016-01-24 11:18:50 -05:00
//Allow us to map a different page every 256 bytes
2017-03-31 22:14:16 -04:00
_prgPages [ i ] = nullptr ;
2018-08-19 13:53:20 -04:00
_prgMemoryOffset [ i ] = - 1 ;
_prgMemoryType [ i ] = PrgMemoryType : : PrgRom ;
_prgMemoryAccess [ i ] = MemoryAccessType : : NoAccess ;
2019-01-09 20:19:16 -05:00
_chrPages [ i ] = nullptr ;
2018-08-19 13:53:20 -04:00
_chrMemoryOffset [ i ] = - 1 ;
_chrMemoryType [ i ] = ChrMemoryType : : Default ;
_chrMemoryAccess [ i ] = MemoryAccessType : : NoAccess ;
}
2016-01-24 11:18:50 -05:00
if ( _chrRomSize = = 0 ) {
//Assume there is CHR RAM if no CHR ROM exists
_onlyChrRam = true ;
2016-06-12 13:53:41 -04:00
InitializeChrRam ( romData . ChrRamSize ) ;
2016-06-13 22:46:01 -04:00
//Map CHR RAM to 0x0000-0x1FFF by default when no CHR ROM exists
SetPpuMemoryMapping ( 0x0000 , 0x1FFF , 0 , ChrMemoryType : : ChrRam ) ;
2016-01-24 11:18:50 -05:00
_chrRomSize = _chrRamSize ;
2016-06-12 13:53:41 -04:00
} else if ( romData . ChrRamSize > = 0 ) {
InitializeChrRam ( romData . ChrRamSize ) ;
2016-07-23 09:21:43 -04:00
} else if ( GetChrRamSize ( ) ) {
InitializeChrRam ( ) ;
2016-01-24 11:18:50 -05:00
}
2016-07-29 17:28:01 -04:00
2018-07-07 14:52:51 -04:00
if ( romData . Info . HasTrainer ) {
2017-04-29 14:08:42 -04:00
if ( _workRamSize > = 0x2000 ) {
memcpy ( _workRam + 0x1000 , romData . TrainerData . data ( ) , 512 ) ;
} else if ( _saveRamSize > = 0x2000 ) {
memcpy ( _saveRam + 0x1000 , romData . TrainerData . data ( ) , 512 ) ;
}
}
2018-06-17 11:28:41 -04:00
SetupDefaultWorkRam ( ) ;
2016-01-24 11:18:50 -05:00
2019-01-09 20:19:16 -05:00
SetMirroringType ( romData . Info . Mirroring ) ;
2016-01-24 11:18:50 -05:00
InitMapper ( ) ;
2016-01-28 20:47:16 -05:00
InitMapper ( romData ) ;
2021-07-30 14:21:56 +02:00
_epsmaudio . reset ( new EPSMAudio ( _console ) ) ;
2021-08-11 17:55:56 +08:00
_invA13Audio . reset ( new InvA13Audio ( _console ) ) ;
_invOE1Audio . reset ( new InvOE1Audio ( _console ) ) ;
2016-01-24 11:18:50 -05:00
2019-01-09 20:53:51 -05:00
//Load battery data if present
LoadBattery ( ) ;
2018-07-07 14:52:51 -04:00
_romInfo . HasChrRam = HasChrRam ( ) ;
2016-01-24 11:18:50 -05:00
}
BaseMapper : : ~ BaseMapper ( )
{
delete [ ] _chrRam ;
delete [ ] _chrRom ;
delete [ ] _prgRom ;
delete [ ] _saveRam ;
delete [ ] _workRam ;
2019-01-09 20:19:16 -05:00
delete [ ] _nametableRam ;
2016-01-24 11:18:50 -05:00
}
void BaseMapper : : GetMemoryRanges ( MemoryRanges & ranges )
{
2018-07-07 14:52:51 -04:00
if ( _romInfo . System = = GameSystem : : VsSystem ) {
2016-04-30 20:08:53 -04:00
ranges . AddHandler ( MemoryOperation : : Read , 0x6000 , 0xFFFF ) ;
ranges . AddHandler ( MemoryOperation : : Write , 0x6000 , 0xFFFF ) ;
} else {
ranges . AddHandler ( MemoryOperation : : Read , 0x4018 , 0xFFFF ) ;
ranges . AddHandler ( MemoryOperation : : Write , 0x4018 , 0xFFFF ) ;
}
2016-01-24 11:18:50 -05:00
}
2018-07-01 15:21:05 -04:00
void BaseMapper : : SetConsole ( shared_ptr < Console > console )
2018-06-25 12:58:01 -04:00
{
2018-07-01 15:21:05 -04:00
_console = console ;
2018-06-25 12:58:01 -04:00
}
2019-01-09 20:19:16 -05:00
uint8_t * BaseMapper : : GetNametable ( uint8_t nametableIndex )
2016-01-24 11:18:50 -05:00
{
2019-01-09 20:19:16 -05:00
if ( nametableIndex > = BaseMapper : : NametableCount ) {
# ifdef _DEBUG
MessageManager : : Log ( " Invalid nametable index " ) ;
# endif
return _nametableRam ;
2016-01-24 11:18:50 -05:00
}
2019-01-13 19:04:43 -05:00
_nametableCount = std : : max < uint8_t > ( _nametableCount , nametableIndex + 1 ) ;
2019-01-09 20:19:16 -05:00
return _nametableRam + ( nametableIndex * BaseMapper : : NametableSize ) ;
2016-01-24 11:18:50 -05:00
}
void BaseMapper : : SetNametable ( uint8_t index , uint8_t nametableIndex )
{
2019-01-09 20:19:16 -05:00
if ( nametableIndex > = BaseMapper : : NametableCount ) {
# ifdef _DEBUG
MessageManager : : Log ( " Invalid nametable index " ) ;
# endif
return ;
2016-01-24 11:18:50 -05:00
}
2019-01-13 19:04:43 -05:00
_nametableCount = std : : max < uint8_t > ( _nametableCount , nametableIndex + 1 ) ;
2016-01-24 11:18:50 -05:00
2019-01-09 20:19:16 -05:00
SetPpuMemoryMapping ( 0x2000 + index * 0x400 , 0x2000 + ( index + 1 ) * 0x400 - 1 , nametableIndex , ChrMemoryType : : NametableRam ) ;
2018-06-02 22:12:00 -04:00
//Mirror $2000-$2FFF to $3000-$3FFF, while keeping a distinction between the addresses
//Previously, $3000-$3FFF was being "redirected" to $2000-$2FFF to avoid MMC3 IRQ issues (which is incorrect)
//More info here: https://forums.nesdev.com/viewtopic.php?p=132145#p132145
2019-01-09 20:19:16 -05:00
SetPpuMemoryMapping ( 0x3000 + index * 0x400 , 0x3000 + ( index + 1 ) * 0x400 - 1 , nametableIndex , ChrMemoryType : : NametableRam ) ;
2016-01-24 11:18:50 -05:00
}
void BaseMapper : : SetNametables ( uint8_t nametable1Index , uint8_t nametable2Index , uint8_t nametable3Index , uint8_t nametable4Index )
{
SetNametable ( 0 , nametable1Index ) ;
SetNametable ( 1 , nametable2Index ) ;
SetNametable ( 2 , nametable3Index ) ;
SetNametable ( 3 , nametable4Index ) ;
}
void BaseMapper : : SetMirroringType ( MirroringType type )
{
_mirroringType = type ;
switch ( type ) {
case MirroringType : : Vertical : SetNametables ( 0 , 1 , 0 , 1 ) ; break ;
case MirroringType : : Horizontal : SetNametables ( 0 , 0 , 1 , 1 ) ; break ;
case MirroringType : : FourScreens : SetNametables ( 0 , 1 , 2 , 3 ) ; break ;
case MirroringType : : ScreenAOnly : SetNametables ( 0 , 0 , 0 , 0 ) ; break ;
case MirroringType : : ScreenBOnly : SetNametables ( 1 , 1 , 1 , 1 ) ; break ;
}
}
2017-11-19 23:08:23 -05:00
ConsoleFeatures BaseMapper : : GetAvailableFeatures ( )
{
return ConsoleFeatures : : None ;
}
shared_ptr < BaseControlDevice > BaseMapper : : GetMapperControlDevice ( )
{
return _mapperControlDevice ;
}
2018-07-07 14:52:51 -04:00
RomInfo BaseMapper : : GetRomInfo ( )
2018-03-20 22:05:38 -04:00
{
2020-02-23 13:00:39 -05:00
RomInfo romInfo = _romInfo ;
romInfo . BusConflicts = _hasBusConflicts ? BusConflictType : : Yes : BusConflictType : : No ;
return romInfo ;
2016-01-28 20:47:16 -05:00
}
2019-02-08 19:39:35 -05:00
uint32_t BaseMapper : : GetMapperDipSwitchCount ( )
{
return GetDipSwitchCount ( ) ;
}
2016-01-24 11:18:50 -05:00
MirroringType BaseMapper : : GetMirroringType ( )
{
return _mirroringType ;
}
uint8_t BaseMapper : : ReadRAM ( uint16_t addr )
{
2016-06-11 13:18:47 -04:00
if ( _allowRegisterRead & & _isReadRegisterAddr [ addr ] ) {
2016-01-24 11:18:50 -05:00
return ReadRegister ( addr ) ;
2019-01-09 20:19:16 -05:00
} else if ( _prgMemoryAccess [ addr > > 8 ] & MemoryAccessType : : Read ) {
2017-03-31 22:14:16 -04:00
return _prgPages [ addr > > 8 ] [ ( uint8_t ) addr ] ;
2016-01-24 11:18:50 -05:00
} else {
//assert(false);
}
2018-07-01 15:21:05 -04:00
return _console - > GetMemoryManager ( ) - > GetOpenBus ( ) ;
2016-01-24 11:18:50 -05:00
}
2018-12-24 23:31:32 -05:00
uint8_t BaseMapper : : PeekRAM ( uint16_t addr )
{
return DebugReadRAM ( addr ) ;
}
2017-08-30 18:31:27 -04:00
uint8_t BaseMapper : : DebugReadRAM ( uint16_t addr )
{
2019-01-09 20:19:16 -05:00
if ( _prgMemoryAccess [ addr > > 8 ] & MemoryAccessType : : Read ) {
2017-08-30 18:31:27 -04:00
return _prgPages [ addr > > 8 ] [ ( uint8_t ) addr ] ;
} else {
//assert(false);
}
2017-12-26 17:33:46 -05:00
//Fake open bus
return addr > > 8 ;
2017-08-30 18:31:27 -04:00
}
2016-01-24 11:18:50 -05:00
void BaseMapper : : WriteRAM ( uint16_t addr , uint8_t value )
{
2021-07-30 14:21:56 +02:00
if ( ( addr = = 0x4016 ) & ( _console - > GetCpu ( ) - > GetCycleCount ( ) % 2 = = 1 ) ) { WriteEPSM ( addr , value ) ; }
2021-08-26 15:03:02 +02:00
if ( ( addr > = 0x401c & & addr < = 0x401f ) ) { WriteEPSM ( addr , value ) ; }
2016-06-11 13:18:47 -04:00
if ( _isWriteRegisterAddr [ addr ] ) {
2016-01-24 11:18:50 -05:00
if ( _hasBusConflicts ) {
2019-12-12 20:55:18 -05:00
uint8_t prgValue = _prgPages [ addr > > 8 ] [ ( uint8_t ) addr ] ;
if ( value ! = prgValue ) {
_console - > DebugProcessEvent ( EventType : : BusConflict ) ;
}
value & = prgValue ;
2016-01-24 11:18:50 -05:00
}
WriteRegister ( addr , value ) ;
} else {
WritePrgRam ( addr , value ) ;
}
}
2017-08-30 18:31:27 -04:00
void BaseMapper : : DebugWriteRAM ( uint16_t addr , uint8_t value )
{
if ( _isWriteRegisterAddr [ addr ] ) {
if ( _hasBusConflicts ) {
value & = _prgPages [ addr > > 8 ] [ ( uint8_t ) addr ] ;
}
} else {
WritePrgRam ( addr , value ) ;
}
}
2016-01-24 11:18:50 -05:00
void BaseMapper : : WritePrgRam ( uint16_t addr , uint8_t value )
{
2019-01-09 20:19:16 -05:00
if ( _prgMemoryAccess [ addr > > 8 ] & MemoryAccessType : : Write ) {
2017-03-31 22:14:16 -04:00
_prgPages [ addr > > 8 ] [ ( uint8_t ) addr ] = value ;
2016-01-24 11:18:50 -05:00
}
}
2016-11-13 22:38:06 -05:00
2017-03-31 22:14:16 -04:00
void BaseMapper : : NotifyVRAMAddressChange ( uint16_t addr )
{
//This is called when the VRAM addr on the PPU memory bus changes
//Used by MMC3/MMC5/etc
}
2016-11-13 22:38:06 -05:00
uint8_t BaseMapper : : InternalReadVRAM ( uint16_t addr )
2016-01-24 11:18:50 -05:00
{
2019-01-09 20:19:16 -05:00
if ( _chrMemoryAccess [ addr > > 8 ] & MemoryAccessType : : Read ) {
2017-03-31 22:14:16 -04:00
return _chrPages [ addr > > 8 ] [ ( uint8_t ) addr ] ;
2016-01-24 11:18:50 -05:00
}
2017-05-25 20:04:49 -04:00
//Open bus - "When CHR is disabled, the pattern tables are open bus. Theoretically, this should return the LSB of the address read, but real-world behavior varies."
return _vramOpenBusValue > = 0 ? _vramOpenBusValue : addr ;
2016-01-24 11:18:50 -05:00
}
2017-10-07 13:31:28 -04:00
uint8_t BaseMapper : : DebugReadVRAM ( uint16_t addr , bool disableSideEffects )
2017-03-04 21:50:19 -05:00
{
2018-06-02 22:12:00 -04:00
addr & = 0x3FFF ;
2017-10-07 13:31:28 -04:00
if ( ! disableSideEffects ) {
NotifyVRAMAddressChange ( addr ) ;
}
2017-03-31 22:14:16 -04:00
return InternalReadVRAM ( addr ) ;
2017-03-04 21:50:19 -05:00
}
2017-03-31 22:14:16 -04:00
uint8_t BaseMapper : : MapperReadVRAM ( uint16_t addr , MemoryOperationType operationType )
2016-11-13 22:38:06 -05:00
{
return InternalReadVRAM ( addr ) ;
}
2017-10-07 13:31:28 -04:00
void BaseMapper : : DebugWriteVRAM ( uint16_t addr , uint8_t value , bool disableSideEffects )
2016-01-24 11:18:50 -05:00
{
2018-06-02 22:12:00 -04:00
addr & = 0x3FFF ;
2017-11-11 12:35:39 -05:00
if ( disableSideEffects ) {
if ( _chrPages [ addr > > 8 ] ) {
//Always allow writes when side-effects are disabled
_chrPages [ addr > > 8 ] [ ( uint8_t ) addr ] = value ;
}
} else {
2017-10-07 13:31:28 -04:00
NotifyVRAMAddressChange ( addr ) ;
2019-01-09 20:19:16 -05:00
if ( _chrMemoryAccess [ addr > > 8 ] & MemoryAccessType : : Write ) {
2017-11-11 12:35:39 -05:00
_chrPages [ addr > > 8 ] [ ( uint8_t ) addr ] = value ;
}
2016-01-24 11:18:50 -05:00
}
}
2017-03-31 22:14:16 -04:00
void BaseMapper : : WriteVRAM ( uint16_t addr , uint8_t value )
2016-01-24 11:18:50 -05:00
{
2018-07-01 15:21:05 -04:00
_console - > DebugProcessVramWriteOperation ( addr , value ) ;
2017-03-31 22:14:16 -04:00
2019-01-09 20:19:16 -05:00
if ( _chrMemoryAccess [ addr > > 8 ] & MemoryAccessType : : Write ) {
2017-03-31 22:14:16 -04:00
_chrPages [ addr > > 8 ] [ ( uint8_t ) addr ] = value ;
}
2016-01-24 11:18:50 -05:00
}
2016-07-26 19:19:28 -04:00
bool BaseMapper : : IsNes20 ( )
{
2018-07-07 14:52:51 -04:00
return _romInfo . NesHeader . GetRomHeaderVersion ( ) = = RomHeaderVersion : : Nes2_0 ;
2016-07-26 19:19:28 -04:00
}
2016-01-24 11:18:50 -05:00
//Debugger Helper Functions
2016-02-13 22:19:42 -05:00
uint8_t * BaseMapper : : GetPrgRom ( )
{
return _prgRom ;
}
2017-03-15 19:19:41 -04:00
uint8_t * BaseMapper : : GetSaveRam ( )
{
return _saveRam ;
}
2016-02-13 22:19:42 -05:00
uint8_t * BaseMapper : : GetWorkRam ( )
{
return _workRam ;
}
2016-09-05 09:05:34 -04:00
uint32_t BaseMapper : : CopyMemory ( DebugMemoryType type , uint8_t * buffer )
2016-01-24 11:18:50 -05:00
{
2019-01-13 19:04:43 -05:00
uint32_t size = GetMemorySize ( type ) ;
2016-09-05 09:05:34 -04:00
switch ( type ) {
2018-06-25 15:56:05 -04:00
default : break ;
2019-01-13 19:04:43 -05:00
case DebugMemoryType : : ChrRam : memcpy ( buffer , _chrRam , size ) ; break ;
case DebugMemoryType : : ChrRom : memcpy ( buffer , _chrRom , size ) ; break ;
case DebugMemoryType : : NametableRam : memcpy ( buffer , _nametableRam , size ) ; break ;
case DebugMemoryType : : SaveRam : memcpy ( buffer , _saveRam , size ) ; break ;
case DebugMemoryType : : PrgRom : memcpy ( buffer , _prgRom , size ) ; break ;
case DebugMemoryType : : WorkRam : memcpy ( buffer , _workRam , size ) ; break ;
2016-09-05 09:05:34 -04:00
}
2019-01-13 19:04:43 -05:00
return size ;
2016-01-24 11:18:50 -05:00
}
2019-01-13 19:15:37 -05:00
void BaseMapper : : WriteMemory ( DebugMemoryType type , uint8_t * buffer , int32_t length )
2016-01-24 11:18:50 -05:00
{
2019-01-13 19:15:37 -05:00
int32_t size = std : : min ( length , ( int32_t ) GetMemorySize ( type ) ) ;
2016-09-05 09:05:34 -04:00
switch ( type ) {
2018-06-25 15:56:05 -04:00
default : break ;
2019-01-13 19:04:43 -05:00
case DebugMemoryType : : ChrRam : memcpy ( _chrRam , buffer , size ) ; break ;
case DebugMemoryType : : SaveRam : memcpy ( _saveRam , buffer , size ) ; break ;
case DebugMemoryType : : WorkRam : memcpy ( _workRam , buffer , size ) ; break ;
case DebugMemoryType : : NametableRam : memcpy ( _nametableRam , buffer , size ) ; break ;
2016-09-05 09:05:34 -04:00
}
2016-01-24 11:18:50 -05:00
}
2016-12-01 19:38:48 -05:00
uint32_t BaseMapper : : GetMemorySize ( DebugMemoryType type )
2016-01-24 11:18:50 -05:00
{
2016-12-01 19:38:48 -05:00
switch ( type ) {
default : return 0 ;
2017-02-26 20:47:39 -05:00
case DebugMemoryType : : ChrRom : return _onlyChrRam ? 0 : _chrRomSize ;
2016-12-01 19:38:48 -05:00
case DebugMemoryType : : ChrRam : return _chrRamSize ;
2019-01-13 18:32:27 -05:00
case DebugMemoryType : : NametableRam : return _nametableCount * BaseMapper : : NametableSize ;
2016-12-01 19:38:48 -05:00
case DebugMemoryType : : SaveRam : return _saveRamSize ;
case DebugMemoryType : : PrgRom : return _prgSize ;
case DebugMemoryType : : WorkRam : return _workRamSize ;
2017-02-26 20:47:39 -05:00
}
}
2018-09-07 21:30:00 -04:00
void BaseMapper : : CopyChrTile ( uint32_t address , uint8_t * dest )
2017-12-18 20:02:25 -05:00
{
2018-09-07 21:30:00 -04:00
if ( _chrRamSize > 0 & & address < = _chrRamSize - 16 ) {
2017-12-18 20:02:25 -05:00
memcpy ( dest , _chrRam + address , 16 ) ;
2018-09-07 21:30:00 -04:00
} else if ( _chrRomSize > 0 & & address < = _chrRomSize - 16 ) {
memcpy ( dest , _chrRom + address , 16 ) ;
2017-12-18 20:02:25 -05:00
}
}
2017-03-04 21:50:19 -05:00
uint8_t BaseMapper : : GetMemoryValue ( DebugMemoryType memoryType , uint32_t address )
{
2017-11-11 13:24:48 -05:00
uint32_t memorySize = GetMemorySize ( memoryType ) ;
if ( memorySize > 0 ) {
if ( address > memorySize ) {
address % = memorySize ;
}
2017-03-04 21:50:19 -05:00
2017-11-11 13:24:48 -05:00
switch ( memoryType ) {
2018-06-25 15:56:05 -04:00
default : break ;
2017-11-11 13:24:48 -05:00
case DebugMemoryType : : ChrRom : return _chrRom [ address ] ;
case DebugMemoryType : : ChrRam : return _chrRam [ address ] ;
case DebugMemoryType : : SaveRam : return _saveRam [ address ] ;
case DebugMemoryType : : PrgRom : return _prgRom [ address ] ;
case DebugMemoryType : : WorkRam : return _workRam [ address ] ;
2019-01-13 19:04:43 -05:00
case DebugMemoryType : : NametableRam : return _nametableRam [ address ] ;
2017-11-11 13:24:48 -05:00
}
}
2017-03-04 21:50:19 -05:00
return 0 ;
}
2017-02-26 20:47:39 -05:00
void BaseMapper : : SetMemoryValue ( DebugMemoryType memoryType , uint32_t address , uint8_t value )
{
2017-11-11 13:24:48 -05:00
uint32_t memorySize = GetMemorySize ( memoryType ) ;
if ( memorySize > 0 ) {
if ( address > memorySize ) {
address % = memorySize ;
}
switch ( memoryType ) {
2018-06-25 15:56:05 -04:00
default : break ;
2017-11-11 13:24:48 -05:00
case DebugMemoryType : : ChrRom : _chrRom [ address ] = value ; break ;
case DebugMemoryType : : ChrRam : _chrRam [ address ] = value ; break ;
case DebugMemoryType : : SaveRam : _saveRam [ address ] = value ; break ;
case DebugMemoryType : : PrgRom : _prgRom [ address ] = value ; break ;
case DebugMemoryType : : WorkRam : _workRam [ address ] = value ; break ;
2019-01-13 19:04:43 -05:00
case DebugMemoryType : : NametableRam : _nametableRam [ address ] = value ; break ;
2017-11-11 13:24:48 -05:00
}
2017-02-26 20:47:39 -05:00
}
2016-01-24 11:18:50 -05:00
}
2018-12-24 21:22:08 -05:00
void BaseMapper : : GetAbsoluteAddressAndType ( uint32_t relativeAddr , AddressTypeInfo * info )
{
if ( relativeAddr < 0x2000 ) {
2020-02-14 21:40:50 -05:00
info - > Address = relativeAddr & 0x7FF ;
2018-12-24 21:22:08 -05:00
info - > Type = AddressType : : InternalRam ;
} else {
uint8_t * prgAddr = _prgPages [ relativeAddr > > 8 ] + ( uint8_t ) relativeAddr ;
if ( prgAddr > = _prgRom & & prgAddr < _prgRom + _prgSize ) {
info - > Address = ( uint32_t ) ( prgAddr - _prgRom ) ;
info - > Type = AddressType : : PrgRom ;
} else if ( prgAddr > = _workRam & & prgAddr < _workRam + _workRamSize ) {
info - > Address = ( uint32_t ) ( prgAddr - _workRam ) ;
info - > Type = AddressType : : WorkRam ;
} else if ( prgAddr > = _saveRam & & prgAddr < _saveRam + _saveRamSize ) {
info - > Address = ( uint32_t ) ( prgAddr - _saveRam ) ;
info - > Type = AddressType : : SaveRam ;
} else {
info - > Address = - 1 ;
info - > Type = AddressType : : InternalRam ;
}
}
}
2016-01-24 11:18:50 -05:00
int32_t BaseMapper : : ToAbsoluteAddress ( uint16_t addr )
{
2017-03-31 22:14:16 -04:00
uint8_t * prgAddr = _prgPages [ addr > > 8 ] + ( uint8_t ) addr ;
2016-01-24 11:18:50 -05:00
if ( prgAddr > = _prgRom & & prgAddr < _prgRom + _prgSize ) {
return ( uint32_t ) ( prgAddr - _prgRom ) ;
}
return - 1 ;
}
2016-11-22 22:38:14 -05:00
int32_t BaseMapper : : ToAbsoluteWorkRamAddress ( uint16_t addr )
2016-02-13 22:19:42 -05:00
{
2017-03-31 22:14:16 -04:00
uint8_t * prgRamAddr = _prgPages [ addr > > 8 ] + ( uint8_t ) addr ;
2016-07-26 19:19:28 -04:00
if ( prgRamAddr > = _workRam & & prgRamAddr < _workRam + _workRamSize ) {
2016-02-13 22:19:42 -05:00
return ( uint32_t ) ( prgRamAddr - _workRam ) ;
}
return - 1 ;
}
2016-11-22 22:38:14 -05:00
int32_t BaseMapper : : ToAbsoluteSaveRamAddress ( uint16_t addr )
{
2017-03-31 22:14:16 -04:00
uint8_t * prgRamAddr = _prgPages [ addr > > 8 ] + ( uint8_t ) addr ;
2016-11-22 22:38:14 -05:00
if ( prgRamAddr > = _saveRam & & prgRamAddr < _saveRam + _saveRamSize ) {
return ( uint32_t ) ( prgRamAddr - _saveRam ) ;
}
return - 1 ;
}
2019-01-13 18:32:27 -05:00
void BaseMapper : : GetPpuAbsoluteAddressAndType ( uint32_t relativeAddr , PpuAddressTypeInfo * info )
{
if ( relativeAddr > = 0x3F00 ) {
info - > Address = relativeAddr & 0x1F ;
info - > Type = PpuAddressType : : PaletteRam ;
} else {
uint8_t * addr = _chrPages [ relativeAddr > > 8 ] + ( uint8_t ) relativeAddr ;
if ( addr > = _chrRom & & addr < _chrRom + _chrRomSize ) {
info - > Address = ( uint32_t ) ( addr - _chrRom ) ;
info - > Type = PpuAddressType : : ChrRom ;
} else if ( addr > = _chrRam & & addr < _chrRam + _chrRamSize ) {
info - > Address = ( uint32_t ) ( addr - _chrRam ) ;
info - > Type = PpuAddressType : : ChrRam ;
} else if ( addr > = _nametableRam & & addr < _nametableRam + BaseMapper : : NametableSize * BaseMapper : : NametableCount ) {
info - > Address = ( uint32_t ) ( addr - _nametableRam ) ;
info - > Type = PpuAddressType : : NametableRam ;
} else {
info - > Address = - 1 ;
info - > Type = PpuAddressType : : None ;
}
}
}
2016-01-24 11:18:50 -05:00
int32_t BaseMapper : : ToAbsoluteChrAddress ( uint16_t addr )
{
2017-03-31 22:14:16 -04:00
uint8_t * chrAddr = _chrPages [ addr > > 8 ] + ( uint8_t ) addr ;
2016-01-24 11:18:50 -05:00
if ( chrAddr > = _chrRom & & chrAddr < _chrRom + _chrRomSize ) {
return ( uint32_t ) ( chrAddr - _chrRom ) ;
}
2017-06-28 19:00:08 -04:00
if ( chrAddr > = _chrRam & & chrAddr < _chrRam + _chrRamSize ) {
return ( uint32_t ) ( chrAddr - _chrRam ) ;
}
2016-01-24 11:18:50 -05:00
return - 1 ;
}
2018-02-10 21:23:22 -05:00
int32_t BaseMapper : : ToAbsoluteChrRamAddress ( uint16_t addr )
{
uint8_t * chrAddr = _chrPages [ addr > > 8 ] + ( uint8_t ) addr ;
if ( chrAddr > = _chrRam & & chrAddr < _chrRam + _chrRamSize ) {
return ( uint32_t ) ( chrAddr - _chrRam ) ;
}
return - 1 ;
}
int32_t BaseMapper : : ToAbsoluteChrRomAddress ( uint16_t addr )
{
uint8_t * chrAddr = _chrPages [ addr > > 8 ] + ( uint8_t ) addr ;
if ( chrAddr > = _chrRom & & chrAddr < _chrRom + _chrRomSize ) {
return ( uint32_t ) ( chrAddr - _chrRom ) ;
}
return - 1 ;
}
2017-12-31 17:22:54 -05:00
int32_t BaseMapper : : FromAbsoluteChrAddress ( uint32_t addr )
{
uint8_t * ptrAddress = ( _onlyChrRam ? _chrRam : _chrRom ) + ( addr & 0x3FFF ) ;
for ( int i = 0 ; i < 64 ; i + + ) {
uint8_t * pageAddress = _chrPages [ i ] ;
if ( pageAddress ! = nullptr & & ptrAddress > = pageAddress & & ptrAddress < = pageAddress + 0xFF ) {
return ( i < < 8 ) + ( uint32_t ) ( ptrAddress - pageAddress ) ;
}
}
//Address is currently not mapped
return - 1 ;
}
2016-11-22 22:38:14 -05:00
int32_t BaseMapper : : FromAbsoluteAddress ( uint32_t addr , AddressType type )
2016-01-24 11:18:50 -05:00
{
2016-11-22 22:38:14 -05:00
uint8_t * ptrAddress ;
switch ( type ) {
case AddressType : : PrgRom : ptrAddress = _prgRom ; break ;
case AddressType : : WorkRam : ptrAddress = _workRam ; break ;
case AddressType : : SaveRam : ptrAddress = _saveRam ; break ;
2016-12-03 10:46:59 -05:00
case AddressType : : Register : return addr & 0xFFFF ; break ;
case AddressType : : InternalRam : return addr & 0x1FFF ; break ;
2016-11-22 22:38:14 -05:00
default : return - 1 ;
}
ptrAddress + = addr ;
2016-01-24 11:18:50 -05:00
for ( int i = 0 ; i < 256 ; i + + ) {
uint8_t * pageAddress = _prgPages [ i ] ;
if ( pageAddress ! = nullptr & & ptrAddress > = pageAddress & & ptrAddress < = pageAddress + 0xFF ) {
return ( i < < 8 ) + ( uint32_t ) ( ptrAddress - pageAddress ) ;
}
}
2016-11-22 22:38:14 -05:00
2016-01-24 11:18:50 -05:00
//Address is currently not mapped
return - 1 ;
2016-09-04 18:08:16 -04:00
}
2019-01-14 19:01:13 -05:00
int32_t BaseMapper : : FromAbsolutePpuAddress ( uint32_t addr , PpuAddressType type )
{
uint8_t * ptrAddress ;
switch ( type ) {
case PpuAddressType : : ChrRom : ptrAddress = _chrRom ; break ;
case PpuAddressType : : ChrRam : ptrAddress = _chrRam ; break ;
case PpuAddressType : : NametableRam : ptrAddress = _nametableRam ; break ;
default : return - 1 ;
}
ptrAddress + = addr ;
for ( int i = 0 ; i < 0x40 ; i + + ) {
uint8_t * pageAddress = _chrPages [ i ] ;
if ( pageAddress ! = nullptr & & ptrAddress > = pageAddress & & ptrAddress < = pageAddress + 0xFF ) {
return ( i < < 8 ) + ( uint32_t ) ( ptrAddress - pageAddress ) ;
}
}
//Address is currently not mapped
return - 1 ;
}
2018-02-18 22:41:50 -05:00
bool BaseMapper : : IsWriteRegister ( uint16_t addr )
{
return _isWriteRegisterAddr [ addr ] ;
}
bool BaseMapper : : IsReadRegister ( uint16_t addr )
{
return _allowRegisterRead & & _isReadRegisterAddr [ addr ] ;
}
2016-09-04 18:08:16 -04:00
CartridgeState BaseMapper : : GetState ( )
{
CartridgeState state ;
2018-02-16 20:33:48 -05:00
state . Mirroring = _mirroringType ;
2018-08-19 13:53:20 -04:00
state . HasBattery = _romInfo . HasBattery ;
2018-02-16 20:33:48 -05:00
2016-09-05 12:09:14 -04:00
state . PrgRomSize = _prgSize ;
2016-09-05 16:34:01 -04:00
state . ChrRomSize = _onlyChrRam ? 0 : _chrRomSize ;
2016-09-05 12:09:14 -04:00
state . ChrRamSize = _chrRamSize ;
2016-09-04 18:08:16 -04:00
state . PrgPageCount = GetPRGPageCount ( ) ;
state . PrgPageSize = InternalGetPrgPageSize ( ) ;
state . ChrPageCount = GetCHRPageCount ( ) ;
state . ChrPageSize = InternalGetChrPageSize ( ) ;
2019-11-23 21:23:35 -05:00
state . ChrRamPageSize = _onlyChrRam ? InternalGetChrPageSize ( ) : InternalGetChrRamPageSize ( ) ;
2018-08-19 13:53:20 -04:00
for ( int i = 0 ; i < 0x100 ; i + + ) {
state . PrgMemoryOffset [ i ] = _prgMemoryOffset [ i ] ;
2018-08-20 19:25:02 -04:00
state . PrgType [ i ] = _prgMemoryType [ i ] ;
2018-08-19 13:53:20 -04:00
state . PrgMemoryAccess [ i ] = _prgMemoryAccess [ i ] ;
2016-09-04 18:08:16 -04:00
}
2018-08-19 13:53:20 -04:00
for ( int i = 0 ; i < 0x40 ; i + + ) {
state . ChrMemoryOffset [ i ] = _chrMemoryOffset [ i ] ;
2018-08-20 19:25:02 -04:00
state . ChrType [ i ] = _chrMemoryType [ i ] ;
2018-08-19 13:53:20 -04:00
state . ChrMemoryAccess [ i ] = _chrMemoryAccess [ i ] ;
2016-09-04 18:08:16 -04:00
}
2018-08-19 13:53:20 -04:00
state . WorkRamPageSize = GetWorkRamPageSize ( ) ;
state . SaveRamPageSize = GetSaveRamPageSize ( ) ;
2016-09-04 18:08:16 -04:00
return state ;
2017-03-04 22:24:41 -05:00
}
2018-01-01 12:09:33 -05:00
void BaseMapper : : GetRomFileData ( vector < uint8_t > & out , bool asIpsFile , uint8_t * header )
2017-03-04 22:24:41 -05:00
{
2018-01-01 12:09:33 -05:00
if ( header ) {
//Get original rom with edited header
2017-08-19 19:40:02 -04:00
vector < uint8_t > originalFile ;
2018-07-01 15:21:05 -04:00
_console - > GetRomPath ( ) . ReadFile ( originalFile ) ;
2018-01-01 12:09:33 -05:00
out . insert ( out . end ( ) , header , header + sizeof ( NESHeader ) ) ;
2018-08-13 18:35:56 -04:00
if ( _romInfo . IsHeaderlessRom ) {
out . insert ( out . end ( ) , originalFile . begin ( ) , originalFile . end ( ) ) ;
} else {
out . insert ( out . end ( ) , originalFile . begin ( ) + sizeof ( NESHeader ) , originalFile . end ( ) ) ;
}
2018-01-01 12:09:33 -05:00
} else {
vector < uint8_t > newFile ;
2018-07-07 14:52:51 -04:00
newFile . insert ( newFile . end ( ) , ( uint8_t * ) & _romInfo . NesHeader , ( ( uint8_t * ) & _romInfo . NesHeader ) + sizeof ( NESHeader ) ) ;
2018-01-01 12:09:33 -05:00
newFile . insert ( newFile . end ( ) , _prgRom , _prgRom + _prgSize ) ;
2018-01-01 13:37:52 -05:00
if ( HasChrRom ( ) ) {
newFile . insert ( newFile . end ( ) , _chrRom , _chrRom + _chrRomSize ) ;
}
2018-01-01 12:09:33 -05:00
//Get edited rom
if ( asIpsFile ) {
vector < uint8_t > originalFile ;
2018-07-01 15:21:05 -04:00
_console - > GetRomPath ( ) . ReadFile ( originalFile ) ;
2018-01-01 12:09:33 -05:00
vector < uint8_t > patchData = IpsPatcher : : CreatePatch ( originalFile , newFile ) ;
out . insert ( out . end ( ) , patchData . begin ( ) , patchData . end ( ) ) ;
2017-08-12 16:52:45 -04:00
} else {
2018-01-01 12:09:33 -05:00
out . insert ( out . end ( ) , newFile . begin ( ) , newFile . end ( ) ) ;
2017-08-12 16:52:45 -04:00
}
2017-03-04 22:24:41 -05:00
}
2017-08-21 23:11:14 -04:00
}
2018-02-24 14:23:54 -05:00
vector < uint8_t > BaseMapper : : GetPrgChrCopy ( )
{
vector < uint8_t > data ;
data . resize ( _prgSize + ( _onlyChrRam ? 0 : _chrRomSize ) ) ;
memcpy ( data . data ( ) , _prgRom , _prgSize ) ;
if ( ! _onlyChrRam ) {
memcpy ( data . data ( ) + _prgSize , _chrRom , _chrRomSize ) ;
}
return data ;
}
void BaseMapper : : RestorePrgChrBackup ( vector < uint8_t > & backupData )
{
memcpy ( _prgRom , backupData . data ( ) , _prgSize ) ;
if ( ! _onlyChrRam ) {
memcpy ( _chrRom , backupData . data ( ) + _prgSize , _chrRomSize ) ;
}
}
2017-08-21 23:11:14 -04:00
void BaseMapper : : RevertPrgChrChanges ( )
{
memcpy ( _prgRom , _originalPrgRom . data ( ) , _originalPrgRom . size ( ) ) ;
if ( _chrRom ) {
memcpy ( _chrRom , _originalChrRom . data ( ) , _originalChrRom . size ( ) ) ;
}
}
bool BaseMapper : : HasPrgChrChanges ( )
{
if ( memcmp ( _prgRom , _originalPrgRom . data ( ) , _originalPrgRom . size ( ) ) ! = 0 ) {
return true ;
}
if ( _chrRom ) {
if ( memcmp ( _chrRom , _originalChrRom . data ( ) , _originalChrRom . size ( ) ) ! = 0 ) {
return true ;
}
}
return false ;
2019-11-17 18:44:36 -05:00
}
void BaseMapper : : CopyPrgChrRom ( shared_ptr < BaseMapper > mapper )
{
if ( _prgSize = = mapper - > _prgSize & & _chrRomSize = = mapper - > _chrRomSize ) {
memcpy ( _prgRom , mapper - > _prgRom , _prgSize ) ;
if ( ! _onlyChrRam ) {
memcpy ( _chrRom , mapper - > _chrRom , _chrRomSize ) ;
}
}
2016-01-24 11:18:50 -05:00
}