DMA: Restrict $2080<->WRAM DMA behavior based on tests

This commit is contained in:
Sour 2019-03-09 14:27:32 -05:00
parent 2cecde26fb
commit a018f1129a
9 changed files with 53 additions and 16 deletions

View file

@ -18,6 +18,7 @@ enum class SnesMemoryType
VideoRam,
SpriteRam,
CGRam,
Register
};
struct AddressInfo

View file

@ -8,6 +8,28 @@ DmaController::DmaController(MemoryManager *memoryManager)
_memoryManager = memoryManager;
}
void DmaController::CopyDmaByte(uint32_t addressBusA, uint16_t addressBusB, bool fromBtoA)
{
if(fromBtoA) {
if(addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA)) {
uint8_t valToWrite = _memoryManager->ReadDma(addressBusB);
_memoryManager->WriteDma(addressBusA, valToWrite);
} else {
//$2180->WRAM do cause a write to occur (but no read), but the value written is invalid
_memoryManager->IncrementMasterClockValue<4>();
_memoryManager->WriteDma(addressBusA, 0xFF);
}
} else {
if(addressBusB != 0x2180 || !_memoryManager->IsWorkRam(addressBusA)) {
uint8_t valToWrite = _memoryManager->ReadDma(addressBusA);
_memoryManager->WriteDma(addressBusB, valToWrite);
} else {
//WRAM->$2180 does not cause a write to occur
_memoryManager->IncrementMasterClockValue<8>();
}
}
}
void DmaController::RunSingleTransfer(DmaChannelConfig &channel)
{
const uint8_t *transferOffsets = _transferOffset[channel.TransferMode];
@ -15,13 +37,11 @@ void DmaController::RunSingleTransfer(DmaChannelConfig &channel)
uint8_t i = 0;
do {
if(channel.InvertDirection) {
uint8_t valToWrite = _memoryManager->ReadDma(0x2100 | channel.DestAddress + transferOffsets[i]);
_memoryManager->WriteDma((channel.SrcBank << 16) | channel.SrcAddress, valToWrite);
} else {
uint8_t valToWrite = _memoryManager->ReadDma((channel.SrcBank << 16) | channel.SrcAddress);
_memoryManager->WriteDma(0x2100 | channel.DestAddress + transferOffsets[i], valToWrite);
}
CopyDmaByte(
(channel.SrcBank << 16) | channel.SrcAddress,
0x2100 | channel.DestAddress + transferOffsets[i],
channel.InvertDirection
);
if(!channel.FixedTransfer) {
channel.SrcAddress += channel.Decrement ? -1 : 1;
@ -105,13 +125,11 @@ void DmaController::RunHdmaTransfer(DmaChannelConfig &channel)
uint8_t i = 0;
do {
if(channel.InvertDirection) {
uint8_t valToWrite = _memoryManager->ReadDma(0x2100 | channel.DestAddress + transferOffsets[i]);
_memoryManager->WriteDma(srcAddress, valToWrite);
} else {
uint8_t valToWrite = _memoryManager->ReadDma(srcAddress);
_memoryManager->WriteDma(0x2100 | channel.DestAddress + transferOffsets[i], valToWrite);
}
CopyDmaByte(
srcAddress,
0x2100 | channel.DestAddress + transferOffsets[i],
channel.InvertDirection
);
srcAddress = (srcAddress + (channel.Decrement ? -1 : 1)) & 0xFFFFFF;

View file

@ -43,6 +43,8 @@ private:
DmaChannelConfig _channel[8] = {};
MemoryManager *_memoryManager;
void CopyDmaByte(uint32_t addressBusA, uint16_t addressBusB, bool fromBtoA);
void RunSingleTransfer(DmaChannelConfig &channel);
void RunDma(DmaChannelConfig &channel);
void RunHdmaTransfer(DmaChannelConfig &channel);

View file

@ -4,11 +4,19 @@
class IMemoryHandler
{
protected:
SnesMemoryType _memoryType;
public:
virtual uint8_t Read(uint32_t addr) = 0;
virtual uint8_t Peek(uint32_t addr) = 0;
virtual void Write(uint32_t addr, uint8_t value) = 0;
__forceinline SnesMemoryType GetMemoryType()
{
return _memoryType;
}
virtual AddressInfo GetAbsoluteAddress(uint32_t address) = 0;
//virtual void GetMemoryRanges(MemoryRanges &ranges) = 0;

View file

@ -248,6 +248,12 @@ bool MemoryManager::IsRegister(uint32_t cpuAddress)
return _handlers[cpuAddress >> 12] == _registerHandlerA.get() || _handlers[cpuAddress >> 12] == _registerHandlerB.get();
}
bool MemoryManager::IsWorkRam(uint32_t cpuAddress)
{
IMemoryHandler* handler = _handlers[cpuAddress >> 12];
return handler && handler->GetMemoryType() == SnesMemoryType::WorkRam;
}
AddressInfo MemoryManager::GetAbsoluteAddress(uint32_t addr)
{
if(_handlers[addr >> 12]) {

View file

@ -62,6 +62,7 @@ public:
uint8_t* DebugGetWorkRam();
bool IsRegister(uint32_t cpuAddress);
bool IsWorkRam(uint32_t cpuAddress);
AddressInfo GetAbsoluteAddress(uint32_t addr);
int GetRelativeAddress(AddressInfo &address, int32_t cpuAddress = -1);
};

View file

@ -9,7 +9,6 @@ private:
uint8_t * _ram;
uint32_t _offset;
uint32_t _mask;
SnesMemoryType _memoryType;
public:
RamHandler(uint8_t *ram, uint32_t offset, uint32_t size, SnesMemoryType memoryType)

View file

@ -18,6 +18,7 @@ public:
_regs = regs;
_dmaController = dmaController;
_controlManager = controlManager;
_memoryType = SnesMemoryType::Register;
}
uint8_t Read(uint32_t addr) override

View file

@ -22,6 +22,7 @@ public:
_spc = spc;
_workRam = workRam;
_wramPosition = 0;
_memoryType = SnesMemoryType::Register;
}
uint8_t Read(uint32_t addr) override