PPU VRAM, partially fixes tests

This commit is contained in:
Souryo 2014-06-15 21:45:36 -04:00
parent cc674a7467
commit 3ad6418726
9 changed files with 160 additions and 71 deletions

View file

@ -27,6 +27,7 @@ class BaseMapper : public IMemoryHandler
class DefaultMapper : public BaseMapper
{
vector<MemoryBank*> _mappedRomBanks;
MemoryBank *_mappedVromBank;
private:
void InitMapper()
{
@ -35,23 +36,40 @@ class DefaultMapper : public BaseMapper
} else {
_mappedRomBanks = { &_romBanks[0], &_romBanks[1] };
}
_mappedVromBank = &_vromBanks[0];
}
public:
std::array<int, 2> GetIOAddresses()
vector<std::array<uint16_t, 2>> GetRAMAddresses()
{
return std::array<int, 2> {{ 0x8000, 0xFFFF }};
return { { { 0x8000, 0xFFFF } } };
}
uint8_t MemoryRead(uint16_t addr)
vector<std::array<uint16_t, 2>> GetVRAMAddresses()
{
return { { { 0x0000, 0x1FFF } } };
}
uint8_t ReadRAM(uint16_t addr)
{
return (*_mappedRomBanks[(addr >> 14) & 0x01])[addr & 0x3FFF];
}
void MemoryWrite(uint16_t addr, uint8_t value)
void WriteRAM(uint16_t addr, uint8_t value)
{
(*_mappedRomBanks[(addr >> 14) & 0x01])[addr & 0x3FFF] = value;
}
uint8_t ReadVRAM(uint16_t addr)
{
return (*_mappedVromBank)[addr & 0x1FFF];
}
void WriteVRAM(uint16_t addr, uint8_t value)
{
(*_mappedVromBank)[addr & 0x1FFF] = value;
}
};
class MapperFactory

View file

