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,
|
VideoRam,
|
||||||
SpriteRam,
|
SpriteRam,
|
||||||
CGRam,
|
CGRam,
|
||||||
|
Register
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AddressInfo
|
struct AddressInfo
|
||||||
|
|
|
@ -8,6 +8,28 @@ DmaController::DmaController(MemoryManager *memoryManager)
|
||||||
_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)
|
void DmaController::RunSingleTransfer(DmaChannelConfig &channel)
|
||||||
{
|
{
|
||||||
const uint8_t *transferOffsets = _transferOffset[channel.TransferMode];
|
const uint8_t *transferOffsets = _transferOffset[channel.TransferMode];
|
||||||
|
@ -15,13 +37,11 @@ void DmaController::RunSingleTransfer(DmaChannelConfig &channel)
|
||||||
|
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
do {
|
do {
|
||||||
if(channel.InvertDirection) {
|
CopyDmaByte(
|
||||||
uint8_t valToWrite = _memoryManager->ReadDma(0x2100 | channel.DestAddress + transferOffsets[i]);
|
(channel.SrcBank << 16) | channel.SrcAddress,
|
||||||
_memoryManager->WriteDma((channel.SrcBank << 16) | channel.SrcAddress, valToWrite);
|
0x2100 | channel.DestAddress + transferOffsets[i],
|
||||||
} else {
|
channel.InvertDirection
|
||||||
uint8_t valToWrite = _memoryManager->ReadDma((channel.SrcBank << 16) | channel.SrcAddress);
|
);
|
||||||
_memoryManager->WriteDma(0x2100 | channel.DestAddress + transferOffsets[i], valToWrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!channel.FixedTransfer) {
|
if(!channel.FixedTransfer) {
|
||||||
channel.SrcAddress += channel.Decrement ? -1 : 1;
|
channel.SrcAddress += channel.Decrement ? -1 : 1;
|
||||||
|
@ -105,13 +125,11 @@ void DmaController::RunHdmaTransfer(DmaChannelConfig &channel)
|
||||||
|
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
do {
|
do {
|
||||||
if(channel.InvertDirection) {
|
CopyDmaByte(
|
||||||
uint8_t valToWrite = _memoryManager->ReadDma(0x2100 | channel.DestAddress + transferOffsets[i]);
|
srcAddress,
|
||||||
_memoryManager->WriteDma(srcAddress, valToWrite);
|
0x2100 | channel.DestAddress + transferOffsets[i],
|
||||||
} else {
|
channel.InvertDirection
|
||||||
uint8_t valToWrite = _memoryManager->ReadDma(srcAddress);
|
);
|
||||||
_memoryManager->WriteDma(0x2100 | channel.DestAddress + transferOffsets[i], valToWrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
srcAddress = (srcAddress + (channel.Decrement ? -1 : 1)) & 0xFFFFFF;
|
srcAddress = (srcAddress + (channel.Decrement ? -1 : 1)) & 0xFFFFFF;
|
||||||
|
|
||||||
|
|
|
@ -43,13 +43,15 @@ private:
|
||||||
DmaChannelConfig _channel[8] = {};
|
DmaChannelConfig _channel[8] = {};
|
||||||
MemoryManager *_memoryManager;
|
MemoryManager *_memoryManager;
|
||||||
|
|
||||||
|
void CopyDmaByte(uint32_t addressBusA, uint16_t addressBusB, bool fromBtoA);
|
||||||
|
|
||||||
void RunSingleTransfer(DmaChannelConfig &channel);
|
void RunSingleTransfer(DmaChannelConfig &channel);
|
||||||
void RunDma(DmaChannelConfig &channel);
|
void RunDma(DmaChannelConfig &channel);
|
||||||
void RunHdmaTransfer(DmaChannelConfig &channel);
|
void RunHdmaTransfer(DmaChannelConfig &channel);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DmaController(MemoryManager *memoryManager);
|
DmaController(MemoryManager *memoryManager);
|
||||||
|
|
||||||
void InitHdmaChannels();
|
void InitHdmaChannels();
|
||||||
void ProcessHdmaChannels();
|
void ProcessHdmaChannels();
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,19 @@
|
||||||
|
|
||||||
class IMemoryHandler
|
class IMemoryHandler
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
SnesMemoryType _memoryType;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual uint8_t Read(uint32_t addr) = 0;
|
virtual uint8_t Read(uint32_t addr) = 0;
|
||||||
virtual uint8_t Peek(uint32_t addr) = 0;
|
virtual uint8_t Peek(uint32_t addr) = 0;
|
||||||
virtual void Write(uint32_t addr, uint8_t value) = 0;
|
virtual void Write(uint32_t addr, uint8_t value) = 0;
|
||||||
|
|
||||||
|
__forceinline SnesMemoryType GetMemoryType()
|
||||||
|
{
|
||||||
|
return _memoryType;
|
||||||
|
}
|
||||||
|
|
||||||
virtual AddressInfo GetAbsoluteAddress(uint32_t address) = 0;
|
virtual AddressInfo GetAbsoluteAddress(uint32_t address) = 0;
|
||||||
|
|
||||||
//virtual void GetMemoryRanges(MemoryRanges &ranges) = 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();
|
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)
|
AddressInfo MemoryManager::GetAbsoluteAddress(uint32_t addr)
|
||||||
{
|
{
|
||||||
if(_handlers[addr >> 12]) {
|
if(_handlers[addr >> 12]) {
|
||||||
|
|
|
@ -62,6 +62,7 @@ public:
|
||||||
uint8_t* DebugGetWorkRam();
|
uint8_t* DebugGetWorkRam();
|
||||||
|
|
||||||
bool IsRegister(uint32_t cpuAddress);
|
bool IsRegister(uint32_t cpuAddress);
|
||||||
|
bool IsWorkRam(uint32_t cpuAddress);
|
||||||
AddressInfo GetAbsoluteAddress(uint32_t addr);
|
AddressInfo GetAbsoluteAddress(uint32_t addr);
|
||||||
int GetRelativeAddress(AddressInfo &address, int32_t cpuAddress = -1);
|
int GetRelativeAddress(AddressInfo &address, int32_t cpuAddress = -1);
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,6 @@ private:
|
||||||
uint8_t * _ram;
|
uint8_t * _ram;
|
||||||
uint32_t _offset;
|
uint32_t _offset;
|
||||||
uint32_t _mask;
|
uint32_t _mask;
|
||||||
SnesMemoryType _memoryType;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RamHandler(uint8_t *ram, uint32_t offset, uint32_t size, SnesMemoryType memoryType)
|
RamHandler(uint8_t *ram, uint32_t offset, uint32_t size, SnesMemoryType memoryType)
|
||||||
|
|
|
@ -18,6 +18,7 @@ public:
|
||||||
_regs = regs;
|
_regs = regs;
|
||||||
_dmaController = dmaController;
|
_dmaController = dmaController;
|
||||||
_controlManager = controlManager;
|
_controlManager = controlManager;
|
||||||
|
_memoryType = SnesMemoryType::Register;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Read(uint32_t addr) override
|
uint8_t Read(uint32_t addr) override
|
||||||
|
|
|
@ -22,6 +22,7 @@ public:
|
||||||
_spc = spc;
|
_spc = spc;
|
||||||
_workRam = workRam;
|
_workRam = workRam;
|
||||||
_wramPosition = 0;
|
_wramPosition = 0;
|
||||||
|
_memoryType = SnesMemoryType::Register;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Read(uint32_t addr) override
|
uint8_t Read(uint32_t addr) override
|
||||||
|
|
Loading…
Add table
Reference in a new issue