From 3f2a5929a3f5de81fcab34e5520f08251847d19e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 15 Feb 2023 20:18:56 -0500 Subject: [PATCH] Consolidate text output and support blinking; add sprites-enabled flag. --- Components/9918/Implementation/9918.cpp | 29 ++++++++--- Components/9918/Implementation/9918Base.hpp | 2 +- Components/9918/Implementation/Draw.hpp | 57 +++++++++------------ Components/9918/Implementation/Fetch.hpp | 2 +- Components/9918/Implementation/Storage.hpp | 27 +++++++--- 5 files changed, 67 insertions(+), 50 deletions(-) diff --git a/Components/9918/Implementation/9918.cpp b/Components/9918/Implementation/9918.cpp index 5a8b20dc3..6787a6ff6 100644 --- a/Components/9918/Implementation/9918.cpp +++ b/Components/9918/Implementation/9918.cpp @@ -292,6 +292,16 @@ void TMS9918::run_for(const HalfCycles cycles) { 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; + if constexpr (is_yamaha_vdp(personality)) { + if(!this->fetch_pointer_.row && Storage::blink_periods_) { + --Storage::blink_counter_; + while(!Storage::blink_counter_) { + Storage::in_blink_ ^= 1; + Storage::blink_counter_ = (Storage::blink_periods_ >> (Storage::in_blink_ << 2)) & 0xf; + } + } + } + LineBuffer &next_line_buffer = this->line_buffers_[this->fetch_pointer_.row]; // Progress towards any delayed events. @@ -366,8 +376,7 @@ void TMS9918::run_for(const HalfCycles cycles) { this->vertical_state(); const bool is_refresh = next_line_buffer.vertical_state == VerticalState::Blank; - // TODO: an actual sprites-enabled flag. - Storage::begin_line(this->screen_mode_, is_refresh, false); + Storage::begin_line(this->screen_mode_, is_refresh); if(is_refresh) { // The Yamaha handles refresh lines via its own microprogram; other VDPs @@ -491,10 +500,10 @@ void TMS9918::run_for(const HalfCycles cycles) { // Left border. border(Timing::StartOfLeftBorder, line_buffer.first_pixel_output_column); -#define draw(function, clock) { \ +#define draw(function, clock) { \ const int relative_start = from_internal(start - line_buffer.first_pixel_output_column); \ const int relative_end = from_internal(end - line_buffer.first_pixel_output_column); \ - if(relative_start == relative_end) break; \ + if(relative_start == relative_end) break; \ this->function; } // Pixel region. @@ -515,7 +524,7 @@ void TMS9918::run_for(const HalfCycles cycles) { switch(line_buffer.fetch_mode) { case FetchMode::SMS: draw(draw_sms(relative_start, relative_end, cram_value), Clock::TMSPixel); break; case FetchMode::Character: draw(draw_tms_character(relative_start, relative_end), Clock::TMSPixel); break; - case FetchMode::Text: draw(draw_tms_text(relative_start, relative_end), Clock::TMSPixel); break; + case FetchMode::Text: draw(template draw_tms_text(relative_start, relative_end), Clock::TMSPixel); break; case FetchMode::Yamaha: draw(draw_yamaha(relative_start, relative_end), Clock::Internal); break; case FetchMode::Refresh: break; /* Dealt with elsewhere. */ @@ -752,6 +761,7 @@ void Base::commit_register(int reg, uint8_t value) { case 8: LOG("TODO: Yamaha VRAM organisation, sprite disable, etc; " << PADHEX(2) << +value); + Storage::sprites_enabled_ = !(value & 0x02); // b7: "1 = input on colour bus, enable mouse; 1 = output on colour bus, disable mouse" [documentation clearly in error] // b6: 1 = enable light pen // b5: sets the colour of code 0 to the colour of the palette (???) @@ -778,12 +788,17 @@ void Base::commit_register(int reg, uint8_t value) { case 11: install_field<15>(sprite_attribute_table_address_, value); break; case 12: - LOG("TODO: Yamaha text and background blink colour; " << PADHEX(2) << +value); + Storage::blink_text_colour_ = value >> 4; + Storage::blink_background_colour_ = value & 0xf; // as per register 7, but in blink mode. break; case 13: - LOG("TODO: Yamaha blink display times; " << PADHEX(2) << +value); + Storage::blink_periods_ = value; + if(!value) { + Storage::in_blink_ = 0; + } + // b0–b3: display time for odd page; // b4–b7: display time for even page. break; diff --git a/Components/9918/Implementation/9918Base.hpp b/Components/9918/Implementation/9918Base.hpp index 36f8353e7..f742a5575 100644 --- a/Components/9918/Implementation/9918Base.hpp +++ b/Components/9918/Implementation/9918Base.hpp @@ -527,7 +527,7 @@ template struct Base: public Storage { // Output serialisers. void draw_tms_character(int start, int end); - void draw_tms_text(int start, int end); + template void draw_tms_text(int start, int end); void draw_sms(int start, int end, uint32_t cram_dot); template void draw_yamaha(LineBuffer &, int start, int end); diff --git a/Components/9918/Implementation/Draw.hpp b/Components/9918/Implementation/Draw.hpp index ace7a180c..1b013dd20 100644 --- a/Components/9918/Implementation/Draw.hpp +++ b/Components/9918/Implementation/Draw.hpp @@ -105,19 +105,32 @@ void Base::draw_tms_character(int start, int end) { } template +template void Base::draw_tms_text(int start, int end) { LineBuffer &line_buffer = line_buffers_[output_pointer_.row]; - const uint32_t colours[2] = { palette()[background_colour_], palette()[text_colour_] }; + + uint32_t colours[2][2] = { + {palette()[background_colour_], palette()[text_colour_]}, + {0, 0} + }; + if constexpr (apply_blink) { + colours[1][0] = palette()[Storage::blink_background_colour_]; + colours[1][1] = palette()[Storage::blink_text_colour_]; + } const int shift = start % 6; int byte_column = start / 6; int pattern = Numeric::bit_reverse(line_buffer.characters.shapes[byte_column]) >> shift; int pixels_left = end - start; int length = std::min(pixels_left, 6 - shift); + int flag = 0; + if constexpr (apply_blink) { + flag = (line_buffer.characters.flags[byte_column >> 3] >> ((byte_column & 7) ^ 7)) & Storage::in_blink_; + } while(true) { pixels_left -= length; for(int c = 0; c < length; ++c) { - pixel_target_[c] = colours[pattern&0x01]; + pixel_target_[c] = colours[flag][(pattern&0x01)]; pattern >>= 1; } pixel_target_ += length; @@ -126,6 +139,9 @@ void Base::draw_tms_text(int start, int end) { length = std::min(6, pixels_left); byte_column++; pattern = Numeric::bit_reverse(line_buffer.characters.shapes[byte_column]); + if constexpr (apply_blink) { + flag = (line_buffer.characters.flags[byte_column >> 3] >> ((byte_column & 7) ^ 7)) & Storage::in_blink_; + } } } @@ -170,14 +186,14 @@ void Base::draw_sms(int start, int end, uint32_t cram_dot) { int length = std::min(pixels_left, 8 - shift); pattern = *reinterpret_cast(line_buffer.tiles.patterns[byte_column]); - if(line_buffer.characters.flags[byte_column]&2) + if(line_buffer.tiles.flags[byte_column]&2) pattern >>= shift; else pattern <<= shift; while(true) { - const int palette_offset = (line_buffer.characters.flags[byte_column]&0x18) << 1; - if(line_buffer.characters.flags[byte_column]&2) { + const int palette_offset = (line_buffer.tiles.flags[byte_column]&0x18) << 1; + if(line_buffer.tiles.flags[byte_column]&2) { for(int c = 0; c < length; ++c) { colour_buffer[tile_offset] = ((pattern_index[3] & 0x01) << 3) | @@ -313,33 +329,6 @@ void Base::draw_yamaha(LineBuffer &buffer, int start, int end) { return; } - - if constexpr (mode == ScreenMode::YamahaText80) { - const uint32_t primary_colours[2] = { palette()[background_colour_], palette()[text_colour_] }; -// const uint32_t inverse_colours[2] = { palette()[background_colour_], palette()[text_colour_] }; // TODO. - - start >>= 1; - end >>= 1; - - const int shift = start % 6; - int byte_column = start / 6; - int pattern = Numeric::bit_reverse(buffer.characters.shapes[byte_column]) >> shift; - int pixels_left = end - start; - int length = std::min(pixels_left, 6 - shift); - while(true) { - pixels_left -= length; - for(int c = 0; c < length; ++c) { - pixel_target_[c] = primary_colours[pattern&0x01]; // TODO. - pattern >>= 1; - } - pixel_target_ += length; - - if(!pixels_left) break; - length = std::min(6, pixels_left); - byte_column++; - pattern = Numeric::bit_reverse(buffer.characters.shapes[byte_column]); - } - } } template @@ -350,9 +339,9 @@ void Base::draw_yamaha(int start, int end) { if constexpr (is_yamaha_vdp(personality)) { switch(line_buffer.screen_mode) { // These modes look the same as on the TMS. - case ScreenMode::Text: draw_tms_text(start >> 2, end >> 2); break; + case ScreenMode::Text: draw_tms_text(start >> 2, end >> 2); break; + case ScreenMode::YamahaText80: draw_tms_text(start >> 1, end >> 1); break; - Dispatch(YamahaText80); Dispatch(YamahaGraphics3); Dispatch(YamahaGraphics4); Dispatch(YamahaGraphics5); diff --git a/Components/9918/Implementation/Fetch.hpp b/Components/9918/Implementation/Fetch.hpp index 886cbf8a7..bf9b67091 100644 --- a/Components/9918/Implementation/Fetch.hpp +++ b/Components/9918/Implementation/Fetch.hpp @@ -504,7 +504,7 @@ template void Base::fetch_yamaha(LineBuffer &line_ case ScreenMode::YamahaText80: { const auto column = AddressT(Storage::data_block_ >> 3); const AddressT address = colour_table_address_ & (0x1fe00 | size_t(y >> 3) * 10); - line_buffer.characters.flags[column] = ram_[address]; + line_buffer.characters.flags[column] = ram_[address + column]; } break; default: break; diff --git a/Components/9918/Implementation/Storage.hpp b/Components/9918/Implementation/Storage.hpp index 8b28063ba..220418fce 100644 --- a/Components/9918/Implementation/Storage.hpp +++ b/Components/9918/Implementation/Storage.hpp @@ -25,7 +25,7 @@ template struct Storage { template <> struct Storage { using AddressT = uint16_t; - void begin_line(ScreenMode, bool, bool) {} + void begin_line(ScreenMode, bool) {} }; // Yamaha-specific storage. @@ -91,8 +91,20 @@ template struct Storageoffset == 1368); @@ -408,15 +420,16 @@ template struct Storage= 182 && grauw_index < 1236) { + if(grauw_index >= 182 && grauw_index < 1238) { const int offset = grauw_index - 182; const int block = offset / 32; const int sub_block = offset & 31; switch(sub_block) { case 0: if(block > 0) return Event::Type::Name; - case 6: if((sub_block & 3) != 3) return Event::Type::External;; - case 12: if(block > 0) return Event::Type::Pattern; - case 18: if(block > 0) return Event::Type::Colour; + case 6: if((sub_block & 3) != 3) return Event::Type::External; + case 12: if(block < 32) return Event::Type::SpriteY; + case 18: if(block > 0) return Event::Type::Pattern; + case 24: if(block > 0) return Event::Type::Colour; } } @@ -463,7 +476,7 @@ template struct Storage