From 80b2ccd418c587dbf89c465dd6cbe6c50b77dc24 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Nov 2023 12:53:09 -0500 Subject: [PATCH 01/10] 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(); } From 12179e486f578e9d9b01a211a217542cea107f45 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Nov 2023 13:18:39 -0500 Subject: [PATCH 02/10] Create a solid white rectangle. --- Machines/PCCompatible/PCCompatible.cpp | 54 ++++++++++++++++++++------ 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index 3ec8078e2..ac880bc28 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -37,13 +37,7 @@ 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); - } + MDA() : crtc_(Motorola::CRTC::Personality::HD6845S, outputter_) {} void run_for(Cycles cycles) { // I _think_ the MDA's CRTC is clocked at 14/9ths the PIT clock. @@ -79,22 +73,58 @@ class MDA { // MARK: - Call-ins for ScanProducer. void set_scan_target(Outputs::Display::ScanTarget *scan_target) { - crt_.set_scan_target(scan_target); + outputter_.crt.set_scan_target(scan_target); } Outputs::Display::ScanStatus get_scaled_scan_status() const { - return crt_.get_scaled_scan_status() / 4.0f; + return outputter_.crt.get_scaled_scan_status() / 4.0f; } private: struct CRTCOutputter { - void perform_bus_cycle_phase1(const Motorola::CRTC::BusState &) { - printf(""); + CRTCOutputter() : + crt(882, 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 perform_bus_cycle_phase1(const Motorola::CRTC::BusState &state) { + const OutputState new_state = + (state.hsync | state.vsync) ? OutputState::Sync : + (state.display_enable ? OutputState::Pixels : OutputState::Border); + if(new_state != output_state) { + switch(output_state) { + case OutputState::Sync: + crt.output_sync(count); + break; + + case OutputState::Border: + case OutputState::Pixels: { + uint8_t *const target = crt.begin_data(1); + if(target) { + target[0] = (output_state == OutputState::Border) ? 0x00 : 0xff; + } + crt.output_level(count); + } break; + } + + output_state = new_state; + count = 0; + } + + count += 9; } void perform_bus_cycle_phase2(const Motorola::CRTC::BusState &) {} + + Outputs::CRT::CRT crt; + + enum class OutputState { + Sync, Pixels, Border + } output_state = OutputState::Sync; + int count = 0; } outputter_; Motorola::CRTC::CRTC6845 crtc_; - Outputs::CRT::CRT crt_; int full_clock_; }; From f249e4ada6f04a3d52d4efdb15980c04506aa185 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Nov 2023 13:40:50 -0500 Subject: [PATCH 03/10] Maintain an actual pixel buffer. --- Machines/PCCompatible/PCCompatible.cpp | 59 ++++++++++++++++++++------ 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index ac880bc28..52aae0d4b 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -90,30 +90,59 @@ class MDA { } void perform_bus_cycle_phase1(const Motorola::CRTC::BusState &state) { + // Determine new output state. const OutputState new_state = (state.hsync | state.vsync) ? OutputState::Sync : (state.display_enable ? OutputState::Pixels : OutputState::Border); - if(new_state != output_state) { - switch(output_state) { - case OutputState::Sync: - crt.output_sync(count); - break; - case OutputState::Border: - case OutputState::Pixels: { - uint8_t *const target = crt.begin_data(1); - if(target) { - target[0] = (output_state == OutputState::Border) ? 0x00 : 0xff; - } - crt.output_level(count); - } break; + // Upon either a state change or just having accumulated too much local time... + if(new_state != output_state || count > 882) { + // (1) flush preexisting state. + if(count) { + switch(output_state) { + case OutputState::Sync: crt.output_sync(count); break; + case OutputState::Border: crt.output_blank(count); break; + case OutputState::Pixels: + crt.output_data(count); + pixels = pixel_pointer = nullptr; + break; + } } + // (2) adopt new state. output_state = new_state; count = 0; } + // Collect pixels if applicable. + if(output_state == OutputState::Pixels) { + if(!pixels) { + pixel_pointer = pixels = crt.begin_data(DefaultAllocationSize); + + // Flush any period where pixels weren't recorded due to back pressure. + if(pixels && count) { + crt.output_blank(count); + count = 0; + } + } + + if(pixels) { + pixel_pointer[0] = pixel_pointer[2] = pixel_pointer[4] = pixel_pointer[6] = 0; + pixel_pointer[1] = pixel_pointer[3] = pixel_pointer[5] = pixel_pointer[7] = pixel_pointer[8] = 1; + pixel_pointer += 9; + } + } + + // Advance. count += 9; + + // Output pixel row prematurely if storage is exhausted. + if(output_state == OutputState::Pixels && pixel_pointer == pixels + DefaultAllocationSize) { + crt.output_data(count); + count = 0; + + pixels = pixel_pointer = nullptr; + } } void perform_bus_cycle_phase2(const Motorola::CRTC::BusState &) {} @@ -123,6 +152,10 @@ class MDA { Sync, Pixels, Border } output_state = OutputState::Sync; int count = 0; + + uint8_t *pixels = nullptr; + uint8_t *pixel_pointer = nullptr; + static constexpr size_t DefaultAllocationSize = 720; } outputter_; Motorola::CRTC::CRTC6845 crtc_; From 381537fde9f1678725135ab2c4694bcf53d62d4f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Nov 2023 13:52:28 -0500 Subject: [PATCH 04/10] Get as far as MDA being able to fetch. --- Machines/PCCompatible/PCCompatible.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index 52aae0d4b..568cb9ec7 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -39,6 +39,10 @@ class MDA { public: MDA() : crtc_(Motorola::CRTC::Personality::HD6845S, outputter_) {} + void set_source(const uint8_t *source) { + outputter_.source = source; + } + void run_for(Cycles cycles) { // I _think_ the MDA's CRTC is clocked at 14/9ths the PIT clock. // Do that conversion here. @@ -127,6 +131,8 @@ class MDA { } if(pixels) { + // TODO: use refresh address to fetch from RAM; use that plus row address to index font. + pixel_pointer[0] = pixel_pointer[2] = pixel_pointer[4] = pixel_pointer[6] = 0; pixel_pointer[1] = pixel_pointer[3] = pixel_pointer[5] = pixel_pointer[7] = pixel_pointer[8] = 1; pixel_pointer += 9; @@ -156,6 +162,8 @@ class MDA { uint8_t *pixels = nullptr; uint8_t *pixel_pointer = nullptr; static constexpr size_t DefaultAllocationSize = 720; + + const uint8_t *source = nullptr; } outputter_; Motorola::CRTC::CRTC6845 crtc_; @@ -492,12 +500,15 @@ struct Memory { } // - // Population. + // External access. // void install(size_t address, const uint8_t *data, size_t length) { std::copy(data, data + length, memory.begin() + std::vector::difference_type(address)); } + const uint8_t *at(uint32_t address) { + return &memory[address]; + } // TEMPORARY HACK. // void print_mda() { @@ -764,6 +775,9 @@ class ConcreteMachine: const auto &bios_contents = roms.find(bios)->second; context.memory.install(0x10'0000 - bios_contents.size(), bios_contents.data(), bios_contents.size()); + + // Give the MDA something to read from. + mda_.set_source(context.memory.at(0xb'0000)); } ~ConcreteMachine() { From 8993a9c4c125c3e0bed67c376024a1398facc79b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Nov 2023 14:04:26 -0500 Subject: [PATCH 05/10] Import MDA font. --- ROMImages/PCCompatible/EUMDA9.F14 | Bin 0 -> 3584 bytes ROMImages/PCCompatible/readme.txt | 1 + 2 files changed, 1 insertion(+) create mode 100644 ROMImages/PCCompatible/EUMDA9.F14 diff --git a/ROMImages/PCCompatible/EUMDA9.F14 b/ROMImages/PCCompatible/EUMDA9.F14 new file mode 100644 index 0000000000000000000000000000000000000000..35bbd716256908ea7e02b97547a8604c1d99f575 GIT binary patch literal 3584 zcmZWs&1&RE5N`_mATR7NGvLE6c#!ZV@8Ac> zCGTJ`%ry^S5P_U_E;%d&>^%f4UsZKW8n(ugy1J_CzpL9y9YS^U`_0YW?M=ngRok@f zZr=)~ObxK8~>2JnrS3Bn}_aE;GO_C59Z?7xY8H71>{%5nxw>w@RPD^3u2trJ<5#1TOpyeRWF zF9Rz)Z}9|_zCd-rIsE|-}9%xN97I*A&v(PT98oY8n< z$~uZpnX^W0tB#gxV4cjGr36DsA3t7$bMw(ClDd|-b{_E{IK(z1ED^863)R2{fnh=O zt!MSolu!kF*9d{inMq{&LmsFi$ykJ+SYKnnk{2>_VQK!>SZR8 z5KQY2OyhNHmwm?=WU~U%fMQ_~|4uoXVaHu%#^lCiSG?{6r#)!E25xo)BJ=9HUS9^Q z$pwH(nZ`a~t=K}5b???TIwm61;D=}cO=E-k{I$*Pz%p7!AW>q?JG2AVKv>hXrPSSy z=JV291`^QFiQ3(7$iiYLm6x+eT8r=K6Bp??bOx!iI3^n9gcW`9YEcmVZuaCnva)lO z+CVs^X%$vlR}|idaTK9I11A`)s{<`HKk023Gtg#Wv=Mhg$TTy^l$fE2QrZtv6H%lf zHi{&J;LMOf&&g~ZCuDwX(czk4*@~+vV4Nn2HKvGWLk7JqeqX88EbA!b!^PP9cY?Nu zz@LqSOt>)cRuU6vlE8qWbOs@(w9mU8SeNKhQsrZa-{27q7*OByo0I2(Y*^;3OMs}5 zT_$7R9gF288j-&!qTWty*+EvYNDXoe&K{$7*kdV5zsDdoFN-pdxrvaJL8c+4$4E+# zku4YG5Z5P4dVry!3^3=!A?_Na+&2+uM!Bmx(^mVKVaj|pfBW_v1Er=Yz#9Hu5+as$ zdkn(*DiF&8jcn+377Gb(v%F;^AY0@XwboFHVG z4!s9KIXeq+AqV?d69%%68DYH-gbnOOO>{MnvGXmAwFB?g%~s+<=x1DII#>qIPWx;X z(je^u7|zk;M?Mkg813}YIfy?xt4ZH~iBA5M{>bW`fp*JH=bK-KzhD0t{{DJD{E^pR zz~{lt=fq>Mir|sohBYenJirb)A0y8x9O2FDo)2h`(X&YNJRV~kAk%A-&(N|YnaZTM zR@!r5rz=DcQyF@q=k(+u=QQ!0-j?%VH@@e39)#mN*F)Nq8ftIV)4@8=$*bGI$sA9C zlWjSq8FMJp+ZlWqXfVcG#!}$Jz|PJiKQ}*E*9s=u`P$`!g3n>(eO%~{-9xZNWhmP1H;s8wOp>~u1H{AyJ2d+1Y9sp;S$bA zP9f-QMQ5Cxv=zD!|0lpC-|75agLf(vyl2`33UCzr{~s__HH~x^rA85uf2-nNq~Jcd zEeb6+7TNn~VoXyt?B+j05lzaTPdyaSwa(x3Frtf|$Hv^F`Xtck;X%$LI;2`|0-^$4 r1b++{eGFt`z$Oz|%W%pu`DdB4)ejWCr6;M)gD&oeX}1i4+<*TEly!7t literal 0 HcmV?d00001 diff --git a/ROMImages/PCCompatible/readme.txt b/ROMImages/PCCompatible/readme.txt index 3321b7137..6fc30a465 100644 --- a/ROMImages/PCCompatible/readme.txt +++ b/ROMImages/PCCompatible/readme.txt @@ -2,5 +2,6 @@ Expected files: GLABIOS_0.2.5_8T.ROM — the 8088 GlaBIOS ROM. Phoenix 80286 ROM BIOS Version 3.05.bin — Phoenix's 80286 AT-clone BIOS. +EUMDA9.F14 — a dump of the MDA font. GlaBIOS is an open-source GPLv3 alternative BIOS for XT clones, available from https://glabios.org/ \ No newline at end of file From 231de8440ee41e86239bee15fb8125d151b2701c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Nov 2023 14:11:22 -0500 Subject: [PATCH 06/10] Add text display. --- Machines/PCCompatible/PCCompatible.cpp | 31 +++++++++++++++++++------- Machines/Utility/ROMCatalogue.cpp | 3 +++ Machines/Utility/ROMCatalogue.hpp | 1 + 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index 568cb9ec7..1d76bcdb2 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -39,8 +39,9 @@ class MDA { public: MDA() : crtc_(Motorola::CRTC::Personality::HD6845S, outputter_) {} - void set_source(const uint8_t *source) { - outputter_.source = source; + void set_source(const uint8_t *ram, std::vector font) { + outputter_.ram = ram; + outputter_.font = font; } void run_for(Cycles cycles) { @@ -131,10 +132,21 @@ class MDA { } if(pixels) { - // TODO: use refresh address to fetch from RAM; use that plus row address to index font. + // TODO: use flags. + const uint8_t glyph = ram[(state.refresh_address << 1) + 0]; +// const uint8_t flags = ram[(state.refresh_address << 1) + 1]; - pixel_pointer[0] = pixel_pointer[2] = pixel_pointer[4] = pixel_pointer[6] = 0; - pixel_pointer[1] = pixel_pointer[3] = pixel_pointer[5] = pixel_pointer[7] = pixel_pointer[8] = 1; + const uint8_t row = font[(glyph * 14) + state.row_address]; + + pixel_pointer[0] = row & 0x80; + pixel_pointer[1] = row & 0x40; + pixel_pointer[2] = row & 0x20; + pixel_pointer[3] = row & 0x10; + pixel_pointer[4] = row & 0x08; + pixel_pointer[5] = row & 0x04; + pixel_pointer[6] = row & 0x02; + pixel_pointer[7] = row & 0x01; + pixel_pointer[8] = 0; // TODO. pixel_pointer += 9; } } @@ -163,7 +175,8 @@ class MDA { uint8_t *pixel_pointer = nullptr; static constexpr size_t DefaultAllocationSize = 720; - const uint8_t *source = nullptr; + const uint8_t *ram = nullptr; + std::vector font; } outputter_; Motorola::CRTC::CRTC6845 crtc_; @@ -766,8 +779,9 @@ class ConcreteMachine: // Fetch the BIOS. [8088 only, for now] const auto bios = ROM::Name::PCCompatibleGLaBIOS; + const auto font = ROM::Name::PCCompatibleMDAFont; - ROM::Request request = ROM::Request(bios); + ROM::Request request = ROM::Request(bios) && ROM::Request(font); auto roms = rom_fetcher(request); if(!request.validate(roms)) { throw ROMMachine::Error::MissingROMs; @@ -777,7 +791,8 @@ class ConcreteMachine: context.memory.install(0x10'0000 - bios_contents.size(), bios_contents.data(), bios_contents.size()); // Give the MDA something to read from. - mda_.set_source(context.memory.at(0xb'0000)); + const auto &font_contents = roms.find(font)->second; + mda_.set_source(context.memory.at(0xb'0000), font_contents); } ~ConcreteMachine() { diff --git a/Machines/Utility/ROMCatalogue.cpp b/Machines/Utility/ROMCatalogue.cpp index 28488454e..14bc0a118 100644 --- a/Machines/Utility/ROMCatalogue.cpp +++ b/Machines/Utility/ROMCatalogue.cpp @@ -573,6 +573,9 @@ Description::Description(Name name) { case Name::PCCompatiblePhoenix80286BIOS: *this = Description(name, "PCCompatible", "Phoenix 80286 BIOS 3.05", "Phoenix 80286 ROM BIOS Version 3.05.bin", 32 * 1024, 0x8d0d318au); break; + case Name::PCCompatibleMDAFont: + *this = Description(name, "PCCompatible", "IBM's MDA font", "EUMDA9.F14", 14 * 256, 0x7754882au); + break; // TODO: CRCs below are incomplete, at best. case Name::MSXGenericBIOS: *this = Description(name, "MSX", "a generix MSX BIOS", "msx.rom", 32*1024, 0x94ee12f3u); break; diff --git a/Machines/Utility/ROMCatalogue.hpp b/Machines/Utility/ROMCatalogue.hpp index da256fa4e..37c53adf8 100644 --- a/Machines/Utility/ROMCatalogue.hpp +++ b/Machines/Utility/ROMCatalogue.hpp @@ -135,6 +135,7 @@ enum Name { // PCCompatible. PCCompatibleGLaBIOS, PCCompatiblePhoenix80286BIOS, + PCCompatibleMDAFont, // Sinclair QL. SinclairQLJS, From b22b48938042d24c724d1cd2070aedb858357a90 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Nov 2023 14:12:57 -0500 Subject: [PATCH 07/10] Mask into 4kb; I don't know whether hardware scrolling is in use. --- Machines/PCCompatible/PCCompatible.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index 1d76bcdb2..759f003f6 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -133,8 +133,8 @@ class MDA { if(pixels) { // TODO: use flags. - const uint8_t glyph = ram[(state.refresh_address << 1) + 0]; -// const uint8_t flags = ram[(state.refresh_address << 1) + 1]; + const uint8_t glyph = ram[((state.refresh_address << 1) + 0) & 0xfff]; +// const uint8_t flags = ram[((state.refresh_address << 1) + 1) & 0xfff]; const uint8_t row = font[(glyph * 14) + state.row_address]; From a293a3a816e911a378de485e85aca2d637c27bee Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Nov 2023 14:14:53 -0500 Subject: [PATCH 08/10] Document the future. --- Machines/PCCompatible/PCCompatible.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index 759f003f6..bb4c3ea5a 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -132,10 +132,10 @@ class MDA { } if(pixels) { - // TODO: use flags. - const uint8_t glyph = ram[((state.refresh_address << 1) + 0) & 0xfff]; -// const uint8_t flags = ram[((state.refresh_address << 1) + 1) & 0xfff]; + // TODO: use attributes, as per http://www.seasip.info/VintagePC/mda.html#memmap +// const uint8_t attributes = ram[((state.refresh_address << 1) + 1) & 0xfff]; + const uint8_t glyph = ram[((state.refresh_address << 1) + 0) & 0xfff]; const uint8_t row = font[(glyph * 14) + state.row_address]; pixel_pointer[0] = row & 0x80; From 825f3184eb2309cf24f4d69b10556e9fae027754 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Nov 2023 14:18:50 -0500 Subject: [PATCH 09/10] Explain provenance. --- ROMImages/PCCompatible/readme.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ROMImages/PCCompatible/readme.txt b/ROMImages/PCCompatible/readme.txt index 6fc30a465..737a1facd 100644 --- a/ROMImages/PCCompatible/readme.txt +++ b/ROMImages/PCCompatible/readme.txt @@ -4,4 +4,7 @@ GLABIOS_0.2.5_8T.ROM — the 8088 GlaBIOS ROM. Phoenix 80286 ROM BIOS Version 3.05.bin — Phoenix's 80286 AT-clone BIOS. EUMDA9.F14 — a dump of the MDA font. -GlaBIOS is an open-source GPLv3 alternative BIOS for XT clones, available from https://glabios.org/ \ No newline at end of file + +GlaBIOS is an open-source GPLv3 alternative BIOS for XT clones, available from https://glabios.org/ + +The MDA font is in the form offered at https://github.com/viler-int10h/vga-text-mode-fonts i.e. it's 256 lots of 14 bytes, the first 14 being the content of character 0, the next 14 being the content of character 1, etc. \ No newline at end of file From e0f72f2048735328f48123d0e36c73c54f5469bb Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Nov 2023 14:18:58 -0500 Subject: [PATCH 10/10] Tidy up. --- Machines/PCCompatible/PCCompatible.cpp | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index bb4c3ea5a..2373bd056 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -631,10 +631,7 @@ class IO { printf("TODO: DMA page write of %02x at %04x\n", value, port); break; - case 0x03b0: - case 0x03b2: - case 0x03b4: - case 0x03b6: + case 0x03b0: case 0x03b2: case 0x03b4: case 0x03b6: if constexpr (std::is_same_v) { mda_.write<0>(value); mda_.write<1>(value >> 8); @@ -643,10 +640,7 @@ class IO { } break; - case 0x03b1: - case 0x03b3: - case 0x03b5: - case 0x03b7: + case 0x03b1: case 0x03b3: case 0x03b5: case 0x03b7: if constexpr (std::is_same_v) { mda_.write<1>(value); mda_.write<0>(value >> 8); @@ -655,15 +649,9 @@ class IO { } 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); + case 0x03b8: case 0x03b9: case 0x03ba: case 0x03bb: + case 0x03bc: case 0x03bd: case 0x03be: case 0x03bf: + mda_.write<8>(value); break; case 0x03d0: case 0x03d1: case 0x03d2: case 0x03d3: