ares-openbsd/ares/ps1/dma/io.cpp

249 行
9.5 KiB
C++

auto DMA::readByte(u32 address) -> u32 {
n32 data;
if((address & ~3) == 0x1f80'10f0) return data = readWord(address & ~3) >> 8 * (address & 3);
if((address & ~3) == 0x1f80'10f4) return data = readWord(address & ~3) >> 8 * (address & 3);
if((address & ~3) == 0x1f80'10f8) return data = readWord(address & ~3) >> 8 * (address & 3);
if((address & ~3) == 0x1f80'10fc) return data = readWord(address & ~3) >> 8 * (address & 3);
auto& channel = channels[address >> 4 & 7];
if((address & 0x1fff'ff8c) == 0x1f80'1080) data = readWord(address & ~3) >> 8 * (address & 3);
if((address & 0x1fff'ff8f) == 0x1f80'1084) data = channel.length.byte(0);
if((address & 0x1fff'ff8f) == 0x1f80'1085) data = channel.length.byte(1);
if((address & 0x1fff'ff8f) == 0x1f80'1086) data = channel.blocks.byte(0);
if((address & 0x1fff'ff8f) == 0x1f80'1087) data = channel.blocks.byte(1);
if((address & 0x1fff'ff8c) == 0x1f80'1088) data = readWord(address & ~3) >> 8 * (address & 3);
if((address & 0x1fff'ff8c) == 0x1f80'108c) data = readWord(address & ~3) >> 8 * (address & 3);
return data;
}
auto DMA::readHalf(u32 address) -> u32 {
n32 data;
if((address & ~3) == 0x1f80'10f0) return data = readWord(address & ~3) >> 8 * (address & 3);
if((address & ~3) == 0x1f80'10f4) return data = readWord(address & ~3) >> 8 * (address & 3);
if((address & ~3) == 0x1f80'10f8) return data = readWord(address & ~3) >> 8 * (address & 3);
if((address & ~3) == 0x1f80'10fc) return data = readWord(address & ~3) >> 8 * (address & 3);
auto& channel = channels[address >> 4 & 7];
if((address & 0x1fff'ff8c) == 0x1f80'1080) data = readWord(address & ~3) >> 8 * (address & 3);
if((address & 0x1fff'ff8e) == 0x1f80'1084) data = channel.length;
if((address & 0x1fff'ff8e) == 0x1f80'1086) data = channel.blocks;
if((address & 0x1fff'ff8c) == 0x1f80'1088) data = readWord(address & ~3) >> 8 * (address & 3);
if((address & 0x1fff'ff8c) == 0x1f80'108c) data = readWord(address & ~3) >> 8 * (address & 3);
return data;
}
auto DMA::readWord(u32 address) -> u32 {
n32 data;
//DPCR: DMA Control
if(address == 0x1f80'10f0) {
data.bit( 0, 2) = channels[0].priority;
data.bit( 3) = channels[0].masterEnable;
data.bit( 4, 6) = channels[1].priority;
data.bit( 7) = channels[1].masterEnable;
data.bit( 8,10) = channels[2].priority;
data.bit(11) = channels[2].masterEnable;
data.bit(12,14) = channels[3].priority;
data.bit(15) = channels[3].masterEnable;
data.bit(16,18) = channels[4].priority;
data.bit(19) = channels[4].masterEnable;
data.bit(20,22) = channels[5].priority;
data.bit(23) = channels[5].masterEnable;
data.bit(24,26) = channels[6].priority;
data.bit(27) = channels[6].masterEnable;
return data;
}
//DICR: DMA Interrupt
if(address == 0x1f80'10f4) {
data.bit( 0, 5) = irq.unknown;
data.bit(16) = channels[0].irq.enable;
data.bit(17) = channels[1].irq.enable;
data.bit(18) = channels[2].irq.enable;
data.bit(19) = channels[3].irq.enable;
data.bit(20) = channels[4].irq.enable;
data.bit(21) = channels[5].irq.enable;
data.bit(22) = channels[6].irq.enable;
data.bit(23) = irq.enable;
data.bit(24) = channels[0].irq.flag;
data.bit(25) = channels[1].irq.flag;
data.bit(26) = channels[2].irq.flag;
data.bit(27) = channels[3].irq.flag;
data.bit(28) = channels[4].irq.flag;
data.bit(29) = channels[5].irq.flag;
data.bit(30) = channels[6].irq.flag;
data.bit(31) = irq.flag;
return data;
}
//unknown
if(address == 0x1f80'10f8) {
data = 0x7fe3'58d1;
return data;
}
//unknown
if(address == 0x1f80'10fc) {
data = 0x00ff'fff7;
return data;
}
auto& channel = channels[address >> 4 & 7];
//DnMADR: DMA Base Address
if((address & 0x1fff'ff8f) == 0x1f80'1080) {
data.bit(0,23) = channel.address;
}
//DnBCR: DMA Block Control
if((address & 0x1fff'ff8f) == 0x1f80'1084) {
data.bit( 0,15) = channel.length;
data.bit(16,31) = channel.blocks;
}
//DnCHCR: DMA Channel Control
if((address & 0x1fff'ff8f) == 0x1f80'1088
|| (address & 0x1fff'ff8f) == 0x1f80'108c
) {
data.bit( 0) = channel.direction;
data.bit( 1) = channel.decrement;
data.bit( 2) = channel.chopping.enable;
data.bit( 9,10) = channel.synchronization;
data.bit(16,18) = channel.chopping.dmaWindow;
data.bit(20,22) = channel.chopping.cpuWindow;
data.bit(24) = channel.enable;
data.bit(28) = channel.trigger;
data.bit(29,30) = channel.unknown;
}
return data;
}
auto DMA::writeByte(u32 address, u32 value) -> void {
n32 data = value;
if((address & ~3) == 0x1f80'10f0) return writeWord(address & ~3, data << 8 * (address & 3));
if((address & ~3) == 0x1f80'10f4) return writeWord(address & ~3, data << 8 * (address & 3));
if((address & ~3) == 0x1f80'10f8) return writeWord(address & ~3, data << 8 * (address & 3));
if((address & ~3) == 0x1f80'10fc) return writeWord(address & ~3, data << 8 * (address & 3));
auto& channel = channels[address >> 4 & 7];
if((address & 0x1fff'ff8c) == 0x1f80'1080) writeWord(address & ~3, data << 8 * (address & 3));
if((address & 0x1fff'ff8f) == 0x1f80'1084) channel.length.byte(0) = data;
if((address & 0x1fff'ff8f) == 0x1f80'1085) channel.length.byte(1) = data;
if((address & 0x1fff'ff8f) == 0x1f80'1086) channel.blocks.byte(0) = data;
if((address & 0x1fff'ff8f) == 0x1f80'1087) channel.blocks.byte(1) = data;
if((address & 0x1fff'ff8c) == 0x1f80'1088) writeWord(address & ~3, data << 8 * (address & 3));
if((address & 0x1fff'ff8c) == 0x1f80'108c) writeWord(address & ~3, data << 8 * (address & 3));
}
auto DMA::writeHalf(u32 address, u32 value) -> void {
n32 data = value;
if((address & ~3) == 0x1f80'10f0) return writeWord(address & ~3, data << 8 * (address & 3));
if((address & ~3) == 0x1f80'10f4) return writeWord(address & ~3, data << 8 * (address & 3));
if((address & ~3) == 0x1f80'10f8) return writeWord(address & ~3, data << 8 * (address & 3));
if((address & ~3) == 0x1f80'10fc) return writeWord(address & ~3, data << 8 * (address & 3));
auto& channel = channels[address >> 4 & 7];
if((address & 0x1fff'ff8c) == 0x1f80'1080) writeWord(address & ~3, data << 8 * (address & 3));
if((address & 0x1fff'fffe) == 0x1f80'1084) channel.length = data;
if((address & 0x1fff'fffe) == 0x1f80'1086) channel.blocks = data;
if((address & 0x1fff'ff8c) == 0x1f80'1088) writeWord(address & ~3, data << 8 * (address & 3));
if((address & 0x1fff'ff8c) == 0x1f80'108c) writeWord(address & ~3, data << 8 * (address & 3));
}
auto DMA::writeWord(u32 address, u32 value) -> void {
n32 data = value;
//DPCR: DMA Control
if(address == 0x1f80'10f0) {
channels[0].priority = data.bit( 0, 2);
channels[0].masterEnable = data.bit( 3);
channels[1].priority = data.bit( 4, 6);
channels[1].masterEnable = data.bit( 7);
channels[2].priority = data.bit( 8,10);
channels[2].masterEnable = data.bit(11);
channels[3].priority = data.bit(12,14);
channels[3].masterEnable = data.bit(15);
channels[4].priority = data.bit(16,18);
channels[4].masterEnable = data.bit(19);
channels[5].priority = data.bit(20,22);
channels[5].masterEnable = data.bit(23);
channels[6].priority = data.bit(24,26);
channels[6].masterEnable = data.bit(27);
sortChannelsByPriority();
return;
}
//DICR: DMA Interrupt
if(address == 0x1f80'10f4) {
irq.unknown = data.bit( 0,5);
irq.force = data.bit(15);
channels[0].irq.enable = data.bit(16);
channels[1].irq.enable = data.bit(17);
channels[2].irq.enable = data.bit(18);
channels[3].irq.enable = data.bit(19);
channels[4].irq.enable = data.bit(20);
channels[5].irq.enable = data.bit(21);
channels[6].irq.enable = data.bit(22);
irq.enable = data.bit(23);
if(data.bit(24)) channels[0].irq.flag = 0;
if(data.bit(25)) channels[1].irq.flag = 0;
if(data.bit(26)) channels[2].irq.flag = 0;
if(data.bit(27)) channels[3].irq.flag = 0;
if(data.bit(28)) channels[4].irq.flag = 0;
if(data.bit(29)) channels[5].irq.flag = 0;
if(data.bit(30)) channels[6].irq.flag = 0;
irq.poll();
return;
}
//unused
if(address == 0x1f80'10f8) {
return;
}
//unused
if(address == 0x1f80'10fc) {
return;
}
auto& channel = channels[address >> 4 & 7];
//DnMADR: DMA Base Address
if((address & 0x1fff'ff8f) == 0x1f80'1080) {
channel.address = data.bit(0,23);
}
//DnBCR: DMA Block Control
if((address & 0x1fff'ff8f) == 0x1f80'1084) {
channel.length = data.bit( 0,15);
channel.blocks = data.bit(16,31);
}
//DnCHCR: DMA Channel Control
if((address & 0x1fff'ff8f) == 0x1f80'1088
|| (address & 0x1fff'ff8f) == 0x1f80'108c
) {
channel.direction = data.bit( 0);
channel.decrement = data.bit( 1);
channel.chopping.enable = data.bit( 2);
channel.synchronization = data.bit( 9,10);
channel.chopping.dmaWindow = data.bit(16,18);
channel.chopping.cpuWindow = data.bit(20,22);
channel.enable = data.bit(24);
channel.trigger = data.bit(28);
channel.unknown = data.bit(29,30);
if(channel.id == OTC) {
//OTC DMA hard-codes certain fields:
channel.direction = 0;
channel.decrement = 1;
channel.chopping.enable = 0;
channel.synchronization = 0;
channel.chopping.dmaWindow = 0;
channel.chopping.cpuWindow = 0;
channel.unknown.bit(0) = 0;
}
channel.state = Waiting;
channel.chain.length = 0;
channel.counter = 1;
}
}