From 9fc0d411fd4757d5ae641c33db245c3bfea404c5 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 30 Nov 2023 22:45:40 -0500 Subject: [PATCH] Further flesh out DMA, breaking POST. --- Machines/PCCompatible/DMA.hpp | 102 ++++++++++++++++++++++--- Machines/PCCompatible/PCCompatible.cpp | 42 +++++----- 2 files changed, 111 insertions(+), 33 deletions(-) diff --git a/Machines/PCCompatible/DMA.hpp b/Machines/PCCompatible/DMA.hpp index ed9f03d63..d0ff6e077 100644 --- a/Machines/PCCompatible/DMA.hpp +++ b/Machines/PCCompatible/DMA.hpp @@ -16,16 +16,21 @@ namespace PCCompatible { class i8237 { public: void flip_flop_reset() { - next_access_low = true; + next_access_low_ = true; } void mask_reset() { - // TODO: set all mask bits off. + for(auto &channel : channels_) { + channel.mask = false; + } } void master_reset() { flip_flop_reset(); - // TODO: clear status, set all mask bits on. + for(auto &channel : channels_) { + channel.mask = true; + channel.transfer_complete = channel.request = false; + } } template @@ -33,8 +38,8 @@ class i8237 { constexpr int channel = (address >> 1) & 3; constexpr bool is_count = address & 1; - next_access_low ^= true; - if(next_access_low) { + next_access_low_ ^= true; + if(next_access_low_) { if constexpr (is_count) { channels_[channel].count.halves.high = value; } else { @@ -54,8 +59,8 @@ class i8237 { constexpr int channel = (address >> 1) & 3; constexpr bool is_count = address & 1; - next_access_low ^= true; - if(next_access_low) { + next_access_low_ ^= true; + if(next_access_low_) { if constexpr (is_count) { return channels_[channel].count.halves.high; } else { @@ -70,12 +75,89 @@ class i8237 { } } - private: - bool next_access_low = true; + void set_reset_mask(uint8_t value) { + channels_[value & 3].mask = value & 4; + } + void set_reset_request(uint8_t value) { + channels_[value & 3].request = value & 4; + } + + void set_mask(uint8_t 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) { + 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) { + 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; + } + return result; + } + + private: + // Low/high byte latch. + bool next_access_low_ = true; + + // Various fields set by the command register. + bool enable_memory_to_memory_ = false; + bool enable_channel0_address_hold_ = false; + bool enable_controller_ = false; + bool compressed_timing_ = false; + bool rotating_priority_ = false; + bool extended_write_selection_ = false; + bool dreq_active_low_ = false; + bool dack_sense_active_high_ = false; + + // Per-channel state. struct Channel { + bool mask = false; + enum class Transfer { + Verify, Write, Read, Invalid + } transfer = Transfer::Verify; + bool autoinitialise = false; + bool address_decrement = false; + enum class Mode { + Demand, Single, Block, Cascade + } mode = Mode::Demand; + + bool request = false; + bool transfer_complete = false; + CPU::RegisterPair16 address, count; - } channels_[4]; + }; + std::array channels_; }; class DMAPages { diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index 90ca5873a..802cfe9a6 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -953,28 +953,22 @@ class IO { printf("TODO: NMIs %s\n", (value & 0x80) ? "masked" : "unmasked"); break; - case 0x0000: dma_.i8237.write<0>(value); break; - case 0x0001: dma_.i8237.write<1>(value); break; - case 0x0002: dma_.i8237.write<2>(value); break; - case 0x0003: dma_.i8237.write<3>(value); break; - case 0x0004: dma_.i8237.write<4>(value); break; - case 0x0005: dma_.i8237.write<5>(value); break; - case 0x0006: dma_.i8237.write<6>(value); break; - case 0x0007: dma_.i8237.write<7>(value); break; - - // TODO: 0x0008 -> command - // TODO: 0x000a -> mask - // TODO: 0x000b -> mode - case 0x000c: dma_.i8237.flip_flop_reset(); break; - - case 0x0008: case 0x0009: - case 0x000a: case 0x000b: - case 0x000f: - printf("TODO: DMA write of %02x at %04x\n", value, port); - break; - - case 0x000d: dma_.i8237.master_reset(); break; - case 0x000e: dma_.i8237.mask_reset(); break; + case 0x0000: dma_.i8237.write<0>(value); break; + case 0x0001: dma_.i8237.write<1>(value); break; + case 0x0002: dma_.i8237.write<2>(value); break; + case 0x0003: dma_.i8237.write<3>(value); break; + case 0x0004: dma_.i8237.write<4>(value); break; + case 0x0005: dma_.i8237.write<5>(value); break; + case 0x0006: dma_.i8237.write<6>(value); break; + case 0x0007: dma_.i8237.write<7>(value); break; + case 0x0008: dma_.i8237.set_command(uint8_t(value)); break; + case 0x0009: dma_.i8237.set_reset_request(uint8_t(value)); break; + case 0x000a: dma_.i8237.set_reset_mask(uint8_t(value)); break; + case 0x000b: dma_.i8237.set_mode(uint8_t(value)); break; + case 0x000c: dma_.i8237.flip_flop_reset(); break; + case 0x000d: dma_.i8237.master_reset(); break; + case 0x000e: dma_.i8237.mask_reset(); break; + case 0x000f: dma_.i8237.set_mask(uint8_t(value)); break; case 0x0020: pic_.write<0>(value); break; case 0x0021: pic_.write<1>(value); break; @@ -1072,7 +1066,9 @@ class IO { case 0x0006: return dma_.i8237.read<6>(); case 0x0007: return dma_.i8237.read<7>(); - case 0x0008: case 0x0009: + case 0x0008: return dma_.i8237.status(); + + case 0x0009: case 0x000a: case 0x000b: case 0x000c: case 0x000f: printf("TODO: DMA read from %04x\n", port);