From a27946102a2aab0fd627353dc3c5cb78afe2260c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 1 Aug 2017 15:49:16 -0400 Subject: [PATCH] Took a shot at the interrupt counter. Attempts at keyboard reading now recur so it'll probably do for now. I think that next puts me into the realm of needing to implement the 8255. --- Machines/AmstradCPC/AmstradCPC.cpp | 109 +++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 31 deletions(-) diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index c41758649..e21245b3e 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -23,12 +23,38 @@ struct CRTCBusHandler { pixel_data_(nullptr), pixel_pointer_(nullptr), was_hsync_(false), - ram_(ram) {} + ram_(ram), + interrupt_counter_(0), + interrupt_request_(false) {} inline void perform_bus_cycle(const Motorola::CRTC::BusState &state) { + bool is_sync = state.hsync || state.vsync; + + // if a transition between sync/border/pixels just occurred, announce it + if(state.display_enable != was_enabled_ || is_sync != was_sync_) { + if(was_sync_) { + crt_->output_sync(cycles_ * 16); + } else { + if(was_enabled_) { + if(cycles_) { + crt_->output_data(cycles_ * 16, pixel_divider_); + pixel_pointer_ = pixel_data_ = nullptr; + } + } else { + uint8_t *colour_pointer = (uint8_t *)crt_->allocate_write_area(1); + if(colour_pointer) *colour_pointer = border_; + crt_->output_level(cycles_ * 16); + } + } + + cycles_ = 0; + was_sync_ = is_sync; + was_enabled_ = state.display_enable; + } + + // increment cycles since state changed cycles_++; - bool is_sync = state.hsync || state.vsync; // collect some more pixels if output is ongoing if(!is_sync && state.display_enable) { if(!pixel_data_) { @@ -80,28 +106,8 @@ struct CRTCBusHandler { } } - // if a transition between sync/border/pixels just occurred, announce it - if(state.display_enable != was_enabled_ || is_sync != was_sync_) { - if(was_sync_) { - crt_->output_sync(cycles_ * 16); - } else { - if(was_enabled_) { - crt_->output_data(cycles_ * 16, pixel_divider_); - pixel_pointer_ = pixel_data_ = nullptr; - } else { - uint8_t *colour_pointer = (uint8_t *)crt_->allocate_write_area(1); - if(colour_pointer) *colour_pointer = border_; - crt_->output_level(cycles_ * 16); - } - } - - cycles_ = 0; - was_sync_ = is_sync; - was_enabled_ = state.display_enable; - } - - // check for a leading hsync, now that pixels have safely been flushed - if(!was_hsync_ && state.hsync) { + // check for a trailing hsync + if(was_hsync_ && !state.hsync) { if(mode_ != next_mode_) { mode_ = next_mode_; switch(mode_) { @@ -111,10 +117,41 @@ struct CRTCBusHandler { case 2: pixel_divider_ = 1; break; } } + + interrupt_counter_++; + if(interrupt_counter_ == 52) { + interrupt_request_ = true; + interrupt_counter_ = false; + } + + if(interrupt_reset_counter_) { + interrupt_reset_counter_--; + if(!interrupt_reset_counter_) { + if(interrupt_counter_ < 32) { + interrupt_request_ = true; + } + interrupt_counter_ = 0; + } + } } + + if(!was_vsync_ && state.vsync) { + interrupt_reset_counter_ = 2; + } + + was_vsync_ = state.vsync; was_hsync_ = state.hsync; } + bool get_interrupt_request() { + return interrupt_request_; + } + + void reset_interrupt_request() { + interrupt_request_ = false; + interrupt_counter_ &= ~32; + } + void setup_output(float aspect_ratio) { crt_.reset(new Outputs::CRT::CRT(1024, 16, Outputs::CRT::DisplayType::PAL50, 1)); crt_->set_rgb_sampling_function( @@ -144,16 +181,16 @@ struct CRTCBusHandler { void set_colour(uint8_t colour) { if(pen_ & 16) { - printf("border: %d -> %02x\n", colour, mapped_palette_value(colour)); +// printf("border: %d -> %02x\n", colour, mapped_palette_value(colour)); border_ = mapped_palette_value(colour); // TODO: should flush any border currently in progress } else { palette_[pen_] = mapped_palette_value(colour); - for(int c = 0; c < 16; c++) { - printf("%02x ", palette_[c]); - } - printf("\n"); +// for(int c = 0; c < 16; c++) { +// printf("%02x ", palette_[c]); +// } +// printf("\n"); // TODO: no need for a full regeneration, of every mode, every time for(int c = 0; c < 256; c++) { @@ -174,6 +211,10 @@ struct CRTCBusHandler { } } + void reset_interrupt_counter() { + interrupt_counter_ = 0; + } + private: uint8_t mapped_palette_value(uint8_t colour) { uint8_t r = (colour / 3) % 3; @@ -183,7 +224,7 @@ struct CRTCBusHandler { } unsigned int cycles_; - bool was_enabled_, was_sync_, was_hsync_; + bool was_enabled_, was_sync_, was_hsync_, was_vsync_; std::shared_ptr crt_; uint8_t *pixel_data_, *pixel_pointer_; @@ -200,6 +241,10 @@ struct CRTCBusHandler { int pen_; uint8_t palette_[16]; uint8_t border_; + + int interrupt_counter_; + bool interrupt_request_; + int interrupt_reset_counter_; }; class ConcreteMachine: @@ -226,6 +271,7 @@ class ConcreteMachine: crtc_counter_ += cycle.length; int crtc_cycles = crtc_counter_.divide(HalfCycles(8)).as_int(); if(crtc_cycles) crtc_.run_for(Cycles(1)); + set_interrupt_line(crtc_bus_handler_.get_interrupt_request()); // Stop now if no action is strictly required. if(!cycle.is_terminal()) return HalfCycles(0); @@ -248,9 +294,9 @@ class ConcreteMachine: case 0: crtc_bus_handler_.select_pen(*cycle.value & 0x1f); break; case 1: crtc_bus_handler_.set_colour(*cycle.value & 0x1f); break; case 2: - printf("Set mode %d, other flags %02x\n", *cycle.value & 3, (*cycle.value >> 2)&7); read_pointers_[0] = (*cycle.value & 4) ? &ram_[0] : os_.data(); read_pointers_[3] = (*cycle.value & 8) ? &ram_[49152] : basic_.data(); + if(*cycle.value & 15) crtc_bus_handler_.reset_interrupt_counter(); crtc_bus_handler_.set_next_mode(*cycle.value & 3); break; case 3: printf("RAM paging?\n"); break; @@ -301,6 +347,7 @@ class ConcreteMachine: case CPU::Z80::PartialMachineCycle::Interrupt: *cycle.value = 0xff; + crtc_bus_handler_.reset_interrupt_request(); break; default: break;