DMA: Added support for HDMA (incorrect timings)
This commit is contained in:
parent
384a5a2c99
commit
221bc44700
6 changed files with 215 additions and 31 deletions
|
@ -6,6 +6,7 @@
|
||||||
#include "InternalRegisters.h"
|
#include "InternalRegisters.h"
|
||||||
#include "ControlManager.h"
|
#include "ControlManager.h"
|
||||||
#include "MemoryManager.h"
|
#include "MemoryManager.h"
|
||||||
|
#include "DmaController.h"
|
||||||
#include "Debugger.h"
|
#include "Debugger.h"
|
||||||
#include "NotificationManager.h"
|
#include "NotificationManager.h"
|
||||||
#include "SoundMixer.h"
|
#include "SoundMixer.h"
|
||||||
|
@ -73,6 +74,7 @@ void Console::Stop()
|
||||||
_internalRegisters.reset();
|
_internalRegisters.reset();
|
||||||
_controlManager.reset();
|
_controlManager.reset();
|
||||||
_memoryManager.reset();
|
_memoryManager.reset();
|
||||||
|
_dmaController.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile)
|
void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile)
|
||||||
|
@ -88,6 +90,8 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile)
|
||||||
_cart = cart;
|
_cart = cart;
|
||||||
_controlManager.reset(new ControlManager(shared_from_this()));
|
_controlManager.reset(new ControlManager(shared_from_this()));
|
||||||
_memoryManager.reset(new MemoryManager());
|
_memoryManager.reset(new MemoryManager());
|
||||||
|
_dmaController.reset(new DmaController(_memoryManager.get()));
|
||||||
|
|
||||||
_memoryManager->Initialize(shared_from_this());
|
_memoryManager->Initialize(shared_from_this());
|
||||||
|
|
||||||
_cpu.reset(new Cpu(_memoryManager));
|
_cpu.reset(new Cpu(_memoryManager));
|
||||||
|
@ -161,6 +165,11 @@ shared_ptr<ControlManager> Console::GetControlManager()
|
||||||
return _controlManager;
|
return _controlManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared_ptr<DmaController> Console::GetDmaController()
|
||||||
|
{
|
||||||
|
return _dmaController;
|
||||||
|
}
|
||||||
|
|
||||||
shared_ptr<Debugger> Console::GetDebugger(bool autoStart)
|
shared_ptr<Debugger> Console::GetDebugger(bool autoStart)
|
||||||
{
|
{
|
||||||
shared_ptr<Debugger> debugger = _debugger;
|
shared_ptr<Debugger> debugger = _debugger;
|
||||||
|
|
|
@ -10,6 +10,7 @@ class BaseCartridge;
|
||||||
class MemoryManager;
|
class MemoryManager;
|
||||||
class InternalRegisters;
|
class InternalRegisters;
|
||||||
class ControlManager;
|
class ControlManager;
|
||||||
|
class DmaController;
|
||||||
class Debugger;
|
class Debugger;
|
||||||
class DebugHud;
|
class DebugHud;
|
||||||
class SoundMixer;
|
class SoundMixer;
|
||||||
|
@ -28,6 +29,7 @@ private:
|
||||||
shared_ptr<BaseCartridge> _cart;
|
shared_ptr<BaseCartridge> _cart;
|
||||||
shared_ptr<InternalRegisters> _internalRegisters;
|
shared_ptr<InternalRegisters> _internalRegisters;
|
||||||
shared_ptr<ControlManager> _controlManager;
|
shared_ptr<ControlManager> _controlManager;
|
||||||
|
shared_ptr<DmaController> _dmaController;
|
||||||
|
|
||||||
shared_ptr<Debugger> _debugger;
|
shared_ptr<Debugger> _debugger;
|
||||||
|
|
||||||
|
@ -64,6 +66,7 @@ public:
|
||||||
shared_ptr<MemoryManager> GetMemoryManager();
|
shared_ptr<MemoryManager> GetMemoryManager();
|
||||||
shared_ptr<InternalRegisters> GetInternalRegisters();
|
shared_ptr<InternalRegisters> GetInternalRegisters();
|
||||||
shared_ptr<ControlManager> GetControlManager();
|
shared_ptr<ControlManager> GetControlManager();
|
||||||
|
shared_ptr<DmaController> GetDmaController();
|
||||||
shared_ptr<Debugger> GetDebugger(bool autoStart = true);
|
shared_ptr<Debugger> GetDebugger(bool autoStart = true);
|
||||||
|
|
||||||
bool IsRunning();
|
bool IsRunning();
|
||||||
|
|
|
@ -8,41 +8,158 @@ DmaController::DmaController(MemoryManager *memoryManager)
|
||||||
_memoryManager = memoryManager;
|
_memoryManager = memoryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DmaController::RunSingleTransfer(DmaChannelConfig &channel, uint32_t &bytesLeft)
|
void DmaController::RunSingleTransfer(DmaChannelConfig &channel)
|
||||||
{
|
{
|
||||||
const uint8_t *transferOffsets = _transferOffset[channel.TransferMode];
|
const uint8_t *transferOffsets = _transferOffset[channel.TransferMode];
|
||||||
uint8_t transferByteCount = _transferByteCount[channel.TransferMode];
|
uint8_t transferByteCount = _transferByteCount[channel.TransferMode];
|
||||||
|
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
while(bytesLeft > 0 && transferByteCount > 0) {
|
do {
|
||||||
if(channel.InvertDirection) {
|
if(channel.InvertDirection) {
|
||||||
uint8_t valToWrite = _memoryManager->Read(0x2100 | channel.DestAddress + transferOffsets[i], MemoryOperationType::DmaRead);
|
uint8_t valToWrite = _memoryManager->Read(0x2100 | channel.DestAddress + transferOffsets[i], MemoryOperationType::DmaRead);
|
||||||
_memoryManager->Write(channel.SrcAddress, valToWrite, MemoryOperationType::DmaWrite);
|
_memoryManager->Write((channel.SrcBank << 16) | channel.SrcAddress, valToWrite, MemoryOperationType::DmaWrite);
|
||||||
} else {
|
} else {
|
||||||
uint8_t valToWrite = _memoryManager->Read(channel.SrcAddress, MemoryOperationType::DmaRead);
|
uint8_t valToWrite = _memoryManager->Read((channel.SrcBank << 16) | channel.SrcAddress, MemoryOperationType::DmaRead);
|
||||||
_memoryManager->Write(0x2100 | channel.DestAddress + transferOffsets[i], valToWrite, MemoryOperationType::DmaWrite);
|
_memoryManager->Write(0x2100 | channel.DestAddress + transferOffsets[i], valToWrite, MemoryOperationType::DmaWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!channel.FixedTransfer) {
|
if(!channel.FixedTransfer) {
|
||||||
channel.SrcAddress = (channel.SrcAddress + (channel.Decrement ? -1 : 1)) & 0xFFFFFF;
|
channel.SrcAddress += channel.Decrement ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel.TransferSize--;
|
||||||
transferByteCount--;
|
transferByteCount--;
|
||||||
bytesLeft--;
|
|
||||||
i++;
|
i++;
|
||||||
}
|
} while(channel.TransferSize > 0 && transferByteCount > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DmaController::RunDma(DmaChannelConfig &channel)
|
void DmaController::RunDma(DmaChannelConfig &channel)
|
||||||
{
|
{
|
||||||
//"Note, however, that writing $0000 to this register actually results in a transfer of $10000 bytes, not 0."
|
do {
|
||||||
uint32_t bytesLeft = channel.TransferSize ? channel.TransferSize : 0x10000;
|
|
||||||
|
|
||||||
MessageManager::Log("Run DMA: " + HexUtilities::ToHex(channel.DestAddress) + " -> " + HexUtilities::ToHex(channel.SrcAddress) + " Bytes: " + std::to_string(bytesLeft));
|
|
||||||
|
|
||||||
while(bytesLeft > 0) {
|
|
||||||
//Manual DMA transfers run to the end of the transfer when started
|
//Manual DMA transfers run to the end of the transfer when started
|
||||||
RunSingleTransfer(channel, bytesLeft);
|
RunSingleTransfer(channel);
|
||||||
|
|
||||||
|
//TODO : Run HDMA when needed, between 2 DMA transfers
|
||||||
|
} while(channel.TransferSize > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DmaController::InitHdmaChannels()
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 8; i++) {
|
||||||
|
DmaChannelConfig &ch = _channel[i];
|
||||||
|
ch.HdmaFinished = false;
|
||||||
|
if(_hdmaChannels & (1 << i)) {
|
||||||
|
//"1. Copy AAddress into Address."
|
||||||
|
ch.HdmaTableAddress = ch.SrcAddress;
|
||||||
|
|
||||||
|
//"2. Load $43xA (Line Counter and Repeat) from the table. I believe $00 will terminate this channel immediately."
|
||||||
|
ch.HdmaLineCounterAndRepeat = _memoryManager->Read((ch.SrcBank << 16) | ch.HdmaTableAddress, MemoryOperationType::DmaRead);
|
||||||
|
ch.HdmaTableAddress++;
|
||||||
|
if(ch.HdmaLineCounterAndRepeat == 0) {
|
||||||
|
ch.HdmaFinished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//3. Load Indirect Address, if necessary.
|
||||||
|
if(ch.HdmaIndirectAddressing) {
|
||||||
|
uint8_t lsb = _memoryManager->Read((ch.SrcBank << 16) | ch.HdmaTableAddress++, MemoryOperationType::DmaRead);
|
||||||
|
uint8_t msb = _memoryManager->Read((ch.SrcBank << 16) | ch.HdmaTableAddress++, MemoryOperationType::DmaRead);
|
||||||
|
ch.TransferSize = (msb << 8) | lsb;
|
||||||
|
}
|
||||||
|
|
||||||
|
//4. Set DoTransfer to true.
|
||||||
|
ch.DoTransfer = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DmaController::RunHdmaTransfer(DmaChannelConfig &channel)
|
||||||
|
{
|
||||||
|
const uint8_t *transferOffsets = _transferOffset[channel.TransferMode];
|
||||||
|
uint8_t transferByteCount = _transferByteCount[channel.TransferMode];
|
||||||
|
|
||||||
|
uint32_t srcAddress;
|
||||||
|
if(channel.HdmaIndirectAddressing) {
|
||||||
|
srcAddress = (channel.HdmaBank << 16) | channel.TransferSize;
|
||||||
|
} else {
|
||||||
|
srcAddress = (channel.SrcBank << 16) | channel.HdmaTableAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t i = 0;
|
||||||
|
do {
|
||||||
|
if(channel.InvertDirection) {
|
||||||
|
uint8_t valToWrite = _memoryManager->Read(0x2100 | channel.DestAddress + transferOffsets[i], MemoryOperationType::DmaRead);
|
||||||
|
_memoryManager->Write(srcAddress, valToWrite, MemoryOperationType::DmaWrite);
|
||||||
|
} else {
|
||||||
|
uint8_t valToWrite = _memoryManager->Read(srcAddress, MemoryOperationType::DmaRead);
|
||||||
|
_memoryManager->Write(0x2100 | channel.DestAddress + transferOffsets[i], valToWrite, MemoryOperationType::DmaWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!channel.FixedTransfer) {
|
||||||
|
srcAddress = (srcAddress + (channel.Decrement ? -1 : 1)) & 0xFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
transferByteCount--;
|
||||||
|
i++;
|
||||||
|
} while(transferByteCount > 0);
|
||||||
|
|
||||||
|
if(channel.HdmaIndirectAddressing) {
|
||||||
|
channel.TransferSize = srcAddress;
|
||||||
|
} else {
|
||||||
|
channel.HdmaTableAddress = srcAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DmaController::ProcessHdmaChannels()
|
||||||
|
{
|
||||||
|
if(_hdmaChannels) {
|
||||||
|
_hdmaPending = true;
|
||||||
|
|
||||||
|
for(int i = 0; i < 8; i++) {
|
||||||
|
DmaChannelConfig &ch = _channel[i];
|
||||||
|
if((_hdmaChannels & (1 << i)) == 0 || ch.HdmaFinished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//1. If DoTransfer is false, skip to step 3.
|
||||||
|
if(ch.DoTransfer) {
|
||||||
|
//2. For the number of bytes (1, 2, or 4) required for this Transfer Mode...
|
||||||
|
RunHdmaTransfer(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
//3. Decrement $43xA.
|
||||||
|
ch.HdmaLineCounterAndRepeat--;
|
||||||
|
|
||||||
|
//4. Set DoTransfer to the value of Repeat.
|
||||||
|
ch.DoTransfer = (ch.HdmaLineCounterAndRepeat & 0x80) != 0;
|
||||||
|
|
||||||
|
//5. If Line Counter is zero...
|
||||||
|
if((ch.HdmaLineCounterAndRepeat & 0x7F) == 0) {
|
||||||
|
//"a. Read the next byte from Address into $43xA (thus, into both Line Counter and Repeat)."
|
||||||
|
ch.HdmaLineCounterAndRepeat = _memoryManager->Read(ch.HdmaTableAddress++, MemoryOperationType::DmaRead);
|
||||||
|
|
||||||
|
//"b. If Addressing Mode is Indirect, read two bytes from Address into Indirect Address(and increment Address by two bytes)."
|
||||||
|
if(ch.HdmaIndirectAddressing) {
|
||||||
|
if(ch.HdmaLineCounterAndRepeat == 0) {
|
||||||
|
//"One oddity: if $43xA is 0 and this is the last active HDMA channel for this scanline, only load one byte for Address,
|
||||||
|
//and use the $00 for the low byte.So Address ends up incremented one less than otherwise expected, and one less CPU Cycle is used."
|
||||||
|
uint8_t msb = _memoryManager->Read(ch.HdmaTableAddress++, MemoryOperationType::DmaRead);
|
||||||
|
ch.TransferSize = (msb << 8);
|
||||||
|
} else {
|
||||||
|
uint8_t lsb = _memoryManager->Read(ch.HdmaTableAddress++, MemoryOperationType::DmaRead);
|
||||||
|
uint8_t msb = _memoryManager->Read(ch.HdmaTableAddress++, MemoryOperationType::DmaRead);
|
||||||
|
ch.TransferSize = (msb << 8) | lsb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//"c. If $43xA is zero, terminate this HDMA channel for this frame. The bit in $420c is not cleared, though, so it may be automatically restarted next frame."
|
||||||
|
if(ch.HdmaLineCounterAndRepeat == 0) {
|
||||||
|
ch.HdmaFinished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//"d. Set DoTransfer to true."
|
||||||
|
ch.DoTransfer = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,9 +177,7 @@ void DmaController::Write(uint16_t addr, uint8_t value)
|
||||||
|
|
||||||
case 0x420C:
|
case 0x420C:
|
||||||
//HDMAEN - HDMA Enable
|
//HDMAEN - HDMA Enable
|
||||||
if(value > 0) {
|
_hdmaChannels = value;
|
||||||
MessageManager::DisplayMessage("Debug", "Unsupported HDMA operation");
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x4300: case 0x4310: case 0x4320: case 0x4330: case 0x4340: case 0x4350: case 0x4360: case 0x4370:
|
case 0x4300: case 0x4310: case 0x4320: case 0x4330: case 0x4340: case 0x4350: case 0x4360: case 0x4370:
|
||||||
|
@ -70,7 +185,7 @@ void DmaController::Write(uint16_t addr, uint8_t value)
|
||||||
//DMAPx - DMA Control for Channel x
|
//DMAPx - DMA Control for Channel x
|
||||||
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
|
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
|
||||||
channel.InvertDirection = (value & 0x80) != 0;
|
channel.InvertDirection = (value & 0x80) != 0;
|
||||||
channel.HdmaPointers = (value & 0x40) != 0;
|
channel.HdmaIndirectAddressing = (value & 0x40) != 0;
|
||||||
channel.Decrement = (value & 0x10) != 0;
|
channel.Decrement = (value & 0x10) != 0;
|
||||||
channel.FixedTransfer = (value & 0x08) != 0;
|
channel.FixedTransfer = (value & 0x08) != 0;
|
||||||
channel.TransferMode = value & 0x07;
|
channel.TransferMode = value & 0x07;
|
||||||
|
@ -85,6 +200,27 @@ void DmaController::Write(uint16_t addr, uint8_t value)
|
||||||
break;
|
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 & 0xFF00) | 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 & 0xFF) | (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.SrcBank = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 0x4305: case 0x4315: case 0x4325: case 0x4335: case 0x4345: case 0x4355: case 0x4365: case 0x4375:
|
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)
|
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
|
||||||
|
@ -101,24 +237,35 @@ void DmaController::Write(uint16_t addr, uint8_t value)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x4302: case 0x4312: case 0x4322: case 0x4332: case 0x4342: case 0x4352: case 0x4362: case 0x4372:
|
case 0x4307: case 0x4317: case 0x4327: case 0x4337: case 0x4347: case 0x4357: case 0x4367: case 0x4377:
|
||||||
{
|
{
|
||||||
|
//DASBx - HDMA Indirect Address bank byte (x=0-7)
|
||||||
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
|
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
|
||||||
channel.SrcAddress = (channel.SrcAddress & 0xFFFF00) | value;
|
channel.HdmaBank = value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x4303: case 0x4313: case 0x4323: case 0x4333: case 0x4343: case 0x4353: case 0x4363: case 0x4373:
|
case 0x4308: case 0x4318: case 0x4328: case 0x4338: case 0x4348: case 0x4358: case 0x4368: case 0x4378:
|
||||||
{
|
{
|
||||||
|
//A2AxL - HDMA Table Address low byte (x=0-7)
|
||||||
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
|
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
|
||||||
channel.SrcAddress = (channel.SrcAddress & 0xFF00FF) | (value << 8);
|
channel.HdmaTableAddress = (channel.HdmaTableAddress & 0xFF00) | value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x4304: case 0x4314: case 0x4324: case 0x4334: case 0x4344: case 0x4354: case 0x4364: case 0x4374:
|
case 0x4309: case 0x4319: case 0x4329: case 0x4339: case 0x4349: case 0x4359: case 0x4369: case 0x4379:
|
||||||
{
|
{
|
||||||
|
//A2AxH - HDMA Table Address high byte (x=0-7)
|
||||||
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
|
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
|
||||||
channel.SrcAddress = (channel.SrcAddress & 0x00FFFF) | (value << 16);
|
channel.HdmaTableAddress = (value << 8) | (channel.HdmaTableAddress & 0xFF);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x430A: case 0x431A: case 0x432A: case 0x433A: case 0x434A: case 0x435A: case 0x436A: case 0x437A:
|
||||||
|
{
|
||||||
|
//DASBx - HDMA Indirect Address bank byte (x=0-7)
|
||||||
|
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
|
||||||
|
channel.HdmaLineCounterAndRepeat = value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,20 @@ struct DmaChannelConfig
|
||||||
bool InvertDirection;
|
bool InvertDirection;
|
||||||
bool Decrement;
|
bool Decrement;
|
||||||
bool FixedTransfer;
|
bool FixedTransfer;
|
||||||
bool HdmaPointers;
|
bool HdmaIndirectAddressing;
|
||||||
uint8_t TransferMode;
|
uint8_t TransferMode;
|
||||||
|
|
||||||
uint32_t SrcAddress;
|
uint16_t SrcAddress;
|
||||||
|
uint16_t SrcBank;
|
||||||
|
|
||||||
uint8_t DestAddress;
|
uint8_t DestAddress;
|
||||||
uint16_t TransferSize;
|
uint16_t TransferSize;
|
||||||
|
|
||||||
|
uint8_t HdmaBank;
|
||||||
|
uint16_t HdmaTableAddress;
|
||||||
|
uint8_t HdmaLineCounterAndRepeat;
|
||||||
|
bool DoTransfer;
|
||||||
|
bool HdmaFinished;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DmaController
|
class DmaController
|
||||||
|
@ -26,14 +34,21 @@ private:
|
||||||
{ 0, 1, 2, 3 }, { 0, 1, 0, 1 }, { 0, 0, 0, 0 }, { 0, 0, 1, 1 }
|
{ 0, 1, 2, 3 }, { 0, 1, 0, 1 }, { 0, 0, 0, 0 }, { 0, 0, 1, 1 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool _hdmaPending = false;
|
||||||
|
uint8_t _hdmaChannels = 0;
|
||||||
|
|
||||||
DmaChannelConfig _channel[8] = {};
|
DmaChannelConfig _channel[8] = {};
|
||||||
MemoryManager *_memoryManager;
|
MemoryManager *_memoryManager;
|
||||||
|
|
||||||
void RunSingleTransfer(DmaChannelConfig &channel, uint32_t &bytesLeft);
|
void RunSingleTransfer(DmaChannelConfig &channel);
|
||||||
void RunDma(DmaChannelConfig &channel);
|
void RunDma(DmaChannelConfig &channel);
|
||||||
|
void RunHdmaTransfer(DmaChannelConfig &channel);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DmaController(MemoryManager *memoryManager);
|
DmaController(MemoryManager *memoryManager);
|
||||||
|
|
||||||
|
void InitHdmaChannels();
|
||||||
|
void ProcessHdmaChannels();
|
||||||
|
|
||||||
void Write(uint16_t addr, uint8_t value);
|
void Write(uint16_t addr, uint8_t value);
|
||||||
};
|
};
|
|
@ -89,7 +89,6 @@ private:
|
||||||
shared_ptr<BaseCartridge> _cart;
|
shared_ptr<BaseCartridge> _cart;
|
||||||
shared_ptr<CpuRegisterHandler> _cpuRegisterHandler;
|
shared_ptr<CpuRegisterHandler> _cpuRegisterHandler;
|
||||||
shared_ptr<Ppu> _ppu;
|
shared_ptr<Ppu> _ppu;
|
||||||
shared_ptr<DmaController> _dmaController;
|
|
||||||
|
|
||||||
IMemoryHandler* _handlers[0x100 * 0x10];
|
IMemoryHandler* _handlers[0x100 * 0x10];
|
||||||
vector<unique_ptr<RamHandler>> _workRamHandlers;
|
vector<unique_ptr<RamHandler>> _workRamHandlers;
|
||||||
|
@ -110,8 +109,14 @@ public:
|
||||||
|
|
||||||
_workRam = new uint8_t[MemoryManager::WorkRamSize];
|
_workRam = new uint8_t[MemoryManager::WorkRamSize];
|
||||||
|
|
||||||
_dmaController.reset(new DmaController(console->GetMemoryManager().get()));
|
_cpuRegisterHandler.reset(new CpuRegisterHandler(
|
||||||
_cpuRegisterHandler.reset(new CpuRegisterHandler(_ppu.get(), console->GetSpc().get(), _dmaController.get(), console->GetInternalRegisters().get(), console->GetControlManager().get(), _workRam));
|
_ppu.get(),
|
||||||
|
console->GetSpc().get(),
|
||||||
|
console->GetDmaController().get(),
|
||||||
|
console->GetInternalRegisters().get(),
|
||||||
|
console->GetControlManager().get(),
|
||||||
|
_workRam
|
||||||
|
));
|
||||||
|
|
||||||
memset(_handlers, 0, sizeof(_handlers));
|
memset(_handlers, 0, sizeof(_handlers));
|
||||||
//memset(_workRam, 0, 128 * 1024);
|
//memset(_workRam, 0, 128 * 1024);
|
||||||
|
|
|
@ -87,6 +87,7 @@ void Ppu::Exec()
|
||||||
} else if(_scanline == 261) {
|
} else if(_scanline == 261) {
|
||||||
_regs->SetNmiFlag(false);
|
_regs->SetNmiFlag(false);
|
||||||
_scanline = 0;
|
_scanline = 0;
|
||||||
|
_console->GetDmaController()->InitHdmaChannels();
|
||||||
RenderScanline();
|
RenderScanline();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +103,10 @@ void Ppu::Exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
_cycle++;
|
_cycle++;
|
||||||
|
|
||||||
|
if(_cycle == 278 && _scanline < 225) {
|
||||||
|
_console->GetDmaController()->ProcessHdmaChannels();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SpriteInfo
|
struct SpriteInfo
|
||||||
|
|
Loading…
Add table
Reference in a new issue