From 5f6bbec7415e51dc5b0609f7055f543d2affbab6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 30 Nov 2023 12:47:50 -0500 Subject: [PATCH] Capture DMA high bytes, add actor for accesses. --- Machines/PCCompatible/DMA.hpp | 37 ++++++++- Machines/PCCompatible/PCCompatible.cpp | 107 +++++++++++++++++-------- Machines/PCCompatible/PIT.hpp | 4 +- 3 files changed, 113 insertions(+), 35 deletions(-) diff --git a/Machines/PCCompatible/DMA.hpp b/Machines/PCCompatible/DMA.hpp index 719bc19f0..ed9f03d63 100644 --- a/Machines/PCCompatible/DMA.hpp +++ b/Machines/PCCompatible/DMA.hpp @@ -13,7 +13,7 @@ namespace PCCompatible { -class DMA { +class i8237 { public: void flip_flop_reset() { next_access_low = true; @@ -78,6 +78,41 @@ class DMA { } channels_[4]; }; +class DMAPages { + public: + template + void set_page(uint8_t value) { + pages_[page_for_index(index)] = value; + } + + template + uint8_t page() { + return pages_[page_for_index(index)]; + } + + uint8_t channel_page(int channel) { + return pages_[channel]; + } + + private: + uint8_t pages_[8]; + + constexpr int page_for_index(int index) { + switch(index) { + case 7: return 0; + case 3: return 1; + case 1: return 2; + case 2: return 3; + + default: + case 0: return 4; + case 4: return 5; + case 5: return 6; + case 6: return 7; + } + } +}; + } #endif /* DMA_hpp */ diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index 27995d5ed..5161abdd1 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -8,10 +8,10 @@ #include "PCCompatible.hpp" -#include "DMA.hpp" #include "KeyboardMapper.hpp" #include "PIC.hpp" #include "PIT.hpp" +#include "DMA.hpp" #include "../../InstructionSets/x86/Decoder.hpp" #include "../../InstructionSets/x86/Flags.hpp" @@ -48,6 +48,22 @@ namespace PCCompatible { //bool log = false; //std::string previous; +struct Memory; + +class DMA { + public: + i8237 i8237; + DMAPages pages; + + // Memory is set posthoc to resolve a startup time. + void set_memory(Memory *memory) { + memory_ = memory; + } + + private: + Memory *memory_; +}; + class FloppyController { public: FloppyController(PIC &pic, DMA &dma) : pic_(pic), dma_(dma) { @@ -106,9 +122,22 @@ class FloppyController { printf("TODO: implement FDC command %d\n", uint8_t(decoder_.command())); break; - case Command::ReadData: + case Command::ReadData: { printf("FDC: Read %d:%d at %d/%d\n", decoder_.target().drive, decoder_.target().head, decoder_.geometry().cylinder, decoder_.geometry().head); - break; + + // Search for a matching sector. + const auto target = decoder_.geometry(); + for(auto &pair: drives_[decoder_.target().drive].cached_track) { + if( + (pair.second.address.track == target.cylinder) && + (pair.second.address.sector == target.sector) && + (pair.second.address.side == target.head) && + (pair.second.size == target.size) + ) { + printf(""); + } + } + } break; case Command::Seek: printf("FDC: Seek %d:%d to %d\n", decoder_.target().drive, decoder_.target().head, decoder_.seek_target()); @@ -274,7 +303,7 @@ class FloppyController { } } drives_[4]; - std::string drive_name(int c) const { + static std::string drive_name(int c) { char name[3] = "A"; name[0] += c; return std::string("Drive ") + name; @@ -588,7 +617,7 @@ class PITObserver { // channel 1 is used for DRAM refresh (presumably connected to DMA?); // channel 2 is gated by a PPI output and feeds into the speaker. }; -using PIT = i8237; +using PIT = i8253; class i8255PortHandler : public Intel::i8255::PortHandler { // Likely to be helpful: https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol @@ -924,14 +953,14 @@ class IO { printf("TODO: NMIs %s\n", (value & 0x80) ? "masked" : "unmasked"); break; - case 0x0000: dma_.write<0>(value); break; - case 0x0001: dma_.write<1>(value); break; - case 0x0002: dma_.write<2>(value); break; - case 0x0003: dma_.write<3>(value); break; - case 0x0004: dma_.write<4>(value); break; - case 0x0005: dma_.write<5>(value); break; - case 0x0006: dma_.write<6>(value); break; - case 0x0007: dma_.write<7>(value); 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: case 0x0009: case 0x000a: case 0x000b: @@ -939,8 +968,8 @@ class IO { printf("TODO: DMA write of %02x at %04x\n", value, port); break; - case 0x000d: dma_.master_reset(); break; - case 0x000e: dma_.mask_reset(); break; + case 0x000d: dma_.i8237.master_reset(); break; + case 0x000e: dma_.i8237.mask_reset(); break; case 0x0020: pic_.write<0>(value); break; case 0x0021: pic_.write<1>(value); break; @@ -954,20 +983,22 @@ class IO { case 0x0064: case 0x0065: case 0x0066: case 0x0067: case 0x0068: case 0x0069: case 0x006a: case 0x006b: case 0x006c: case 0x006d: case 0x006e: case 0x006f: - ppi_.write(port, value); + ppi_.write(port, uint8_t(value)); break; - case 0x0080: case 0x0081: case 0x0082: case 0x0083: - case 0x0084: case 0x0085: case 0x0086: case 0x0087: - case 0x0088: case 0x0089: case 0x008a: case 0x008b: - case 0x008c: case 0x008d: case 0x008e: case 0x008f: - printf("TODO: DMA page write of %02x at %04x\n", value, port); - break; + case 0x0080: dma_.pages.set_page<0>(uint8_t(value)); break; + case 0x0081: dma_.pages.set_page<1>(uint8_t(value)); break; + case 0x0082: dma_.pages.set_page<2>(uint8_t(value)); break; + case 0x0083: dma_.pages.set_page<3>(uint8_t(value)); break; + case 0x0084: dma_.pages.set_page<4>(uint8_t(value)); break; + case 0x0085: dma_.pages.set_page<5>(uint8_t(value)); break; + case 0x0086: dma_.pages.set_page<6>(uint8_t(value)); break; + case 0x0087: dma_.pages.set_page<7>(uint8_t(value)); break; case 0x03b0: case 0x03b2: case 0x03b4: case 0x03b6: if constexpr (std::is_same_v) { - mda_.write<0>(value); - mda_.write<1>(value >> 8); + mda_.write<0>(uint8_t(value)); + mda_.write<1>(uint8_t(value >> 8)); } else { mda_.write<0>(value); } @@ -1027,14 +1058,14 @@ class IO { printf("Unhandled in: %04x\n", port); break; - case 0x0000: return dma_.read<0>(); - case 0x0001: return dma_.read<1>(); - case 0x0002: return dma_.read<2>(); - case 0x0003: return dma_.read<3>(); - case 0x0004: return dma_.read<4>(); - case 0x0005: return dma_.read<5>(); - case 0x0006: return dma_.read<6>(); - case 0x0007: return dma_.read<7>(); + case 0x0000: return dma_.i8237.read<0>(); + case 0x0001: return dma_.i8237.read<1>(); + case 0x0002: return dma_.i8237.read<2>(); + case 0x0003: return dma_.i8237.read<3>(); + case 0x0004: return dma_.i8237.read<4>(); + case 0x0005: return dma_.i8237.read<5>(); + case 0x0006: return dma_.i8237.read<6>(); + case 0x0007: return dma_.i8237.read<7>(); case 0x0008: case 0x0009: case 0x000a: case 0x000b: @@ -1055,6 +1086,15 @@ class IO { case 0x006c: case 0x006d: case 0x006e: case 0x006f: return ppi_.read(port); + case 0x0080: return dma_.pages.page<0>(); + case 0x0081: return dma_.pages.page<1>(); + case 0x0082: return dma_.pages.page<2>(); + case 0x0083: return dma_.pages.page<3>(); + case 0x0084: return dma_.pages.page<4>(); + case 0x0085: return dma_.pages.page<5>(); + case 0x0086: return dma_.pages.page<6>(); + case 0x0087: return dma_.pages.page<7>(); + case 0x0201: break; // Ignore game port. case 0x0278: case 0x0279: case 0x027a: @@ -1148,6 +1188,9 @@ class ConcreteMachine: ppi_(ppi_handler_), context(pit_, dma_, ppi_, pic_, mda_, fdc_) { + // Set up DMA source/target. + dma_.set_memory(&context.memory); + // Use clock rate as a MIPS count; keeping it as a multiple or divisor of the PIT frequency is easy. static constexpr int pit_frequency = 1'193'182; set_clock_rate(double(pit_frequency)); diff --git a/Machines/PCCompatible/PIT.hpp b/Machines/PCCompatible/PIT.hpp index 0261d98f7..015dca604 100644 --- a/Machines/PCCompatible/PIT.hpp +++ b/Machines/PCCompatible/PIT.hpp @@ -12,9 +12,9 @@ namespace PCCompatible { template -class i8237 { +class i8253 { public: - i8237(PITObserver &observer) : observer_(observer) {} + i8253(PITObserver &observer) : observer_(observer) {} template uint8_t read() { return channels_[channel].read();