@ -144,7 +144,7 @@ private:
uint8_t SP() { return _state.SP; }
void SetSP(uint8_t value) { _state.SP = value; }
uint8_t PS() { return _state.PS; }
void SetPS(uint8_t value) { _state.PS = value | PSFlags::Reserved; }
void SetPS(uint8_t value) { _state.PS = (value & 0xDF) | PSFlags::Reserved; }
uint16_t PC() { return _state.PC; }
void SetPC(uint16_t value) { _state.PC = value; }
@ -182,8 +182,7 @@ private:
uint16_t GetInd() {
uint16_t addr = ReadWord();
if(addr & 0xFF == 0xFF) {
//Emulate a CPU bug when crossing page boundary
if((addr & 0xFF) == 0xFF) {
auto lo = MemoryRead(addr);
auto hi = MemoryRead(addr - 0xFF);
return (lo | hi << 8);
@ -250,7 +249,7 @@ private:
if(reg == value) {
SetFlags(PSFlags::Zero);
}
if(result & 0x80 == 0x80) {
if((result & 0x80) == 0x80) {
SetFlags(PSFlags::Negative);
}
}
@ -437,8 +436,8 @@ private:
void PHA() { Push(A()); }
void PHP() {
SetFlags(PSFlags::Break);
Push((uint8_t)PS());
uint8_t flags = PS() | PSFlags::Break;
Push((uint8_t)flags);
}
void PLA() { SetA(Pop()); }
void PLP() { SetPS(Pop()); }
@ -607,11 +606,11 @@ private:
void SEI() { SetFlags(PSFlags::Interrupt); }
void BRK() {
SetFlags(PSFlags::Break);
Push((uint16_t)(PC() + 1));
Push((uint8_t)PS());
uint8_t flags = PS() | PSFlags::Break;
Push((uint8_t)flags);
SetFlags(PSFlags::Interrupt);
ClearFlags(PSFlags::Break);
SetPC(MemoryReadWord(0xFFFE));
}

View file

@ -6,13 +6,13 @@ Console::Console(string filename)
{
_mapper = MapperFactory::InitializeFromFile(filename);
_memoryManager.RegisterIODevice(_mapper.get());
_memoryManager.RegisterIODevice(&_ppu);
_cpu.reset(new CPU(&_memoryManager));
_ppu.reset(new PPU(&_memoryManager));
_memoryManager.RegisterIODevice(_ppu.get());
}
Console::~Console()
{
_cpu.release();
}
void Console::Reset()
@ -24,36 +24,33 @@ void Console::Run()
{
while(true) {
_cpu->Exec();
_ppu.Exec();
_ppu->Exec();
}
}
void Console::RunTest(bool callback(Console*))
{
while(true) {
_cpu->Exec();
_ppu.Exec();
if(callback(this)) {
break;
}
_cpu->Exec();
_ppu->Exec();
}
}
void Console::RunTests()
{
/*Console *console = new Console("mario.nes");
console->Run();
delete console;*/
vector<std::string> testROMs = { {
vector<string> testROMs {
//"mario"
"01-basics",
"02-implied",
//"03-immediate",
//"04-zero_page",
//"05-zp_xy",
//"06-absolute",
//"07-abs_xy",
"03-immediate",
"04-zero_page",
"05-zp_xy",
"06-absolute",
"07-abs_xy",
"08-ind_x",
"09-ind_y",
"10-branches",
@ -61,28 +58,38 @@ void Console::RunTests()
"12-jmp_jsr",
"13-rts",
"14-rti",
//"15-brk",
"15-brk",
"16-special"
} };
};
for(string testROM : testROMs) {
Console *console = new Console(string("TestSuite/") + testROM + ".nes");
if(testROM == "nestest") {
console->RunTest([] (Console *console) {
auto state = console->_cpu->GetState();
std::stringstream ss;
ss << std::hex << (short)state.PC << " A:" << (short)state.A << " X:" << (short)state.X << " Y:" << (short)state.Y << std::endl;
OutputDebugStringA(ss.str().c_str());
State state = console->_cpu->GetState();
std::cout << std::hex << std::uppercase <<
"A:" << std::setfill('0') << std::setw(2) << (short)state.A <<
" X:" << std::setfill('0') << std::setw(2) << (short)state.X <<
" Y:" << std::setfill('0') << std::setw(2) << (short)state.Y <<
" S:" << std::setfill('0') << std::setw(2) << (short)state.SP <<
" P:........ $" <<
std::setfill('0') << std::setw(4) << (short)state.PC <<std::endl;
return false;
});
} else {
console->RunTest([] (Console *console) {
//static std::ofstream output("test.log", ios::out | ios::binary);
static std::ofstream output("test.log", ios::out | ios::binary);
static bool testStarted = false;
uint8_t testStatus = console->_memoryManager.Read(0x6000);
State state = console->_cpu->GetState();
//output << std::hex << (short)state.PC << " A:" << (short)state.A << " X:" << (short)state.X << " Y:" << (short)state.Y << std::endl;
/*output << std::hex << std::uppercase <<
"A:" << std::setfill('0') << std::setw(2) << (short)state.A <<
" X:" << std::setfill('0') << std::setw(2) << (short)state.X <<
" Y:" << std::setfill('0') << std::setw(2) << (short)state.Y <<
" S:" << std::setfill('0') << std::setw(2) << (short)state.SP <<
" P:........ $" <<
std::setfill('0') << std::setw(4) << (short)state.PC <<std::endl;*/
if(testStatus == 0x81) {
//need reset

View file

@ -8,7 +8,7 @@ class Console
{
private:
unique_ptr<CPU> _cpu;
PPU _ppu;
unique_ptr<PPU> _ppu;
shared_ptr<BaseMapper> _mapper;
MemoryManager _memoryManager;

View file

@ -5,7 +5,10 @@
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;
virtual vector<std::array<uint16_t, 2>> GetRAMAddresses() = 0;
virtual vector<std::array<uint16_t, 2>> GetVRAMAddresses() { return{}; }
virtual uint8_t ReadRAM(uint16_t addr) = 0;
virtual void WriteRAM(uint16_t addr, uint8_t value) = 0;
virtual uint8_t ReadVRAM(uint16_t addr) { return 0; }
virtual void WriteVRAM(uint16_t addr, uint8_t value) { }
};

View file

@ -3,8 +3,8 @@
uint8_t MemoryManager::ReadRegister(uint16_t addr)
{
if(_registerHandlers[addr]) {
return _registerHandlers[addr]->MemoryRead(addr);
if(_ramHandlers[addr]) {
return _ramHandlers[addr]->ReadRAM(addr);
} else {
return 0;
}
@ -12,8 +12,24 @@ uint8_t MemoryManager::ReadRegister(uint16_t addr)
void MemoryManager::WriteRegister(uint16_t addr, uint8_t value)
{
if(_registerHandlers[addr]) {
_registerHandlers[addr]->MemoryWrite(addr, value);
if(_ramHandlers[addr]) {
_ramHandlers[addr]->WriteRAM(addr, value);
}
}
uint8_t MemoryManager::ReadMappedVRAM(uint16_t addr)
{
if(_vramHandlers[addr]) {
return _vramHandlers[addr]->ReadVRAM(addr);
} else {
return 0;
}
}
void MemoryManager::WriteMappedVRAM(uint16_t addr, uint8_t value)
{
if(_vramHandlers[addr]) {
_vramHandlers[addr]->WriteVRAM(addr, value);
}
}
@ -21,13 +37,19 @@ MemoryManager::MemoryManager()
{
_internalRAM = new uint8_t[InternalRAMSize];
_SRAM = new uint8_t[SRAMSize];
_videoRAM = new uint8_t[VRAMSize];
_expansionRAM = new uint8_t[0x2000];
ZeroMemory(_internalRAM, InternalRAMSize);
ZeroMemory(_SRAM, SRAMSize);
ZeroMemory(_videoRAM, VRAMSize);
ZeroMemory(_expansionRAM, 0x2000);
for(int i = 0; i <= 0xFFFF; i++) {
_registerHandlers.push_back(nullptr);
_ramHandlers.push_back(nullptr);
}
for(int i = 0; i <= 0x3FFF; i++) {
_vramHandlers.push_back(nullptr);
}
}
@ -40,9 +62,18 @@ MemoryManager::~MemoryManager()
void MemoryManager::RegisterIODevice(IMemoryHandler *handler)
{
std::array<int, 2> addresses = handler->GetIOAddresses();
for(int i = addresses[0]; i < addresses[1]; i++) {
_registerHandlers[i] = handler;
vector<std::array<uint16_t, 2>> addresses = handler->GetRAMAddresses();
for(std::array<uint16_t, 2> startEndAddr : addresses) {
for(int i = startEndAddr[0]; i <= startEndAddr[1]; i++) {
_ramHandlers[i] = handler;
}
}
addresses = handler->GetVRAMAddresses();
for(std::array<uint16_t, 2> startEndAddr : addresses) {
for(int i = startEndAddr[0]; i <= startEndAddr[1]; i++) {
_vramHandlers[i] = handler;
}
}
}
@ -83,3 +114,20 @@ uint16_t MemoryManager::ReadWord(uint16_t addr)
return lo | hi << 8;
}
uint8_t MemoryManager::ReadVRAM(uint16_t addr)
{
if(addr <= 0x1FFF) {
return ReadMappedVRAM(addr & 0x1FFF);
} else {
return _videoRAM[addr & 0x3FFF];
}
}
void MemoryManager::WriteVRAM(uint16_t addr, uint8_t value)
{
if(addr <= 0x1FFF) {
WriteMappedVRAM(addr, value);
} else {
_videoRAM[addr & 0x3FFF] = value;
}
}

View file

@ -8,15 +8,21 @@ class MemoryManager
private:
const int InternalRAMSize = 0x800;
const int SRAMSize = 0x2000;
const int VRAMSize = 0x4000;
uint8_t *_internalRAM;
uint8_t *_expansionRAM;
uint8_t *_SRAM;
uint8_t *_videoRAM;
vector<IMemoryHandler*> _registerHandlers;
vector<IMemoryHandler*> _ramHandlers;
vector<IMemoryHandler*> _vramHandlers;
inline uint8_t ReadRegister(uint16_t addr);
inline void WriteRegister(uint16_t addr, uint8_t value);
uint8_t ReadRegister(uint16_t addr);
void WriteRegister(uint16_t addr, uint8_t value);
uint8_t ReadMappedVRAM(uint16_t addr);
void WriteMappedVRAM(uint16_t addr, uint8_t value);
public:
MemoryManager();
@ -25,8 +31,12 @@ class 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);
void Write(uint16_t addr, uint8_t value);
uint8_t ReadVRAM(uint16_t addr);
void WriteVRAM(uint16_t addr, uint8_t value);
char* GetTestResult()
{

View file

@ -2,8 +2,9 @@
#include "PPU.h"
#include "CPU.h"
PPU::PPU()
PPU::PPU(MemoryManager *memoryManager)
{
_memoryManager = memoryManager;
_state = {};
_flags = {};
_statusFlags = {};
@ -21,7 +22,7 @@ bool PPU::CheckFlag(PPUControlFlags flag)
return false;
}
uint8_t PPU::MemoryRead(uint16_t addr)
uint8_t PPU::ReadRAM(uint16_t addr)
{
switch(GetRegisterID(addr)) {
case PPURegisters::Control:
@ -36,13 +37,14 @@ uint8_t PPU::MemoryRead(uint16_t addr)
return _spriteRAM[_state.SpriteRamAddr];
case PPURegisters::VideoMemoryData:
uint8_t returnValue = _memoryReadBuffer;
_memoryReadBuffer = _videoRAM[_state.VideoRamAddr];
_memoryReadBuffer = _memoryManager->ReadVRAM(_state.VideoRamAddr);
_state.VideoRamAddr += _flags.VerticalWrite ? 32 : 1;
return returnValue;
}
return 0;
}
void PPU::MemoryWrite(uint16_t addr, uint8_t value)
void PPU::WriteRAM(uint16_t addr, uint8_t value)
{
switch(GetRegisterID(addr)) {
case PPURegisters::Control:
@ -72,7 +74,8 @@ void PPU::MemoryWrite(uint16_t addr, uint8_t value)
_writeLow = !_writeLow;
break;
case PPURegisters::VideoMemoryData:
_videoRAM[_state.VideoRamAddr&0x3FFF] = value;
_memoryManager->WriteVRAM(_state.VideoRamAddr, value);
_state.VideoRamAddr += _flags.VerticalWrite ? 32 : 1;
break;
}
}
@ -125,8 +128,8 @@ void PPU::Exec()
/*if(_flags.BackgroundEnabled || _flags.SpritesEnabled) {
//p->registers.vramAddress = p->registers.vramLatch;
}*/
} else if(_cycle == 339 && (_frameCount % 2 == 1)) {
//Skip a cycle for odd frames
} else if(_cycle == 339 && _flags.BackgroundEnabled && (_frameCount % 2 == 1)) {
//Skip a cycle for odd frames, if background drawing is enabled
_cycle++;
}
} else if(_scanline < 240) {

View file

@ -1,7 +1,7 @@
#pragma once
#include "stdafx.h"
#include "IMemoryHandler.h"
#include "MemoryManager.h"
enum PPURegisters
{
@ -53,12 +53,13 @@ struct PPUState
class PPU : public IMemoryHandler
{
private:
MemoryManager *_memoryManager;
PPUState _state;
uint64_t _cycleCount;
uint8_t _memoryReadBuffer;
uint8_t _spriteRAM[0x100];
uint8_t _videoRAM[0x4000];
uint8_t *_outputBuffer;
@ -82,16 +83,16 @@ class PPU : public IMemoryHandler
}
public:
PPU();
PPU(MemoryManager *memoryManager);
~PPU();
std::array<int, 2> GetIOAddresses()
vector<std::array<uint16_t, 2>> GetRAMAddresses()
{
return std::array<int, 2> {{ 0x2000, 0x3FFF }};
return{ { { 0x2000, 0x3FFF } }, { {0x4014, 0x4014 } } };
}
uint8_t MemoryRead(uint16_t addr);
void MemoryWrite(uint16_t addr, uint8_t value);
uint8_t ReadRAM(uint16_t addr);
void WriteRAM(uint16_t addr, uint8_t value);
void Exec();
};