Improved code structure

This commit is contained in:
Souryo 2014-06-14 11:27:55 -04:00
parent 909e73a8d5
commit 630db30484
17 changed files with 410 additions and 439 deletions

66
Core/BaseMapper.h Normal file
View File

@ -0,0 +1,66 @@
#pragma once
#include "stdafx.h"
#include "ROMLoader.h"
#include "IMemoryHandler.h"
class BaseMapper : public IMemoryHandler
{
protected:
NESHeader _header;
vector<MemoryBank> _romBanks;
vector<MemoryBank> _vromBanks;
public:
void Initialize(NESHeader header, vector<MemoryBank> romBanks, vector<MemoryBank> vromBanks)
{
_header = header;
_romBanks = romBanks;
_vromBanks = vromBanks;
}
};
class DefaultMapper : public BaseMapper
{
private:
public:
std::array<int, 2> GetIOAddresses()
{
return std::array<int, 2> {{ 0x8000, 0xFFFF }};
}
uint8_t MemoryRead(uint16_t addr)
{
return _romBanks[(addr >> 14) & 0x01][addr & 0x3FFF];
}
void MemoryWrite(uint16_t addr, uint8_t value)
{
_romBanks[(addr >> 14) & 0x01][addr & 0x3FFF] = value;
}
};
class MapperFactory
{
public:
static shared_ptr<BaseMapper> InitializeFromFile(char *filename)
{
ROMLoader loader(filename);
NESHeader header = loader.GetHeader();
uint8_t mapperID = header.GetMapperID();
shared_ptr<BaseMapper> mapper = nullptr;
switch(mapperID) {
case 0: mapper = shared_ptr<BaseMapper>(new DefaultMapper()); break;
}
if(!mapper) {
throw std::exception("Unsupported mapper");
}
mapper->Initialize(header, loader.GetROMBanks(), loader.GetVROMBanks());
return mapper;
}
};

View File

@ -60,7 +60,6 @@ void CPU::Reset()
void CPU::Exec()
{
uint16_t lastPC = 65535;
uint32_t cycleCount = 0;
Timer timer;
@ -75,7 +74,6 @@ void CPU::Exec()
//std::cout << "Invalid opcode: PC:" << _currentPC << std::endl;
throw std::exception("Invalid opcode");
}
lastPC = _currentPC;
if(cycleCount >= 200000000) {
break;
@ -84,21 +82,3 @@ void CPU::Exec()
std::wstring result = L"Frequency: " + std::to_wstring((int)(cycleCount / timer.GetElapsedMS() * 1000 / 1000000)) + L"mhz\n";
OutputDebugString(result.c_str());
}
void CPU::RunBenchmark()
{
std::ifstream romFile("6502_functional_test.bin", std::ios::in | std::ios::binary);
if(!romFile) {
return;
}
uint8_t *romMemory = new uint8_t[65536];
romFile.read((char *)romMemory, 65536);
//Test a;
MemoryManager memoryManager(MapperFactory::InitializeFromFile("mario.nes"));
//memoryManager.OnMemoryRead()->RegisterHandler(&a, &IMemoryHandler::MemoryRead);
CPU core(&memoryManager);
core.Exec();
}

View File

@ -1,5 +1,7 @@
#pragma once
#include "stdafx.h"
#include "Memory.h"
#include "MemoryManager.h"
namespace PSFlags
{
@ -38,7 +40,6 @@ private:
MemoryManager *_memoryManager = nullptr;
uint16_t _currentPC = 0;
uint8_t _cyclePenalty = 0;
@ -600,5 +601,4 @@ public:
CPU(MemoryManager *memoryManager);
void Reset();
void Exec();
static void RunBenchmark();
};
};

