DMA: Fix behavior when trying to write to B bus registers using the A bus (and when trying to read/write DMA registers using DMA) + fixed DMA wrapping when it reaches the end of a bank

This commit is contained in:
Sour 2019-03-16 16:36:58 -04:00
parent 9f29e86e2a
commit bb0c8b1f10
3 changed files with 68 additions and 44 deletions

View file

@ -26,17 +26,17 @@ void DmaController::CopyDmaByte(uint32_t addressBusA, uint16_t addressBusB, bool
{ {
if(fromBtoA) { if(fromBtoA) {
if(addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA)) { if(addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA)) {
uint8_t valToWrite = _memoryManager->ReadDma(addressBusB); uint8_t valToWrite = _memoryManager->ReadDma(addressBusB, false);
_memoryManager->WriteDma(addressBusA, valToWrite); _memoryManager->WriteDma(addressBusA, valToWrite, true);
} else { } else {
//$2180->WRAM do cause a write to occur (but no read), but the value written is invalid //$2180->WRAM do cause a write to occur (but no read), but the value written is invalid
_memoryManager->IncrementMasterClockValue<4>(); _memoryManager->IncrementMasterClockValue<4>();
_memoryManager->WriteDma(addressBusA, 0xFF); _memoryManager->WriteDma(addressBusA, 0xFF, true);
} }
} else { } else {
if(addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA)) { if(addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA)) {
uint8_t valToWrite = _memoryManager->ReadDma(addressBusA); uint8_t valToWrite = _memoryManager->ReadDma(addressBusA, true);
_memoryManager->WriteDma(addressBusB, valToWrite); _memoryManager->WriteDma(addressBusB, valToWrite, false);
} else { } else {
//WRAM->$2180 does not cause a write to occur //WRAM->$2180 does not cause a write to occur
_memoryManager->IncrementMasterClockValue<8>(); _memoryManager->IncrementMasterClockValue<8>();
@ -98,7 +98,7 @@ void DmaController::InitHdmaChannels()
ch.InterruptedByHdma = true; ch.InterruptedByHdma = true;
//"2. Load $43xA (Line Counter and Repeat) from the table. I believe $00 will terminate this channel immediately." //"2. Load $43xA (Line Counter and Repeat) from the table. I believe $00 will terminate this channel immediately."
ch.HdmaLineCounterAndRepeat = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress); ch.HdmaLineCounterAndRepeat = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress, true);
ch.HdmaTableAddress++; ch.HdmaTableAddress++;
if(ch.HdmaLineCounterAndRepeat == 0) { if(ch.HdmaLineCounterAndRepeat == 0) {
ch.HdmaFinished = true; ch.HdmaFinished = true;
@ -106,8 +106,8 @@ void DmaController::InitHdmaChannels()
//3. Load Indirect Address, if necessary. //3. Load Indirect Address, if necessary.
if(ch.HdmaIndirectAddressing) { if(ch.HdmaIndirectAddressing) {
uint8_t lsb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++); uint8_t lsb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++); uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
ch.TransferSize = (msb << 8) | lsb; ch.TransferSize = (msb << 8) | lsb;
//"and 24 master cycles for each channel set for indirect HDMA" //"and 24 master cycles for each channel set for indirect HDMA"
@ -127,34 +127,31 @@ void DmaController::RunHdmaTransfer(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];
channel.InterruptedByHdma = true; channel.InterruptedByHdma = true;
uint32_t srcAddress;
if(channel.HdmaIndirectAddressing) {
srcAddress = (channel.HdmaBank << 16) | channel.TransferSize;
} else {
srcAddress = (channel.SrcBank << 16) | channel.HdmaTableAddress;
}
uint8_t i = 0; uint8_t i = 0;
do {
CopyDmaByte(
srcAddress,
0x2100 | channel.DestAddress + transferOffsets[i],
channel.InvertDirection
);
srcAddress = (srcAddress + (channel.Decrement ? -1 : 1)) & 0xFFFFFF;
transferByteCount--;
i++;
} while(transferByteCount > 0);
if(channel.HdmaIndirectAddressing) { if(channel.HdmaIndirectAddressing) {
channel.TransferSize = srcAddress; do {
CopyDmaByte(
(channel.HdmaBank << 16) | channel.TransferSize,
0x2100 | channel.DestAddress + transferOffsets[i],
channel.InvertDirection
);
channel.TransferSize += (channel.Decrement ? -1 : 1);
transferByteCount--;
i++;
} while(transferByteCount > 0);
} else { } else {
channel.HdmaTableAddress = srcAddress; do {
CopyDmaByte(
(channel.SrcBank << 16) | channel.HdmaTableAddress,
0x2100 | channel.DestAddress + transferOffsets[i],
channel.InvertDirection
);
channel.HdmaTableAddress += (channel.Decrement ? -1 : 1);
transferByteCount--;
i++;
} while(transferByteCount > 0);
} }
} }
@ -200,18 +197,18 @@ void DmaController::ProcessHdmaChannels()
//5. If Line Counter is zero... //5. If Line Counter is zero...
if((ch.HdmaLineCounterAndRepeat & 0x7F) == 0) { if((ch.HdmaLineCounterAndRepeat & 0x7F) == 0) {
//"a. Read the next byte from Address into $43xA (thus, into both Line Counter and Repeat)." //"a. Read the next byte from Address into $43xA (thus, into both Line Counter and Repeat)."
ch.HdmaLineCounterAndRepeat = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++); ch.HdmaLineCounterAndRepeat = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
//"b. If Addressing Mode is Indirect, read two bytes from Address into Indirect Address(and increment Address by two bytes)." //"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.HdmaIndirectAddressing) {
if(ch.HdmaLineCounterAndRepeat == 0) { 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, //"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." //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->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++); uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
ch.TransferSize = (msb << 8); ch.TransferSize = (msb << 8);
} else { } else {
uint8_t lsb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++); uint8_t lsb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++); uint8_t msb = _memoryManager->ReadDma((ch.SrcBank << 16) | ch.HdmaTableAddress++, true);
ch.TransferSize = (msb << 8) | lsb; ch.TransferSize = (msb << 8) | lsb;
} }

