From cb19c2ffb0519292afab3a376480957b6fe1f270 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 8 Jan 2023 14:10:06 -0500 Subject: [PATCH] Honour internal-clocked timing constants. --- Components/9918/Implementation/9918.cpp | 61 +++++++++++-------- .../9918/Implementation/ClockConverter.hpp | 3 + 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/Components/9918/Implementation/9918.cpp b/Components/9918/Implementation/9918.cpp index 57530c6cf..b13dc2c31 100644 --- a/Components/9918/Implementation/9918.cpp +++ b/Components/9918/Implementation/9918.cpp @@ -341,6 +341,11 @@ void TMS9918::run_for(const HalfCycles cycles) { // Output video stream. // -------------------- +#define crt_convert(action, time) this->crt_.action(this->clock_converter_.to_crt_clock(time)) +#define output_sync(x) crt_convert(output_sync, x) +#define output_blank(x) crt_convert(output_blank, x) +#define output_default_colour_burst(x) crt_convert(output_default_colour_burst, x) + #define intersect(left, right, code) { \ const int start = std::max(this->read_pointer_.column, left); \ const int end = std::min(end_column, right); \ @@ -359,43 +364,46 @@ void TMS9918::run_for(const HalfCycles cycles) { // Vertical sync. // TODO: the Mega Drive supports interlaced video, I think? if(end_column == Timing::CyclesPerLine) { - this->crt_.output_sync( - this->clock_converter_.to_crt_clock(Timing::CyclesPerLine) - ); + output_sync(Timing::CyclesPerLine); } } else { // Right border. border(0, Timing::EndOfRightBorder); - // Blanking region; total length is 58 cycles, - // and 58+15 = 73. So output the lot when the - // cursor passes 73. - if(this->read_pointer_.column < 73 && end_column >= 73) { - this->crt_.output_blank(8*4); - this->crt_.output_sync(26*4); - this->crt_.output_blank(2*4); - this->crt_.output_default_colour_burst(14*4); - this->crt_.output_blank(8*4); + // Blanking region: output the entire sequence when the cursor + // crosses the start-of-border point. + if( + this->read_pointer_.column < Timing::StartOfLeftBorder && + end_column >= Timing::StartOfLeftBorder + ) { + output_blank(Timing::StartOfSync - Timing::EndOfRightBorder); + output_sync(Timing::EndOfSync - Timing::StartOfSync); + output_blank(Timing::StartOfColourBurst - Timing::EndOfSync); + output_default_colour_burst(Timing::EndOfColourBurst - Timing::StartOfColourBurst); + output_blank(Timing::StartOfLeftBorder - Timing::EndOfColourBurst); } // Border colour for the rest of the line. - border(73, 342); + border(Timing::StartOfLeftBorder, Timing::CyclesPerLine); } } else { // Right border. - border(0, 15); + border(0, Timing::EndOfRightBorder); // Blanking region. - if(this->read_pointer_.column < 73 && end_column >= 73) { - this->crt_.output_blank(8*4); - this->crt_.output_sync(26*4); - this->crt_.output_blank(2*4); - this->crt_.output_default_colour_burst(14*4); - this->crt_.output_blank(8*4); + if( + this->read_pointer_.column < Timing::StartOfLeftBorder && + end_column >= Timing::StartOfLeftBorder + ) { + output_blank(Timing::StartOfSync - Timing::EndOfRightBorder); + output_sync(Timing::EndOfSync - Timing::StartOfSync); + output_blank(Timing::StartOfColourBurst - Timing::EndOfSync); + output_default_colour_burst(Timing::EndOfColourBurst - Timing::StartOfColourBurst); + output_blank(Timing::StartOfLeftBorder - Timing::EndOfColourBurst); } // Left border. - border(73, line_buffer.first_pixel_output_column); + border(Timing::StartOfLeftBorder, line_buffer.first_pixel_output_column); // Pixel region. intersect( @@ -422,21 +430,26 @@ void TMS9918::run_for(const HalfCycles cycles) { if(end == line_buffer.next_border_column) { const int length = line_buffer.next_border_column - line_buffer.first_pixel_output_column; - this->crt_.output_data(length * 4, size_t(length)); + this->crt_.output_data(this->clock_converter_.to_crt_clock(length), size_t(length)); this->pixel_origin_ = this->pixel_target_ = nullptr; this->asked_for_write_area_ = false; } ); // Additional right border, if called for. - if(line_buffer.next_border_column != 342) { - border(line_buffer.next_border_column, 342); + if(line_buffer.next_border_column != Timing::CyclesPerLine) { + border(line_buffer.next_border_column, Timing::CyclesPerLine); } } #undef border #undef intersect +#undef crt_convert +#undef output_sync +#undef output_blank +#undef output_default_colour_burst + // ------------- diff --git a/Components/9918/Implementation/ClockConverter.hpp b/Components/9918/Implementation/ClockConverter.hpp index ef4975801..ab1b438cf 100644 --- a/Components/9918/Implementation/ClockConverter.hpp +++ b/Components/9918/Implementation/ClockConverter.hpp @@ -68,6 +68,9 @@ struct Timing>: public template <> struct Timing: public StandardTiming<3420> { + // Implementation note: descending from StandardTiming works as long as the numbers computed + // end up being a multiple of 2.5. In practice they're all multiples of 10, so that's guaranteed. + // Coupled logic is as per to_crt_clock below. }; constexpr int TMSAccessWindowsPerLine = 171;