From 9b7a925816765522ddd0dc8f1e07b4486f1f91a2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 20 Jan 2023 20:29:15 -0500 Subject: [PATCH] Give clearer names to the two pointers. --- Components/9918/Implementation/9918.cpp | 98 ++++++++++----------- Components/9918/Implementation/9918Base.hpp | 6 +- Components/9918/Implementation/Draw.hpp | 8 +- Components/9918/Implementation/Fetch.hpp | 42 ++++----- 4 files changed, 77 insertions(+), 77 deletions(-) diff --git a/Components/9918/Implementation/9918.cpp b/Components/9918/Implementation/9918.cpp index 3ea99a45a..a7eae4314 100644 --- a/Components/9918/Implementation/9918.cpp +++ b/Components/9918/Implementation/9918.cpp @@ -39,10 +39,10 @@ Base::Base() : // Establish that output is delayed after reading by `output_lag` cycles; start // at a random position. - read_pointer_.row = rand() % 262; - read_pointer_.column = rand() % (Timing::CyclesPerLine - output_lag); - write_pointer_.row = read_pointer_.row; - write_pointer_.column = read_pointer_.column + output_lag; + fetch_pointer_.row = rand() % 262; + fetch_pointer_.column = rand() % (Timing::CyclesPerLine - output_lag); + output_pointer_.row = output_pointer_.row; + output_pointer_.column = output_pointer_.column + output_lag; } template @@ -155,20 +155,20 @@ void TMS9918::run_for(const HalfCycles cycles) { while(write_cycles_pool || read_cycles_pool) { #ifndef NDEBUG - LineBufferPointer backup = this->read_pointer_; + LineBufferPointer backup = this->output_pointer_; #endif if(write_cycles_pool) { // Determine how much writing to do. const int write_cycles = std::min( - Timing::CyclesPerLine - this->write_pointer_.column, + Timing::CyclesPerLine - this->fetch_pointer_.column, write_cycles_pool ); - const int end_column = this->write_pointer_.column + write_cycles; - LineBuffer &line_buffer = this->line_buffers_[this->write_pointer_.row]; + const int end_column = this->fetch_pointer_.column + write_cycles; + LineBuffer &line_buffer = this->line_buffers_[this->fetch_pointer_.row]; // Determine what this does to any enqueued VRAM access. - this->minimum_access_column_ = this->write_pointer_.column + this->cycles_until_access_; + this->minimum_access_column_ = this->fetch_pointer_.column + this->cycles_until_access_; this->cycles_until_access_ -= write_cycles; @@ -176,8 +176,8 @@ void TMS9918::run_for(const HalfCycles cycles) { // Latch scrolling position, if necessary. // --------------------------------------- if constexpr (is_sega_vdp(personality)) { - if(this->write_pointer_.column < 61 && end_column >= 61) { - if(!this->write_pointer_.row) { + if(this->fetch_pointer_.column < 61 && end_column >= 61) { + if(!this->fetch_pointer_.row) { Storage::latched_vertical_scroll_ = Storage::vertical_scroll_; if(Storage::mode4_enable_) { @@ -201,7 +201,7 @@ void TMS9918::run_for(const HalfCycles cycles) { // Perform memory accesses. // ------------------------ #define fetch(function, clock) \ - const int first_window = from_internal(this->write_pointer_.column);\ + const int first_window = from_internal(this->fetch_pointer_.column);\ const int final_window = from_internal(end_column); \ if(first_window == final_window) break; \ if(final_window != clock_rate()) { \ @@ -224,12 +224,12 @@ void TMS9918::run_for(const HalfCycles cycles) { // ------------------------------- // Check for interrupt conditions. // ------------------------------- - if(this->write_pointer_.column < this->mode_timing_.line_interrupt_position && end_column >= this->mode_timing_.line_interrupt_position) { + if(this->fetch_pointer_.column < this->mode_timing_.line_interrupt_position && end_column >= this->mode_timing_.line_interrupt_position) { // The Sega VDP offers a decrementing counter for triggering line interrupts; // it is reloaded either when it overflows or upon every non-pixel line after the first. // It is otherwise decremented. if constexpr (is_sega_vdp(personality)) { - if(this->write_pointer_.row >= 0 && this->write_pointer_.row <= this->mode_timing_.pixel_lines) { + if(this->fetch_pointer_.row >= 0 && this->fetch_pointer_.row <= this->mode_timing_.pixel_lines) { --this->line_interrupt_counter_; if(this->line_interrupt_counter_ == 0xff) { this->line_interrupt_pending_ = true; @@ -245,8 +245,8 @@ void TMS9918::run_for(const HalfCycles cycles) { } if( - this->write_pointer_.row == this->mode_timing_.end_of_frame_interrupt_position.row && - this->write_pointer_.column < this->mode_timing_.end_of_frame_interrupt_position.column && + this->fetch_pointer_.row == this->mode_timing_.end_of_frame_interrupt_position.row && + this->fetch_pointer_.column < this->mode_timing_.end_of_frame_interrupt_position.column && end_column >= this->mode_timing_.end_of_frame_interrupt_position.column ) { this->status_ |= StatusInterrupt; @@ -257,13 +257,13 @@ void TMS9918::run_for(const HalfCycles cycles) { // ------------- // Advance time. // ------------- - this->write_pointer_.column = end_column; + this->fetch_pointer_.column = end_column; write_cycles_pool -= write_cycles; - if(this->write_pointer_.column == Timing::CyclesPerLine) { - this->write_pointer_.column = 0; - this->write_pointer_.row = (this->write_pointer_.row + 1) % this->mode_timing_.total_lines; - LineBuffer &next_line_buffer = this->line_buffers_[this->write_pointer_.row]; + if(this->fetch_pointer_.column == Timing::CyclesPerLine) { + this->fetch_pointer_.column = 0; + this->fetch_pointer_.row = (this->fetch_pointer_.row + 1) % this->mode_timing_.total_lines; + LineBuffer &next_line_buffer = this->line_buffers_[this->fetch_pointer_.row]; // Establish the current screen output mode, which will be captured as a // line mode momentarily. @@ -292,22 +292,22 @@ void TMS9918::run_for(const HalfCycles cycles) { if( (this->screen_mode_ == ScreenMode::Blank) || - (this->write_pointer_.row >= this->mode_timing_.pixel_lines && this->write_pointer_.row != this->mode_timing_.total_lines-1)) + (this->fetch_pointer_.row >= this->mode_timing_.pixel_lines && this->fetch_pointer_.row != this->mode_timing_.total_lines-1)) next_line_buffer.line_mode = LineMode::Refresh; } } #ifndef NDEBUG - assert(backup.row == this->read_pointer_.row && backup.column == this->read_pointer_.column); - backup = this->write_pointer_; + assert(backup.row == this->output_pointer_.row && backup.column == this->output_pointer_.column); + backup = this->fetch_pointer_; #endif if(read_cycles_pool) { // Determine how much time has passed in the remainder of this line, and proceed. const int target_read_cycles = std::min( - Timing::CyclesPerLine - this->read_pointer_.column, + Timing::CyclesPerLine - this->output_pointer_.column, read_cycles_pool ); int read_cycles_performed = 0; @@ -322,8 +322,8 @@ void TMS9918::run_for(const HalfCycles cycles) { if constexpr (is_sega_vdp(personality)) { next_cram_value = 0; - if(!this->upcoming_cram_dots_.empty() && this->upcoming_cram_dots_.front().location.row == this->read_pointer_.row) { - int time_until_dot = this->upcoming_cram_dots_.front().location.column - this->read_pointer_.column; + if(!this->upcoming_cram_dots_.empty() && this->upcoming_cram_dots_.front().location.row == this->output_pointer_.row) { + int time_until_dot = this->upcoming_cram_dots_.front().location.column - this->output_pointer_.column; if(time_until_dot < read_cycles) { read_cycles = time_until_dot; @@ -335,8 +335,8 @@ void TMS9918::run_for(const HalfCycles cycles) { read_cycles_performed += read_cycles; - const int end_column = this->read_pointer_.column + read_cycles; - LineBuffer &line_buffer = this->line_buffers_[this->read_pointer_.row]; + const int end_column = this->output_pointer_.column + read_cycles; + LineBuffer &line_buffer = this->line_buffers_[this->output_pointer_.row]; // -------------------- @@ -349,7 +349,7 @@ void TMS9918::run_for(const HalfCycles cycles) { #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 start = std::max(this->output_pointer_.column, left); \ const int end = std::min(end_column, right); \ if(end > start) {\ code;\ @@ -358,10 +358,10 @@ void TMS9918::run_for(const HalfCycles cycles) { #define border(left, right) intersect(left, right, this->output_border(end - start, cram_value)) - if(line_buffer.line_mode == LineMode::Refresh || this->read_pointer_.row > this->mode_timing_.pixel_lines) { + if(line_buffer.line_mode == LineMode::Refresh || this->output_pointer_.row > this->mode_timing_.pixel_lines) { if( - this->read_pointer_.row >= this->mode_timing_.first_vsync_line && - this->read_pointer_.row < this->mode_timing_.first_vsync_line + 4 + this->output_pointer_.row >= this->mode_timing_.first_vsync_line && + this->output_pointer_.row < this->mode_timing_.first_vsync_line + 4 ) { // Vertical sync. // TODO: the Mega Drive supports interlaced video, I think? @@ -375,7 +375,7 @@ void TMS9918::run_for(const HalfCycles cycles) { // Blanking region: output the entire sequence when the cursor // crosses the start-of-border point. if( - this->read_pointer_.column < Timing::StartOfLeftBorder && + this->output_pointer_.column < Timing::StartOfLeftBorder && end_column >= Timing::StartOfLeftBorder ) { output_blank(Timing::StartOfSync - Timing::EndOfRightBorder); @@ -394,7 +394,7 @@ void TMS9918::run_for(const HalfCycles cycles) { // Blanking region. if( - this->read_pointer_.column < Timing::StartOfLeftBorder && + this->output_pointer_.column < Timing::StartOfLeftBorder && end_column >= Timing::StartOfLeftBorder ) { output_blank(Timing::StartOfSync - Timing::EndOfRightBorder); @@ -464,17 +464,17 @@ void TMS9918::run_for(const HalfCycles cycles) { // ------------- // Advance time. // ------------- - this->read_pointer_.column = end_column; + this->output_pointer_.column = end_column; } read_cycles_pool -= target_read_cycles; - if(this->read_pointer_.column == Timing::CyclesPerLine) { - this->read_pointer_.column = 0; - this->read_pointer_.row = (this->read_pointer_.row + 1) % this->mode_timing_.total_lines; + if(this->output_pointer_.column == Timing::CyclesPerLine) { + this->output_pointer_.column = 0; + this->output_pointer_.row = (this->output_pointer_.row + 1) % this->mode_timing_.total_lines; } } - assert(backup.row == this->write_pointer_.row && backup.column == this->write_pointer_.column); + assert(backup.row == this->fetch_pointer_.row && backup.column == this->fetch_pointer_.column); } } @@ -776,9 +776,9 @@ uint8_t TMS9918::get_current_line() const { // Determine the row to return. constexpr int row_change_position = 63; // This is the proper Master System value; substitute if any other VDPs turn out to have this functionality. int source_row = - (this->write_pointer_.column < row_change_position) - ? (this->write_pointer_.row + this->mode_timing_.total_lines - 1) % this->mode_timing_.total_lines - : this->write_pointer_.row; + (this->fetch_pointer_.column < row_change_position) + ? (this->fetch_pointer_.row + this->mode_timing_.total_lines - 1) % this->mode_timing_.total_lines + : this->fetch_pointer_.row; if(this->tv_standard_ == TVStandard::NTSC) { if(this->mode_timing_.pixel_lines == 240) { @@ -815,7 +815,7 @@ HalfCycles TMS9918::get_next_sequence_point() const { int time_until_frame_interrupt = ( ((this->mode_timing_.end_of_frame_interrupt_position.row * Timing::CyclesPerLine) + this->mode_timing_.end_of_frame_interrupt_position.column + frame_length) - - ((this->write_pointer_.row * Timing::CyclesPerLine) + this->write_pointer_.column) + ((this->fetch_pointer_.row * Timing::CyclesPerLine) + this->fetch_pointer_.column) ) % frame_length; if(!time_until_frame_interrupt) time_until_frame_interrupt = frame_length; @@ -826,8 +826,8 @@ HalfCycles TMS9918::get_next_sequence_point() const { // Calculate when the next line interrupt will occur. int next_line_interrupt_row = -1; - int cycles_to_next_interrupt_threshold = this->mode_timing_.line_interrupt_position - this->write_pointer_.column; - int line_of_next_interrupt_threshold = this->write_pointer_.row; + int cycles_to_next_interrupt_threshold = this->mode_timing_.line_interrupt_position - this->fetch_pointer_.column; + int line_of_next_interrupt_threshold = this->fetch_pointer_.row; if(cycles_to_next_interrupt_threshold <= 0) { cycles_to_next_interrupt_threshold += Timing::CyclesPerLine; ++line_of_next_interrupt_threshold; @@ -866,8 +866,8 @@ template HalfCycles TMS9918::get_time_until_line(int line) { if(line < 0) line += this->mode_timing_.total_lines; - int cycles_to_next_interrupt_threshold = this->mode_timing_.line_interrupt_position - this->write_pointer_.column; - int line_of_next_interrupt_threshold = this->write_pointer_.row; + int cycles_to_next_interrupt_threshold = this->mode_timing_.line_interrupt_position - this->fetch_pointer_.column; + int line_of_next_interrupt_threshold = this->fetch_pointer_.row; if(cycles_to_next_interrupt_threshold <= 0) { cycles_to_next_interrupt_threshold += Timing::CyclesPerLine; ++line_of_next_interrupt_threshold; @@ -900,7 +900,7 @@ template uint8_t TMS9918::get_latched_hori template void TMS9918::latch_horizontal_counter() { - this->latched_column_ = this->write_pointer_.column; + this->latched_column_ = this->fetch_pointer_.column; } template class TI::TMS::TMS9918; diff --git a/Components/9918/Implementation/9918Base.hpp b/Components/9918/Implementation/9918Base.hpp index 273d87a25..32f296ab1 100644 --- a/Components/9918/Implementation/9918Base.hpp +++ b/Components/9918/Implementation/9918Base.hpp @@ -300,7 +300,7 @@ template struct Base: public Storage { // to update sprites and tiles, but writing time affects when the palette is used and when the collision flag // may end up being set. So the two processes are slightly decoupled. The end of reading one line may overlap // with the beginning of writing the next, hence the two separate line buffers. - LineBufferPointer read_pointer_, write_pointer_; + LineBufferPointer output_pointer_, fetch_pointer_; int masked_address(int address); void write_vram(uint8_t); @@ -370,8 +370,8 @@ template struct Base: public Storage { // on screen. So it's wherever the output stream would be now. Which // is output_lag cycles ago from the point of view of the input stream. auto &dot = Storage::upcoming_cram_dots_.emplace_back(); - dot.location.column = write_pointer_.column - output_lag; - dot.location.row = write_pointer_.row; + dot.location.column = fetch_pointer_.column - output_lag; + dot.location.row = fetch_pointer_.row; // Handle before this row conditionally; then handle after (or, more realistically, // exactly at the end of) naturally. diff --git a/Components/9918/Implementation/Draw.hpp b/Components/9918/Implementation/Draw.hpp index f0eef02d3..8b40fcbe3 100644 --- a/Components/9918/Implementation/Draw.hpp +++ b/Components/9918/Implementation/Draw.hpp @@ -13,7 +13,7 @@ template void Base::draw_tms_character(int start, int end) { - LineBuffer &line_buffer = line_buffers_[read_pointer_.row]; + LineBuffer &line_buffer = line_buffers_[output_pointer_.row]; // Paint the background tiles. const int pixels_left = end - start; @@ -106,7 +106,7 @@ void Base::draw_tms_character(int start, int end) { template void Base::draw_tms_text(int start, int end) { - LineBuffer &line_buffer = line_buffers_[read_pointer_.row]; + LineBuffer &line_buffer = line_buffers_[output_pointer_.row]; const uint32_t colours[2] = { palette[background_colour_], palette[text_colour_] }; const int shift = start % 6; @@ -135,7 +135,7 @@ template void Base::draw_sms(int start, int end, uint32_t cram_dot) { if constexpr (is_sega_vdp(personality)) { - LineBuffer &line_buffer = line_buffers_[read_pointer_.row]; + LineBuffer &line_buffer = line_buffers_[output_pointer_.row]; int colour_buffer[256]; /* @@ -143,7 +143,7 @@ void Base::draw_sms(int start, int end, uint32_t cram_dot) { */ int tile_start = start, tile_end = end; int tile_offset = start; - if(read_pointer_.row >= 16 || !Storage::horizontal_scroll_lock_) { + if(output_pointer_.row >= 16 || !Storage::horizontal_scroll_lock_) { for(int c = start; c < (line_buffer.latched_horizontal_scroll & 7); ++c) { colour_buffer[c] = 16 + background_colour_; ++tile_offset; diff --git a/Components/9918/Implementation/Fetch.hpp b/Components/9918/Implementation/Fetch.hpp index 11b3bd7f0..cf987a67c 100644 --- a/Components/9918/Implementation/Fetch.hpp +++ b/Components/9918/Implementation/Fetch.hpp @@ -139,9 +139,9 @@ template void Base::fetch_tms_text(int start, int end fetch_columns_4(location, column); \ fetch_columns_4(location+12, column+4); - LineBuffer &line_buffer = line_buffers_[write_pointer_.row]; - const size_t row_base = pattern_name_address_ & (0x3c00 | size_t(write_pointer_.row >> 3) * 40); - const size_t row_offset = pattern_generator_table_address_ & (0x3800 | (write_pointer_.row & 7)); + LineBuffer &line_buffer = line_buffers_[fetch_pointer_.row]; + const size_t row_base = pattern_name_address_ & (0x3c00 | size_t(fetch_pointer_.row >> 3) * 40); + const size_t row_offset = pattern_generator_table_address_ & (0x3800 | (fetch_pointer_.row & 7)); switch(start) { default: assert(false); @@ -210,7 +210,7 @@ template void Base::fetch_tms_character(int start, in sprite_fetch_graphics(location+2, sprite) #define sprite_y_read(location, sprite) \ - slot(location): posit_sprite(sprite_selection_buffer, sprite, ram_[sprite_attribute_table_address_ & (((sprite) << 2) | 0x3f80)], write_pointer_.row); + slot(location): posit_sprite(sprite_selection_buffer, sprite, ram_[sprite_attribute_table_address_ & (((sprite) << 2) | 0x3f80)], fetch_pointer_.row); #define fetch_tile_name(column) line_buffer.names[column].offset = ram_[(row_base + column) & 0x3fff]; @@ -237,9 +237,9 @@ template void Base::fetch_tms_character(int start, in slot(location+14): \ slot(location+15): fetch_tile(column+3) - LineBuffer &line_buffer = line_buffers_[write_pointer_.row]; - LineBuffer &sprite_selection_buffer = line_buffers_[(write_pointer_.row + 1) % mode_timing_.total_lines]; - const size_t row_base = pattern_name_address_ & (size_t((write_pointer_.row << 2)&~31) | 0x3c00); + LineBuffer &line_buffer = line_buffers_[fetch_pointer_.row]; + LineBuffer &sprite_selection_buffer = line_buffers_[(fetch_pointer_.row + 1) % mode_timing_.total_lines]; + const size_t row_base = pattern_name_address_ & (size_t((fetch_pointer_.row << 2)&~31) | 0x3c00); size_t pattern_base = pattern_generator_table_address_; size_t colour_base = colour_table_address_; @@ -247,10 +247,10 @@ template void Base::fetch_tms_character(int start, in if(screen_mode_ == ScreenMode::Graphics) { // If this is high resolution mode, allow the row number to affect the pattern and colour addresses. - pattern_base &= size_t(0x2000 | ((write_pointer_.row & 0xc0) << 5)); - colour_base &= size_t(0x2000 | ((write_pointer_.row & 0xc0) << 5)); + pattern_base &= size_t(0x2000 | ((fetch_pointer_.row & 0xc0) << 5)); + colour_base &= size_t(0x2000 | ((fetch_pointer_.row & 0xc0) << 5)); - colour_base += size_t(write_pointer_.row & 7); + colour_base += size_t(fetch_pointer_.row & 7); colour_name_shift = 0; } else { colour_base &= size_t(0xffc0); @@ -258,9 +258,9 @@ template void Base::fetch_tms_character(int start, in } if(screen_mode_ == ScreenMode::MultiColour) { - pattern_base += size_t((write_pointer_.row >> 2) & 7); + pattern_base += size_t((fetch_pointer_.row >> 2) & 7); } else { - pattern_base += size_t(write_pointer_.row & 7); + pattern_base += size_t(fetch_pointer_.row & 7); } switch(start) { @@ -348,8 +348,8 @@ template void Base::fetch_sms(int start, int end) { #define sprite_y_read(location, sprite) \ slot(location): \ - posit_sprite(sprite_selection_buffer, sprite, ram_[Storage::sprite_attribute_table_address_ & ((sprite) | 0x3f00)], write_pointer_.row); \ - posit_sprite(sprite_selection_buffer, sprite+1, ram_[Storage::sprite_attribute_table_address_ & ((sprite + 1) | 0x3f00)], write_pointer_.row); \ + posit_sprite(sprite_selection_buffer, sprite, ram_[Storage::sprite_attribute_table_address_ & ((sprite) | 0x3f00)], fetch_pointer_.row); \ + posit_sprite(sprite_selection_buffer, sprite+1, ram_[Storage::sprite_attribute_table_address_ & ((sprite + 1) | 0x3f00)], fetch_pointer_.row); \ #define fetch_tile_name(column, row_info) {\ const size_t scrolled_column = (column - horizontal_offset) & 0x1f;\ @@ -391,9 +391,9 @@ template void Base::fetch_sms(int start, int end) { slot(location+15): fetch_tile(column+3) // Determine the coarse horizontal scrolling offset; this isn't applied on the first two lines if the programmer has requested it. - LineBuffer &line_buffer = line_buffers_[write_pointer_.row]; - LineBuffer &sprite_selection_buffer = line_buffers_[(write_pointer_.row + 1) % mode_timing_.total_lines]; - const int horizontal_offset = (write_pointer_.row >= 16 || !Storage::horizontal_scroll_lock_) ? (line_buffer.latched_horizontal_scroll >> 3) : 0; + LineBuffer &line_buffer = line_buffers_[fetch_pointer_.row]; + LineBuffer &sprite_selection_buffer = line_buffers_[(fetch_pointer_.row + 1) % mode_timing_.total_lines]; + const int horizontal_offset = (fetch_pointer_.row >= 16 || !Storage::horizontal_scroll_lock_) ? (line_buffer.latched_horizontal_scroll >> 3) : 0; // Limit address bits in use if this is a SMS2 mode. const bool is_tall_mode = mode_timing_.pixel_lines != 192; @@ -402,7 +402,7 @@ template void Base::fetch_sms(int start, int end) { // Determine row info for the screen both (i) if vertical scrolling is applied; and (ii) if it isn't. // The programmer can opt out of applying vertical scrolling to the right-hand portion of the display. - const int scrolled_row = (write_pointer_.row + Storage::latched_vertical_scroll_) % (is_tall_mode ? 256 : 224); + const int scrolled_row = (fetch_pointer_.row + Storage::latched_vertical_scroll_) % (is_tall_mode ? 256 : 224); struct RowInfo { size_t pattern_address_base; size_t sub_row[2]; @@ -413,9 +413,9 @@ template void Base::fetch_sms(int start, int end) { }; RowInfo row_info; if(Storage::vertical_scroll_lock_) { - row_info.pattern_address_base = (pattern_name_address & size_t(((write_pointer_.row & ~7) << 3) | 0x3800)) - pattern_name_offset; - row_info.sub_row[0] = size_t((write_pointer_.row & 7) << 2); - row_info.sub_row[1] = 28 ^ size_t((write_pointer_.row & 7) << 2); + row_info.pattern_address_base = (pattern_name_address & size_t(((fetch_pointer_.row & ~7) << 3) | 0x3800)) - pattern_name_offset; + row_info.sub_row[0] = size_t((fetch_pointer_.row & 7) << 2); + row_info.sub_row[1] = 28 ^ size_t((fetch_pointer_.row & 7) << 2); } else row_info = scrolled_row_info; // ... and do the actual fetching, which follows this routine: