ROM loader, Mappers, Memory manager

This commit is contained in:
Souryo 2014-06-13 23:12:56 -04:00
parent cca56693f3
commit ebb1182453
8 changed files with 253 additions and 87 deletions

View file

@ -51,7 +51,7 @@ CPU::CPU(MemoryManager *memoryManager) : _memoryManager(memoryManager)
void CPU::Reset()
{
_state.A = 0;
_state.PC = 0x0400;
_state.PC = MemoryReadWord(0xFFFC);
_state.SP = 0xFF;
_state.X = 0;
_state.Y = 0;
@ -72,8 +72,8 @@ void CPU::Exec()
cycleCount += this->_cycles[opCode];
//std::cout << "OPCode: " << std::hex << (short)opCode << " PC:" << _currentPC << std::endl;
} else {
std::cout << "Invalid opcode: PC:" << _currentPC << std::endl;
throw;
//std::cout << "Invalid opcode: PC:" << _currentPC << std::endl;
throw std::exception("Invalid opcode");
}
lastPC = _currentPC;
@ -85,19 +85,6 @@ void CPU::Exec()
OutputDebugString(result.c_str());
}
class Test : public IMemoryHandler
{
public:
int _counter = 0;
public:
void MemoryRead(uint16_t aa) {
//_counter++;
}
void MemoryWrite(uint16_t aa) {
}
};
void CPU::RunBenchmark()
{
std::ifstream romFile("6502_functional_test.bin", std::ios::in | std::ios::binary);
@ -108,10 +95,10 @@ void CPU::RunBenchmark()
uint8_t *romMemory = new uint8_t[65536];
romFile.read((char *)romMemory, 65536);
Test a;
//Test a;
MemoryManager memoryManager(romMemory);
memoryManager.OnMemoryRead()->RegisterHandler(&a, &IMemoryHandler::MemoryRead);
MemoryManager memoryManager(MapperFactory::InitializeFromFile("mario.nes"));
//memoryManager.OnMemoryRead()->RegisterHandler(&a, &IMemoryHandler::MemoryRead);
CPU core(&memoryManager);
core.Exec();
}

View file

@ -1,28 +1,234 @@
#include "stdafx.h"
#include "EventHandler.h"
#include "PPU.h"
class IMemoryHandler
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:
virtual void MemoryRead(uint16_t aa) = 0;
virtual void MemoryWrite(uint16_t aa) = 0;
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:
EventHandler<IMemoryHandler, uint16_t> _readHandler;
EventHandler<IMemoryHandler, uint16_t> _writeHandler;
uint8_t *_memory = nullptr;
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(uint8_t *memory) : _memory(memory) { }
EventHandler<IMemoryHandler, uint16_t> *OnMemoryRead() { return &_readHandler; }
EventHandler<IMemoryHandler, uint16_t> *OnMemoryWrite() { return &_writeHandler; }
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) {
//_readHandler(addr);
return _memory[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) {
@ -30,10 +236,5 @@ class MemoryManager
uint8_t hi = Read(addr+1);
return lo | hi << 8;
}
void Write(uint16_t addr, uint8_t value) {
//_writeHandler(addr);
_memory[addr] = value;
}
};

View file

@ -19,8 +19,17 @@
#include <memory>
#include <thread>
#include <list>
#include <vector>
#include <windows.h>
class IMemoryHandler
{
public:
virtual uint8_t MemoryRead(uint16_t addr) = 0;
virtual void MemoryWrite(uint16_t addr, uint8_t value) = 0;
};
// TODO: reference additional headers your program requires here

View file

@ -59,7 +59,13 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>DirectXTK.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OptimizeReferences>
</OptimizeReferences>
<EnableCOMDATFolding>
</EnableCOMDATFolding>
<ImageHasSafeExceptionHandlers>
</ImageHasSafeExceptionHandlers>
</Link>
<FxCompile>
<DisableOptimizations>false</DisableOptimizations>
@ -83,7 +89,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>DirectXTK.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<FxCompile>
<ShaderType>