View file

@ -177,12 +177,26 @@ uint8_t MemoryManager::Read(uint32_t addr, MemoryOperationType type)
return value; return value;
} }
uint8_t MemoryManager::ReadDma(uint32_t addr) uint8_t MemoryManager::ReadDma(uint32_t addr, bool forBusA)
{ {
IncrementMasterClockValue<4>(); IncrementMasterClockValue<4>();
uint8_t value; uint8_t value;
if(_handlers[addr >> 12]) { IMemoryHandler* handlers = _handlers[addr >> 12];
value = _handlers[addr >> 12]->Read(addr); if(handlers) {
if(forBusA && handlers == _registerHandlerB.get()) {
//Trying to read from bus B using bus A returns open bus
value = _openBus;
} else if(handlers == _registerHandlerA.get()) {
uint16_t regAddr = addr & 0xFFFF;
if(regAddr == 0x420B || regAddr == 0x420C || (regAddr >= 0x4300 && regAddr <= 0x437F)) {
//Trying to read the DMA controller with DMA returns open bus
value = _openBus;
} else {
value = handlers->Read(addr);
}
} else {
value = handlers->Read(addr);
}
_openBus = value; _openBus = value;
} else { } else {
//open bus //open bus
@ -216,19 +230,32 @@ void MemoryManager::Write(uint32_t addr, uint8_t value, MemoryOperationType type
_console->ProcessCpuWrite(addr, value, type); _console->ProcessCpuWrite(addr, value, type);
if(_handlers[addr >> 12]) { if(_handlers[addr >> 12]) {
return _handlers[addr >> 12]->Write(addr, value); _handlers[addr >> 12]->Write(addr, value);
} else { } else {
MessageManager::Log("[Debug] Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); MessageManager::Log("[Debug] Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value));
} }
} }
void MemoryManager::WriteDma(uint32_t addr, uint8_t value) void MemoryManager::WriteDma(uint32_t addr, uint8_t value, bool forBusA)
{ {
IncrementMasterClockValue<4>(); IncrementMasterClockValue<4>();
_console->ProcessCpuWrite(addr, value, MemoryOperationType::DmaWrite); _console->ProcessCpuWrite(addr, value, MemoryOperationType::DmaWrite);
if(_handlers[addr >> 12]) {
return _handlers[addr >> 12]->Write(addr, value); IMemoryHandler* handlers = _handlers[addr >> 12];
if(handlers) {
if(forBusA && handlers == _registerHandlerB.get()) {
//Trying to write to bus B using bus A does nothing
} else if(handlers == _registerHandlerA.get()) {
uint16_t regAddr = addr & 0xFFFF;
if(regAddr == 0x420B || regAddr == 0x420C || (regAddr >= 0x4300 && regAddr <= 0x437F)) {
//Trying to write to the DMA controller with DMA does nothing
} else {
handlers->Write(addr, value);
}
} else {
handlers->Write(addr, value);
}
} else { } else {
MessageManager::Log("[Debug] Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); MessageManager::Log("[Debug] Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value));
} }

View file

@ -52,12 +52,12 @@ public:
void IncrementMasterClockValue(uint16_t value); void IncrementMasterClockValue(uint16_t value);
uint8_t Read(uint32_t addr, MemoryOperationType type); uint8_t Read(uint32_t addr, MemoryOperationType type);
uint8_t ReadDma(uint32_t addr); uint8_t ReadDma(uint32_t addr, bool forBusA);
uint8_t Peek(uint32_t addr); uint8_t Peek(uint32_t addr);
uint16_t PeekWord(uint32_t addr); uint16_t PeekWord(uint32_t addr);
void Write(uint32_t addr, uint8_t value, MemoryOperationType type); void Write(uint32_t addr, uint8_t value, MemoryOperationType type);
void WriteDma(uint32_t addr, uint8_t value); void WriteDma(uint32_t addr, uint8_t value, bool forBusA);
uint8_t GetOpenBus(); uint8_t GetOpenBus();
uint64_t GetMasterClock(); uint64_t GetMasterClock();