diff --git a/Components/6847/6847.cpp b/Components/6847/6847.cpp index acc31c600..27a5f67e4 100644 --- a/Components/6847/6847.cpp +++ b/Components/6847/6847.cpp @@ -140,23 +140,40 @@ MC6847Base::MC6847Base(const Outputs::Display::Type display_type) : crt_.set_display_type(Outputs::Display::DisplayType::CompositeColour); } -void MC6847Base::pixel_line(const int line_begin, const int line_end) { - if(line_begin < LineLayout::EndOfLeftBorder && line_end >= LineLayout::EndOfLeftBorder) [[unlikely]] { - crt_.output_sync(LineLayout::EndOfSync); - if(display_type_ == Outputs::Display::Type::NTSC60) { - crt_.output_colour_burst(LineLayout::EndOfColourBurst - LineLayout::EndOfSync, ColourPhase); - } else { - crt_.output_default_colour_burst(LineLayout::EndOfColourBurst - LineLayout::EndOfSync); +void MC6847Base::sync_and_burst(const int line_begin, const int line_end) { + Numeric::if_includes( + line_begin, + line_end, + [&] { + crt_.output_sync(LineLayout::EndOfSync); + if(display_type_ == Outputs::Display::Type::NTSC60) { + crt_.output_colour_burst(LineLayout::EndOfColourBurst - LineLayout::EndOfSync, ColourPhase); + } else { + crt_.output_default_colour_burst(LineLayout::EndOfColourBurst - LineLayout::EndOfSync); + } } - crt_.output_blank(LineLayout::EndOfLeftBorder - LineLayout::EndOfColourBurst); + ); +} - pixels_ = reinterpret_cast(crt_.begin_data(256)); - } - if(pixels_) [[likely]] { - Numeric::clamp( - line_begin, - line_end, +void MC6847Base::pixel_line(const int line_begin, const int line_end) { + sync_and_burst(line_begin, line_end); + Numeric::ActionRange(line_begin, line_end) + .clamp( [&](const int begin, const int end) { + crt_.output_level(end - begin, border_colour_); + } + ) + .if_includes( + [&] { + pixels_ = reinterpret_cast(crt_.begin_data(256)); + } + ) + .clamp( + [&](const int begin, const int end) { + if(!pixels_) [[unlikely]] { + return; + } + const int row = address_.row(); const int column_begin = (begin - LineLayout::EndOfLeftBorder) >> 3; const int column_end = (end - LineLayout::EndOfLeftBorder) >> 3; @@ -295,26 +312,42 @@ void MC6847Base::pixel_line(const int line_begin, const int line_end) { pixels_ += 8; } } + ) + .if_includes( + [&] { + crt_.output_data(256); + } + ) + .clamp( + [&](const int begin, const int end) { + crt_.output_level(end - begin, border_colour_); + } + ) + .if_ends_at( + [&] { + address_.apply_hsync(); + } ); - } - if(line_end == LineLayout::EndOfLine) [[unlikely]] { - crt_.output_data(256); - address_.apply_hsync(); - crt_.output_blank(LineLayout::EndOfLine - LineLayout::EndOfPixels); - } } -void MC6847Base::border_line(const int, const int end) { +void MC6847Base::border_line(const int line_begin, const int line_end) { + sync_and_burst(line_begin, line_end); + Numeric::clamp( + line_begin, + line_end, + [&](const int begin, const int end) { + crt_.output_level(end - begin, border_colour_); + } + ); +} + +void MC6847Base::porch_line(const int, const int end) { if(end == LineLayout::EndOfLine) { crt_.output_sync(LineLayout::EndOfSync); crt_.output_blank(LineLayout::EndOfLine - LineLayout::EndOfSync); } } -void MC6847Base::porch_line(const int begin, const int end) { - border_line(begin, end); -} - void MC6847Base::sync_line(const int, const int end) { if(end == LineLayout::EndOfLine) { crt_.output_sync(LineLayout::EndOfLine); @@ -402,10 +435,14 @@ void MC6847Base::set_mode( address_.target_row_ = repeated_rows(mode); if(is_2bpp(mode)) { mode_ |= Mode::BPP2; + border_colour_ = colour_select ? Colours::colour1[0] : Colours::colour0[0]; + } else { + border_colour_ = colour_select ? Colours::resolution1[1] : Colours::resolution0[1]; } } else { set_32bytes(); address_.target_row_ = 12; + border_colour_ = 0; } // TODO: apply my net understanding, which is now this: diff --git a/Components/6847/6847.hpp b/Components/6847/6847.hpp index c4d12d0bb..d9f61ac00 100644 --- a/Components/6847/6847.hpp +++ b/Components/6847/6847.hpp @@ -116,6 +116,8 @@ constexpr uint8_t repeated_rows(const GraphicsMode mode) { struct MC6847Base { MC6847Base(Outputs::Display::Type); + void sync_and_burst(int begin, int end); + void pixel_line(int begin, int end); void border_line(int begin, int end); void porch_line(int begin, int end); @@ -137,6 +139,7 @@ struct MC6847Base { Outputs::CRT::CRT crt_; uint32_t *pixels_ = nullptr; + uint32_t border_colour_ = 0; void set_mode( bool graphics, diff --git a/Numeric/SegmentCounter.hpp b/Numeric/SegmentCounter.hpp index 17001a0d8..7ade0d6c7 100644 --- a/Numeric/SegmentCounter.hpp +++ b/Numeric/SegmentCounter.hpp @@ -80,4 +80,56 @@ void clamp(const int begin, const int end, const FuncT &&function) { } } +/// Calls @c function if and only if [begin, end] contains the event point. +template +void if_includes(const int begin, const int end, const FuncT &&function) { + if(begin <= EventPoint && end > EventPoint) { + function(); + } +} + +// Provides a factory-method-esque means of chaining potential events across a fixed range +// without repeating the range ad nauseam, +class ActionRange { +public: + ActionRange(const int begin, const int end) : begin_(begin), end_(end) {} + + template + ActionRange &if_at_start(const FuncT &&function) { + if(!begin_) { + function(); + } + return *this; + } + + template + ActionRange &clamp(const FuncT &&function) { + const int range_begin = std::max(begin_, RangeBegin); + const int range_end = std::min(end_, RangeEnd); + if(range_end > range_begin) { + function(range_begin, range_end); + } + return *this; + } + + template + ActionRange &if_includes(const FuncT &&function) { + if(begin_ <= EventPoint && end_ > EventPoint) { + function(); + } + return *this; + } + + template + ActionRange &if_ends_at(const FuncT &&function) { + if(end_ == EventPoint) { + function(); + } + return *this; + } + +private: + int begin_, end_; +}; + }