From 0f657ccf63772faa22891fc461a139945fe07970 Mon Sep 17 00:00:00 2001 From: Sour Date: Fri, 15 Feb 2019 00:08:50 -0500 Subject: [PATCH] DMA: Refactoring + improvements/fixes --- Core/Console.cpp | 5 +- Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 +++ Core/CpuTypes.h | 4 +- Core/DmaController.cpp | 110 ++++++++++++++++++++++++++++++++++++++ Core/DmaController.h | 32 +++++++++++ Core/MemoryManager.h | 43 ++++++++++++--- Core/Ppu.cpp | 49 ++--------------- Core/Ppu.h | 3 -- 9 files changed, 198 insertions(+), 56 deletions(-) create mode 100644 Core/DmaController.cpp create mode 100644 Core/DmaController.h diff --git a/Core/Console.cpp b/Core/Console.cpp index ba97efa..1430016 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -57,7 +57,10 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile) shared_ptr cart = BaseCartridge::CreateCartridge(romFile, patchFile); if(cart) { _ppu.reset(new Ppu(shared_from_this())); - _memoryManager.reset(new MemoryManager(cart, shared_from_this())); + + _memoryManager.reset(new MemoryManager()); + _memoryManager->Initialize(cart, shared_from_this()); + _cpu.reset(new Cpu(_memoryManager)); _debugger.reset(new Debugger(_cpu, _ppu, _memoryManager)); } diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index dda4e94..d2b7c04 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -53,6 +53,7 @@ + @@ -88,6 +89,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 977fbcd..1a0340c 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -98,6 +98,9 @@ Video\DebugHud + + SNES + @@ -149,6 +152,9 @@ Video\DebugHud + + SNES + diff --git a/Core/CpuTypes.h b/Core/CpuTypes.h index 3a282aa..dad6495 100644 --- a/Core/CpuTypes.h +++ b/Core/CpuTypes.h @@ -93,5 +93,7 @@ enum class MemoryOperationType ExecOpCode = 2, ExecOperand = 3, DummyRead = 5, - DummyWrite = 6 + DummyWrite = 6, + DmaRead = 7, + DmaWrite = 8 }; \ No newline at end of file diff --git a/Core/DmaController.cpp b/Core/DmaController.cpp new file mode 100644 index 0000000..dab0a12 --- /dev/null +++ b/Core/DmaController.cpp @@ -0,0 +1,110 @@ +#include "stdafx.h" +#include "DmaController.h" +#include "MemoryManager.h" + +DmaController::DmaController(shared_ptr memoryManager) +{ + _memoryManager = memoryManager; +} + +void DmaController::RunDma(DmaChannelConfig &channel) +{ + //"Note, however, that writing $0000 to this register actually results in a transfer of $10000 bytes, not 0." + uint32_t transferSize = channel.TransferSize ? channel.TransferSize : 0x10000; + + uint8_t offset = 0; + if(channel.InvertDirection) { + for(uint32_t i = 0; i < transferSize; i++) { + uint8_t valToWrite = _memoryManager->Read(0x2100 | channel.DestAddress + offset, MemoryOperationType::DmaRead); + _memoryManager->Write(channel.SrcAddress, valToWrite, MemoryOperationType::DmaWrite); + + if(!channel.FixedTransfer) { + channel.SrcAddress += channel.Decrement ? -1 : 1; + } + } + } else { + for(uint32_t i = 0; i < transferSize; i++) { + uint8_t valToWrite = _memoryManager->Read(channel.SrcAddress, MemoryOperationType::DmaRead); + _memoryManager->Write(0x2100 | channel.DestAddress + offset, valToWrite, MemoryOperationType::DmaWrite); + + if(channel.TransferMode == 1) { + offset = (offset + 1) & 0x01; + } + + if(!channel.FixedTransfer) { + channel.SrcAddress += channel.Decrement ? -1 : 1; + } + } + } +} + +void DmaController::Write(uint16_t addr, uint8_t value) +{ + switch(addr) { + case 0x420B: + //MDMAEN - DMA Enable + for(int i = 0; i < 8; i++) { + if(value & (1 << i)) { + RunDma(_channel[i]); + } + } + break; + + case 0x4300: case 0x4310: case 0x4320: case 0x4330: case 0x4340: case 0x4350: case 0x4360: case 0x4370: + { + //DMAPx - DMA Control for Channel x + DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + channel.InvertDirection = (value & 0x80) != 0; + channel.HdmaPointers = (value & 0x40) != 0; + channel.Decrement = (value & 0x10) != 0; + channel.FixedTransfer = (value & 0x08) != 0; + channel.TransferMode = value & 0x07; + break; + } + + case 0x4301: case 0x4311: case 0x4321: case 0x4331: case 0x4341: case 0x4351: case 0x4361: case 0x4371: + { + //BBADx - DMA Destination Register for Channel x + DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + channel.DestAddress = value; + break; + } + + case 0x4305: case 0x4315: case 0x4325: case 0x4335: case 0x4345: case 0x4355: case 0x4365: case 0x4375: + { + //DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7) + DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + channel.TransferSize = (channel.TransferSize & 0xFF00) | value; + break; + } + + case 0x4306: case 0x4316: case 0x4326: case 0x4336: case 0x4346: case 0x4356: case 0x4366: case 0x4376: + { + //DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7) + DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + channel.TransferSize = (channel.TransferSize & 0xFF) | (value << 8); + break; + } + + case 0x4302: case 0x4312: case 0x4322: case 0x4332: case 0x4342: case 0x4352: case 0x4362: case 0x4372: + { + DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + channel.SrcAddress = (channel.SrcAddress & 0xFFFF00) | value; + break; + } + + case 0x4303: case 0x4313: case 0x4323: case 0x4333: case 0x4343: case 0x4353: case 0x4363: case 0x4373: + { + DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + channel.SrcAddress = (channel.SrcAddress & 0xFF00FF) | (value << 8); + break; + } + + case 0x4304: case 0x4314: case 0x4324: case 0x4334: case 0x4344: case 0x4354: case 0x4364: case 0x4374: + { + DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4]; + channel.SrcAddress = (channel.SrcAddress & 0x00FFFF) | (value << 16); + break; + } + } +} diff --git a/Core/DmaController.h b/Core/DmaController.h new file mode 100644 index 0000000..01a7829 --- /dev/null +++ b/Core/DmaController.h @@ -0,0 +1,32 @@ +#pragma once +#include "stdafx.h" +#include "CpuTypes.h" + +class MemoryManager; + +struct DmaChannelConfig +{ + bool InvertDirection; + bool Decrement; + bool FixedTransfer; + bool HdmaPointers; + uint8_t TransferMode; + + uint32_t SrcAddress; + uint8_t DestAddress; + uint16_t TransferSize; +}; + +class DmaController +{ +private: + DmaChannelConfig _channel[8] = {}; + shared_ptr _memoryManager; + +public: + DmaController(shared_ptr memoryManager); + + void RunDma(DmaChannelConfig & channel); + + void Write(uint16_t addr, uint8_t value); +}; \ No newline at end of file diff --git a/Core/MemoryManager.h b/Core/MemoryManager.h index 8e5a1f6..ca6e92b 100644 --- a/Core/MemoryManager.h +++ b/Core/MemoryManager.h @@ -2,6 +2,7 @@ #include "stdafx.h" #include "Console.h" #include "Ppu.h" +#include "DmaController.h" #include "../Utilities/HexUtilities.h" #include "../Utilities/VirtualFile.h" @@ -56,21 +57,26 @@ class CpuRegisterHandler : public IMemoryHandler { private: shared_ptr _ppu; + shared_ptr _memoryManager; + unique_ptr _dmaController; public: - CpuRegisterHandler(shared_ptr ppu) + CpuRegisterHandler(shared_ptr console) { - _ppu = ppu; + _ppu = console->GetPpu(); + _memoryManager = console->GetMemoryManager(); + _dmaController.reset(new DmaController(_memoryManager)); } uint8_t Read(uint32_t addr) override { - return _ppu->Read(addr); + return _ppu->Read(addr & 0xFFFF); } void Write(uint32_t addr, uint8_t value) override { - _ppu->Write(addr, value); + _ppu->Write(addr & 0xFFFF, value); + _dmaController->Write(addr & 0xFFFF, value); } }; @@ -107,12 +113,16 @@ private: shared_ptr _cart; shared_ptr _cpuRegisterHandler; shared_ptr _ppu; + + unique_ptr _dmaController; + + uint32_t _wramPosition; uint64_t _masterClock; uint64_t _lastMasterClock; public: - MemoryManager(shared_ptr cart, shared_ptr console) + void Initialize(shared_ptr cart, shared_ptr console) { _lastMasterClock = 0; _masterClock = 0; @@ -120,11 +130,11 @@ public: _cart = cart; _ppu = console->GetPpu(); - _cpuRegisterHandler.reset(new CpuRegisterHandler(_ppu)); + _cpuRegisterHandler.reset(new CpuRegisterHandler(console)); memset(_handlers, 0, sizeof(_handlers)); _workRam = new uint8_t[128 * 1024]; - memset(_workRam, 0, 128 * 1024); + //memset(_workRam, 0, 128 * 1024); for(uint32_t i = 0; i < 128 * 1024; i += 0x1000) { _workRamHandlers.push_back(unique_ptr(new WorkRamHandler(_workRam + i))); @@ -234,6 +244,25 @@ public: { IncrementMasterClock(addr); + switch(addr & 0xFFFF) { + case 0x2180: + _workRam[_wramPosition] = value; + _wramPosition++; + break; + + case 0x2181: + _wramPosition = (_wramPosition & 0x1FF00) | value; + break; + + case 0x2182: + _wramPosition = (_wramPosition & 0x100FF) | (value << 8); + break; + + case 0x2183: + _wramPosition = (_wramPosition & 0xFFFF) | ((value & 0x01) << 16); + break; + } + _console->ProcessCpuWrite(addr, value, type); if(_handlers[addr >> 12]) { return _handlers[addr >> 12]->Write(addr, value); diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index 267e399..e70fb99 100644 --- a/Core/Ppu.cpp +++ b/Core/Ppu.cpp @@ -86,7 +86,9 @@ void Ppu::SendFrame() color >>= 1; } - uint16_t paletteColor = _cgram[(palette * 4 + color) * 2] | (_cgram[(palette * 4 + color) * 2 + 1] << 8); + uint16_t paletteRamOffset = color == 0 ? 0 : ((palette * 4 + color) * 2); + + uint16_t paletteColor = _cgram[paletteRamOffset] | (_cgram[paletteRamOffset + 1] << 8); _currentBuffer[(y * 8 + i) * 256 + x * 8 + j] = paletteColor; } } @@ -106,9 +108,9 @@ uint8_t Ppu::Read(uint16_t addr) case 0x4212: return ( - (_scanline >= 225 ? 0x80 : 0) || + (_scanline >= 225 ? 0x80 : 0) | ((_cycle >= 0x121 || _cycle <= 0x15) ? 0x40 : 0) - ); + ); } return 0; @@ -184,46 +186,5 @@ void Ppu::Write(uint32_t addr, uint8_t value) _enableNmi = (value & 0x80) != 0; break; - case 0x420B: - //MDMAEN - DMA Enable - if(value & 0x01) { - for(int i = 0; i < _dmaSize; i++) { - uint8_t valToWrite = _console->GetMemoryManager()->Read(_dmaSource, MemoryOperationType::Read); - _console->GetMemoryManager()->Write(0x2100 | _dmaDest, valToWrite, MemoryOperationType::Write); - _dmaSource++; - } - } - break; - - case 0x4300: - //DMAPx - DMA Control for Channel x - break; - - case 0x4301: - //BBADx - DMA Destination Register for Channel x - _dmaDest = value; - break; - - case 0x4305: - //DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7) - _dmaSize = (_dmaSize & 0xFF00) | value; - break; - - case 0x4306: - //DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7) - _dmaSize = (_dmaSize & 0xFF) | (value << 8); - break; - - case 0x4302: - _dmaSource = (_dmaSource & 0xFFFF00) | value; - break; - - case 0x4303: - _dmaSource = (_dmaSource & 0xFF00FF) | (value << 8); - break; - - case 0x4304: - _dmaSource = (_dmaSource & 0x00FFFF) | (value << 16); - break; } } diff --git a/Core/Ppu.h b/Core/Ppu.h index 6902713..0982921 100644 --- a/Core/Ppu.h +++ b/Core/Ppu.h @@ -29,9 +29,6 @@ private: LayerConfig _layerConfig[4]; - uint8_t _dmaDest = 0; - uint32_t _dmaSource = 0; - uint16_t _dmaSize = 0; public: Ppu(shared_ptr console);