31
Core/Console.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "stdafx.h"
#include "Console.h"
Console::Console(char* filename)
{
_mapper = MapperFactory::InitializeFromFile(filename);
_memoryManager.RegisterIODevice(_mapper.get());
_memoryManager.RegisterIODevice(&_ppu);
_cpu.reset(new CPU(&_memoryManager));
}
Console::~Console()
{
}
void Console::Reset()
{
_cpu->Reset();
}
void Console::Run()
{
_cpu->Exec();
}
void Console::RunBenchmark()
{
Console console("mario.nes");
console.Run();
}

21
Core/Console.h Normal file
View File

@ -0,0 +1,21 @@
#include "stdafx.h"
#include "CPU.h"
#include "PPU.h"
#include "BaseMapper.h"
#include "MemoryManager.h"
class Console
{
private:
unique_ptr<CPU> _cpu;
PPU _ppu;
shared_ptr<BaseMapper> _mapper;
MemoryManager _memoryManager;
public:
Console(char* filename);
~Console();
void Run();
void Reset();
static void RunBenchmark();
};

View File

@ -73,7 +73,7 @@
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<OmitFramePointers>false</OmitFramePointers>
<OmitFramePointers>true</OmitFramePointers>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
</ClCompile>
<Link>
@ -84,16 +84,20 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="BaseMapper.h" />
<ClInclude Include="IMemoryHandler.h" />
<ClInclude Include="Console.h" />
<ClInclude Include="PPU.h" />
<ClInclude Include="CPU.h" />
<ClInclude Include="EventHandler.h" />
<ClInclude Include="Memory.h" />
<ClInclude Include="MemoryManager.h" />
<ClInclude Include="ROMLoader.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Console.cpp" />
<ClCompile Include="MemoryManager.cpp" />
<ClCompile Include="PPU.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="CPU.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>

View File

@ -24,20 +24,26 @@
<ClInclude Include="CPU.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="EventHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Memory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PPU.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MemoryManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<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>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Timer.h">
<Filter>Header Files</Filter>
</ClCompile>
@ -50,5 +56,11 @@
<ClCompile Include="PPU.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MemoryManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Console.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

11
Core/IMemoryHandler.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "stdafx.h"
class IMemoryHandler
{
public:
virtual std::array<int, 2> GetIOAddresses() = 0;
virtual uint8_t MemoryRead(uint16_t addr) = 0;
virtual void MemoryWrite(uint16_t addr, uint8_t value) = 0;
};

View File

