DMA: Restrict $2080<->WRAM DMA behavior based on tests
This commit is contained in:
parent
2cecde26fb
commit
a018f1129a
9 changed files with 53 additions and 16 deletions
|
@ -18,6 +18,7 @@ enum class SnesMemoryType
|
|||
VideoRam,
|
||||
SpriteRam,
|
||||
CGRam,
|
||||
Register
|
||||
};
|
||||
|
||||
struct AddressInfo
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -43,13 +43,15 @@ 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);
|
||||
|
||||
public:
|
||||
DmaController(MemoryManager *memoryManager);
|
||||
|
||||
|
||||
void InitHdmaChannels();
|
||||
void ProcessHdmaChannels();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]) {
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -18,6 +18,7 @@ public:
|
|||
_regs = regs;
|
||||
_dmaController = dmaController;
|
||||
_controlManager = controlManager;
|
||||
_memoryType = SnesMemoryType::Register;
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
_spc = spc;
|
||||
_workRam = workRam;
|
||||
_wramPosition = 0;
|
||||
_memoryType = SnesMemoryType::Register;
|
||||
}
|
||||
|
||||
uint8_t Read(uint32_t addr) override
|
||||
|
|
Loading…
Add table
Reference in a new issue