From a5423454564a9cd95bfc6a8b4a1b010c1ccfe377 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 1 Jan 2025 22:34:47 -0500 Subject: [PATCH] Iterate towards supporting all video modes. --- Machines/Commodore/Plus4/Plus4.cpp | 12 ++- Machines/Commodore/Plus4/Video.hpp | 168 ++++++++++++++++++++++------- 2 files changed, 143 insertions(+), 37 deletions(-) diff --git a/Machines/Commodore/Plus4/Plus4.cpp b/Machines/Commodore/Plus4/Plus4.cpp index f8ec1fd9c..bdacc23f7 100644 --- a/Machines/Commodore/Plus4/Plus4.cpp +++ b/Machines/Commodore/Plus4/Plus4.cpp @@ -291,9 +291,15 @@ public: case 0xff1c: *value = video_.read<0xff1c>(); break; case 0xff1d: *value = video_.read<0xff1d>(); break; + case 0xff0e: *value = ff0e_; break; + case 0xff0f: *value = ff0f_; break; + case 0xff10: *value = ff10_; break; + case 0xff11: *value = ff11_; break; case 0xff12: *value = ff12_; break; case 0xff13: *value = ff13_ | (rom_is_paged_ ? 1 : 0); break; + case 0xff0c: *value = video_.read<0xff0c>(); break; + case 0xff0d: *value = video_.read<0xff0d>(); break; case 0xff14: *value = video_.read<0xff14>(); break; case 0xff15: *value = video_.read<0xff15>(); break; case 0xff16: *value = video_.read<0xff16>(); break; @@ -340,18 +346,22 @@ public: case 0xff0c: video_.write<0xff0c>(*value); break; case 0xff0d: video_.write<0xff0d>(*value); break; case 0xff0e: + ff0e_ = *value; update_audio(); audio_.set_frequency_low<0>(*value); break; case 0xff0f: + ff0f_ = *value; update_audio(); audio_.set_frequency_low<1>(*value); break; case 0xff10: + ff10_ = *value; update_audio(); audio_.set_frequency_high<1>(*value); break; case 0xff11: + ff11_ = *value; update_audio(); audio_.set_constrol(*value); break; @@ -474,7 +484,7 @@ private: std::array ram_; std::vector kernel_; std::vector basic_; - uint8_t ff12_, ff13_; + uint8_t ff0e_, ff0f_, ff10_, ff11_, ff12_, ff13_; Interrupts interrupts_; Cycles timers_subcycles_; diff --git a/Machines/Commodore/Plus4/Video.hpp b/Machines/Commodore/Plus4/Video.hpp index 9432ac152..1ebd62c89 100644 --- a/Machines/Commodore/Plus4/Video.hpp +++ b/Machines/Commodore/Plus4/Video.hpp @@ -46,6 +46,8 @@ public: case 0xff06: return ff06_; case 0xff07: return ff07_; case 0xff0b: return uint8_t(raster_interrupt_); + case 0xff0c: return cursor_position_ >> 8; + case 0xff0d: return uint8_t(cursor_position_); case 0xff1c: return uint8_t(vertical_counter_ >> 8); case 0xff1d: return uint8_t(vertical_counter_); case 0xff14: return uint8_t((video_matrix_base_ >> 8) & 0xf8); @@ -69,6 +71,27 @@ public: (target & 0xff00) | value ); }; + const auto set_video_mode = [&] { + if(bitmap_mode_) { + if(extended_colour_mode_) { + video_mode_ = VideoMode::Blank; + } else if(multicolour_mode_) { + video_mode_ = VideoMode::BitmapMulticolour; + } else { + video_mode_ = VideoMode::BitmapHighRes; + } + } else { + if(multicolour_mode_) { + video_mode_ = extended_colour_mode_ ? VideoMode::Blank : VideoMode::MulticolourText; + } else if(extended_colour_mode_) { + video_mode_ = VideoMode::ExtendedColourText; + } else { + video_mode_ = VideoMode::Text; + } + } + +// printf("Mode: %d %d %d -> %d\n", bitmap_mode_, extended_colour_mode_, multicolour_mode_, int(video_mode_)); + }; switch(address) { case 0xff06: @@ -78,6 +101,7 @@ public: display_enable_ = value & 0x10; rows_25_ = value & 8; y_scroll_ = value & 7; + set_video_mode(); break; case 0xff07: @@ -88,6 +112,7 @@ public: multicolour_mode_ = value & 0x10; columns_40_ = value & 8; x_scroll_ = value & 7; + set_video_mode(); break; case 0xff12: @@ -487,42 +512,6 @@ public: } } - template - void draw() { - draw_standard_character_mode(); - output_.set_attributes(next_attribute_.read()); - draw_standard_character_mode<8 - scroll>(); - } - - template - void draw_standard_character_mode() { - if constexpr (length == 0) return; - - const auto attributes = output_.attributes(); - const auto pixels = output_.pixels(); - output_.advance_pixels(length); - - const uint16_t colours[] = { background_[0], colour(attributes) }; - const auto target = pixels_; - pixels_ += length; - - target[0] = (pixels & 0x80) ? colours[1] : colours[0]; - if constexpr (length == 1) return; - target[1] = (pixels & 0x40) ? colours[1] : colours[0]; - if constexpr (length == 2) return; - target[2] = (pixels & 0x20) ? colours[1] : colours[0]; - if constexpr (length == 3) return; - target[3] = (pixels & 0x10) ? colours[1] : colours[0]; - if constexpr (length == 4) return; - target[4] = (pixels & 0x08) ? colours[1] : colours[0]; - if constexpr (length == 5) return; - target[5] = (pixels & 0x04) ? colours[1] : colours[0]; - if constexpr (length == 6) return; - target[6] = (pixels & 0x02) ? colours[1] : colours[0]; - if constexpr (length == 7) return; - target[7] = (pixels & 0x01) ? colours[1] : colours[0]; - } - void set_scan_target(Outputs::Display::ScanTarget *const target) { crt_.set_scan_target(target); } @@ -549,6 +538,16 @@ private: bool columns_40_ = false; int x_scroll_ = 0; + // Graphics mode, summarised. + enum class VideoMode { + Text, + MulticolourText, + ExtendedColourText, + BitmapMulticolour, + BitmapHighRes, + Blank, + } video_mode_ = VideoMode::Text; + uint16_t cursor_position_ = 0; uint16_t character_base_ = 0; uint16_t video_matrix_base_ = 0; @@ -795,6 +794,103 @@ private: IDLE, THALT1, THALT2, THALT3, TDMA, } dma_state_ = DMAState::IDLE; + + // + // Various pixel outputters. + // + template + void draw() { + switch(video_mode_) { + case VideoMode::Text: + draw(); + break; + case VideoMode::MulticolourText: + draw(); + break; + case VideoMode::ExtendedColourText: + draw(); + break; + case VideoMode::BitmapMulticolour: + draw(); + break; + case VideoMode::BitmapHighRes: + draw(); + break; + case VideoMode::Blank: + draw(); + break; + } + } + + template + void draw() { + draw_segment(); + output_.set_attributes(next_attribute_.read()); + draw_segment<8 - scroll, mode>(); + } + + template + void draw_segment() { + if constexpr (length == 0) return; + switch(mode) { + default: + case VideoMode::Text: + draw_segment_text(); + break; + case VideoMode::Blank: + draw_blank(); + break; + } + } + + template + void draw_segment_text() { + const auto attributes = output_.attributes(); + const auto pixels = output_.pixels(); + output_.advance_pixels(length); + + const uint16_t colours[] = { background_[0], colour(attributes) }; + const auto target = pixels_; + pixels_ += length; + + target[0] = (pixels & 0x80) ? colours[1] : colours[0]; + if constexpr (length == 1) return; + target[1] = (pixels & 0x40) ? colours[1] : colours[0]; + if constexpr (length == 2) return; + target[2] = (pixels & 0x20) ? colours[1] : colours[0]; + if constexpr (length == 3) return; + target[3] = (pixels & 0x10) ? colours[1] : colours[0]; + if constexpr (length == 4) return; + target[4] = (pixels & 0x08) ? colours[1] : colours[0]; + if constexpr (length == 5) return; + target[5] = (pixels & 0x04) ? colours[1] : colours[0]; + if constexpr (length == 6) return; + target[6] = (pixels & 0x02) ? colours[1] : colours[0]; + if constexpr (length == 7) return; + target[7] = (pixels & 0x01) ? colours[1] : colours[0]; + } + + template + void draw_blank() { + const auto target = pixels_; + pixels_ += length; + + target[0] = 0x0000; + if constexpr (length == 1) return; + target[1] = 0x0000; + if constexpr (length == 2) return; + target[2] = 0x0000; + if constexpr (length == 3) return; + target[3] = 0x0000; + if constexpr (length == 4) return; + target[4] = 0x0000; + if constexpr (length == 5) return; + target[5] = 0x0000; + if constexpr (length == 6) return; + target[6] = 0x0000; + if constexpr (length == 7) return; + target[7] = 0x0000; + } }; }