@ -1,240 +0,0 @@
#include "stdafx.h"
#include "EventHandler.h"
#include "PPU.h"
using std::vector;
using std::shared_ptr;
using std::unique_ptr;
using std::ios;
using std::ifstream;
struct NESHeader
{
char NES[4];
uint8_t ROMCount;
uint8_t VROMCount;
uint8_t Flags1;
uint8_t Flags2;
uint8_t RAMCount;
uint8_t CartType;
uint8_t Reserved[6];
uint8_t GetMapperID()
{
return (Flags2 & 0xF0) | (Flags1 >> 4);
}
};
typedef vector<uint8_t> MemoryBank;
class ROMLoader
{
private:
const int ROMBankSize = 0x4000;
const int VROMBankSize = 0x2000;
NESHeader _header;
vector<MemoryBank> _romBanks;
vector<MemoryBank> _vromBanks;
public:
ROMLoader(const char* filename)
{
_romBanks.clear();
_vromBanks.clear();
ifstream romFile(filename, ios::in | ios::binary);
if(!romFile) {
return;
}
romFile.read((char*)&_header, sizeof(NESHeader));
uint8_t *buffer = new uint8_t[max(ROMBankSize, VROMBankSize)];
for(int i = 0; i < _header.ROMCount; i++) {
romFile.read((char*)buffer, ROMBankSize);
_romBanks.push_back(MemoryBank(buffer, buffer + ROMBankSize));
}
for(int i = 0; i < _header.VROMCount; i++) {
romFile.read((char*)buffer, VROMBankSize);
_vromBanks.push_back(MemoryBank(buffer, buffer + VROMBankSize));
}
delete[] buffer;
romFile.close();
}
vector<MemoryBank> GetROMBanks()
{
return _romBanks;
}
vector<MemoryBank> GetVROMBanks()
{
return _vromBanks;
}
NESHeader GetHeader()
{
return _header;
}
};
class BaseMapper : public IMemoryHandler
{
protected:
NESHeader _header;
vector<MemoryBank> _romBanks;
vector<MemoryBank> _vromBanks;
public:
void Initialize(NESHeader header, vector<MemoryBank> romBanks, vector<MemoryBank> vromBanks)
{
_header = header;
_romBanks = romBanks;
_vromBanks = vromBanks;
}
};
class DefaultMapper : public BaseMapper
{
private:
public:
uint8_t MemoryRead(uint16_t addr)
{
return _romBanks[addr <= 0xC000 ? 0 : 1][addr & 0x3FFF];
}
void MemoryWrite(uint16_t addr, uint8_t value)
{
_romBanks[addr <= 0xC000 ? 0 : 1][addr & 0x3FFF] = value;
}
};
class MapperFactory
{
public:
static shared_ptr<BaseMapper> InitializeFromFile(char *filename)
{
ROMLoader loader(filename);
NESHeader header = loader.GetHeader();
uint8_t mapperID = header.GetMapperID();
shared_ptr<BaseMapper> mapper = nullptr;
switch(mapperID) {
case 0: mapper = shared_ptr<BaseMapper>(new DefaultMapper()); break;
}
if(!mapper) {
throw std::exception("Unsupported mapper");
}
mapper->Initialize(header, loader.GetROMBanks(), loader.GetVROMBanks());
return mapper;
}
};
class MemoryManager
{
private:
const int InternalRAMSize = 0x800;
const int SRAMSize = 0x800;
/*EventHandler<IMemoryHandler, uint16_t> _readRegisterHandler;
EventHandler<IMemoryHandler, uint16_t> _writeRegisterHandler;*/
shared_ptr<BaseMapper> _mapper;
uint8_t *_internalRAM;
uint8_t *_SRAM;
PPU _ppu;
vector<IMemoryHandler*> _registerHandlers;
void RegisterIODevice(IMemoryHandler *handler, uint16_t startAddr, uint16_t endAddr)
{
for(int i = startAddr; i < endAddr; i++) {
_registerHandlers[i] = handler;
}
}
uint8_t ReadRegister(uint16_t addr)
{
if(_registerHandlers[addr] != nullptr) {
return _registerHandlers[addr]->MemoryRead(addr);
} else {
return 0;
}
}
void WriteRegister(uint16_t addr, uint8_t value)
{
if(_registerHandlers[addr] != nullptr) {
_registerHandlers[addr]->MemoryWrite(addr, value);
}
}
public:
MemoryManager(shared_ptr<BaseMapper> mapper) : _mapper(mapper)
{
_internalRAM = new uint8_t[InternalRAMSize];
_SRAM = new uint8_t[SRAMSize];
ZeroMemory(_SRAM, SRAMSize);
ZeroMemory(_internalRAM, InternalRAMSize);
for(int i = 0; i < 0xFFFF; i++) {
_registerHandlers.push_back(nullptr);
}
RegisterIODevice(&_ppu, 0x2000, 0x3FFF);
}
~MemoryManager()
{
delete[] _internalRAM;
delete[] _SRAM;
}
uint8_t Read(uint16_t addr) {
if(addr <= 0x1FFF) {
return _internalRAM[addr & 0x07FF];
} else if(addr <= 0x401F) {
return ReadRegister(addr);
} else if(addr <= 0x5FFF) {
throw std::exception("Not implemented yet");
//return ReadExpansionROM();
} else if(addr <= 0x7FFF) {
return _SRAM[addr];
} else {
return _mapper->MemoryRead(addr);
}
}
void Write(uint16_t addr, uint8_t value) {
//_writeHandler(addr);
if(addr <= 0x1FFFF) {
_internalRAM[addr & 0x07FF] = value;
} else if(addr <= 0x401F) {
WriteRegister(addr, value);
} else if(addr <= 0x5FFF) {
throw std::exception("Not implemented yet");
//return ReadExpansionROM();
} else if(addr <= 0x7FFF) {
_SRAM[addr] = value;
} else {
_mapper->MemoryWrite(addr, value);
}
}
uint16_t ReadWord(uint16_t addr) {
uint8_t lo = Read(addr);
uint8_t hi = Read(addr+1);
return lo | hi << 8;
}
};

