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"
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 ;
}
}
2016-01-24 11:18:50 -05:00
bool BaseMapper : : HasBattery ( )
{
return _hasBattery ;
}
void BaseMapper : : LoadBattery ( )
{
2016-07-29 17:28:01 -04:00
if ( HasBattery ( ) ) {
ifstream batteryFile ( _batteryFilename , ios : : in | ios : : binary ) ;
if ( batteryFile ) {
batteryFile . read ( ( char * ) _saveRam , _saveRamSize ) ;
batteryFile . close ( ) ;
}
2016-01-24 11:18:50 -05:00
}
2016-07-29 17:28:01 -04:00
if ( _hasChrBattery ) {
ifstream batteryFile ( _batteryFilename + " .chr " , ios : : in | ios : : binary ) ;
if ( batteryFile ) {
batteryFile . read ( ( char * ) _chrRam , _chrRamSize ) ;
batteryFile . close ( ) ;
}
}
2016-01-24 11:18:50 -05:00
}
void BaseMapper : : SaveBattery ( )
{
2016-07-26 19:19:28 -04:00
if ( HasBattery ( ) ) {
ofstream batteryFile ( _batteryFilename , ios : : out | ios : : binary ) ;
2016-01-24 11:18:50 -05:00
2016-07-26 19:19:28 -04:00
if ( batteryFile ) {
batteryFile . write ( ( char * ) _saveRam , _saveRamSize ) ;
2016-01-24 11:18:50 -05:00
2016-07-26 19:19:28 -04:00
batteryFile . close ( ) ;
}
2016-01-24 11:18:50 -05:00
}
2016-07-29 17:28:01 -04:00
if ( _hasChrBattery ) {
ofstream batteryFile ( _batteryFilename + " .chr " , ios : : out | ios : : binary ) ;
if ( batteryFile ) {
batteryFile . write ( ( char * ) _chrRam , _chrRamSize ) ;
batteryFile . close ( ) ;
}
}
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
}
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-10-07 20:32:55 -04:00
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 ] ;
}
ArrayInfo < uint8_t > ram = { _cartNametableRam [ i ] , 0x400 } ;
Stream ( ram ) ;
}
}
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
2016-08-27 13:29:02 -04:00
_hasBattery = ( romData . HasBattery | | ForceBattery ( ) ) ;
2016-08-26 21:57:32 -04:00
if ( romData . SaveRamSize = = - 1 | | ForceSaveRamSize ( ) ) {
2016-07-26 19:19:28 -04:00
_saveRamSize = GetSaveRamSize ( ) ; //Needed because we need to call SaveBattery() in the destructor (and calling virtual functions in the destructor doesn't work correctly)
} else {
_saveRamSize = romData . SaveRamSize ;
}
2016-08-27 13:29:02 -04:00
if ( _saveRamSize = = 0 ) {
_hasBattery = false ;
}
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 ;
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
}
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 ) ;
}
}
2016-01-24 11:18:50 -05:00
//Setup a default work/save ram in 0x6000-0x7FFF space
2016-07-26 19:19:28 -04:00
if ( HasBattery ( ) & & _saveRamSize > 0 ) {
SetCpuMemoryMapping ( 0x6000 , 0x7FFF , 0 , PrgMemoryType : : SaveRam ) ;
} else if ( _workRamSize > 0 ) {
SetCpuMemoryMapping ( 0x6000 , 0x7FFF , 0 , PrgMemoryType : : WorkRam ) ;
}
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 ) ) ;
}
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 ;
}
}
2016-06-15 21:59:34 -04:00
GameSystem BaseMapper : : GetGameSystem ( )
2016-01-24 11:18:50 -05:00
{
2016-06-15 21:59:34 -04:00
return _gameSystem ;
2016-04-30 20:08:53 -04:00
}
2016-06-17 20:53:05 -04:00
string BaseMapper : : GetRomName ( )
{
return _romName ;
}
2017-03-04 22:24:41 -05:00
RomFormat BaseMapper : : GetRomFormat ( )
{
return _romFormat ;
}
2017-04-22 13:19:21 -04:00
HashInfo BaseMapper : : GetHashInfo ( )
2016-01-28 20:47:16 -05:00
{
2017-04-24 18:28:50 -04:00
return _hashInfo ;
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);
}
return MemoryManager : : GetOpenBus ( ) ;
}
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 : : ProcessVramAccess ( uint16_t & addr )
{
addr & = 0x3FFF ;
if ( addr > = 0x3000 ) {
//Need to mirror 0x3000 writes to 0x2000, this appears to be how hardware behaves
//Required for proper MMC3 IRQ timing in Burai Fighter
addr - = 0x1000 ;
}
}
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
{
2017-03-31 22:14:16 -04:00
ProcessVramAccess ( addr ) ;
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
{
2017-10-07 13:31:28 -04:00
ProcessVramAccess ( addr ) ;
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-03-31 22:14:16 -04:00
ProcessVramAccess ( addr ) ;
2017-08-05 17:18:09 -04:00
Debugger : : ProcessVramWriteOperation ( addr , value ) ;
2017-03-31 22:14:16 -04:00
NotifyVRAMAddressChange ( addr ) ;
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-03-04 21:50:19 -05:00
uint8_t BaseMapper : : GetMemoryValue ( DebugMemoryType memoryType , uint32_t address )
{
switch ( memoryType ) {
2017-06-28 19:00:08 -04:00
case DebugMemoryType : : ChrRom : return _onlyChrRam ? _chrRam [ address ] : _chrRom [ address ] ;
2017-03-04 21:50:19 -05:00
case DebugMemoryType : : ChrRam : return _chrRam [ address ] ;
case DebugMemoryType : : SaveRam : return _saveRam [ address ] ;
case DebugMemoryType : : PrgRom : return _prgRom [ address ] ;
case DebugMemoryType : : WorkRam : return _workRam [ address ] ;
}
return 0 ;
}
2017-02-26 20:47:39 -05:00
void BaseMapper : : SetMemoryValue ( DebugMemoryType memoryType , uint32_t address , uint8_t value )
{
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 ;
}
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 ;
}
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
}
CartridgeState BaseMapper : : GetState ( )
{
CartridgeState state ;
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 ] ;
}
return state ;
2017-03-04 22:24:41 -05:00
}
2017-08-12 16:52:45 -04:00
NESHeader BaseMapper : : GetNesHeader ( )
{
return _nesHeader ;
}
2017-08-19 19:40:02 -04:00
void BaseMapper : : SaveRomToDisk ( string filename , bool saveAsIps , uint8_t * header )
2017-03-04 22:24:41 -05:00
{
ofstream file ( filename , ios : : out | ios : : binary ) ;
if ( file . good ( ) ) {
2017-08-19 19:40:02 -04:00
vector < uint8_t > originalFile ;
Console : : GetRomPath ( ) . ReadFile ( originalFile ) ;
2017-08-12 16:52:45 -04:00
if ( header ) {
//Save original rom with edited header
file . write ( ( char * ) header , sizeof ( NESHeader ) ) ;
2017-10-07 20:37:39 -04:00
file . write ( ( char * ) originalFile . data ( ) + sizeof ( NESHeader ) , originalFile . size ( ) - sizeof ( NESHeader ) ) ;
2017-08-12 16:52:45 -04:00
} else {
2017-08-19 19:40:02 -04:00
vector < uint8_t > newFile ;
newFile . insert ( newFile . end ( ) , ( uint8_t * ) & _nesHeader , ( ( uint8_t * ) & _nesHeader ) + sizeof ( NESHeader ) ) ;
newFile . insert ( newFile . end ( ) , _prgRom , _prgRom + _prgSize ) ;
newFile . insert ( newFile . end ( ) , _chrRom , _chrRom + _chrRomSize ) ;
2017-08-12 16:52:45 -04:00
//Save edited rom
2017-08-19 19:40:02 -04:00
if ( saveAsIps ) {
vector < uint8_t > patchData = IpsPatcher : : CreatePatch ( originalFile , newFile ) ;
file . write ( ( char * ) patchData . data ( ) , patchData . size ( ) ) ;
} else {
file . write ( ( char * ) newFile . data ( ) , newFile . size ( ) ) ;
}
2017-08-12 16:52:45 -04:00
}
2017-03-04 22:24:41 -05:00
file . close ( ) ;
}
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
}