2020-07-08 20:59:00 +09:00
|
|
|
auto DMA::readByte(u32 address) -> u32 {
|
2021-02-08 18:11:00 +09:00
|
|
|
n32 data;
|
2021-01-15 06:00:00 +09:00
|
|
|
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 & 0xffff'ff8c) == 0x1f80'1080) data = readWord(address & ~3) >> 8 * (address & 3);
|
|
|
|
if((address & 0xffff'ff8f) == 0x1f80'1084) data = channel.length.byte(0);
|
|
|
|
if((address & 0xffff'ff8f) == 0x1f80'1085) data = channel.length.byte(1);
|
|
|
|
if((address & 0xffff'ff8f) == 0x1f80'1086) data = channel.blocks.byte(0);
|
|
|
|
if((address & 0xffff'ff8f) == 0x1f80'1087) data = channel.blocks.byte(1);
|
|
|
|
if((address & 0xffff'ff8c) == 0x1f80'1088) data = readWord(address & ~3) >> 8 * (address & 3);
|
|
|
|
if((address & 0xffff'ff8c) == 0x1f80'108c) data = readWord(address & ~3) >> 8 * (address & 3);
|
|
|
|
return data;
|
2020-06-24 18:25:00 +09:00
|
|
|
}
|
|
|
|
|
2020-07-08 20:59:00 +09:00
|
|
|
auto DMA::readHalf(u32 address) -> u32 {
|
2021-02-08 18:11:00 +09:00
|
|
|
n32 data;
|
2021-01-15 06:00:00 +09:00
|
|
|
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 & 0xffff'ff8c) == 0x1f80'1080) data = readWord(address & ~3) >> 8 * (address & 3);
|
|
|
|
if((address & 0xffff'ff8e) == 0x1f80'1084) data = channel.length;
|
|
|
|
if((address & 0xffff'ff8e) == 0x1f80'1086) data = channel.blocks;
|
|
|
|
if((address & 0xffff'ff8c) == 0x1f80'1088) data = readWord(address & ~3) >> 8 * (address & 3);
|
|
|
|
if((address & 0xffff'ff8c) == 0x1f80'108c) data = readWord(address & ~3) >> 8 * (address & 3);
|
|
|
|
return data;
|
2020-06-24 18:25:00 +09:00
|
|
|
}
|
|
|
|
|
2020-07-08 20:59:00 +09:00
|
|
|
auto DMA::readWord(u32 address) -> u32 {
|
2021-02-08 18:11:00 +09:00
|
|
|
n32 data;
|
2020-06-23 06:49:00 +09:00
|
|
|
|
|
|
|
//DPCR: DMA Control
|
|
|
|
if(address == 0x1f80'10f0) {
|
2021-01-15 06:00:00 +09:00
|
|
|
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;
|
2020-06-23 06:49:00 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
//DICR: DMA Interrupt
|
|
|
|
if(address == 0x1f80'10f4) {
|
|
|
|
data.bit( 0, 5) = irq.unknown;
|
2021-01-15 06:00:00 +09:00
|
|
|
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;
|
2020-06-23 06:49:00 +09:00
|
|
|
data.bit(31) = irq.flag;
|
2021-01-15 06:00:00 +09:00
|
|
|
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 & 0xffff'ff8f) == 0x1f80'1080) {
|
|
|
|
data.bit(0,23) = channel.address;
|
|
|
|
}
|
|
|
|
|
|
|
|
//DnBCR: DMA Block Control
|
|
|
|
if((address & 0xffff'ff8f) == 0x1f80'1084) {
|
|
|
|
data.bit( 0,15) = channel.length;
|
|
|
|
data.bit(16,31) = channel.blocks;
|
|
|
|
}
|
|
|
|
|
|
|
|
//DnCHCR: DMA Channel Control
|
|
|
|
if((address & 0xffff'ff8f) == 0x1f80'1088
|
|
|
|
|| (address & 0xffff'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;
|
2020-06-23 06:49:00 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2020-07-08 20:59:00 +09:00
|
|
|
auto DMA::writeByte(u32 address, u32 value) -> void {
|
2021-02-08 18:11:00 +09:00
|
|
|
n32 data = value;
|
2021-01-15 06:00:00 +09:00
|
|
|
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 & 0xffff'ff8c) == 0x1f80'1080) writeWord(address & ~3, data << 8 * (address & 3));
|
|
|
|
if((address & 0xffff'ff8f) == 0x1f80'1084) channel.length.byte(0) = data;
|
|
|
|
if((address & 0xffff'ff8f) == 0x1f80'1085) channel.length.byte(1) = data;
|
|
|
|
if((address & 0xffff'ff8f) == 0x1f80'1086) channel.blocks.byte(0) = data;
|
|
|
|
if((address & 0xffff'ff8f) == 0x1f80'1087) channel.blocks.byte(1) = data;
|
|
|
|
if((address & 0xffff'ff8c) == 0x1f80'1088) writeWord(address & ~3, data << 8 * (address & 3));
|
|
|
|
if((address & 0xffff'ff8c) == 0x1f80'108c) writeWord(address & ~3, data << 8 * (address & 3));
|
2020-06-24 18:25:00 +09:00
|
|
|
}
|
|
|
|
|
2020-07-08 20:59:00 +09:00
|
|
|
auto DMA::writeHalf(u32 address, u32 value) -> void {
|
2021-02-08 18:11:00 +09:00
|
|
|
n32 data = value;
|
2021-01-15 06:00:00 +09:00
|
|
|
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 & 0xffff'ff8c) == 0x1f80'1080) writeWord(address & ~3, data << 8 * (address & 3));
|
|
|
|
if((address & 0xffff'fffe) == 0x1f80'1084) channel.length = data;
|
|
|
|
if((address & 0xffff'fffe) == 0x1f80'1086) channel.blocks = data;
|
|
|
|
if((address & 0xffff'ff8c) == 0x1f80'1088) writeWord(address & ~3, data << 8 * (address & 3));
|
|
|
|
if((address & 0xffff'ff8c) == 0x1f80'108c) writeWord(address & ~3, data << 8 * (address & 3));
|
2020-06-24 18:25:00 +09:00
|
|
|
}
|
|
|
|
|
2020-07-08 20:59:00 +09:00
|
|
|
auto DMA::writeWord(u32 address, u32 value) -> void {
|
2021-02-08 18:11:00 +09:00
|
|
|
n32 data = value;
|
2021-01-15 06:00:00 +09:00
|
|
|
|
|
|
|
//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];
|
2020-06-23 06:49:00 +09:00
|
|
|
|
|
|
|
//DnMADR: DMA Base Address
|
2021-01-15 06:00:00 +09:00
|
|
|
if((address & 0xffff'ff8f) == 0x1f80'1080) {
|
|
|
|
channel.address = data.bit(0,23);
|
2020-06-23 06:49:00 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
//DnBCR: DMA Block Control
|
2021-01-15 06:00:00 +09:00
|
|
|
if((address & 0xffff'ff8f) == 0x1f80'1084) {
|
|
|
|
channel.length = data.bit( 0,15);
|
|
|
|
channel.blocks = data.bit(16,31);
|
2020-06-23 06:49:00 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
//DnCHCR: DMA Channel Control
|
2021-01-15 06:00:00 +09:00
|
|
|
if((address & 0xffff'ff8f) == 0x1f80'1088
|
|
|
|
|| (address & 0xffff'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;
|
2020-06-23 06:49:00 +09:00
|
|
|
}
|
|
|
|
|
2021-01-15 06:00:00 +09:00
|
|
|
channel.state = Waiting;
|
|
|
|
channel.chain.length = 0;
|
|
|
|
channel.counter = 1;
|
2020-06-23 06:49:00 +09:00
|
|
|
}
|
|
|
|
}
|