84
Core/MemoryManager.cpp Normal file
View File

@ -0,0 +1,84 @@
#include "stdafx.h"
#include "MemoryManager.h"
uint8_t MemoryManager::ReadRegister(uint16_t addr)
{
if(_registerHandlers[addr]) {
return _registerHandlers[addr]->MemoryRead(addr);
} else {
return 0;
}
}
void MemoryManager::WriteRegister(uint16_t addr, uint8_t value)
{
if(_registerHandlers[addr]) {
_registerHandlers[addr]->MemoryWrite(addr, value);
}
}
MemoryManager::MemoryManager()
{
_internalRAM = new uint8_t[InternalRAMSize];
_SRAM = new uint8_t[SRAMSize];
ZeroMemory(_SRAM, SRAMSize);
ZeroMemory(_internalRAM, InternalRAMSize);
for(int i = 0; i < 0xFFFF; i++) {
_registerHandlers.push_back(nullptr);
}
}
MemoryManager::~MemoryManager()
{
delete[] _internalRAM;
delete[] _SRAM;
}
void MemoryManager::RegisterIODevice(IMemoryHandler *handler)
{
std::array<int, 2> addresses = handler->GetIOAddresses();
for(int i = addresses[0]; i < addresses[1]; i++) {
_registerHandlers[i] = handler;
}
}
uint8_t MemoryManager::Read(uint16_t addr)
{
if(addr <= 0x1FFF) {
return _internalRAM[addr & 0x07FF];
} else if(addr <= 0x401F) {
return ReadRegister(addr);
} else if(addr <= 0x5FFF) {
throw std::exception("Not implemented yet");
//return ReadExpansionROM();
} else if(addr <= 0x7FFF) {
return _SRAM[addr];
} else {
return ReadRegister(addr);
}
}
void MemoryManager::Write(uint16_t addr, uint8_t value)
{
if(addr <= 0x1FFFF) {
_internalRAM[addr & 0x07FF] = value;
} else if(addr <= 0x401F) {
WriteRegister(addr, value);
} else if(addr <= 0x5FFF) {
throw std::exception("Not implemented yet");
//return ReadExpansionROM();
} else if(addr <= 0x7FFF) {
_SRAM[addr] = value;
} else {
WriteRegister(addr, value);
}
}
uint16_t MemoryManager::ReadWord(uint16_t addr)
{
uint8_t lo = Read(addr);
uint8_t hi = Read(addr+1);
return lo | hi << 8;
}

30
Core/MemoryManager.h Normal file
View File

@ -0,0 +1,30 @@
#pragma once
#include "stdafx.h"
#include "IMemoryHandler.h"
class MemoryManager
{
private:
const int InternalRAMSize = 0x800;
const int SRAMSize = 0x800;
uint8_t *_internalRAM;
uint8_t *_SRAM;
vector<IMemoryHandler*> _registerHandlers;
inline uint8_t ReadRegister(uint16_t addr);
inline void WriteRegister(uint16_t addr, uint8_t value);
public:
MemoryManager();
~MemoryManager();
void RegisterIODevice(IMemoryHandler *handler);
uint8_t Read(uint16_t addr);
void Write(uint16_t addr, uint8_t value);
uint16_t ReadWord(uint16_t addr);
};