View file

@ -32,14 +32,14 @@ namespace NES
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
_renderer.Render();
/*_renderer.Render();
frameCount++;
if(frameCount == 500) {
double fps = (double)frameCount / (timer.GetElapsedMS() / 1000);
OutputDebugString((std::to_wstring((int)fps) + L"\n").c_str());
timer.Reset();
frameCount = 0;
}
}*/
}
//std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(50));
}

View file

@ -16,40 +16,6 @@ namespace NES
}
}
//--------------------------------------------------------------------------------------
// Helper for compiling shaders with D3DCompile
//
// With VS 11, we could load up prebuilt .cso files instead...
//--------------------------------------------------------------------------------------
HRESULT Renderer::CompileShaderFromFile(WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut)
{
HRESULT hr = S_OK;
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
// Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
// Setting this flag improves the shader debugging experience, but still allows
// the shaders to be optimized and to run exactly the way they will run in
// the release configuration of this program.
dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif
ID3DBlob* pErrorBlob = nullptr;
hr = D3DCompileFromFile(szFileName, nullptr, nullptr, szEntryPoint, szShaderModel,
dwShaderFlags, 0, ppBlobOut, &pErrorBlob);
if(FAILED(hr)) {
if(pErrorBlob) {
OutputDebugStringA(reinterpret_cast<const char*>(pErrorBlob->GetBufferPointer()));
pErrorBlob->Release();
}
return hr;
}
if(pErrorBlob) pErrorBlob->Release();
return S_OK;
}
//--------------------------------------------------------------------------------------
// Create Direct3D device and swap chain
//--------------------------------------------------------------------------------------
@ -218,12 +184,7 @@ namespace NES
void Renderer::Render()
{
// Clear the back buffer
_pImmediateContext->ClearRenderTargetView(_pRenderTargetView, Colors::MidnightBlue);
// Render a triangle
/*_pImmediateContext->VSSetShader(_pVertexShader, nullptr, 0);
_pImmediateContext->PSSetShader(_pPixelShader, nullptr, 0);
_pImmediateContext->Draw(3, 0);*/
//_pImmediateContext->ClearRenderTargetView(_pRenderTargetView, Colors::MidnightBlue);
UINT screenwidth = 320, screenheight = 240;
@ -239,10 +200,7 @@ namespace NES
dd.DepthPitch = screenwidth* screenheight * 4;
_pImmediateContext->Map(_pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &dd);
memcpy(dd.pData, _videoRAM, screenwidth*screenheight * 4);
_pImmediateContext->Unmap(_pTexture, 0);
///////////////////////////////////////////////////////////////////////////////
@ -259,11 +217,11 @@ namespace NES
ID3D11ShaderResourceView *pSRView = NULL;
_pd3dDevice->CreateShaderResourceView(_pTexture, &srvDesc, &pSRView);
/*
D3D11_RENDER_TARGET_VIEW_DESC rtDesc;
rtDesc.Format = desc.Format;
rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtDesc.Texture2D.MipSlice = 0;
rtDesc.Texture2D.MipSlice = 0;*/
////////////////////////////////////////////////////////////////////////////

View file

@ -30,10 +30,9 @@ namespace NES {
ID3D11Texture2D* _pTexture = nullptr;
byte* _videoRAM;
//SpriteBatch* _sprites;
std::unique_ptr<SpriteBatch> _sprites;
HRESULT Renderer::CompileShaderFromFile(WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut);
HRESULT Renderer::InitDevice();
void Renderer::CleanupDevice();

View file

@ -11,6 +11,12 @@
// Windows Header Files:
#include <windows.h>
#ifdef _DEBUG
#pragma comment( lib, "DirectXTK.debug.lib" )
#else
#pragma comment( lib, "DirectXTK.lib" )
#endif
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>