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:
parent
9f29e86e2a
commit
bb0c8b1f10
3 changed files with 68 additions and 44 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Add table
Reference in a new issue