Mesen-SX/Core/DmaController.cpp
2019-02-15 00:08:50 -05:00

110 lines
3.5 KiB
C++

#include "stdafx.h"
#include "DmaController.h"
#include "MemoryManager.h"
DmaController::DmaController(shared_ptr<MemoryManager> memoryManager)
{
_memoryManager = memoryManager;
}
void DmaController::RunDma(DmaChannelConfig &channel)
{
//"Note, however, that writing $0000 to this register actually results in a transfer of $10000 bytes, not 0."
uint32_t transferSize = channel.TransferSize ? channel.TransferSize : 0x10000;
uint8_t offset = 0;
if(channel.InvertDirection) {
for(uint32_t i = 0; i < transferSize; i++) {
uint8_t valToWrite = _memoryManager->Read(0x2100 | channel.DestAddress + offset, MemoryOperationType::DmaRead);
_memoryManager->Write(channel.SrcAddress, valToWrite, MemoryOperationType::DmaWrite);
if(!channel.FixedTransfer) {
channel.SrcAddress += channel.Decrement ? -1 : 1;
}
}
} else {
for(uint32_t i = 0; i < transferSize; i++) {
uint8_t valToWrite = _memoryManager->Read(channel.SrcAddress, MemoryOperationType::DmaRead);
_memoryManager->Write(0x2100 | channel.DestAddress + offset, valToWrite, MemoryOperationType::DmaWrite);
if(channel.TransferMode == 1) {
offset = (offset + 1) & 0x01;
}
if(!channel.FixedTransfer) {
channel.SrcAddress += channel.Decrement ? -1 : 1;
}
}
}
}
void DmaController::Write(uint16_t addr, uint8_t value)
{
switch(addr) {
case 0x420B:
//MDMAEN - DMA Enable
for(int i = 0; i < 8; i++) {
if(value & (1 << i)) {
RunDma(_channel[i]);
}
}
break;
case 0x4300: case 0x4310: case 0x4320: case 0x4330: case 0x4340: case 0x4350: case 0x4360: case 0x4370:
{
//DMAPx - DMA Control for Channel x
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.InvertDirection = (value & 0x80) != 0;
channel.HdmaPointers = (value & 0x40) != 0;
channel.Decrement = (value & 0x10) != 0;
channel.FixedTransfer = (value & 0x08) != 0;
channel.TransferMode = value & 0x07;
break;
}
case 0x4301: case 0x4311: case 0x4321: case 0x4331: case 0x4341: case 0x4351: case 0x4361: case 0x4371:
{
//BBADx - DMA Destination Register for Channel x
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.DestAddress = value;
break;
}
case 0x4305: case 0x4315: case 0x4325: case 0x4335: case 0x4345: case 0x4355: case 0x4365: case 0x4375:
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.TransferSize = (channel.TransferSize & 0xFF00) | value;
break;
}
case 0x4306: case 0x4316: case 0x4326: case 0x4336: case 0x4346: case 0x4356: case 0x4366: case 0x4376:
{
//DASxL - DMA Size / HDMA Indirect Address low byte(x = 0 - 7)
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.TransferSize = (channel.TransferSize & 0xFF) | (value << 8);
break;
}
case 0x4302: case 0x4312: case 0x4322: case 0x4332: case 0x4342: case 0x4352: case 0x4362: case 0x4372:
{
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.SrcAddress = (channel.SrcAddress & 0xFFFF00) | value;
break;
}
case 0x4303: case 0x4313: case 0x4323: case 0x4333: case 0x4343: case 0x4353: case 0x4363: case 0x4373:
{
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.SrcAddress = (channel.SrcAddress & 0xFF00FF) | (value << 8);
break;
}
case 0x4304: case 0x4314: case 0x4324: case 0x4334: case 0x4344: case 0x4354: case 0x4364: case 0x4374:
{
DmaChannelConfig &channel = _channel[(addr & 0x70) >> 4];
channel.SrcAddress = (channel.SrcAddress & 0x00FFFF) | (value << 16);
break;
}
}
}