From 0d7646d42a2c70033fe0a3916b63f92deed27ef0 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 4 Dec 2023 09:45:32 -0500 Subject: [PATCH 1/3] Add a cursor-type template parameter. --- Components/6845/CRTC6845.hpp | 15 ++++++++++++++- Machines/AmstradCPC/AmstradCPC.cpp | 7 ++++--- Machines/PCCompatible/PCCompatible.cpp | 18 +++++++++--------- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/Components/6845/CRTC6845.hpp b/Components/6845/CRTC6845.hpp index 67d065a25..a187c0dfb 100644 --- a/Components/6845/CRTC6845.hpp +++ b/Components/6845/CRTC6845.hpp @@ -50,9 +50,22 @@ enum Personality { AMS40226 // Type 3. Status is get register, fixed-length VSYNC, no zero-length HSYNC. }; +// https://www.pcjs.org/blog/2018/03/20/ advises that "the behavior of bits 5 and 6 [of register 10, the cursor start +// register is really card specific". +// +// This enum captures those specifics. +enum CursorType { + /// No cursor signal is generated. + None, + /// MDA style: 00 => symmetric blinking; 01 or 10 => no blinking; 11 => short on, long off. + MDA, + /// EGA style: ignore the bits completely. + EGA, +}; + // TODO UM6845R and R12/R13; see http://www.cpcwiki.eu/index.php/CRTC#CRTC_Differences -template class CRTC6845 { +template class CRTC6845 { public: CRTC6845(Personality p, T &bus_handler) noexcept : diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index d720303db..7c2848fee 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -585,6 +585,7 @@ class CRTCBusHandler { InterruptTimer &interrupt_timer_; }; +using CRTC = Motorola::CRTC::CRTC6845; /*! Holds and vends the current keyboard state, acting as the AY's port handler. @@ -683,7 +684,7 @@ class i8255PortHandler : public Intel::i8255::PortHandler { public: i8255PortHandler( KeyboardState &key_state, - const Motorola::CRTC::CRTC6845 &crtc, + const CRTC &crtc, AYDeferrer &ay, Storage::Tape::BinaryTapePlayer &tape_player) : ay_(ay), @@ -742,7 +743,7 @@ class i8255PortHandler : public Intel::i8255::PortHandler { private: AYDeferrer &ay_; - const Motorola::CRTC::CRTC6845 &crtc_; + const CRTC &crtc_; KeyboardState &key_state_; Storage::Tape::BinaryTapePlayer &tape_player_; }; @@ -1219,7 +1220,7 @@ template class ConcreteMachine: CPU::Z80::Processor z80_; CRTCBusHandler crtc_bus_handler_; - Motorola::CRTC::CRTC6845 crtc_; + CRTC crtc_; AYDeferrer ay_; i8255PortHandler i8255_port_handler_; diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index aa2e3c61e..d525086c2 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -625,7 +625,7 @@ class MDA { const uint8_t *ram = nullptr; std::vector font; } outputter_; - Motorola::CRTC::CRTC6845 crtc_; + Motorola::CRTC::CRTC6845 crtc_; int full_clock_; }; @@ -885,14 +885,14 @@ class IO { printf("Unhandled in: %04x\n", port); break; - case 0x0000: return dma_.controller.read<0>(); - case 0x0001: return dma_.controller.read<1>(); - case 0x0002: return dma_.controller.read<2>(); - case 0x0003: return dma_.controller.read<3>(); - case 0x0004: return dma_.controller.read<4>(); - case 0x0005: return dma_.controller.read<5>(); - case 0x0006: return dma_.controller.read<6>(); - case 0x0007: return dma_.controller.read<7>(); + 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 0x0008: return dma_.controller.status(); From 646c6b08f7bedf4760d0f50e88efde1e1eb84840 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 4 Dec 2023 09:52:46 -0500 Subject: [PATCH 2/3] Make cursor blink. --- Components/6845/CRTC6845.hpp | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/Components/6845/CRTC6845.hpp b/Components/6845/CRTC6845.hpp index a187c0dfb..2e9392547 100644 --- a/Components/6845/CRTC6845.hpp +++ b/Components/6845/CRTC6845.hpp @@ -65,7 +65,7 @@ enum CursorType { // TODO UM6845R and R12/R13; see http://www.cpcwiki.eu/index.php/CRTC#CRTC_Differences -template class CRTC6845 { +template class CRTC6845 { public: CRTC6845(Personality p, T &bus_handler) noexcept : @@ -136,7 +136,7 @@ template class CRTC6845 { bus_state_.refresh_address = (bus_state_.refresh_address + 1) & 0x3fff; bus_state_.cursor = is_cursor_line_ && - bus_state_.refresh_address == ((registers_[15] | (registers_[14] << 8))&0x3fff); + bus_state_.refresh_address == (registers_[15] | (registers_[14] << 8)); // Check for end-of-line. if(character_counter_ == registers_[0]) { @@ -192,9 +192,11 @@ template class CRTC6845 { } inline void do_end_of_line() { - // Check for cursor disable. - // TODO: this is handled differently on the EGA, should I ever implement that. - is_cursor_line_ &= bus_state_.row_address != (registers_[11] & 0x1f); + if constexpr (cursor_type != CursorType::None) { + // Check for cursor disable. + // TODO: this is handled differently on the EGA, should I ever implement that. + is_cursor_line_ &= bus_state_.row_address != (registers_[11] & 0x1f); + } // Check for end of vertical sync. if(bus_state_.vsync) { @@ -255,8 +257,21 @@ template class CRTC6845 { character_counter_ = 0; character_is_visible_ = (registers_[1] != 0); - // Check for cursor enable. - is_cursor_line_ |= bus_state_.row_address == (registers_[10] & 0x1f); + if constexpr (cursor_type != CursorType::None) { + // Check for cursor enable. + is_cursor_line_ |= bus_state_.row_address == (registers_[10] & 0x1f); + + switch(cursor_type) { + // MDA-style blinking; timings are a bit of a guess for now. + case CursorType::MDA: + switch(registers_[10] >> 5) { + case 0b11: is_cursor_line_ &= (field_count_ & 15) < 5; break; + case 0b00: is_cursor_line_ &= bool(field_count_ & 16); break; + default: break; + } + break; + } + } } inline void do_end_of_frame() { @@ -264,6 +279,9 @@ template class CRTC6845 { line_is_visible_ = true; line_address_ = uint16_t((registers_[12] << 8) | registers_[13]); bus_state_.refresh_address = line_address_; + if constexpr (cursor_type != CursorType::None) { + ++field_count_; + } } Personality personality_; @@ -291,6 +309,8 @@ template class CRTC6845 { unsigned int character_is_visible_shifter_ = 0; bool is_cursor_line_ = false; + + int field_count_ = 0; }; } From 5845ce0a395de6d091405bb351274101b4d9faef Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 4 Dec 2023 09:56:06 -0500 Subject: [PATCH 3/3] Ameliorate for race condition. --- Concurrency/AsyncTaskQueue.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Concurrency/AsyncTaskQueue.hpp b/Concurrency/AsyncTaskQueue.hpp index f0de9f640..ba723103d 100644 --- a/Concurrency/AsyncTaskQueue.hpp +++ b/Concurrency/AsyncTaskQueue.hpp @@ -128,7 +128,7 @@ template