From 80b2ccd418c587dbf89c465dd6cbe6c50b77dc24 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Nov 2023 12:53:09 -0500 Subject: [PATCH] Attempt to wire in a CRTC. --- Machines/PCCompatible/PCCompatible.cpp | 127 ++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 11 deletions(-) diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index 9275b20de..3ec8078e2 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -17,10 +17,13 @@ #include "../../InstructionSets/x86/Instruction.hpp" #include "../../InstructionSets/x86/Perform.hpp" -#include "../../Components/AudioToggle/AudioToggle.hpp" +#include "../../Components/6845/CRTC6845.hpp" #include "../../Components/8255/i8255.hpp" +#include "../../Components/AudioToggle/AudioToggle.hpp" #include "../../Numeric/RegisterSizes.hpp" + +#include "../../Outputs/CRT/CRT.hpp" #include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp" #include "../AudioProducer.hpp" @@ -32,6 +35,70 @@ namespace PCCompatible { +class MDA { + public: + MDA() : + crtc_(Motorola::CRTC::Personality::HD6845S, outputter_), + crt_(873, 9, 382, 3, Outputs::Display::InputDataType::Luminance1) + { + crt_.set_visible_area(Outputs::Display::Rect(0.1072f, 0.1f, 0.842105263157895f, 0.842105263157895f)); + crt_.set_display_type(Outputs::Display::DisplayType::CompositeMonochrome); + } + + void run_for(Cycles cycles) { + // I _think_ the MDA's CRTC is clocked at 14/9ths the PIT clock. + // Do that conversion here. + full_clock_ += 14 * cycles.as(); + crtc_.run_for(Cycles(full_clock_ / 9)); + full_clock_ %= 9; + } + + template + void write(uint8_t value) { + if constexpr (address & 0x8) { + printf("TODO: write MDA control %02x\n", value); + } else { + if constexpr (address & 0x1) { + crtc_.set_register(value); + } else { + crtc_.select_register(value); + } + } + } + + template + uint8_t read() { + if constexpr (address & 0x8) { + printf("TODO: read MDA control\n"); + return 0xff; + } else { + return crtc_.get_register(); + } + } + + // MARK: - Call-ins for ScanProducer. + + void set_scan_target(Outputs::Display::ScanTarget *scan_target) { + crt_.set_scan_target(scan_target); + } + + Outputs::Display::ScanStatus get_scaled_scan_status() const { + return crt_.get_scaled_scan_status() / 4.0f; + } + + private: + struct CRTCOutputter { + void perform_bus_cycle_phase1(const Motorola::CRTC::BusState &) { + printf(""); + } + void perform_bus_cycle_phase2(const Motorola::CRTC::BusState &) {} + } outputter_; + Motorola::CRTC::CRTC6845 crtc_; + Outputs::CRT::CRT crt_; + + int full_clock_; +}; + struct PCSpeaker { PCSpeaker() : toggle(queue), @@ -425,7 +492,8 @@ struct Memory { class IO { public: - IO(PIT &pit, DMA &dma, PPI &ppi, PIC &pic) : pit_(pit), dma_(dma), ppi_(ppi), pic_(pic) {} + IO(PIT &pit, DMA &dma, PPI &ppi, PIC &pic, MDA &mda) : + pit_(pit), dma_(dma), ppi_(ppi), pic_(pic), mda_(mda) {} template void out(uint16_t port, IntT value) { switch(port) { @@ -476,10 +544,38 @@ class IO { printf("TODO: DMA page write of %02x at %04x\n", value, port); break; - case 0x03b0: case 0x03b1: case 0x03b2: case 0x03b3: - case 0x03b4: case 0x03b5: case 0x03b6: case 0x03b7: - case 0x03b8: case 0x03b9: case 0x03ba: case 0x03bb: - case 0x03bc: case 0x03bd: case 0x03be: case 0x03bf: + case 0x03b0: + case 0x03b2: + case 0x03b4: + case 0x03b6: + if constexpr (std::is_same_v) { + mda_.write<0>(value); + mda_.write<1>(value >> 8); + } else { + mda_.write<0>(value); + } + break; + + case 0x03b1: + case 0x03b3: + case 0x03b5: + case 0x03b7: + if constexpr (std::is_same_v) { + mda_.write<1>(value); + mda_.write<0>(value >> 8); + } else { + mda_.write<1>(value); + } + break; + + case 0x03b8: + case 0x03b9: + case 0x03ba: + case 0x03bb: + case 0x03bc: + case 0x03bd: + case 0x03be: + case 0x03bf: printf("TODO: MDA write of %02x at %04x\n", value, port); break; @@ -532,6 +628,7 @@ class IO { DMA &dma_; PPI &ppi_; PIC &pic_; + MDA &mda_; }; class FlowController { @@ -586,7 +683,7 @@ class ConcreteMachine: ppi_handler_(speaker_), pit_(pit_observer_), ppi_(ppi_handler_), - context(pit_, dma_, ppi_, pic_) + context(pit_, dma_, ppi_, pic_, mda_) { // 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; @@ -634,6 +731,11 @@ class ConcreteMachine: pit_.run_for(1); ++speaker_.cycles_since_update; + // + // Advance CRTC at a more approximate rate. + // + mda_.run_for(Cycles(3)); + // // Perform one CPU instruction every three PIT cycles. // i.e. CPU instruction rate is 1/3 * ~1.19Mhz ~= 0.4 MIPS. @@ -692,9 +794,11 @@ class ConcreteMachine: } // MARK: - ScanProducer. - void set_scan_target([[maybe_unused]] Outputs::Display::ScanTarget *scan_target) override {} + void set_scan_target(Outputs::Display::ScanTarget *scan_target) override { + mda_.set_scan_target(scan_target); + } Outputs::Display::ScanStatus get_scaled_scan_status() const override { - return Outputs::Display::ScanStatus(); + return mda_.get_scaled_scan_status(); } // MARK: - AudioProducer. @@ -713,6 +817,7 @@ class ConcreteMachine: PIC pic_; DMA dma_; PCSpeaker speaker_; + MDA mda_; PITObserver pit_observer_; i8255PortHandler ppi_handler_; @@ -721,11 +826,11 @@ class ConcreteMachine: PPI ppi_; struct Context { - Context(PIT &pit, DMA &dma, PPI &ppi, PIC &pic) : + Context(PIT &pit, DMA &dma, PPI &ppi, PIC &pic, MDA &mda) : segments(registers), memory(registers, segments), flow_controller(registers, segments), - io(pit, dma, ppi, pic) + io(pit, dma, ppi, pic, mda) { reset(); }