2014-06-14 11:27:55 -04:00
# pragma once
# include "stdafx.h"
2014-06-25 21:52:37 -04:00
# include "Snapshotable.h"
2014-06-14 11:27:55 -04:00
# include "IMemoryHandler.h"
2014-06-24 02:47:32 -04:00
# include "ROMLoader.h"
2014-06-28 13:22:42 -04:00
# include <assert.h>
2014-07-02 20:28:29 -04:00
# include "../Utilities/FolderUtilities.h"
2015-07-05 19:05:33 -04:00
# include "CheatManager.h"
# include "MessageManager.h"
2014-06-14 11:27:55 -04:00
2015-07-29 22:10:34 -04:00
enum class PrgMemoryType
{
PrgRom ,
SaveRam ,
WorkRam ,
} ;
enum MemoryAccessType
{
NoAccess = 0x00 ,
Read = 0x01 ,
Write = 0x02 ,
ReadWrite = 0x03
} ;
2015-07-05 19:05:33 -04:00
class BaseMapper : public IMemoryHandler , public Snapshotable , public INotificationListener
2014-06-14 11:27:55 -04:00
{
2015-07-29 22:10:34 -04:00
private :
2015-12-30 11:47:36 -05:00
const uint16_t PrgAddressRangeSize = 0x8000 ;
const uint16_t ChrAddressRangeSize = 0x2000 ;
2015-07-29 22:10:34 -04:00
MirroringType _mirroringType ;
2015-08-09 00:00:40 -04:00
string _batteryFilename ;
2015-12-30 11:47:36 -05:00
uint16_t InternalGetPrgPageSize ( )
{
//Make sure the page size is no bigger than the size of the ROM itself
//Otherwise we will end up reading from unallocated memory
return std : : min ( ( uint32_t ) GetPRGPageSize ( ) , _prgSize ) ;
}
uint16_t InternalGetChrPageSize ( )
{
//Make sure the page size is no bigger than the size of the ROM itself
//Otherwise we will end up reading from unallocated memory
return std : : min ( ( uint32_t ) GetCHRPageSize ( ) , _chrSize ) ;
}
2014-07-12 22:22:40 -04:00
2015-07-29 22:10:34 -04:00
protected :
uint8_t * _prgRom ;
uint8_t * _originalPrgRom ;
uint8_t * _chrRam ;
2014-06-24 02:47:32 -04:00
uint32_t _prgSize ;
uint32_t _chrSize ;
2014-07-12 22:22:40 -04:00
2015-07-29 22:10:34 -04:00
uint8_t * _saveRam ;
uint32_t _saveRamSize ;
uint8_t * _workRam ;
uint8_t * _nesNametableRam [ 2 ] ;
uint8_t * _cartNametableRam [ 2 ] ;
bool _hasChrRam ;
2014-06-24 16:16:23 -04:00
bool _hasBattery ;
2015-07-21 23:05:27 -04:00
bool _isPalRom ;
2015-07-11 08:27:22 -04:00
string _romFilename ;
2015-07-29 22:10:34 -04:00
bool _allowRegisterRead ;
uint16_t _registerStartAddress ;
uint16_t _registerEndAddress ;
2014-06-14 11:27:55 -04:00
2014-06-24 10:19:24 -04:00
vector < uint8_t * > _prgPages ;
vector < uint8_t * > _chrPages ;
2015-07-29 22:10:34 -04:00
vector < uint8_t > _prgPageAccessType ;
vector < uint8_t > _chrPageAccessType ;
2014-06-24 10:19:24 -04:00
2015-07-29 22:10:34 -04:00
uint32_t _prgPageNumbers [ 64 ] ;
uint32_t _chrPageNumbers [ 64 ] ;
2014-06-25 12:22:48 -04:00
2014-06-14 18:20:56 -04:00
virtual void InitMapper ( ) = 0 ;
2014-06-24 10:19:24 -04:00
protected :
2015-08-09 20:45:45 -04:00
virtual uint16_t GetPRGPageSize ( ) = 0 ;
virtual uint16_t GetCHRPageSize ( ) = 0 ;
2015-07-29 22:10:34 -04:00
//Save ram is battery backed and saved to disk
virtual uint32_t GetSaveRamSize ( ) { return 0x2000 ; }
virtual uint32_t GetSaveRamPageSize ( ) { return 0x2000 ; }
2015-12-28 15:16:50 -05:00
virtual uint32_t GetChrRamSize ( ) { return 0x2000 ; }
2015-07-29 22:10:34 -04:00
//Work ram is NOT saved - aka Expansion ram, etc.
2015-08-06 23:03:36 -04:00
virtual uint32_t GetWorkRamPageSize ( ) { return 0x2000 ; }
virtual uint32_t GetWorkRamSize ( ) { return 0x2000 ; }
2015-07-29 22:10:34 -04:00
virtual uint16_t RegisterStartAddress ( ) { return 0x8000 ; }
virtual uint16_t RegisterEndAddress ( ) { return 0xFFFF ; }
virtual bool AllowRegisterRead ( ) { return false ; }
2014-06-24 10:19:24 -04:00
2015-07-29 22:10:34 -04:00
virtual void WriteRegister ( uint16_t addr , uint8_t value ) { }
virtual uint8_t ReadRegister ( uint16_t addr ) { return 0 ; }
2015-08-09 20:45:45 -04:00
void SetCpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr , uint16_t pageNumber , PrgMemoryType type , int8_t accessType = - 1 )
2014-06-24 10:19:24 -04:00
{
2015-07-29 22:10:34 -04:00
# 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 ( ) ;
2015-12-30 11:47:36 -05:00
pageSize = InternalGetPrgPageSize ( ) ;
2015-07-29 22:10:34 -04:00
break ;
case PrgMemoryType : : SaveRam :
source = _saveRam ;
pageCount = _saveRamSize / GetSaveRamPageSize ( ) ;
pageSize = GetSaveRamPageSize ( ) ;
defaultAccessType | = MemoryAccessType : : Write ;
break ;
case PrgMemoryType : : WorkRam :
source = _workRam ;
pageCount = GetWorkRamSize ( ) / GetWorkRamPageSize ( ) ;
pageSize = GetWorkRamPageSize ( ) ;
defaultAccessType | = MemoryAccessType : : Write ;
break ;
2015-08-09 20:45:45 -04:00
default :
throw new std : : runtime_error ( " Invalid parameter " ) ;
2015-07-29 22:10:34 -04:00
}
pageNumber = pageNumber % pageCount ;
source = & source [ pageNumber * pageSize ] ;
startAddr > > = 8 ;
endAddr > > = 8 ;
for ( uint16_t i = startAddr ; i < = endAddr ; i + + ) {
_prgPages [ i ] = source ;
_prgPageAccessType [ i ] = accessType ! = - 1 ? accessType : defaultAccessType ;
source + = 0x100 ;
}
2014-06-24 10:19:24 -04:00
}
2015-12-28 20:07:27 -05:00
void SetPpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr , uint16_t pageNumber , int8_t accessType = - 1 )
2014-06-24 10:19:24 -04:00
{
2015-07-29 22:10:34 -04:00
pageNumber = pageNumber % GetCHRPageCount ( ) ;
2015-12-30 11:47:36 -05:00
SetPpuMemoryMapping ( startAddr , endAddr , & _chrRam [ pageNumber * InternalGetChrPageSize ( ) ] , accessType ) ;
2014-06-24 10:19:24 -04:00
}
2015-08-09 20:45:45 -04:00
void SetPpuMemoryMapping ( uint16_t startAddr , uint16_t endAddr , uint8_t * sourceMemory , int8_t accessType = - 1 )
2014-06-24 10:19:24 -04:00
{
2015-07-29 22:10:34 -04:00
# 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 ;
sourceMemory + = 0x100 ;
}
2014-06-24 10:19:24 -04:00
}
2015-07-29 22:10:34 -04:00
uint8_t InternalReadRam ( uint16_t addr )
2014-06-24 10:19:24 -04:00
{
2015-07-29 22:10:34 -04:00
return _prgPages [ addr > > 8 ] ? _prgPages [ addr > > 8 ] [ addr & 0xFF ] : 0 ;
2014-06-24 10:19:24 -04:00
}
2015-08-09 20:45:45 -04:00
void SelectPRGPage ( uint16_t slot , uint16_t page , PrgMemoryType memoryType = PrgMemoryType : : PrgRom )
2014-06-24 10:19:24 -04:00
{
2015-07-29 22:10:34 -04:00
_prgPageNumbers [ slot ] = page ;
2015-12-30 11:47:36 -05:00
if ( _prgSize < PrgAddressRangeSize ) {
//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
MessageManager : : DisplayMessage ( " Debug " , " PRG size is smaller than 32kb " ) ;
# endif
for ( slot = 0 ; slot < PrgAddressRangeSize / _prgSize ; slot + + ) {
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 ) ;
}
2014-06-24 10:19:24 -04:00
}
2015-08-09 20:45:45 -04:00
void SelectCHRPage ( uint16_t slot , uint16_t page )
2014-06-24 10:19:24 -04:00
{
2015-07-29 22:10:34 -04:00
_chrPageNumbers [ slot ] = page ;
2015-12-30 11:47:36 -05:00
if ( _chrSize < ChrAddressRangeSize ) {
//Total CHR size is smaller than available memory range, map the entire CHR to all slots
//Unsure if any game needs this, but assuming same behavior as PRG in similar situations
# ifdef _DEBUG
MessageManager : : DisplayMessage ( " Debug " , " CHR size is smaller than 8kb " ) ;
# endif
for ( slot = 0 ; slot < ChrAddressRangeSize / _chrSize ; slot + + ) {
uint16_t startAddr = slot * _chrSize ;
uint16_t endAddr = startAddr + _chrSize - 1 ;
SetPpuMemoryMapping ( startAddr , endAddr , ( uint16_t ) 0 , _hasChrRam ? MemoryAccessType : : ReadWrite : MemoryAccessType : : Read ) ;
}
} else {
uint16_t startAddr = slot * InternalGetChrPageSize ( ) ;
uint16_t endAddr = startAddr + InternalGetChrPageSize ( ) - 1 ;
SetPpuMemoryMapping ( startAddr , endAddr , page , _hasChrRam ? MemoryAccessType : : ReadWrite : MemoryAccessType : : Read ) ;
}
2015-07-29 22:10:34 -04:00
}
bool HasBattery ( )
{
return _hasBattery ;
}
void LoadBattery ( )
{
2015-08-09 00:00:40 -04:00
ifstream batteryFile ( _batteryFilename , ios : : in | ios : : binary ) ;
2015-07-29 22:10:34 -04:00
if ( batteryFile ) {
batteryFile . read ( ( char * ) _saveRam , _saveRamSize ) ;
batteryFile . close ( ) ;
}
//Set a default mapping for save ram (this is what most games/mappers use)
SetCpuMemoryMapping ( 0x6000 , 0x7FFF , 0 , PrgMemoryType : : SaveRam ) ;
2014-06-24 10:19:24 -04:00
}
2015-07-29 22:10:34 -04:00
void SaveBattery ( )
2014-06-24 10:19:24 -04:00
{
2015-08-09 00:00:40 -04:00
ofstream batteryFile ( _batteryFilename , ios : : out | ios : : binary ) ;
2015-07-29 22:10:34 -04:00
if ( batteryFile ) {
batteryFile . write ( ( char * ) _saveRam , _saveRamSize ) ;
batteryFile . close ( ) ;
2014-06-24 10:19:24 -04:00
}
}
2015-07-29 22:10:34 -04:00
uint32_t GetPRGPageCount ( )
2014-06-24 10:19:24 -04:00
{
2015-12-30 11:47:36 -05:00
return _prgSize / InternalGetPrgPageSize ( ) ;
2014-06-24 10:19:24 -04:00
}
2015-07-29 22:10:34 -04:00
uint32_t GetCHRPageCount ( )
2014-06-24 10:19:24 -04:00
{
2015-12-30 11:47:36 -05:00
return _chrSize / InternalGetChrPageSize ( ) ;
2014-06-24 10:19:24 -04:00
}
2015-07-11 08:27:22 -04:00
string GetBatteryFilename ( )
2014-06-24 16:16:23 -04:00
{
2015-07-11 08:27:22 -04:00
return FolderUtilities : : GetSaveFolder ( ) + _romFilename + " .sav " ;
2014-06-24 16:16:23 -04:00
}
2015-07-05 19:05:33 -04:00
void RestoreOriginalPrgRam ( )
{
2015-08-05 20:40:10 -04:00
memcpy ( _prgRom , _originalPrgRom , GetPrgSize ( ) ) ;
2015-07-05 19:05:33 -04:00
}
2014-06-24 16:16:23 -04:00
2014-06-25 21:52:37 -04:00
virtual void StreamState ( bool saving )
{
2015-07-29 22:10:34 -04:00
Stream < bool > ( _hasChrRam ) ;
if ( _hasChrRam ) {
StreamArray < uint8_t > ( _chrRam , _chrSize ) ;
2014-06-25 21:52:37 -04:00
}
2014-06-26 18:48:55 -04:00
Stream < MirroringType > ( _mirroringType ) ;
2015-07-29 22:10:34 -04:00
StreamArray < uint8_t > ( _workRam , GetWorkRamSize ( ) ) ;
StreamArray < uint8_t > ( _saveRam , _saveRamSize ) ;
StreamArray < uint32_t > ( _prgPageNumbers , 64 ) ;
StreamArray < uint32_t > ( _chrPageNumbers , 64 ) ;
2014-06-25 21:52:37 -04:00
if ( ! saving ) {
2015-08-09 20:45:45 -04:00
for ( uint16_t i = 0 ; i < 64 ; i + + ) {
2015-07-29 22:10:34 -04:00
if ( _prgPageNumbers [ i ] ! = 0xEEEEEEEE ) {
2015-08-09 20:45:45 -04:00
SelectPRGPage ( i , ( uint16_t ) _prgPageNumbers [ i ] ) ;
2015-07-29 22:10:34 -04:00
}
2014-06-25 21:52:37 -04:00
}
2015-08-09 20:45:45 -04:00
for ( uint16_t i = 0 ; i < 64 ; i + + ) {
2015-07-29 22:10:34 -04:00
if ( _chrPageNumbers [ i ] ! = 0xEEEEEEEE ) {
2015-08-09 20:45:45 -04:00
SelectCHRPage ( i , ( uint16_t ) _chrPageNumbers [ i ] ) ;
2015-07-29 22:10:34 -04:00
}
2014-06-25 21:52:37 -04:00
}
2014-07-12 22:22:40 -04:00
2015-07-29 22:10:34 -04:00
if ( _mirroringType ! = MirroringType : : Custom ) {
SetMirroringType ( _mirroringType ) ;
}
2014-07-12 22:22:40 -04:00
}
2014-06-25 21:52:37 -04:00
}
2014-06-24 02:47:32 -04:00
public :
2014-06-24 10:19:24 -04:00
void Initialize ( ROMLoader & romLoader )
2014-06-14 11:27:55 -04:00
{
2015-08-09 00:00:40 -04:00
_romFilename = romLoader . GetFilename ( ) ;
_batteryFilename = GetBatteryFilename ( ) ;
2015-07-29 22:10:34 -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)
_allowRegisterRead = AllowRegisterRead ( ) ;
_registerStartAddress = RegisterStartAddress ( ) ;
_registerEndAddress = RegisterEndAddress ( ) ;
2014-06-24 10:19:24 -04:00
_mirroringType = romLoader . GetMirroringType ( ) ;
2015-07-29 22:10:34 -04:00
romLoader . GetPRGRam ( & _prgRom ) ;
romLoader . GetPRGRam ( & _originalPrgRom ) ;
romLoader . GetCHRRam ( & _chrRam ) ;
2014-06-24 02:47:32 -04:00
_prgSize = romLoader . GetPRGSize ( ) ;
_chrSize = romLoader . GetCHRSize ( ) ;
2014-06-24 16:16:23 -04:00
_hasBattery = romLoader . HasBattery ( ) ;
2015-07-21 23:05:27 -04:00
_isPalRom = romLoader . IsPalRom ( ) ;
2014-06-24 02:47:32 -04:00
2015-07-29 22:10:34 -04:00
_saveRam = new uint8_t [ _saveRamSize ] ;
_workRam = new uint8_t [ GetWorkRamSize ( ) ] ;
memset ( _saveRam , 0 , _saveRamSize ) ;
memset ( _workRam , 0 , GetWorkRamSize ( ) ) ;
2014-07-12 22:22:40 -04:00
2015-07-29 22:10:34 -04:00
memset ( _prgPageNumbers , 0xEE , sizeof ( _prgPageNumbers ) ) ;
memset ( _chrPageNumbers , 0xEE , sizeof ( _chrPageNumbers ) ) ;
for ( int i = 0 ; i < = 0xFF ; i + + ) {
//Allow us to map a different page every 256 bytes
_prgPages . push_back ( nullptr ) ;
_prgPageAccessType . push_back ( MemoryAccessType : : NoAccess ) ;
_chrPages . push_back ( nullptr ) ;
_chrPageAccessType . push_back ( MemoryAccessType : : NoAccess ) ;
}
2014-07-12 22:22:40 -04:00
//Load battery data if present
if ( HasBattery ( ) ) {
LoadBattery ( ) ;
}
2014-06-24 02:47:32 -04:00
if ( _chrSize = = 0 ) {
2015-07-29 22:10:34 -04:00
_hasChrRam = true ;
2015-12-28 15:16:50 -05:00
_chrRam = new uint8_t [ GetChrRamSize ( ) ] ;
_chrSize = GetChrRamSize ( ) ;
2014-06-24 02:47:32 -04:00
}
2014-06-14 18:20:56 -04:00
2015-08-09 19:27:57 -04:00
//Setup a default work/save ram in 0x6000-0x7FFF space
SetCpuMemoryMapping ( 0x6000 , 0x7FFF , 0 , HasBattery ( ) ? PrgMemoryType : : SaveRam : PrgMemoryType : : WorkRam ) ;
2014-06-14 18:20:56 -04:00
InitMapper ( ) ;
2015-07-05 19:05:33 -04:00
MessageManager : : RegisterNotificationListener ( this ) ;
ApplyCheats ( ) ;
2014-06-14 11:27:55 -04:00
}
2014-06-19 19:58:15 -04:00
2014-06-26 11:41:27 -04:00
virtual ~ BaseMapper ( )
2014-06-19 19:58:15 -04:00
{
2014-07-12 22:22:40 -04:00
if ( HasBattery ( ) ) {
SaveBattery ( ) ;
}
2015-07-29 22:10:34 -04:00
delete [ ] _chrRam ;
delete [ ] _prgRom ;
delete [ ] _originalPrgRom ;
delete [ ] _saveRam ;
delete [ ] _workRam ;
2015-07-05 19:05:33 -04:00
MessageManager : : UnregisterNotificationListener ( this ) ;
}
2015-12-28 20:07:27 -05:00
virtual void ProcessCpuClock ( ) { }
2015-12-26 17:11:00 -05:00
void ProcessNotification ( ConsoleNotificationType type , void * parameter )
2015-07-05 19:05:33 -04:00
{
switch ( type ) {
case ConsoleNotificationType : : CheatAdded :
case ConsoleNotificationType : : CheatRemoved :
ApplyCheats ( ) ;
break ;
2015-08-28 21:01:18 -04:00
default :
break ;
2015-07-05 19:05:33 -04:00
}
}
void ApplyCheats ( )
{
RestoreOriginalPrgRam ( ) ;
2015-08-05 20:40:10 -04:00
CheatManager : : ApplyPrgCodes ( _prgRom , GetPrgSize ( ) ) ;
2014-06-24 02:47:32 -04:00
}
2014-06-25 12:22:48 -04:00
void GetMemoryRanges ( MemoryRanges & ranges )
2014-06-15 21:45:36 -04:00
{
2015-07-29 22:10:34 -04:00
ranges . AddHandler ( MemoryOperation : : Read , 0x4018 , 0xFFFF ) ;
ranges . AddHandler ( MemoryOperation : : Write , 0x4018 , 0xFFFF ) ;
}
2014-06-25 12:22:48 -04:00
2015-07-29 22:10:34 -04:00
void SetDefaultNametables ( uint8_t * nametableA , uint8_t * nametableB )
{
_nesNametableRam [ 0 ] = nametableA ;
_nesNametableRam [ 1 ] = nametableB ;
SetMirroringType ( _mirroringType ) ;
2014-06-14 11:27:55 -04:00
}
2015-07-29 22:10:34 -04:00
void SetMirroringType ( MirroringType type )
2014-06-24 16:16:23 -04:00
{
2015-07-29 22:10:34 -04:00
switch ( type ) {
case MirroringType : : Vertical :
SetMirroringType ( _nesNametableRam [ 0 ] , _nesNametableRam [ 1 ] , _nesNametableRam [ 0 ] , _nesNametableRam [ 1 ] ) ;
break ;
case MirroringType : : Horizontal :
SetMirroringType ( _nesNametableRam [ 0 ] , _nesNametableRam [ 0 ] , _nesNametableRam [ 1 ] , _nesNametableRam [ 1 ] ) ;
break ;
case MirroringType : : FourScreens :
default :
SetMirroringType ( _nesNametableRam [ 0 ] , _nesNametableRam [ 1 ] , _cartNametableRam [ 0 ] , _cartNametableRam [ 1 ] ) ;
break ;
case MirroringType : : ScreenAOnly :
SetMirroringType ( _nesNametableRam [ 0 ] , _nesNametableRam [ 0 ] , _nesNametableRam [ 0 ] , _nesNametableRam [ 0 ] ) ;
break ;
case MirroringType : : ScreenBOnly :
SetMirroringType ( _nesNametableRam [ 1 ] , _nesNametableRam [ 1 ] , _nesNametableRam [ 1 ] , _nesNametableRam [ 1 ] ) ;
break ;
}
_mirroringType = type ;
}
void SetMirroringType ( uint8_t * nt0 , uint8_t * nt1 , uint8_t * nt2 , uint8_t * nt3 )
{
_mirroringType = MirroringType : : Custom ;
SetPpuMemoryMapping ( 0x2000 , 0x23FF , nt0 ) ;
SetPpuMemoryMapping ( 0x2400 , 0x27FF , nt1 ) ;
SetPpuMemoryMapping ( 0x2800 , 0x2BFF , nt2 ) ;
SetPpuMemoryMapping ( 0x2C00 , 0x2FFF , nt3 ) ;
2014-06-24 16:16:23 -04:00
}
2015-07-21 23:05:27 -04:00
bool IsPalRom ( )
{
return _isPalRom ;
}
2014-06-24 16:16:23 -04:00
MirroringType GetMirroringType ( )
2014-06-14 11:27:55 -04:00
{
2014-06-24 10:19:24 -04:00
return _mirroringType ;
2014-06-14 11:27:55 -04:00
}
2015-07-29 22:10:34 -04:00
uint8_t ReadRAM ( uint16_t addr )
2014-06-24 16:16:23 -04:00
{
2015-07-29 22:10:34 -04:00
if ( _allowRegisterRead & & addr > = _registerStartAddress & & addr < = _registerEndAddress ) {
return ReadRegister ( addr ) ;
} else if ( _prgPageAccessType [ addr > > 8 ] & MemoryAccessType : : Read ) {
return _prgPages [ addr > > 8 ] [ addr & 0xFF ] ;
2015-08-18 18:02:40 -04:00
} else {
//assert(false);
2014-06-24 16:16:23 -04:00
}
2015-07-29 22:10:34 -04:00
return 0 ;
2014-06-24 16:16:23 -04:00
}
2015-07-29 22:10:34 -04:00
virtual void WriteRAM ( uint16_t addr , uint8_t value )
2014-06-24 16:16:23 -04:00
{
2015-07-29 22:10:34 -04:00
if ( addr > = _registerStartAddress & & addr < = _registerEndAddress ) {
WriteRegister ( addr , value ) ;
} else if ( _prgPageAccessType [ addr > > 8 ] & MemoryAccessType : : Write ) {
_prgPages [ addr > > 8 ] [ addr & 0xFF ] = value ;
2015-08-18 18:02:40 -04:00
} else {
//assert(false);
2014-06-24 16:16:23 -04:00
}
}
2015-07-29 22:10:34 -04:00
virtual uint8_t ReadVRAM ( uint16_t addr )
2014-06-14 11:27:55 -04:00
{
2015-07-29 22:10:34 -04:00
if ( _chrPageAccessType [ addr > > 8 ] & MemoryAccessType : : Read ) {
return _chrPages [ addr > > 8 ] [ addr & 0xFF ] ;
2015-08-18 18:02:40 -04:00
} else {
//assert(false);
2014-07-12 22:22:40 -04:00
}
return 0 ;
2014-06-14 11:27:55 -04:00
}
2014-06-15 21:45:36 -04:00
2015-07-29 22:10:34 -04:00
void WriteVRAM ( uint16_t addr , uint8_t value )
{
if ( _chrPageAccessType [ addr > > 8 ] & MemoryAccessType : : Write ) {
_chrPages [ addr > > 8 ] [ addr & 0xFF ] = value ;
2015-08-18 18:02:40 -04:00
} else {
//assert(false);
2015-07-29 22:10:34 -04:00
}
}
virtual void NotifyVRAMAddressChange ( uint16_t addr )
{
//This is called when the VRAM addr on the PPU memory bus changes
//Used by MMC3/MMC5/etc
}
2015-08-28 21:01:18 -04:00
//Debugger Helper Functions
2015-08-05 20:40:10 -04:00
void GetPrgCopy ( uint8_t * * buffer )
2015-06-24 19:26:19 -04:00
{
2015-08-05 20:40:10 -04:00
* buffer = new uint8_t [ _prgSize ] ;
memcpy ( * buffer , _prgRom , _prgSize ) ;
2015-06-24 19:26:19 -04:00
}
2015-08-05 20:40:10 -04:00
uint32_t GetPrgSize ( )
2015-06-24 19:26:19 -04:00
{
return _prgSize ;
}
2015-08-05 20:40:10 -04:00
void GetChrCopy ( uint8_t * * buffer )
{
* buffer = new uint8_t [ _chrSize ] ;
memcpy ( * buffer , _chrRam , _chrSize ) ;
}
2015-08-17 19:32:10 -04:00
uint32_t GetChrSize ( bool includeChrRam = true )
2015-08-05 20:40:10 -04:00
{
2015-08-17 19:32:10 -04:00
if ( includeChrRam | | ! _hasChrRam ) {
return _chrSize ;
} else {
return 0 ;
}
2015-08-05 20:40:10 -04:00
}
2015-08-17 19:32:10 -04:00
int32_t ToAbsoluteAddress ( uint16_t addr )
2015-06-24 19:26:19 -04:00
{
2015-07-29 22:10:34 -04:00
uint8_t * prgAddr = _prgPages [ addr > > 8 ] + ( addr & 0xFF ) ;
if ( prgAddr > = _prgRom & & prgAddr < _prgRom + _prgSize ) {
return ( uint32_t ) ( prgAddr - _prgRom ) ;
}
2015-08-17 19:32:10 -04:00
return - 1 ;
2015-06-24 19:26:19 -04:00
}
2015-08-17 19:32:10 -04:00
int32_t ToAbsoluteChrAddress ( uint16_t addr )
2015-08-14 21:50:14 -04:00
{
uint8_t * chrAddr = _chrPages [ addr > > 8 ] + ( addr & 0xFF ) ;
if ( chrAddr > = _chrRam & & chrAddr < _chrRam + _chrSize ) {
return ( uint32_t ) ( chrAddr - _chrRam ) ;
}
2015-08-17 19:32:10 -04:00
return - 1 ;
2015-08-14 21:50:14 -04:00
}
2015-06-24 19:26:19 -04:00
int32_t FromAbsoluteAddress ( uint32_t addr )
{
2015-08-09 14:47:27 -04:00
uint8_t * ptrAddress = _prgRom + addr ;
for ( int i = 0 ; i < 256 ; i + + ) {
uint8_t * pageAddress = _prgPages [ i ] ;
if ( pageAddress ! = nullptr & & ptrAddress > = pageAddress & & ptrAddress < = pageAddress + 0xFF ) {
2015-08-09 19:49:42 -04:00
return ( i < < 8 ) + ( uint32_t ) ( ptrAddress - pageAddress ) ;
2015-06-24 19:26:19 -04:00
}
}
2015-08-09 14:47:27 -04:00
2015-06-24 19:26:19 -04:00
//Address is currently not mapped
return - 1 ;
}
2015-08-21 22:42:44 -04:00
vector < int32_t > GetPRGRanges ( )
2015-06-24 19:26:19 -04:00
{
2015-08-21 22:42:44 -04:00
vector < int32_t > memoryRanges ;
2015-06-24 19:26:19 -04:00
2015-07-29 22:10:34 -04:00
for ( uint32_t i = 0x8000 ; i < = 0xFFFF ; i + = 0x100 ) {
2015-08-21 22:42:44 -04:00
int32_t pageStart = ToAbsoluteAddress ( ( uint16_t ) i ) ;
int32_t pageEnd = ToAbsoluteAddress ( ( uint16_t ) i + 0xFF ) ;
2015-06-24 19:26:19 -04:00
memoryRanges . push_back ( pageStart ) ;
memoryRanges . push_back ( pageEnd ) ;
}
return memoryRanges ;
}
2014-06-24 02:47:32 -04:00
} ;