2014-06-14 11:27:55 -04:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "IMemoryHandler.h"
|
2014-06-24 02:47:32 -04:00
|
|
|
#include "ROMLoader.h"
|
2014-06-14 11:27:55 -04:00
|
|
|
|
|
|
|
class BaseMapper : public IMemoryHandler
|
|
|
|
{
|
|
|
|
protected:
|
2014-06-24 02:47:32 -04:00
|
|
|
uint8_t* _prgRAM;
|
|
|
|
uint8_t* _chrRAM;
|
|
|
|
uint32_t _prgSize;
|
|
|
|
uint32_t _chrSize;
|
2014-06-24 15:11:04 -04:00
|
|
|
|
2014-06-24 16:16:23 -04:00
|
|
|
bool _hasBattery;
|
|
|
|
wstring _romFilename;
|
|
|
|
|
2014-06-24 15:11:04 -04:00
|
|
|
MirroringType _mirroringType;
|
2014-06-14 11:27:55 -04:00
|
|
|
|
2014-06-24 10:19:24 -04:00
|
|
|
vector<uint8_t*> _prgPages;
|
|
|
|
vector<uint8_t*> _chrPages;
|
|
|
|
|
2014-06-25 12:22:48 -04:00
|
|
|
uint32_t _chrShift = -1;
|
|
|
|
uint32_t _prgShift = -1;
|
|
|
|
|
2014-06-14 18:20:56 -04:00
|
|
|
virtual void InitMapper() = 0;
|
|
|
|
|
2014-06-14 11:27:55 -04:00
|
|
|
public:
|
2014-06-24 02:47:32 -04:00
|
|
|
const static int PRGSize = 0x8000;
|
|
|
|
const static int CHRSize = 0x2000;
|
2014-06-24 16:16:23 -04:00
|
|
|
const static int PRGRAMSize = 0x2000;
|
2014-06-24 02:47:32 -04:00
|
|
|
|
2014-06-24 10:19:24 -04:00
|
|
|
protected:
|
|
|
|
virtual uint32_t GetPRGPageSize() = 0;
|
|
|
|
virtual uint32_t GetCHRPageSize() = 0;
|
|
|
|
|
|
|
|
void SelectPRGPage(uint32_t slot, uint32_t page)
|
|
|
|
{
|
|
|
|
//std::cout << std::dec << "PRG Slot " << (short)slot << ": " << (short)page << std::endl;
|
|
|
|
_prgPages[slot] = &_prgRAM[(page & (GetPRGPageCount() - 1)) * GetPRGPageSize()];
|
|
|
|
}
|
|
|
|
|
|
|
|
void SelectCHRPage(uint32_t slot, uint32_t page)
|
|
|
|
{
|
|
|
|
//std::cout << std::dec << "CHR Slot " << (short)slot << ": " << (short)page << std::endl;
|
|
|
|
_chrPages[slot] = &_chrRAM[(page & (GetCHRPageCount() - 1)) * GetCHRPageSize()];
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t GetPRGSlotCount()
|
|
|
|
{
|
|
|
|
return BaseMapper::PRGSize / GetPRGPageSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t GetCHRSlotCount()
|
|
|
|
{
|
|
|
|
return BaseMapper::CHRSize / GetCHRPageSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t GetPRGPageCount()
|
|
|
|
{
|
|
|
|
return _prgSize / GetPRGPageSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t GetCHRPageCount()
|
|
|
|
{
|
|
|
|
return _chrSize / GetCHRPageSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t log2(uint32_t value)
|
|
|
|
{
|
|
|
|
uint32_t counter = 0;
|
|
|
|
while(value >>= 1) {
|
|
|
|
counter++;
|
|
|
|
}
|
|
|
|
return counter;
|
|
|
|
}
|
|
|
|
|
2014-06-24 10:31:33 -04:00
|
|
|
uint32_t AddrToPRGSlot(uint16_t addr)
|
2014-06-24 10:19:24 -04:00
|
|
|
{
|
2014-06-25 12:22:48 -04:00
|
|
|
if(_prgShift == -1) {
|
|
|
|
_prgShift = this->log2(GetPRGSlotCount());
|
2014-06-24 10:19:24 -04:00
|
|
|
}
|
|
|
|
|
2014-06-25 12:22:48 -04:00
|
|
|
return (addr >> (15 - _prgShift)) & (GetPRGSlotCount() - 1);
|
2014-06-24 10:19:24 -04:00
|
|
|
}
|
|
|
|
|
2014-06-24 10:31:33 -04:00
|
|
|
uint32_t AddrToCHRSlot(uint16_t addr)
|
2014-06-24 10:19:24 -04:00
|
|
|
{
|
2014-06-25 12:22:48 -04:00
|
|
|
if(_chrShift == -1) {
|
|
|
|
_chrShift = this->log2(GetCHRSlotCount());
|
2014-06-24 10:19:24 -04:00
|
|
|
}
|
|
|
|
|
2014-06-25 12:22:48 -04:00
|
|
|
return (addr >> (13 - _chrShift)) & (GetCHRSlotCount() - 1);
|
2014-06-24 10:19:24 -04:00
|
|
|
}
|
|
|
|
|
2014-06-24 16:16:23 -04:00
|
|
|
wstring GetBatteryFilename()
|
|
|
|
{
|
|
|
|
wstring filename = _romFilename;
|
|
|
|
std::transform(filename.begin(), filename.end(), filename.begin(), std::tolower);
|
|
|
|
if(filename.compare(filename.length() - 4, 4, L".nes") == 0) {
|
|
|
|
//filename ends in .nes, remove it
|
|
|
|
filename = _romFilename.substr(0, _romFilename.length() - 4);
|
|
|
|
} else {
|
|
|
|
filename = _romFilename;
|
|
|
|
}
|
|
|
|
filename += L".sav";
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2014-06-24 10:19:24 -04:00
|
|
|
_mirroringType = romLoader.GetMirroringType();
|
2014-06-24 02:47:32 -04:00
|
|
|
_prgRAM = romLoader.GetPRGRam();
|
|
|
|
_chrRAM = romLoader.GetCHRRam();
|
|
|
|
_prgSize = romLoader.GetPRGSize();
|
|
|
|
_chrSize = romLoader.GetCHRSize();
|
2014-06-24 16:16:23 -04:00
|
|
|
_hasBattery = romLoader.HasBattery();
|
|
|
|
_romFilename = romLoader.GetFilename();
|
2014-06-24 02:47:32 -04:00
|
|
|
|
|
|
|
if(_chrSize == 0) {
|
|
|
|
_chrRAM = new uint8_t[BaseMapper::CHRSize];
|
|
|
|
_chrSize = BaseMapper::CHRSize;
|
|
|
|
}
|
2014-06-14 18:20:56 -04:00
|
|
|
|
2014-06-24 10:19:24 -04:00
|
|
|
for(int i = GetPRGSlotCount(); i > 0; i--) {
|
|
|
|
_prgPages.push_back(nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(int i = GetCHRSlotCount(); i > 0; i--) {
|
|
|
|
_chrPages.push_back(nullptr);
|
|
|
|
}
|
|
|
|
|
2014-06-14 18:20:56 -04:00
|
|
|
InitMapper();
|
2014-06-14 11:27:55 -04:00
|
|
|
}
|
2014-06-19 19:58:15 -04:00
|
|
|
|
2014-06-24 02:47:32 -04:00
|
|
|
~BaseMapper()
|
2014-06-19 19:58:15 -04:00
|
|
|
{
|
2014-06-24 02:47:32 -04:00
|
|
|
delete[] _prgRAM;
|
|
|
|
delete[] _chrRAM;
|
|
|
|
}
|
|
|
|
|
2014-06-25 12:22:48 -04:00
|
|
|
void GetMemoryRanges(MemoryRanges &ranges)
|
2014-06-15 21:45:36 -04:00
|
|
|
{
|
2014-06-25 12:22:48 -04:00
|
|
|
ranges.AddHandler(MemoryType::RAM, MemoryOperation::Read, 0x8000, 0xFFFF);
|
|
|
|
ranges.AddHandler(MemoryType::RAM, MemoryOperation::Write, 0x8000, 0xFFFF);
|
|
|
|
|
|
|
|
ranges.AddHandler(MemoryType::VRAM, MemoryOperation::Read, 0x0000, 0x1FFF);
|
|
|
|
ranges.AddHandler(MemoryType::VRAM, MemoryOperation::Write, 0x0000, 0x1FFF);
|
2014-06-14 11:27:55 -04:00
|
|
|
}
|
|
|
|
|
2014-06-24 16:16:23 -04:00
|
|
|
bool HasBattery()
|
|
|
|
{
|
|
|
|
return _hasBattery;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
2014-06-24 16:16:23 -04:00
|
|
|
|
|
|
|
void LoadBattery(uint8_t *sramBuffer)
|
|
|
|
{
|
|
|
|
ifstream batteryFile(GetBatteryFilename(), ios::in | ios::binary);
|
|
|
|
|
|
|
|
if(batteryFile) {
|
|
|
|
batteryFile.read((char*)sramBuffer, BaseMapper::PRGRAMSize);
|
|
|
|
|
|
|
|
batteryFile.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SaveBattery(uint8_t *sramBuffer)
|
|
|
|
{
|
|
|
|
ofstream batteryFile(GetBatteryFilename(), ios::out | ios::binary);
|
|
|
|
|
|
|
|
if(batteryFile) {
|
|
|
|
batteryFile.write((char*)sramBuffer, BaseMapper::PRGRAMSize);
|
|
|
|
|
|
|
|
batteryFile.close();
|
|
|
|
}
|
|
|
|
}
|
2014-06-24 10:19:24 -04:00
|
|
|
|
|
|
|
uint8_t ReadRAM(uint16_t addr)
|
2014-06-14 11:27:55 -04:00
|
|
|
{
|
2014-06-24 10:31:33 -04:00
|
|
|
return _prgPages[AddrToPRGSlot(addr)][addr & (GetPRGPageSize() - 1)];
|
2014-06-14 11:27:55 -04:00
|
|
|
}
|
2014-06-15 21:45:36 -04:00
|
|
|
|
2014-06-24 10:19:24 -04:00
|
|
|
void WriteRAM(uint16_t addr, uint8_t value)
|
|
|
|
{
|
2014-06-24 10:31:33 -04:00
|
|
|
_prgPages[AddrToPRGSlot(addr)][addr & (GetPRGPageSize() - 1)] = value;
|
2014-06-24 10:19:24 -04:00
|
|
|
}
|
|
|
|
|
2014-06-24 02:47:32 -04:00
|
|
|
virtual uint8_t ReadVRAM(uint16_t addr)
|
2014-06-15 21:45:36 -04:00
|
|
|
{
|
2014-06-24 10:31:33 -04:00
|
|
|
return _chrPages[AddrToCHRSlot(addr)][addr & (GetCHRPageSize() - 1)];
|
2014-06-15 21:45:36 -04:00
|
|
|
}
|
|
|
|
|
2014-06-24 02:47:32 -04:00
|
|
|
virtual void WriteVRAM(uint16_t addr, uint8_t value)
|
2014-06-15 21:45:36 -04:00
|
|
|
{
|
2014-06-24 10:31:33 -04:00
|
|
|
_chrPages[AddrToCHRSlot(addr)][addr & (GetCHRPageSize() - 1)] = value;
|
2014-06-15 21:45:36 -04:00
|
|
|
}
|
2014-06-24 02:47:32 -04:00
|
|
|
};
|