View File

@ -1 +1,30 @@
#include "stdafx.h"
#include "stdafx.h"
#include "PPU.h"
PPU::PPU()
{
_state = {};
_state.Status |= 0xFF;
}
uint8_t PPU::MemoryRead(uint16_t addr)
{
switch(GetRegisterID(addr)) {
case PPURegisters::Control:
return (uint8_t)_state.Control;
case PPURegisters::Control2:
return (uint8_t)(_state.Control >> 8);
case PPURegisters::Status:
return _state.Status;
case PPURegisters::SpriteData:
return _spriteRAM[_state.SpriteRamAddr];
case PPURegisters::VideoMemoryData:
return _videoRAM[_state.VideoRamAddr];
}
return 0;
}
void PPU::MemoryWrite(uint16_t addr, uint8_t value)
{
}

View File

@ -1,4 +1,7 @@
#pragma once
#include "stdafx.h"
#include "IMemoryHandler.h"
enum PPURegisters
{
@ -22,37 +25,24 @@ struct PPUState
class PPU : public IMemoryHandler
{
private:
PPUState _state;
uint8_t _spriteRAM[256];
uint8_t _videoRAM[16*1024];
private:
PPUState _state;
uint8_t _spriteRAM[256];
uint8_t _videoRAM[16*1024];
PPURegisters GetRegisterID(uint16_t addr) {
return (PPURegisters)(addr & 0x07);
}
public:
PPU() {
_state = {};
_state.Status |= 0xFF;
}
uint8_t MemoryRead(uint16_t addr) {
switch(GetRegisterID(addr)) {
case PPURegisters::Control:
return (uint8_t)_state.Control;
case PPURegisters::Control2:
return (uint8_t)(_state.Control >> 8);
case PPURegisters::Status:
return _state.Status;
case PPURegisters::SpriteData:
return _spriteRAM[_state.SpriteRamAddr];
case PPURegisters::VideoMemoryData:
return _videoRAM[_state.VideoRamAddr];
PPURegisters GetRegisterID(uint16_t addr)
{
return (PPURegisters)(addr & 0x07);
}
}
void MemoryWrite(uint16_t addr, uint8_t value) {
public:
PPU();
std::array<int, 2> GetIOAddresses()
{
return std::array<int, 2> {{ 0x2000, 0x3FFF }};
}
}
uint8_t MemoryRead(uint16_t addr);
void MemoryWrite(uint16_t addr, uint8_t value);
};

77
Core/ROMLoader.h Normal file
View File

@ -0,0 +1,77 @@
#pragma once
#include "stdafx.h"
struct NESHeader
{
char NES[4];
uint8_t ROMCount;
uint8_t VROMCount;
uint8_t Flags1;
uint8_t Flags2;
uint8_t RAMCount;
uint8_t CartType;
uint8_t Reserved[6];
uint8_t GetMapperID()
{
return (Flags2 & 0xF0) | (Flags1 >> 4);
}
};
typedef vector<uint8_t> MemoryBank;
class ROMLoader
{
private:
const int ROMBankSize = 0x4000;
const int VROMBankSize = 0x2000;
NESHeader _header;
vector<MemoryBank> _romBanks;
vector<MemoryBank> _vromBanks;
public:
ROMLoader(const char* filename)
{
_romBanks.clear();
_vromBanks.clear();
ifstream romFile(filename, ios::in | ios::binary);
if(!romFile) {
return;
}
romFile.read((char*)&_header, sizeof(NESHeader));
uint8_t *buffer = new uint8_t[max(ROMBankSize, VROMBankSize)];
for(int i = 0; i < _header.ROMCount; i++) {
romFile.read((char*)buffer, ROMBankSize);
_romBanks.push_back(MemoryBank(buffer, buffer + ROMBankSize));
}
for(int i = 0; i < _header.VROMCount; i++) {
romFile.read((char*)buffer, VROMBankSize);
_vromBanks.push_back(MemoryBank(buffer, buffer + VROMBankSize));
}
delete[] buffer;
romFile.close();
}
vector<MemoryBank> GetROMBanks()
{
return _romBanks;
}
vector<MemoryBank> GetVROMBanks()
{
return _vromBanks;
}
NESHeader GetHeader()
{
return _header;
}
};

View File

@ -1,121 +0,0 @@
#include "stdafx.h"
#include "CPU.h"
/*
template<typename T>
class TemplatedClass
{
public:
T Sum(T a, T b);
};
template<typename T>
T TemplatedClass<T>::Sum(T a, T b)
{
return a + b;
}
template<typename T> using ptr = std::unique_ptr<T>;
class Test
{
private:
int counter = 0;
Test();
public:
int Sum(int, int);
void NewThread();
static std::unique_ptr<Test> NewInstance();
};
Test::Test()
{
}
int Test::Sum(int x, int y)
{
return x + y;
}
void Test::NewThread()
{
for (int i = 0; i < 100; i++) {
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(1000));
printf("test %i", this->counter);
this->counter++;
}
}
std::unique_ptr<Test> Test::NewInstance()
{
return std::unique_ptr<Test>(new Test());
}
void somefunction(void)
{
printf("test11111");
}
void func2(int a)
{
//printf("%i", a);
}*/
int _tmain(int argc, _TCHAR* argv[])
{
/* BaseMemoryHandler a;
Test b;
EventHandler<BaseMemoryHandler, uint16_t> eventHandler;
eventHandler.RegisterHandler(&a, &BaseMemoryHandler::CallbackTest);
eventHandler.RegisterHandler(&b, &BaseMemoryHandler::CallbackTest);
eventHandler(eMemoryOperation::Read, 0);
*/
CPU::RunBenchmark();
/*Event<> eventHandler;
eventHandler += somefunction;
Event<int> intHandler;
intHandler += func2;
intHandler += func2;
intHandler += func2;
for (int i = 0; i < 1000000; i++) {
intHandler(i);
}
eventHandler();
TemplatedClass<double> DoubleSum;
printf("%d", DoubleSum.Sum(10.0, 20.0));
TemplatedClass<std::string> StringSum;
std::cout << StringSum.Sum("asdas", "dsadasdsa");
auto str1 = std::string("aaaa");
auto str2 = std::string("bbbb");
auto str3 = str1 + str2;
std::cout << str3;
std::unique_ptr<Test> test;
if (!test) {
test = Test::NewInstance();
}
std::thread t1(&Test::NewThread, test.get());
std::thread t2([]() {
printf("test2");
});
if (test) {
printf("%i", test->Sum(1000, 10));
}
t1.join();
*/
return 0;
}

View File

@ -18,18 +18,15 @@
#include <string>
#include <memory>
#include <thread>
#include <list>
#include <vector>
#include <array>
#include <windows.h>
class IMemoryHandler
{
public:
virtual uint8_t MemoryRead(uint16_t addr) = 0;
virtual void MemoryWrite(uint16_t addr, uint8_t value) = 0;
};
using std::vector;
using std::shared_ptr;
using std::unique_ptr;
using std::ios;
using std::ifstream;
// TODO: reference additional headers your program requires here

View File

@ -1,7 +1,7 @@
#include "stdafx.h"
#include "resource.h"
#include "MainWindow.h"
#include "..\Core\CPU.h"
#include "..\Core\Console.h"
#include "..\Core\Timer.h"
using namespace DirectX;
@ -106,7 +106,7 @@ namespace NES
void MainWindow::RunBenchmark()
{
std::thread bmThread(&CPU::RunBenchmark);
std::thread bmThread(&Console::RunBenchmark);
bmThread.detach();
}