From a4c910f1dea2d716576f1e3b53ddb62d72eb4482 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 10 Aug 2017 11:12:53 -0400 Subject: [PATCH 1/5] =?UTF-8?q?This=20appears=20to=20be=20a=20more=20accur?= =?UTF-8?q?ate=20take=20on=206845=20address=20advancement=20=E2=80=94=20it?= =?UTF-8?q?=20is=20necessary=20that=20character=20output=20has=20finished?= =?UTF-8?q?=20for=20the=20line=20address=20to=20be=20updated.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Components/6845/CRTC6845.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Components/6845/CRTC6845.hpp b/Components/6845/CRTC6845.hpp index 2e113ed9e..15a50e6ba 100644 --- a/Components/6845/CRTC6845.hpp +++ b/Components/6845/CRTC6845.hpp @@ -71,9 +71,6 @@ template class CRTC6845 { // check for end-of-line if(is_end_of_line) { - character_counter_ = 0; - character_is_visible_ = true; - // check for end of vertical sync if(vsync_down_counter_) { vsync_down_counter_--; @@ -94,7 +91,8 @@ template class CRTC6845 { } else { // advance vertical counter if(bus_state_.row_address == registers_[9]) { - line_address_ = bus_state_.refresh_address; + if(!character_is_visible_) + line_address_ = bus_state_.refresh_address; bus_state_.row_address = 0; bool is_at_end_of_frame = line_counter_ == registers_[4]; @@ -126,9 +124,12 @@ template class CRTC6845 { } } else { bus_state_.row_address++; - bus_state_.refresh_address = line_address_; } + bus_state_.refresh_address = line_address_; } + + character_counter_ = 0; + character_is_visible_ = true; } bus_state_.display_enable = character_is_visible_ && line_is_visible_; From be8e7a41448315b46f1a63a225d363d124399c4f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 10 Aug 2017 11:22:30 -0400 Subject: [PATCH 2/5] Eliminated false register aliasing, restricted register sizes and locked out reading and writing where appropriate. --- Components/6845/CRTC6845.hpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Components/6845/CRTC6845.hpp b/Components/6845/CRTC6845.hpp index 15a50e6ba..0f3d1e768 100644 --- a/Components/6845/CRTC6845.hpp +++ b/Components/6845/CRTC6845.hpp @@ -138,7 +138,7 @@ template class CRTC6845 { } void select_register(uint8_t r) { - selected_register_ = (int)r & 15; + selected_register_ = r; } uint8_t get_status() { @@ -146,18 +146,25 @@ template class CRTC6845 { } uint8_t get_register() { + if(selected_register_ < 12 || selected_register_ > 17) return 0xff; return registers_[selected_register_]; } void set_register(uint8_t value) { - registers_[selected_register_] = value; + static uint8_t masks[] = { + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, + 0xff, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff + }; + + if(selected_register_ < 16) + registers_[selected_register_] = value & masks[selected_register_]; } private: T &bus_handler_; BusState bus_state_; - uint8_t registers_[16]; + uint8_t registers_[18]; int selected_register_; uint8_t character_counter_; From 02d792c003591b1b4e9626867072c73198e824e1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 10 Aug 2017 11:48:37 -0400 Subject: [PATCH 3/5] Simplified logic slightly, avoiding repetition. --- Components/6845/CRTC6845.hpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Components/6845/CRTC6845.hpp b/Components/6845/CRTC6845.hpp index 0f3d1e768..1181c6cb1 100644 --- a/Components/6845/CRTC6845.hpp +++ b/Components/6845/CRTC6845.hpp @@ -58,15 +58,14 @@ template class CRTC6845 { if(hsync_down_counter_) bus_state_.hsync = true; } + // update refresh address + if(character_is_visible_) { + bus_state_.refresh_address++; + } + // check for end of visible characters if(character_counter_ == registers_[1]) { - bus_state_.refresh_address++; character_is_visible_ = false; - } else { - // update refresh address - if(character_is_visible_) { - bus_state_.refresh_address++; - } } // check for end-of-line From 6a6e5ae79c14599ca1c60a6f9eb7453356436102 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 10 Aug 2017 12:28:57 -0400 Subject: [PATCH 4/5] Forced users of the 6845 to be explicit about which type. So far with no effect. --- Components/6845/CRTC6845.hpp | 12 +++++++++++- Machines/AmstradCPC/AmstradCPC.cpp | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Components/6845/CRTC6845.hpp b/Components/6845/CRTC6845.hpp index 1181c6cb1..5a87c649c 100644 --- a/Components/6845/CRTC6845.hpp +++ b/Components/6845/CRTC6845.hpp @@ -31,9 +31,18 @@ class BusHandler { void perform_bus_cycle(const BusState &) {} }; +enum Personality { + HD6845S, // + UM6845R, // + MC6845, // + AMS40226 // +}; + template class CRTC6845 { public: - CRTC6845(T &bus_handler) : bus_handler_(bus_handler) {} + + CRTC6845(Personality p, T &bus_handler) : + personality_(p), bus_handler_(bus_handler) {} void run_for(Cycles cycles) { int cyles_remaining = cycles.as_int(); @@ -160,6 +169,7 @@ template class CRTC6845 { } private: + Personality personality_; T &bus_handler_; BusState bus_state_; diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 7b7e8b0c4..43fa74d95 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -528,7 +528,7 @@ class ConcreteMachine: ConcreteMachine() : z80_(*this), crtc_counter_(HalfCycles(4)), // This starts the CRTC exactly out of phase with the memory accesses - crtc_(crtc_bus_handler_), + crtc_(Motorola::CRTC::HD6845S, crtc_bus_handler_), crtc_bus_handler_(ram_, interrupt_timer_), i8255_(i8255_port_handler_), i8255_port_handler_(key_state_, crtc_bus_handler_, ay_, tape_player_), From 4961fda2a980231e43fddb1a62ae95939934bf5f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 10 Aug 2017 12:39:19 -0400 Subject: [PATCH 5/5] Ensured counter-intuitive CRTC writes get through, taking the opportunity to correct my handling of port IO in general: selecting multiple devices for input results in a logical AND (i.e. open collector mode), and both the CRTC and gate array will receive data from 'input's if applicable. --- Machines/AmstradCPC/AmstradCPC.cpp | 120 ++++++++++++++++------------- 1 file changed, 66 insertions(+), 54 deletions(-) diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 43fa74d95..9d7359321 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -579,48 +579,7 @@ class ConcreteMachine: case CPU::Z80::PartialMachineCycle::Output: // Check for a gate array access. if((address & 0xc000) == 0x4000) { - switch(*cycle.value >> 6) { - case 0: crtc_bus_handler_.select_pen(*cycle.value & 0x1f); break; - case 1: crtc_bus_handler_.set_colour(*cycle.value & 0x1f); break; - case 2: - // Perform ROM paging. - read_pointers_[0] = (*cycle.value & 4) ? write_pointers_[0] : roms_[rom_model_].data(); - - upper_rom_is_paged_ = !(*cycle.value & 8); - read_pointers_[3] = upper_rom_is_paged_ ? roms_[upper_rom_].data() : write_pointers_[3]; - - // Reset the interrupt timer if requested. - if(*cycle.value & 0x10) interrupt_timer_.reset_count(); - - // Post the next mode. - crtc_bus_handler_.set_next_mode(*cycle.value & 3); - break; - case 3: - // Perform RAM paging, if 128kb is permitted. - if(has_128k_) { - bool adjust_low_read_pointer = read_pointers_[0] == write_pointers_[0]; - bool adjust_high_read_pointer = read_pointers_[3] == write_pointers_[3]; -#define RAM_BANK(x) &ram_[x * 16384] -#define RAM_CONFIG(a, b, c, d) write_pointers_[0] = RAM_BANK(a); write_pointers_[1] = RAM_BANK(b); write_pointers_[2] = RAM_BANK(c); write_pointers_[3] = RAM_BANK(d); - switch(*cycle.value & 7) { - case 0: RAM_CONFIG(0, 1, 2, 3); break; - case 1: RAM_CONFIG(0, 1, 2, 7); break; - case 2: RAM_CONFIG(4, 5, 6, 7); break; - case 3: RAM_CONFIG(0, 3, 2, 7); break; - case 4: RAM_CONFIG(0, 4, 2, 3); break; - case 5: RAM_CONFIG(0, 5, 2, 3); break; - case 6: RAM_CONFIG(0, 6, 2, 3); break; - case 7: RAM_CONFIG(0, 7, 2, 3); break; - } -#undef RAM_CONFIG -#undef RAM_BANK - if(adjust_low_read_pointer) read_pointers_[0] = write_pointers_[0]; - read_pointers_[1] = write_pointers_[1]; - read_pointers_[2] = write_pointers_[2]; - if(adjust_high_read_pointer) read_pointers_[3] = write_pointers_[3]; - } - break; - } + write_to_gate_array(*cycle.value); } // Check for an upper ROM selection @@ -634,7 +593,7 @@ class ConcreteMachine: switch((address >> 8) & 3) { case 0: crtc_.select_register(*cycle.value); break; case 1: crtc_.set_register(*cycle.value); break; - case 2: case 3: printf("Illegal CRTC write?\n"); break; + default: break; } } @@ -657,23 +616,31 @@ class ConcreteMachine: // Default to nothing answering *cycle.value = 0xff; - // Check for a CRTC access - if(!(address & 0x4000)) { - switch((address >> 8) & 3) { - case 0: case 1: printf("Illegal CRTC read?\n"); break; - case 2: *cycle.value = crtc_.get_status(); break; - case 3: *cycle.value = crtc_.get_register(); break; - } - } - // Check for a PIO access if(!(address & 0x800)) { - *cycle.value = i8255_.get_register((address >> 8) & 3); + *cycle.value &= i8255_.get_register((address >> 8) & 3); } // Check for an FDC access if(has_fdc_ && (address & 0x580) == 0x100) { - *cycle.value = fdc_.get_register(address & 1); + *cycle.value &= fdc_.get_register(address & 1); + } + + // Check for a CRTC access; the below is not a typo — the CRTC can be selected + // for writing via an input, and will sample whatever happens to be available + if(!(address & 0x4000)) { + switch((address >> 8) & 3) { + case 0: crtc_.select_register(*cycle.value); break; + case 1: crtc_.set_register(*cycle.value); break; + case 2: *cycle.value &= crtc_.get_status(); break; + case 3: *cycle.value &= crtc_.get_register(); break; + } + } + + // As with the CRTC, the gate array will sample the bus if the address decoding + // implies that it should, unaware of data direction + if((address & 0xc000) == 0x4000) { + write_to_gate_array(*cycle.value); } break; @@ -794,6 +761,51 @@ class ConcreteMachine: } private: + inline void write_to_gate_array(uint8_t value) { + switch(value >> 6) { + case 0: crtc_bus_handler_.select_pen(value & 0x1f); break; + case 1: crtc_bus_handler_.set_colour(value & 0x1f); break; + case 2: + // Perform ROM paging. + read_pointers_[0] = (value & 4) ? write_pointers_[0] : roms_[rom_model_].data(); + + upper_rom_is_paged_ = !(value & 8); + read_pointers_[3] = upper_rom_is_paged_ ? roms_[upper_rom_].data() : write_pointers_[3]; + + // Reset the interrupt timer if requested. + if(value & 0x10) interrupt_timer_.reset_count(); + + // Post the next mode. + crtc_bus_handler_.set_next_mode(value & 3); + break; + case 3: + // Perform RAM paging, if 128kb is permitted. + if(has_128k_) { + bool adjust_low_read_pointer = read_pointers_[0] == write_pointers_[0]; + bool adjust_high_read_pointer = read_pointers_[3] == write_pointers_[3]; +#define RAM_BANK(x) &ram_[x * 16384] +#define RAM_CONFIG(a, b, c, d) write_pointers_[0] = RAM_BANK(a); write_pointers_[1] = RAM_BANK(b); write_pointers_[2] = RAM_BANK(c); write_pointers_[3] = RAM_BANK(d); + switch(value & 7) { + case 0: RAM_CONFIG(0, 1, 2, 3); break; + case 1: RAM_CONFIG(0, 1, 2, 7); break; + case 2: RAM_CONFIG(4, 5, 6, 7); break; + case 3: RAM_CONFIG(0, 3, 2, 7); break; + case 4: RAM_CONFIG(0, 4, 2, 3); break; + case 5: RAM_CONFIG(0, 5, 2, 3); break; + case 6: RAM_CONFIG(0, 6, 2, 3); break; + case 7: RAM_CONFIG(0, 7, 2, 3); break; + } +#undef RAM_CONFIG +#undef RAM_BANK + if(adjust_low_read_pointer) read_pointers_[0] = write_pointers_[0]; + read_pointers_[1] = write_pointers_[1]; + read_pointers_[2] = write_pointers_[2]; + if(adjust_high_read_pointer) read_pointers_[3] = write_pointers_[3]; + } + break; + } + } + CPU::Z80::Processor z80_; CRTCBusHandler crtc_bus_handler_;