MMC1 support + Mapper refactoring
Zelda 1, MegaMan 2, Final Fantasy2 working correctly
This commit is contained in:
parent
4cd681c02b
commit
6437be44f5
10 changed files with 357 additions and 106 deletions
|
@ -1,53 +1,70 @@
|
|||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ROMLoader.h"
|
||||
#include "IMemoryHandler.h"
|
||||
#include "ROMLoader.h"
|
||||
|
||||
class BaseMapper : public IMemoryHandler
|
||||
{
|
||||
private:
|
||||
MirroringType _mirroringType;
|
||||
|
||||
protected:
|
||||
NESHeader _header;
|
||||
vector<MemoryBank> _romBanks;
|
||||
vector<MemoryBank> _vromBanks;
|
||||
uint8_t* _prgRAM;
|
||||
uint8_t* _chrRAM;
|
||||
uint32_t _prgSize;
|
||||
uint32_t _chrSize;
|
||||
|
||||
virtual void InitMapper() = 0;
|
||||
|
||||
public:
|
||||
void Initialize(NESHeader header, vector<MemoryBank> romBanks, vector<MemoryBank> vromBanks)
|
||||
const static int PRGSize = 0x8000;
|
||||
const static int CHRSize = 0x2000;
|
||||
|
||||
public:
|
||||
void Initialize(MirroringType mirroringType, ROMLoader &romLoader)
|
||||
{
|
||||
_header = header;
|
||||
_romBanks = romBanks;
|
||||
_vromBanks = vromBanks;
|
||||
_mirroringType = mirroringType;
|
||||
_prgRAM = romLoader.GetPRGRam();
|
||||
_chrRAM = romLoader.GetCHRRam();
|
||||
_prgSize = romLoader.GetPRGSize();
|
||||
_chrSize = romLoader.GetCHRSize();
|
||||
|
||||
if(_chrSize == 0) {
|
||||
_chrRAM = new uint8_t[BaseMapper::CHRSize];
|
||||
_chrSize = BaseMapper::CHRSize;
|
||||
}
|
||||
|
||||
InitMapper();
|
||||
}
|
||||
|
||||
const NESHeader GetHeader()
|
||||
~BaseMapper()
|
||||
{
|
||||
return _header;
|
||||
delete[] _prgRAM;
|
||||
delete[] _chrRAM;
|
||||
}
|
||||
|
||||
virtual MirroringType GetMirroringType()
|
||||
{
|
||||
return _mirroringType;
|
||||
}
|
||||
};
|
||||
|
||||
class DefaultMapper : public BaseMapper
|
||||
{
|
||||
protected:
|
||||
vector<MemoryBank*> _mappedRomBanks;
|
||||
MemoryBank *_mappedVromBank;
|
||||
vector<uint8_t*> _mappedRomBanks;
|
||||
vector<uint8_t*> _mappedVromBanks;
|
||||
|
||||
void InitMapper()
|
||||
virtual void InitMapper()
|
||||
{
|
||||
if(_romBanks.size() == 1) {
|
||||
_mappedRomBanks = { &_romBanks[0], &_romBanks[0] };
|
||||
if(_prgSize == 0x4000) {
|
||||
_mappedRomBanks = { _prgRAM, _prgRAM };
|
||||
} else {
|
||||
_mappedRomBanks = { &_romBanks[0], &_romBanks[1] };
|
||||
_mappedRomBanks = { _prgRAM, &_prgRAM[0x4000] };
|
||||
}
|
||||
|
||||
if(_vromBanks.size() == 0) {
|
||||
uint8_t *buffer = new uint8_t[ROMLoader::VROMBankSize];
|
||||
_vromBanks.push_back(MemoryBank(buffer, buffer + ROMLoader::VROMBankSize));
|
||||
}
|
||||
_mappedVromBank = &_vromBanks[0];
|
||||
_mappedVromBanks.push_back(_chrRAM);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -61,24 +78,24 @@ class DefaultMapper : public BaseMapper
|
|||
return { { { 0x0000, 0x1FFF } } };
|
||||
}
|
||||
|
||||
uint8_t ReadRAM(uint16_t addr)
|
||||
virtual uint8_t ReadRAM(uint16_t addr)
|
||||
{
|
||||
return (*_mappedRomBanks[(addr >> 14) & 0x01])[addr & 0x3FFF];
|
||||
return _mappedRomBanks[(addr >> 14) & 0x01][addr & 0x3FFF];
|
||||
}
|
||||
|
||||
void WriteRAM(uint16_t addr, uint8_t value)
|
||||
virtual void WriteRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
(*_mappedRomBanks[(addr >> 14) & 0x01])[addr & 0x3FFF] = value;
|
||||
_mappedRomBanks[(addr >> 14) & 0x01][addr & 0x3FFF] = value;
|
||||
}
|
||||
|
||||
uint8_t ReadVRAM(uint16_t addr)
|
||||
virtual uint8_t ReadVRAM(uint16_t addr)
|
||||
{
|
||||
return (*_mappedVromBank)[addr & 0x1FFF];
|
||||
return _mappedVromBanks[0][addr & 0x1FFF];
|
||||
}
|
||||
|
||||
void WriteVRAM(uint16_t addr, uint8_t value)
|
||||
virtual void WriteVRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
(*_mappedVromBank)[addr & 0x1FFF] = value;
|
||||
_mappedVromBanks[0][addr & 0x1FFF] = value;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -89,38 +106,13 @@ class Mapper2 : public DefaultMapper
|
|||
{
|
||||
DefaultMapper::InitMapper();
|
||||
|
||||
_mappedRomBanks[1] = &_romBanks[_romBanks.size() - 1];
|
||||
uint8_t numberOfBanks = _prgSize / 0x4000;
|
||||
_mappedRomBanks[1] = &_prgRAM[(numberOfBanks - 1) * 0x4000];
|
||||
}
|
||||
|
||||
public:
|
||||
void WriteRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
_mappedRomBanks[0] = &_romBanks[value];
|
||||
//(*_mappedRomBanks[(addr >> 14) & 0x01])[addr & 0x3FFF] = value;
|
||||
_mappedRomBanks[0] = &_prgRAM[value * 0x4000];
|
||||
}
|
||||
};
|
||||
|
||||
class MapperFactory
|
||||
{
|
||||
public:
|
||||
static unique_ptr<BaseMapper> InitializeFromFile(wstring filename)
|
||||
{
|
||||
ROMLoader loader(filename);
|
||||
|
||||
NESHeader header = loader.GetHeader();
|
||||
|
||||
uint8_t mapperID = header.GetMapperID();
|
||||
BaseMapper* mapper = nullptr;
|
||||
switch(mapperID) {
|
||||
case 0: mapper = new DefaultMapper(); break;
|
||||
case 2: mapper = new Mapper2(); break;
|
||||
}
|
||||
|
||||
if(!mapper) {
|
||||
throw std::exception("Unsupported mapper");
|
||||
}
|
||||
|
||||
mapper->Initialize(header, loader.GetROMBanks(), loader.GetVROMBanks());
|
||||
return unique_ptr<BaseMapper>(mapper);
|
||||
}
|
||||
};
|
||||
};
|
|
@ -1,5 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "Console.h"
|
||||
#include "MapperFactory.h"
|
||||
#include "../Utilities/Timer.h"
|
||||
|
||||
uint32_t Console::Flags = 0;
|
||||
|
@ -10,7 +11,7 @@ Console::Console(wstring filename)
|
|||
_romFilename = filename;
|
||||
|
||||
_mapper = MapperFactory::InitializeFromFile(filename);
|
||||
_memoryManager.reset(new MemoryManager(_mapper->GetHeader()));
|
||||
_memoryManager.reset(new MemoryManager(_mapper));
|
||||
_cpu.reset(new CPU(_memoryManager.get()));
|
||||
_ppu.reset(new PPU(_memoryManager.get()));
|
||||
_apu.reset(new APU());
|
||||
|
@ -22,7 +23,7 @@ Console::Console(wstring filename)
|
|||
_memoryManager->RegisterIODevice(_apu.get());
|
||||
_memoryManager->RegisterIODevice(_controlManager.get());
|
||||
|
||||
Reset();
|
||||
ResetComponents();
|
||||
}
|
||||
|
||||
Console::~Console()
|
||||
|
@ -34,6 +35,13 @@ void Console::Reset()
|
|||
_reset = true;
|
||||
}
|
||||
|
||||
void Console::ResetComponents()
|
||||
{
|
||||
_cpu->Reset();
|
||||
_ppu->Reset();
|
||||
_apu->Reset();
|
||||
}
|
||||
|
||||
void Console::Stop()
|
||||
{
|
||||
_stop = true;
|
||||
|
@ -100,9 +108,7 @@ void Console::Run()
|
|||
fpsTimer.Reset();
|
||||
lastFrameCount = 0;
|
||||
elapsedTime = 0;
|
||||
_cpu->Reset();
|
||||
_ppu->Reset();
|
||||
_apu->Reset();
|
||||
ResetComponents();
|
||||
_reset = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class Console
|
|||
unique_ptr<CPU> _cpu;
|
||||
unique_ptr<PPU> _ppu;
|
||||
unique_ptr<APU> _apu;
|
||||
unique_ptr<BaseMapper> _mapper;
|
||||
shared_ptr<BaseMapper> _mapper;
|
||||
unique_ptr<ControlManager> _controlManager;
|
||||
unique_ptr<MemoryManager> _memoryManager;
|
||||
|
||||
|
@ -31,6 +31,8 @@ class Console
|
|||
bool _stop = false;
|
||||
bool _reset = false;
|
||||
|
||||
void ResetComponents();
|
||||
|
||||
public:
|
||||
Console(wstring filename);
|
||||
~Console();
|
||||
|
|
|
@ -95,6 +95,8 @@
|
|||
<ClInclude Include="IMemoryHandler.h" />
|
||||
<ClInclude Include="Console.h" />
|
||||
<ClInclude Include="IVideoDevice.h" />
|
||||
<ClInclude Include="MapperFactory.h" />
|
||||
<ClInclude Include="MMC1.h" />
|
||||
<ClInclude Include="Nes_Apu\apu_snapshot.h" />
|
||||
<ClInclude Include="Nes_Apu\blargg_common.h" />
|
||||
<ClInclude Include="Nes_Apu\blargg_source.h" />
|
||||
|
|
|
@ -16,6 +16,12 @@
|
|||
<Filter Include="Header Files\Nes_Apu">
|
||||
<UniqueIdentifier>{c6dc2048-98f6-4551-89dc-830f12f1bb2e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Interfaces">
|
||||
<UniqueIdentifier>{ca661408-b52a-4378-aef4-80fda1d64cd6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Mappers">
|
||||
<UniqueIdentifier>{67b52e86-0ff2-4dbe-b9ed-7c92aace61d5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
|
@ -36,21 +42,9 @@
|
|||
<ClInclude Include="ROMLoader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BaseMapper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IMemoryHandler.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IVideoDevice.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IControlDevice.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ControlManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -91,7 +85,25 @@
|
|||
<Filter>Header Files\Nes_Apu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IAudioDevice.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<Filter>Header Files\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IControlDevice.h">
|
||||
<Filter>Header Files\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IMemoryHandler.h">
|
||||
<Filter>Header Files\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IVideoDevice.h">
|
||||
<Filter>Header Files\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BaseMapper.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MapperFactory.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MMC1.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
203
Core/MMC1.h
Normal file
203
Core/MMC1.h
Normal file
|
@ -0,0 +1,203 @@
|
|||
#include "stdafx.h"
|
||||
#include "BaseMapper.h"
|
||||
|
||||
class MMC1 : public DefaultMapper
|
||||
{
|
||||
private:
|
||||
enum class MMC1Registers
|
||||
{
|
||||
Reg8000 = 0,
|
||||
RegA000 = 1,
|
||||
RegC000 = 2,
|
||||
RegE000 = 3
|
||||
};
|
||||
|
||||
enum class PrgMode
|
||||
{
|
||||
_16k = 16,
|
||||
_32k = 32,
|
||||
};
|
||||
|
||||
enum class ChrMode
|
||||
{
|
||||
_4k = 4,
|
||||
_8k = 8,
|
||||
};
|
||||
|
||||
enum class SlotSelect
|
||||
{
|
||||
x8000 = 0x8000,
|
||||
xC000 = 0xC000,
|
||||
};
|
||||
|
||||
uint8_t _writeBuffer = 0;
|
||||
uint8_t _shiftCount = 0;
|
||||
|
||||
MirroringType _mirroringType;
|
||||
bool _wramDisable;
|
||||
ChrMode _chrMode;
|
||||
PrgMode _prgMode;
|
||||
SlotSelect _slotSelect;
|
||||
|
||||
uint8_t _chrReg1;
|
||||
uint8_t _chrReg2;
|
||||
uint8_t _prgReg;
|
||||
|
||||
struct {
|
||||
uint8_t Reg8000;
|
||||
uint8_t RegA000;
|
||||
uint8_t RegC000;
|
||||
uint8_t RegE000;
|
||||
} _state;
|
||||
|
||||
private:
|
||||
bool HasResetFlag(uint8_t value)
|
||||
{
|
||||
return (value & 0x80) == 0x80;
|
||||
}
|
||||
|
||||
void ResetBuffer()
|
||||
{
|
||||
_shiftCount = 0;
|
||||
_writeBuffer = 0;
|
||||
}
|
||||
|
||||
bool IsBufferFull(uint8_t value)
|
||||
{
|
||||
if(HasResetFlag(value)) {
|
||||
//When 'r' is set:
|
||||
// - 'd' is ignored
|
||||
// - hidden temporary reg is reset (so that the next write is the "first" write)
|
||||
// - bits 2,3 of reg $8000 are set (16k PRG mode, $8000 swappable)
|
||||
// - other bits of $8000 (and other regs) are unchanged
|
||||
ResetBuffer();
|
||||
_state.Reg8000 |= 0x0C;
|
||||
return false;
|
||||
} else {
|
||||
//std::cout << std::hex << "input value: " << (short)value << std::endl;
|
||||
_writeBuffer >>= 1;
|
||||
_writeBuffer |= ((value << 4) & 0x10);
|
||||
|
||||
_shiftCount++;
|
||||
|
||||
if(_shiftCount == 5) {
|
||||
//std::cout << std::hex << "value: " << (short)_writeBuffer << std::endl;
|
||||
}
|
||||
|
||||
return _shiftCount == 5;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateState()
|
||||
{
|
||||
switch(_state.Reg8000 & 0x03) {
|
||||
case 0: _mirroringType = MirroringType::ScreenAOnly; break;
|
||||
case 1: _mirroringType = MirroringType::ScreenBOnly; break;
|
||||
case 2: _mirroringType = MirroringType::Vertical; break;
|
||||
case 3: _mirroringType = MirroringType::Horizontal; break;
|
||||
}
|
||||
|
||||
_wramDisable = (_state.RegE000 & 0x10) == 0x10;
|
||||
|
||||
_slotSelect = ((_state.Reg8000 & 0x04) == 0x04) ? SlotSelect::x8000 : SlotSelect::xC000;
|
||||
_prgMode = ((_state.Reg8000 & 0x08) == 0x08) ? PrgMode::_16k : PrgMode::_32k;
|
||||
_chrMode = ((_state.Reg8000 & 0x10) == 0x10) ? ChrMode::_4k : ChrMode::_8k;
|
||||
|
||||
_chrReg1 = _state.RegA000 & 0x1F;
|
||||
_chrReg2 = _state.RegC000 & 0x1F;
|
||||
_prgReg = _state.RegE000 & 0x0F;
|
||||
|
||||
uint8_t page1;
|
||||
uint8_t page2;
|
||||
|
||||
if(_prgMode == PrgMode::_32k) {
|
||||
page1 = (_prgReg >> 1);
|
||||
page2 = page1 + 1;
|
||||
} else if(_prgMode == PrgMode::_16k) {
|
||||
if(_slotSelect == SlotSelect::x8000) {
|
||||
page1 = _prgReg;
|
||||
page2 = 0x0F; //$C000 fixed to page $0F (mode B)
|
||||
} else if(_slotSelect == SlotSelect::xC000) {
|
||||
page1 = 0;
|
||||
page2 = _prgReg;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t numberOfPRGPages = _prgSize / 0x4000;
|
||||
page1 &= (numberOfPRGPages - 1);
|
||||
page2 &= (numberOfPRGPages - 1);
|
||||
_mappedRomBanks[0] = &_prgRAM[page1 * 0x4000];
|
||||
_mappedRomBanks[1] = &_prgRAM[page2 * 0x4000];
|
||||
//std::cout << std::dec << "PRG Bank: " << (short)page1 << " & " << (short)page2 << std::endl;
|
||||
|
||||
|
||||
if(_chrMode == ChrMode::_8k) {
|
||||
page1 = (_chrReg1 >> 1);
|
||||
page2 = page1 + 1;
|
||||
} else if(_chrMode == ChrMode::_4k) {
|
||||
page1 = _chrReg1;
|
||||
page2 = _chrReg2;
|
||||
}
|
||||
|
||||
uint8_t numberOfCHRPages = _chrSize / 0x1000;
|
||||
page1 &= (numberOfCHRPages - 1);
|
||||
page2 &= (numberOfCHRPages - 1);
|
||||
_mappedVromBanks[0] = &_chrRAM[page1 * 0x1000];
|
||||
_mappedVromBanks[1] = &_chrRAM[page2 * 0x1000];
|
||||
//std::cout << std::dec << "CHR Bank: " << (short)page1 << " & " << (short)page2 << std::endl;
|
||||
}
|
||||
|
||||
protected:
|
||||
void InitMapper()
|
||||
{
|
||||
_mappedRomBanks.push_back(nullptr);
|
||||
_mappedRomBanks.push_back(nullptr);
|
||||
_mappedVromBanks.push_back(nullptr);
|
||||
_mappedVromBanks.push_back(nullptr);
|
||||
|
||||
_state.Reg8000 = 0x0C; //On powerup: bits 2,3 of $8000 are set
|
||||
_state.RegA000 = 0x00;
|
||||
_state.RegC000 = 0x00;
|
||||
_state.RegE000 = 0x10; //WRAM Disable: assume it's enabled at startup
|
||||
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
public:
|
||||
void WriteRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(IsBufferFull(value)) {
|
||||
switch((MMC1Registers)((addr & 0x6000) >> 13)) {
|
||||
case MMC1Registers::Reg8000: _state.Reg8000 = _writeBuffer; break;
|
||||
case MMC1Registers::RegA000: _state.RegA000 = _writeBuffer; break;
|
||||
case MMC1Registers::RegC000: _state.RegC000 = _writeBuffer; break;
|
||||
case MMC1Registers::RegE000: _state.RegE000 = _writeBuffer; break;
|
||||
}
|
||||
|
||||
UpdateState();
|
||||
|
||||
//Reset buffer after writing 5 bits
|
||||
ResetBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ReadRAM(uint16_t addr)
|
||||
{
|
||||
return _mappedRomBanks[(addr >> 14) & 0x01][addr & 0x3FFF];
|
||||
}
|
||||
|
||||
uint8_t ReadVRAM(uint16_t addr)
|
||||
{
|
||||
return _mappedVromBanks[(addr >> 12) & 0x01][addr & 0x0FFF];
|
||||
}
|
||||
|
||||
void WriteVRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
_mappedVromBanks[(addr >> 12) & 0x01][addr & 0x0FFF] = value;
|
||||
}
|
||||
|
||||
MirroringType GetMirroringType()
|
||||
{
|
||||
return _mirroringType;
|
||||
}
|
||||
};
|
30
Core/MapperFactory.h
Normal file
30
Core/MapperFactory.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include "stdafx.h"
|
||||
#include "BaseMapper.h"
|
||||
#include "MMC1.h"
|
||||
#include "ROMLoader.h"
|
||||
|
||||
class MapperFactory
|
||||
{
|
||||
public:
|
||||
static shared_ptr<BaseMapper> InitializeFromFile(wstring filename)
|
||||
{
|
||||
ROMLoader loader(filename);
|
||||
|
||||
NESHeader header = loader.GetHeader();
|
||||
|
||||
uint8_t mapperID = header.GetMapperID();
|
||||
BaseMapper* mapper = nullptr;
|
||||
switch(mapperID) {
|
||||
case 0: mapper = new DefaultMapper(); break;
|
||||
case 1: mapper = new MMC1(); break;
|
||||
case 2: mapper = new Mapper2(); break;
|
||||
}
|
||||
|
||||
if(!mapper) {
|
||||
throw std::exception("Unsupported mapper");
|
||||
}
|
||||
|
||||
mapper->Initialize(header.GetMirroringType(), loader);
|
||||
return shared_ptr<BaseMapper>(mapper);
|
||||
}
|
||||
};
|
|
@ -1,11 +1,9 @@
|
|||
#include "stdafx.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "ROMLoader.h"
|
||||
|
||||
MemoryManager::MemoryManager(NESHeader header)
|
||||
MemoryManager::MemoryManager(shared_ptr<BaseMapper> mapper)
|
||||
{
|
||||
_header = header;
|
||||
_mirroringType = _header.GetMirroringType();
|
||||
_mapper = mapper;
|
||||
|
||||
_internalRAM = new uint8_t[InternalRAMSize];
|
||||
_SRAM = new uint8_t[SRAMSize];
|
||||
|
@ -142,7 +140,7 @@ void MemoryManager::WriteVRAM(uint16_t addr, uint8_t value)
|
|||
|
||||
_videoRAM[addr] = value;
|
||||
|
||||
if(_mirroringType == MirroringType::Vertical) {
|
||||
if(_mapper->GetMirroringType() == MirroringType::Vertical) {
|
||||
if(addr >= 0x2000 && addr < 0x2400) {
|
||||
_videoRAM[addr + 0x800] = value;
|
||||
} else if(addr >= 0x2400 && addr < 0x2800) {
|
||||
|
@ -152,7 +150,7 @@ void MemoryManager::WriteVRAM(uint16_t addr, uint8_t value)
|
|||
} else if(addr >= 0x2C00 && addr < 0x3000) {
|
||||
_videoRAM[addr - 0x800] = value;
|
||||
}
|
||||
} else if(_mirroringType == MirroringType::Horizontal) {
|
||||
} else if(_mapper->GetMirroringType() == MirroringType::Horizontal) {
|
||||
if(addr >= 0x2000 && addr < 0x2400) {
|
||||
_videoRAM[addr + 0x400] = value;
|
||||
} else if(addr >= 0x2400 && addr < 0x2800) {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "stdafx.h"
|
||||
#include "IMemoryHandler.h"
|
||||
#include "ROMLoader.h"
|
||||
#include "BaseMapper.h"
|
||||
|
||||
class MemoryManager
|
||||
{
|
||||
|
@ -11,8 +12,7 @@ class MemoryManager
|
|||
const int SRAMSize = 0x2000;
|
||||
const int VRAMSize = 0x4000;
|
||||
|
||||
NESHeader _header;
|
||||
MirroringType _mirroringType;
|
||||
shared_ptr<BaseMapper> _mapper;
|
||||
|
||||
uint8_t *_internalRAM;
|
||||
uint8_t *_expansionRAM;
|
||||
|
@ -29,7 +29,7 @@ class MemoryManager
|
|||
void WriteMappedVRAM(uint16_t addr, uint8_t value);
|
||||
|
||||
public:
|
||||
MemoryManager(NESHeader header);
|
||||
MemoryManager(shared_ptr<BaseMapper> mapper);
|
||||
~MemoryManager();
|
||||
|
||||
void RegisterIODevice(IMemoryHandler *handler);
|
||||
|
|
|
@ -6,6 +6,8 @@ enum class MirroringType
|
|||
{
|
||||
Horizontal,
|
||||
Vertical,
|
||||
ScreenAOnly,
|
||||
ScreenBOnly,
|
||||
FourScreens,
|
||||
};
|
||||
|
||||
|
@ -35,23 +37,18 @@ struct NESHeader
|
|||
}
|
||||
};
|
||||
|
||||
typedef vector<uint8_t> MemoryBank;
|
||||
class ROMLoader
|
||||
{
|
||||
private:
|
||||
NESHeader _header;
|
||||
vector<MemoryBank> _romBanks;
|
||||
vector<MemoryBank> _vromBanks;
|
||||
uint8_t* _prgRAM;
|
||||
uint32_t _prgSize;
|
||||
uint8_t* _chrRAM;
|
||||
uint32_t _chrSize;
|
||||
|
||||
public:
|
||||
const static int ROMBankSize = 0x4000;
|
||||
const static int VROMBankSize = 0x2000;
|
||||
|
||||
ROMLoader(wstring filename)
|
||||
{
|
||||
_romBanks.clear();
|
||||
_vromBanks.clear();
|
||||
|
||||
ifstream romFile(filename, ios::in | ios::binary);
|
||||
|
||||
if(!romFile) {
|
||||
|
@ -60,30 +57,39 @@ class ROMLoader
|
|||
|
||||
romFile.read((char*)&_header, sizeof(NESHeader));
|
||||
|
||||
uint8_t *buffer = new uint8_t[max(ROMBankSize, VROMBankSize)];
|
||||
uint8_t* prgBuffer = new uint8_t[0x4000 * _header.ROMCount];
|
||||
for(int i = 0; i < _header.ROMCount; i++) {
|
||||
romFile.read((char*)buffer, ROMBankSize);
|
||||
_romBanks.push_back(MemoryBank(buffer, buffer + ROMBankSize));
|
||||
romFile.read((char*)prgBuffer+i*0x4000, 0x4000);
|
||||
}
|
||||
_prgRAM = prgBuffer;
|
||||
|
||||
uint8_t* chrBuffer = new uint8_t[0x2000 * _header.VROMCount];
|
||||
for(int i = 0; i < _header.VROMCount; i++) {
|
||||
romFile.read((char*)buffer, VROMBankSize);
|
||||
_vromBanks.push_back(MemoryBank(buffer, buffer + VROMBankSize));
|
||||
romFile.read((char*)chrBuffer+i*0x2000, 0x2000);
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
_chrRAM = chrBuffer;
|
||||
|
||||
romFile.close();
|
||||
}
|
||||
|
||||
vector<MemoryBank> GetROMBanks()
|
||||
uint8_t* GetPRGRam()
|
||||
{
|
||||
return _romBanks;
|
||||
return _prgRAM;
|
||||
}
|
||||
|
||||
vector<MemoryBank> GetVROMBanks()
|
||||
uint8_t* GetCHRRam()
|
||||
{
|
||||
return _vromBanks;
|
||||
return _chrRAM;
|
||||
}
|
||||
|
||||
uint32_t GetPRGSize()
|
||||
{
|
||||
return _header.ROMCount * 0x4000;
|
||||
}
|
||||
|
||||
uint32_t GetCHRSize()
|
||||
{
|
||||
return _header.VROMCount * 0x2000;
|
||||
}
|
||||
|
||||
NESHeader GetHeader()
|
||||
|
|
Loading…
Add table
Reference in a new issue