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"
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 ) { }
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
void BaseMapper : : SetCpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr , int16_t pageNumber , PrgMemoryType type , int8_t accessType )
{
# ifdef _DEBUG
if ( ( startAddr & 0xFF ) | | ( endAddr & 0xFF ) ! = 0xFF ) {
throw new std : : runtime_error ( " Start/End address must be multiples of 256/0x100 " ) ;
}
# endif
uint8_t * source = nullptr ;
uint32_t pageCount ;
uint32_t pageSize ;
uint8_t defaultAccessType = MemoryAccessType : : Read ;
switch ( type ) {
case PrgMemoryType : : PrgRom :
source = _prgRom ;
pageCount = GetPRGPageCount ( ) ;
pageSize = InternalGetPrgPageSize ( ) ;
break ;
case PrgMemoryType : : SaveRam :
source = _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 :
source = _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 ) ;
uint8_t * sourceBuffer = & source [ pageNumber * pageSize ] ;
2016-01-24 11:18:50 -05:00
2016-06-25 20:46:54 -04:00
accessType = accessType ! = - 1 ? accessType : defaultAccessType ;
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 ) {
SetCpuMemoryMapping ( addr , addr + pageSize - 1 , sourceBuffer , accessType ) ;
addr + = pageSize ;
pageNumber + + ;
wrapPageNumber ( pageNumber ) ;
sourceBuffer = & source [ pageNumber * pageSize ] ;
2016-08-26 21:50:52 -04:00
}
} else {
2017-04-09 15:10:04 -04:00
SetCpuMemoryMapping ( startAddr , endAddr , sourceBuffer , accessType ) ;
2016-08-18 23:41:58 -04:00
}
2016-06-25 20:46:54 -04:00
}
void BaseMapper : : SetCpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr , uint8_t * source , int8_t accessType )
{
# ifdef _DEBUG
if ( ( startAddr & 0xFF ) | | ( endAddr & 0xFF ) ! = 0xFF ) {
throw new std : : runtime_error ( " Start/End address must be multiples of 256/0x100 " ) ;
}
# endif
2016-01-24 11:18:50 -05:00
startAddr > > = 8 ;
endAddr > > = 8 ;
for ( uint16_t i = startAddr ; i < = endAddr ; i + + ) {
_prgPages [ i ] = source ;
2016-06-25 20:46:54 -04:00
_prgPageAccessType [ i ] = accessType ! = - 1 ? 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)
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 )
{
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 * sourceMemory = nullptr ;
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
sourceMemory = _onlyChrRam ? _chrRam : _chrRom ;
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
sourceMemory = _chrRom ;
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 ;
sourceMemory = _chrRam ;
defaultAccessType | = MemoryAccessType : : Write ;
break ;
}
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
2017-04-09 15:10:04 -04:00
uint8_t * sourceBuffer = sourceMemory + pageNumber * pageSize ;
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 ) {
SetPpuMemoryMapping ( addr , addr + pageSize - 1 , sourceBuffer , accessType ) ;
addr + = pageSize ;
pageNumber = ( pageNumber + 1 ) % pageCount ;
sourceBuffer = & sourceMemory [ pageNumber * pageSize ] ;
2017-02-23 19:58:46 -05:00
}
} else {
2017-04-09 15:10:04 -04:00
SetPpuMemoryMapping ( startAddr , endAddr , sourceBuffer , accessType = = - 1 ? defaultAccessType : accessType ) ;
2017-02-23 19:58:46 -05:00
}
2016-01-24 11:18:50 -05:00
}
void BaseMapper : : SetPpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr , uint8_t * sourceMemory , int8_t accessType )
{
# ifdef _DEBUG
if ( ( startAddr & 0xFF ) | | ( endAddr & 0xFF ) ! = 0xFF ) {
throw new std : : runtime_error ( " Start/End address must be multiples of 256/0x100 " ) ;
}
# endif
startAddr > > = 8 ;
endAddr > > = 8 ;
for ( uint16_t i = startAddr ; i < = endAddr ; i + + ) {
_chrPages [ i ] = sourceMemory ;
_chrPageAccessType [ i ] = accessType ! = - 1 ? accessType : MemoryAccessType : : ReadWrite ;
if ( sourceMemory ! = nullptr ) {
sourceMemory + = 0x100 ;
}
}
}
void BaseMapper : : RemovePpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr )
{
//Unmap this section of memory (causing open bus behavior)
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 )
{
_prgPageNumbers [ slot ] = page ;
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 )
{
_chrPageNumbers [ slot ] = page ;
2016-11-06 12:00:45 -05:00
uint16_t pageSize = memoryType = = ChrMemoryType : : ChrRam ? InternalGetChrRamPageSize ( ) : InternalGetChrPageSize ( ) ;
uint16_t startAddr = slot * pageSize ;
uint16_t endAddr = startAddr + pageSize - 1 ;
2016-06-11 13:18:47 -04:00
if ( page = = ChrSpecialPage : : NametableA ) {
SetPpuMemoryMapping ( startAddr , endAddr , GetNametable ( 0 ) ) ;
} else if ( page = = ChrSpecialPage : : NametableB ) {
SetPpuMemoryMapping ( startAddr , endAddr , GetNametable ( 1 ) ) ;
} else {
SetPpuMemoryMapping ( startAddr , endAddr , page , memoryType ) ;
}
2016-01-24 11:18:50 -05:00
}
2016-08-24 20:48:14 -04:00
void BaseMapper : : InitializeRam ( void * data , uint32_t length )
{
switch ( EmulationSettings : : GetRamPowerOnState ( ) ) {
default :
case RamPowerOnState : : AllZeros : memset ( data , 0 , length ) ; break ;
case RamPowerOnState : : AllOnes : memset ( data , 0xFF , length ) ; break ;
case RamPowerOnState : : Random :
std : : random_device rd ;
std : : mt19937 mt ( rd ( ) ) ;
std : : uniform_int_distribution < > dist ( 0 , 255 ) ;
for ( uint32_t i = 0 ; i < length ; i + + ) {
( ( uint8_t * ) data ) [ i ] = dist ( mt ) ;
}
break ;
}
}
2018-04-14 22:12:05 -04:00
uint8_t BaseMapper : : GetPowerOnByte ( uint8_t defaultValue )
{
if ( EmulationSettings : : CheckFlag ( EmulationFlags : : RandomizeMapperPowerOnState ) ) {
std : : random_device rd ;
std : : mt19937 mt ( rd ( ) ) ;
std : : uniform_int_distribution < > dist ( 0 , 255 ) ;
return dist ( mt ) ;
} else {
return defaultValue ;
}
}
2016-01-24 11:18:50 -05:00
bool BaseMapper : : HasBattery ( )
{
return _hasBattery ;
}
void BaseMapper : : LoadBattery ( )
{
2018-03-15 23:57:35 -04:00
if ( HasBattery ( ) & & _saveRamSize > 0 ) {
2017-11-19 23:08:23 -05:00
BatteryManager : : LoadBattery ( " .sav " , _saveRam , _saveRamSize ) ;
2016-01-24 11:18:50 -05:00
}
2018-03-15 23:57:35 -04:00
if ( _hasChrBattery & & _chrRamSize > 0 ) {
2017-11-19 23:08:23 -05:00
BatteryManager : : 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 ) {
2017-11-19 23:08:23 -05:00
BatteryManager : : 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 ) {
2017-11-19 23:08:23 -05:00
BatteryManager : : 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 ( )
{
return _prgSize / InternalGetPrgPageSize ( ) ;
}
uint32_t BaseMapper : : GetCHRPageCount ( )
{
return _chrRomSize / InternalGetChrPageSize ( ) ;
}
string BaseMapper : : GetBatteryFilename ( )
{
2016-12-13 22:44:52 -05:00
return FolderUtilities : : CombinePath ( FolderUtilities : : GetSaveFolder ( ) , FolderUtilities : : GetFilename ( _romName , false ) + " .sav " ) ;
2016-01-24 11:18:50 -05:00
}
void BaseMapper : : RestoreOriginalPrgRam ( )
{
2016-01-28 20:47:16 -05:00
memcpy ( _prgRom , _originalPrgRom . data ( ) , _originalPrgRom . size ( ) ) ;
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 ] ;
2017-02-23 20:01:48 -05:00
BaseMapper : : 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 )
{
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 } ;
ArrayInfo < uint32_t > prgPageNumbers = { _prgPageNumbers , 64 } ;
ArrayInfo < uint32_t > chrPageNumbers = { _chrPageNumbers , 64 } ;
ArrayInfo < uint8_t > nametableIndexes = { _nametableIndexes , 4 } ;
Stream ( _mirroringType , chrRam , workRam , saveRam , prgPageNumbers , chrPageNumbers , nametableIndexes ) ;
2016-01-24 11:18:50 -05:00
2017-11-19 23:08:23 -05:00
if ( GetStateVersion ( ) > = 7 ) {
bool hasExtraNametable [ 2 ] = { _cartNametableRam [ 0 ] ! = nullptr , _cartNametableRam [ 1 ] ! = nullptr } ;
Stream ( hasExtraNametable [ 0 ] , hasExtraNametable [ 1 ] ) ;
for ( int i = 0 ; i < 2 ; i + + ) {
if ( hasExtraNametable [ i ] ) {
if ( ! _cartNametableRam [ i ] ) {
_cartNametableRam [ i ] = new uint8_t [ 0x400 ] ;
}
2017-10-07 20:32:55 -04:00
2017-11-19 23:08:23 -05:00
ArrayInfo < uint8_t > ram = { _cartNametableRam [ i ] , 0x400 } ;
Stream ( ram ) ;
}
2017-10-07 20:32:55 -04:00
}
}
2016-01-24 11:18:50 -05:00
if ( ! saving ) {
for ( uint16_t i = 0 ; i < 64 ; i + + ) {
if ( _prgPageNumbers [ i ] ! = 0xEEEEEEEE ) {
2016-10-26 22:07:36 -04:00
BaseMapper : : SelectPRGPage ( i , ( uint16_t ) _prgPageNumbers [ i ] ) ;
2016-01-24 11:18:50 -05:00
}
}
for ( uint16_t i = 0 ; i < 64 ; i + + ) {
if ( _chrPageNumbers [ i ] ! = 0xEEEEEEEE ) {
2016-10-26 22:07:36 -04:00
BaseMapper : : SelectCHRPage ( i , ( uint16_t ) _chrPageNumbers [ i ] ) ;
2016-01-24 11:18:50 -05:00
}
}
for ( int i = 0 ; i < 4 ; i + + ) {
SetNametable ( i , _nametableIndexes [ i ] ) ;
}
}
}
2016-01-28 20:47:16 -05:00
void BaseMapper : : Initialize ( RomData & romData )
2016-01-24 11:18:50 -05:00
{
2016-06-03 19:16:31 -04:00
_mapperID = romData . MapperID ;
_subMapperID = romData . SubMapperID ;
2016-07-26 19:19:28 -04:00
_databaseInfo = romData . DatabaseInfo ;
2016-06-17 20:53:05 -04:00
_romName = romData . RomName ;
2016-01-28 20:47:16 -05:00
_romFilename = romData . Filename ;
2016-01-24 11:18:50 -05:00
_batteryFilename = GetBatteryFilename ( ) ;
2016-07-26 19:19:28 -04:00
2018-03-15 23:57:35 -04:00
_hasBattery = romData . HasBattery ;
2016-08-27 13:29:02 -04:00
2016-08-26 21:57:32 -04:00
if ( romData . SaveRamSize = = - 1 | | ForceSaveRamSize ( ) ) {
2017-11-19 23:08:23 -05:00
_saveRamSize = GetSaveRamSize ( ) ;
2016-07-26 19:19:28 -04:00
} else {
_saveRamSize = romData . SaveRamSize ;
}
2016-08-26 21:57:32 -04:00
if ( romData . WorkRamSize = = - 1 | | ForceWorkRamSize ( ) ) {
2016-07-26 19:19:28 -04:00
_workRamSize = GetWorkRamSize ( ) ;
} else {
_workRamSize = romData . WorkRamSize ;
}
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-06-18 18:16:25 -04:00
_nesHeader = romData . NesHeader ;
2017-03-04 22:24:41 -05:00
_romFormat = romData . Format ;
2016-06-18 18:16:25 -04:00
2016-12-11 10:56:23 -05:00
_mirroringType = romData . Mirroring ;
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 ( ) ;
2016-06-15 21:59:34 -04:00
_gameSystem = romData . System ;
2017-04-24 18:28:50 -04:00
_hashInfo . Crc32Hash = romData . Crc32 ;
2017-07-30 09:03:54 -04:00
_hashInfo . PrgCrc32Hash = romData . PrgCrc32 ;
2018-01-09 23:15:08 -05:00
_hashInfo . PrgChrCrc32Hash = romData . PrgChrCrc32 ;
2017-04-24 18:28:50 -04:00
_hashInfo . Sha1Hash = romData . Sha1 ;
_hashInfo . PrgChrMd5Hash = romData . PrgChrMd5 ;
2017-04-01 15:47:43 -04:00
switch ( romData . BusConflicts ) {
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
_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
2017-02-23 20:01:48 -05:00
BaseMapper : : InitializeRam ( _saveRam , _saveRamSize ) ;
BaseMapper : : InitializeRam ( _workRam , _workRamSize ) ;
2016-01-24 11:18:50 -05:00
memset ( _prgPageNumbers , 0xEE , sizeof ( _prgPageNumbers ) ) ;
memset ( _chrPageNumbers , 0xEE , sizeof ( _chrPageNumbers ) ) ;
memset ( _cartNametableRam , 0 , sizeof ( _cartNametableRam ) ) ;
memset ( _nametableIndexes , 0 , sizeof ( _nametableIndexes ) ) ;
for ( int i = 0 ; i < = 0xFF ; i + + ) {
//Allow us to map a different page every 256 bytes
2017-03-31 22:14:16 -04:00
_prgPages [ i ] = nullptr ;
_prgPageAccessType [ i ] = MemoryAccessType : : NoAccess ;
_chrPages [ i ] = nullptr ;
_chrPageAccessType [ 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
}
2017-11-19 23:08:23 -05:00
2016-07-29 17:28:01 -04:00
//Load battery data if present
LoadBattery ( ) ;
2017-04-29 14:08:42 -04:00
if ( romData . HasTrainer ) {
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
InitMapper ( ) ;
2016-01-28 20:47:16 -05:00
InitMapper ( romData ) ;
2016-01-24 11:18:50 -05:00
MessageManager : : RegisterNotificationListener ( this ) ;
ApplyCheats ( ) ;
}
BaseMapper : : ~ BaseMapper ( )
{
delete [ ] _chrRam ;
delete [ ] _chrRom ;
delete [ ] _prgRom ;
delete [ ] _saveRam ;
delete [ ] _workRam ;
if ( _cartNametableRam [ 0 ] ) {
delete [ ] _cartNametableRam [ 0 ] ;
}
if ( _cartNametableRam [ 1 ] ) {
delete [ ] _cartNametableRam [ 1 ] ;
}
MessageManager : : UnregisterNotificationListener ( this ) ;
}
void BaseMapper : : ProcessNotification ( ConsoleNotificationType type , void * parameter )
{
switch ( type ) {
case ConsoleNotificationType : : CheatAdded :
case ConsoleNotificationType : : CheatRemoved :
ApplyCheats ( ) ;
break ;
default :
break ;
}
}
void BaseMapper : : ApplyCheats ( )
{
RestoreOriginalPrgRam ( ) ;
2016-12-01 19:38:48 -05:00
CheatManager : : ApplyPrgCodes ( _prgRom , _prgSize ) ;
2016-01-24 11:18:50 -05:00
}
void BaseMapper : : GetMemoryRanges ( MemoryRanges & ranges )
{
2016-06-15 21:59:34 -04:00
if ( _gameSystem = = GameSystem : : VsUniSystem ) {
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
}
void BaseMapper : : SetDefaultNametables ( uint8_t * nametableA , uint8_t * nametableB )
{
_nesNametableRam [ 0 ] = nametableA ;
_nesNametableRam [ 1 ] = nametableB ;
SetMirroringType ( _mirroringType ) ;
}
void BaseMapper : : AddNametable ( uint8_t index , uint8_t * nametable )
{
assert ( index > = 4 ) ;
_cartNametableRam [ index - 2 ] = nametable ;
}
uint8_t * BaseMapper : : GetNametable ( uint8_t index )
{
if ( index < = 1 ) {
return _nesNametableRam [ index ] ;
} else {
return _cartNametableRam [ index - 2 ] ;
}
}
void BaseMapper : : SetNametable ( uint8_t index , uint8_t nametableIndex )
{
if ( nametableIndex = = 2 & & _cartNametableRam [ 0 ] = = nullptr ) {
_cartNametableRam [ 0 ] = new uint8_t [ 0x400 ] ;
2017-02-23 20:01:48 -05:00
BaseMapper : : InitializeRam ( _cartNametableRam [ 0 ] , 0x400 ) ;
2016-01-24 11:18:50 -05:00
}
if ( nametableIndex = = 3 & & _cartNametableRam [ 1 ] = = nullptr ) {
_cartNametableRam [ 1 ] = new uint8_t [ 0x400 ] ;
2017-02-23 20:01:48 -05:00
BaseMapper : : InitializeRam ( _cartNametableRam [ 1 ] , 0x400 ) ;
2016-01-24 11:18:50 -05:00
}
_nametableIndexes [ index ] = nametableIndex ;
SetPpuMemoryMapping ( 0x2000 + index * 0x400 , 0x2000 + ( index + 1 ) * 0x400 - 1 , GetNametable ( nametableIndex ) ) ;
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
SetPpuMemoryMapping ( 0x3000 + index * 0x400 , 0x3000 + ( index + 1 ) * 0x400 - 1 , GetNametable ( nametableIndex ) ) ;
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-03-20 22:05:38 -04:00
MapperInfo BaseMapper : : GetMapperInfo ( )
{
return {
_romName ,
_romFormat ,
_gameSystem ,
_mapperID ,
_subMapperID ,
_hashInfo ,
HasChrRam ( )
} ;
2016-01-28 20:47:16 -05:00
}
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 ) ;
} else if ( _prgPageAccessType [ 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);
}
2017-03-31 22:14:16 -04:00
return MemoryManager : : GetOpenBus ( ) ;
2016-01-24 11:18:50 -05:00
}
2017-08-30 18:31:27 -04:00
uint8_t BaseMapper : : DebugReadRAM ( uint16_t addr )
{
if ( _prgPageAccessType [ addr > > 8 ] & MemoryAccessType : : Read ) {
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 )
{
2016-06-11 13:18:47 -04:00
if ( _isWriteRegisterAddr [ addr ] ) {
2016-01-24 11:18:50 -05:00
if ( _hasBusConflicts ) {
2017-03-31 22:14:16 -04:00
value & = _prgPages [ addr > > 8 ] [ ( uint8_t ) addr ] ;
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 )
{
if ( _prgPageAccessType [ 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
{
if ( _chrPageAccessType [ 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 ) ;
2017-11-11 12:35:39 -05:00
if ( _chrPageAccessType [ addr > > 8 ] & MemoryAccessType : : Write ) {
_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
{
2017-08-05 17:18:09 -04:00
Debugger : : ProcessVramWriteOperation ( addr , value ) ;
2017-03-31 22:14:16 -04:00
if ( _chrPageAccessType [ addr > > 8 ] & MemoryAccessType : : Write ) {
_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 ( )
{
return _nesHeader . GetRomHeaderVersion ( ) = = RomHeaderVersion : : Nes2_0 ;
}
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
{
2017-02-26 20:47:39 -05:00
uint32_t chrRomSize = _onlyChrRam ? 0 : _chrRomSize ;
2016-09-05 09:05:34 -04:00
switch ( type ) {
case DebugMemoryType : : ChrRam : memcpy ( buffer , _chrRam , _chrRamSize ) ; return _chrRamSize ;
2017-02-26 20:47:39 -05:00
case DebugMemoryType : : ChrRom : memcpy ( buffer , _chrRom , chrRomSize ) ; return chrRomSize ;
2016-09-05 09:05:34 -04:00
case DebugMemoryType : : PrgRom : memcpy ( buffer , _prgRom , _prgSize ) ; return _prgSize ;
case DebugMemoryType : : SaveRam : memcpy ( buffer , _saveRam , _saveRamSize ) ; return _saveRamSize ;
case DebugMemoryType : : WorkRam : memcpy ( buffer , _workRam , _workRamSize ) ; return _workRamSize ;
}
return 0 ;
2016-01-24 11:18:50 -05:00
}
2016-09-05 09:05:34 -04:00
void BaseMapper : : WriteMemory ( DebugMemoryType type , uint8_t * buffer )
2016-01-24 11:18:50 -05:00
{
2016-09-05 09:05:34 -04:00
switch ( type ) {
case DebugMemoryType : : ChrRam : memcpy ( _chrRam , buffer , _chrRamSize ) ; break ;
case DebugMemoryType : : SaveRam : memcpy ( _saveRam , buffer , _saveRamSize ) ; break ;
case DebugMemoryType : : WorkRam : memcpy ( _workRam , buffer , _workRamSize ) ; break ;
}
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 ;
case DebugMemoryType : : SaveRam : return _saveRamSize ;
case DebugMemoryType : : PrgRom : return _prgSize ;
case DebugMemoryType : : WorkRam : return _workRamSize ;
2017-02-26 20:47:39 -05:00
}
}
2017-12-18 20:02:25 -05:00
void BaseMapper : : CopyChrRamTile ( uint32_t address , uint8_t * dest )
{
2017-12-22 21:01:53 -05:00
if ( address < = _chrRamSize - 16 ) {
2017-12-18 20:02:25 -05:00
memcpy ( dest , _chrRam + address , 16 ) ;
}
}
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 ) {
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 ] ;
}
}
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 ) {
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 ;
}
2017-02-26 20:47:39 -05:00
}
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 ;
}
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
}
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 ;
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 ( ) ;
2017-03-03 21:03:20 -05:00
for ( int i = 0 , max = 0x8000 / state . PrgPageSize ; i < max ; i + + ) {
2016-09-04 18:08:16 -04:00
if ( _prgPageNumbers [ i ] ! = 0xEEEEEEEE ) {
int16_t pageNumber = ( int16_t ) _prgPageNumbers [ i ] ;
state . PrgSelectedPages [ i ] = pageNumber < 0 ? state . PrgPageCount + pageNumber : pageNumber ;
} else {
state . PrgSelectedPages [ i ] = 0xEEEEEEEE ;
}
}
2017-03-03 21:03:20 -05:00
for ( int i = 0 , max = 0x2000 / state . ChrPageSize ; i < max ; i + + ) {
2016-09-04 18:08:16 -04:00
if ( _chrPageNumbers [ i ] ! = 0xEEEEEEEE ) {
int16_t pageNumber = ( int16_t ) _chrPageNumbers [ i ] ;
state . ChrSelectedPages [ i ] = pageNumber < 0 ? state . ChrPageCount + pageNumber : pageNumber ;
} else {
state . ChrSelectedPages [ i ] = 0xEEEEEEEE ;
}
}
for ( int i = 0 ; i < 4 ; i + + ) {
state . Nametables [ i ] = _nametableIndexes [ i ] ;
}
2018-01-02 12:06:20 -05:00
state . WorkRamStart = - 1 ;
state . WorkRamEnd = - 1 ;
state . SaveRamStart = - 1 ;
state . SaveRamEnd = - 1 ;
for ( int i = 0x40 ; i < 0x100 ; i + + ) {
int32_t address = ToAbsoluteWorkRamAddress ( i < < 8 ) ;
if ( address > = 0 ) {
if ( state . WorkRamStart < 0 ) {
state . WorkRamStart = i < < 8 ;
} else {
state . WorkRamEnd = ( i < < 8 ) + 0x100 ;
}
} else {
address = ToAbsoluteSaveRamAddress ( i < < 8 ) ;
if ( address > = 0 ) {
if ( state . SaveRamStart < 0 ) {
state . SaveRamStart = i < < 8 ;
} else {
state . SaveRamEnd = ( i < < 8 ) + 0x100 ;
}
}
}
}
2016-09-04 18:08:16 -04:00
return state ;
2017-03-04 22:24:41 -05:00
}
2017-08-12 16:52:45 -04:00
NESHeader BaseMapper : : GetNesHeader ( )
{
return _nesHeader ;
}
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 ;
Console : : GetRomPath ( ) . ReadFile ( originalFile ) ;
2018-01-01 12:09:33 -05:00
out . insert ( out . end ( ) , header , header + sizeof ( NESHeader ) ) ;
out . insert ( out . end ( ) , originalFile . begin ( ) + sizeof ( NESHeader ) , originalFile . end ( ) ) ;
} else {
vector < uint8_t > newFile ;
newFile . insert ( newFile . end ( ) , ( uint8_t * ) & _nesHeader , ( ( uint8_t * ) & _nesHeader ) + sizeof ( NESHeader ) ) ;
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 ;
Console : : GetRomPath ( ) . ReadFile ( originalFile ) ;
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 ;
2016-01-24 11:18:50 -05:00
}