1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-30 22:29:56 +00:00

Unify DMA interface.

This commit is contained in:
Thomas Harte 2023-12-05 14:52:14 -05:00
parent 0bcb17985b
commit 4265455c31
2 changed files with 170 additions and 143 deletions

View File

@ -25,135 +25,73 @@ enum class AccessResult {
class i8237 {
public:
void flip_flop_reset() {
printf("DMA: Flip flop reset\n");
next_access_low_ = true;
}
void mask_reset() {
printf("DMA: Mask reset\n");
for(auto &channel : channels_) {
channel.mask = false;
}
}
void master_reset() {
printf("DMA: Master reset\n");
flip_flop_reset();
for(auto &channel : channels_) {
channel.mask = true;
channel.transfer_complete = false;
channel.request = false;
}
// This is a bit of a hack; DMA channel 0 is supposed to be linked to the PIT,
// performing DRAM refresh. It isn't yet. So hack this, and hack that.
channels_[0].transfer_complete = true;
}
//
// CPU-facing interface.
//
template <int address>
void write(uint8_t value) {
printf("DMA: Write %02x to %d\n", value, address);
constexpr int channel = (address >> 1) & 3;
constexpr bool is_count = address & 1;
next_access_low_ ^= true;
if(next_access_low_) {
if constexpr (is_count) {
channels_[channel].count.halves.high = value;
} else {
channels_[channel].address.halves.high = value;
}
} else {
if constexpr (is_count) {
channels_[channel].count.halves.low = value;
} else {
channels_[channel].address.halves.low = value;
}
switch(address) {
default: {
constexpr int channel = (address >> 1) & 3;
constexpr bool is_count = address & 1;
next_access_low_ ^= true;
if(next_access_low_) {
if constexpr (is_count) {
channels_[channel].count.halves.high = value;
} else {
channels_[channel].address.halves.high = value;
}
} else {
if constexpr (is_count) {
channels_[channel].count.halves.low = value;
} else {
channels_[channel].address.halves.low = value;
}
}
} break;
case 0x8: set_command(value); break;
case 0x9: set_reset_request(value); break;
case 0xa: set_reset_mask(value); break;
case 0xb: set_mode(value); break;
case 0xc: flip_flop_reset(); break;
case 0xd: master_reset(); break;
case 0xe: mask_reset(); break;
case 0xf: set_mask(value); break;
}
}
template <int address>
uint8_t read() {
printf("DMA: Read %d\n", address);
constexpr int channel = (address >> 1) & 3;
constexpr bool is_count = address & 1;
switch(address) {
default: {
constexpr int channel = (address >> 1) & 3;
constexpr bool is_count = address & 1;
next_access_low_ ^= true;
if(next_access_low_) {
if constexpr (is_count) {
return channels_[channel].count.halves.high;
} else {
return channels_[channel].address.halves.high;
}
} else {
if constexpr (is_count) {
return channels_[channel].count.halves.low;
} else {
return channels_[channel].address.halves.low;
}
next_access_low_ ^= true;
if(next_access_low_) {
if constexpr (is_count) {
return channels_[channel].count.halves.high;
} else {
return channels_[channel].address.halves.high;
}
} else {
if constexpr (is_count) {
return channels_[channel].count.halves.low;
} else {
return channels_[channel].address.halves.low;
}
}
} break;
case 0x8: return status(); break;
case 0xd: return temporary_register(); break;
}
}
void set_reset_mask(uint8_t value) {
printf("DMA: Set/reset mask %02x\n", value);
channels_[value & 3].mask = value & 4;
}
void set_reset_request(uint8_t value) {
printf("DMA: Set/reset request %02x\n", value);
channels_[value & 3].request = value & 4;
}
void set_mask(uint8_t value) {
printf("DMA: Set mask %02x\n", value);
channels_[0].mask = value & 1;
channels_[1].mask = value & 2;
channels_[2].mask = value & 4;
channels_[3].mask = value & 8;
}
void set_mode(uint8_t value) {
printf("DMA: Set mode %02x\n", value);
channels_[value & 3].transfer = Channel::Transfer((value >> 2) & 3);
channels_[value & 3].autoinitialise = value & 0x10;
channels_[value & 3].address_decrement = value & 0x20;
channels_[value & 3].mode = Channel::Mode(value >> 6);
}
void set_command(uint8_t value) {
printf("DMA: Set command %02x\n", value);
enable_memory_to_memory_ = value & 0x01;
enable_channel0_address_hold_ = value & 0x02;
enable_controller_ = value & 0x04;
compressed_timing_ = value & 0x08;
rotating_priority_ = value & 0x10;
extended_write_selection_ = value & 0x20;
dreq_active_low_ = value & 0x40;
dack_sense_active_high_ = value & 0x80;
}
uint8_t status() {
const uint8_t result =
(channels_[0].transfer_complete ? 0x01 : 0x00) |
(channels_[1].transfer_complete ? 0x02 : 0x00) |
(channels_[2].transfer_complete ? 0x04 : 0x00) |
(channels_[3].transfer_complete ? 0x08 : 0x00) |
(channels_[0].request ? 0x10 : 0x00) |
(channels_[1].request ? 0x20 : 0x00) |
(channels_[2].request ? 0x40 : 0x00) |
(channels_[3].request ? 0x80 : 0x00);
for(auto &channel : channels_) {
channel.transfer_complete = false;
}
printf("DMA: status is %02x\n", result);
return result;
}
//
// Interface for reading/writing via DMA.
//
@ -192,6 +130,96 @@ class i8237 {
}
private:
uint8_t status() {
const uint8_t result =
(channels_[0].transfer_complete ? 0x01 : 0x00) |
(channels_[1].transfer_complete ? 0x02 : 0x00) |
(channels_[2].transfer_complete ? 0x04 : 0x00) |
(channels_[3].transfer_complete ? 0x08 : 0x00) |
(channels_[0].request ? 0x10 : 0x00) |
(channels_[1].request ? 0x20 : 0x00) |
(channels_[2].request ? 0x40 : 0x00) |
(channels_[3].request ? 0x80 : 0x00);
for(auto &channel : channels_) {
channel.transfer_complete = false;
}
printf("DMA: status is %02x\n", result);
return result;
}
uint8_t temporary_register() const {
// Not actually implemented, so...
return 0xff;
}
void flip_flop_reset() {
printf("DMA: Flip flop reset\n");
next_access_low_ = true;
}
void mask_reset() {
printf("DMA: Mask reset\n");
for(auto &channel : channels_) {
channel.mask = false;
}
}
void master_reset() {
printf("DMA: Master reset\n");
flip_flop_reset();
for(auto &channel : channels_) {
channel.mask = true;
channel.transfer_complete = false;
channel.request = false;
}
// This is a bit of a hack; DMA channel 0 is supposed to be linked to the PIT,
// performing DRAM refresh. It isn't yet. So hack this, and hack that.
channels_[0].transfer_complete = true;
}
void set_reset_mask(uint8_t value) {
printf("DMA: Set/reset mask %02x\n", value);
channels_[value & 3].mask = value & 4;
}
void set_reset_request(uint8_t value) {
printf("DMA: Set/reset request %02x\n", value);
channels_[value & 3].request = value & 4;
}
void set_mask(uint8_t value) {
printf("DMA: Set mask %02x\n", value);
channels_[0].mask = value & 1;
channels_[1].mask = value & 2;
channels_[2].mask = value & 4;
channels_[3].mask = value & 8;
}
void set_mode(uint8_t value) {
printf("DMA: Set mode %02x\n", value);
channels_[value & 3].transfer = Channel::Transfer((value >> 2) & 3);
channels_[value & 3].autoinitialise = value & 0x10;
channels_[value & 3].address_decrement = value & 0x20;
channels_[value & 3].mode = Channel::Mode(value >> 6);
}
void set_command(uint8_t value) {
printf("DMA: Set command %02x\n", value);
enable_memory_to_memory_ = value & 0x01;
enable_channel0_address_hold_ = value & 0x02;
enable_controller_ = value & 0x04;
compressed_timing_ = value & 0x08;
rotating_priority_ = value & 0x10;
extended_write_selection_ = value & 0x20;
dreq_active_low_ = value & 0x40;
dack_sense_active_high_ = value & 0x80;
}
// Low/high byte latch.
bool next_access_low_ = true;

View File

@ -806,22 +806,22 @@ class IO {
printf("TODO: NMIs %s\n", (value & 0x80) ? "masked" : "unmasked");
break;
case 0x0000: dma_.controller.write<0>(uint8_t(value)); break;
case 0x0001: dma_.controller.write<1>(uint8_t(value)); break;
case 0x0002: dma_.controller.write<2>(uint8_t(value)); break;
case 0x0003: dma_.controller.write<3>(uint8_t(value)); break;
case 0x0004: dma_.controller.write<4>(uint8_t(value)); break;
case 0x0005: dma_.controller.write<5>(uint8_t(value)); break;
case 0x0006: dma_.controller.write<6>(uint8_t(value)); break;
case 0x0007: dma_.controller.write<7>(uint8_t(value)); break;
case 0x0008: dma_.controller.set_command(uint8_t(value)); break;
case 0x0009: dma_.controller.set_reset_request(uint8_t(value)); break;
case 0x000a: dma_.controller.set_reset_mask(uint8_t(value)); break;
case 0x000b: dma_.controller.set_mode(uint8_t(value)); break;
case 0x000c: dma_.controller.flip_flop_reset(); break;
case 0x000d: dma_.controller.master_reset(); break;
case 0x000e: dma_.controller.mask_reset(); break;
case 0x000f: dma_.controller.set_mask(uint8_t(value)); break;
case 0x0000: dma_.controller.write<0x0>(uint8_t(value)); break;
case 0x0001: dma_.controller.write<0x1>(uint8_t(value)); break;
case 0x0002: dma_.controller.write<0x2>(uint8_t(value)); break;
case 0x0003: dma_.controller.write<0x3>(uint8_t(value)); break;
case 0x0004: dma_.controller.write<0x4>(uint8_t(value)); break;
case 0x0005: dma_.controller.write<0x5>(uint8_t(value)); break;
case 0x0006: dma_.controller.write<0x6>(uint8_t(value)); break;
case 0x0007: dma_.controller.write<0x7>(uint8_t(value)); break;
case 0x0008: dma_.controller.write<0x8>(uint8_t(value)); break;
case 0x0009: dma_.controller.write<0x9>(uint8_t(value)); break;
case 0x000a: dma_.controller.write<0xa>(uint8_t(value)); break;
case 0x000b: dma_.controller.write<0xb>(uint8_t(value)); break;
case 0x000c: dma_.controller.write<0xc>(uint8_t(value)); break;
case 0x000d: dma_.controller.write<0xd>(uint8_t(value)); break;
case 0x000e: dma_.controller.write<0xe>(uint8_t(value)); break;
case 0x000f: dma_.controller.write<0xf>(uint8_t(value)); break;
case 0x0020: pic_.write<0>(uint8_t(value)); break;
case 0x0021: pic_.write<1>(uint8_t(value)); break;
@ -910,21 +910,20 @@ class IO {
printf("Unhandled in: %04x\n", port);
break;
case 0x0000: return dma_.controller.template read<0>();
case 0x0001: return dma_.controller.template read<1>();
case 0x0002: return dma_.controller.template read<2>();
case 0x0003: return dma_.controller.template read<3>();
case 0x0004: return dma_.controller.template read<4>();
case 0x0005: return dma_.controller.template read<5>();
case 0x0006: return dma_.controller.template read<6>();
case 0x0007: return dma_.controller.template read<7>();
case 0x0000: return dma_.controller.read<0x0>();
case 0x0001: return dma_.controller.read<0x1>();
case 0x0002: return dma_.controller.read<0x2>();
case 0x0003: return dma_.controller.read<0x3>();
case 0x0004: return dma_.controller.read<0x4>();
case 0x0005: return dma_.controller.read<0x5>();
case 0x0006: return dma_.controller.read<0x6>();
case 0x0007: return dma_.controller.read<0x7>();
case 0x0008: return dma_.controller.read<0x8>();
case 0x000d: return dma_.controller.read<0xd>();
case 0x0008: return dma_.controller.status();
case 0x0009:
case 0x000a: case 0x000b:
case 0x0009: case 0x000b:
case 0x000c: case 0x000f:
printf("TODO: DMA read from %04x\n", port);
// DMA area, but it doesn't respond.
break;
case 0x0020: return pic_.read<0>();