diff --git a/Components/6847/6847.cpp b/Components/6847/6847.cpp index 6a489a8c2..080c0648c 100644 --- a/Components/6847/6847.cpp +++ b/Components/6847/6847.cpp @@ -130,18 +130,24 @@ using namespace Motorola::MC6847; MC6847Base::MC6847Base(const Outputs::Display::Type display_type) : crt_( - 455, - 1, - display_type, - Outputs::Display::InputDataType::Red8Green8Blue8 -) { + 455, + 1, + display_type, + Outputs::Display::InputDataType::Red8Green8Blue8 + ), + 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); - crt_.output_colour_burst(LineLayout::EndOfColourBurst - LineLayout::EndOfSync, ColourPhase); + 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)); @@ -268,8 +274,13 @@ void MC6847Base::pixel_line(const int line_begin, const int line_end) { pixels_[7] = palette[(pixels >> 0) & 1]; } else { const uint32_t *const palette = mode & Mode::ColourSelect ? Colours::text1 : Colours::text0; - const uint8_t pixels = - font[data & 63][row] ^ (mode & Mode::Invert ? 0xff : 0x00) ^ (data & 64 ? 0xff : 0x00); + uint8_t pixels = (mode & Mode::Invert ? 0xff : 0x00) ^ (data & 64 ? 0xff : 0x00); + + if(mode & Mode::ExternalROM) { + // TODO: external ROM. + } else { + pixels ^= font[data & 63][row]; + } pixels_[0] = palette[(pixels >> 7) & 1]; pixels_[1] = palette[(pixels >> 6) & 1]; diff --git a/Components/6847/6847.hpp b/Components/6847/6847.hpp index b47049bbc..8b2814963 100644 --- a/Components/6847/6847.hpp +++ b/Components/6847/6847.hpp @@ -39,13 +39,6 @@ template struct FrameLayout { static_assert(FrameLayout::EndOfField == 262, "NTSC frames should be 262 lines long"); static_assert(FrameLayout::EndOfField == 312, "PAL-padded frames should be 312 lines long"); -// TODO: allow a delegate to be specified, and signal it. -struct MC6847Delegate { - virtual void set_hsync(bool active) = 0; - virtual void set_vsync(bool active) = 0; - virtual void set_row_preset(bool active) = 0; -}; - namespace Mode { using IntT = uint8_t; @@ -184,6 +177,8 @@ struct MC6847Base { uint16_t address_ = 0; Numeric::SizedInt<4> row_; } address_; + + Outputs::Display::Type display_type_; }; struct NullMapper { @@ -192,10 +187,21 @@ struct NullMapper { } }; -template +struct NullDelegate { + void set_hsync(bool) {} + void set_field_sync(bool) {} + void set_row_preset(bool) {} +}; + +template < + FrameTiming timing, + typename MemoryAccessT, + typename DelegateT = NullDelegate, + typename ModeMapperT = NullMapper +> class MC6847: private MC6847Base { public: - MC6847(MemoryAccessT &); + MC6847(MemoryAccessT &, DelegateT &delegate); void run_for(const Cycles); Cycles next_sequence_point() const; @@ -214,27 +220,33 @@ public: private: MemoryAccessT &memory_; Numeric::DividingAccumulator::EndOfField> position_{2}; + DelegateT &delegate_; }; // MARK: - Implementation. -template -MC6847::MC6847(MemoryAccessT &memory) : +template +MC6847::MC6847(MemoryAccessT &memory, DelegateT &delegate) : MC6847Base(is_ntsc(timing) ? Outputs::Display::Type::NTSC60 : Outputs::Display::Type::PAL50), - memory_(memory) { + memory_(memory), + delegate_(delegate) { crt_.set_fixed_framing([&] { run_for(Cycles(10'000)); }); } -template -void MC6847::run_for(const Cycles cycles) { +template +void MC6847::run_for(const Cycles cycles) { // This template binds the drawing logic to whatever was supplied // as MemoryAccessT; a consequence of that is that frame layout logic is here. position_.advance( cycles.as(), [&] (const int line, const int begin, const int end) { + if(!begin) delegate_.set_hsync(true); + if(line < FrameLayout::EndOfPixels) { + if(!begin && !address_.row()) delegate_.set_row_preset(true); + Numeric::clamp( begin, end, @@ -251,17 +263,27 @@ void MC6847::run_for(const Cycles cycles) { } ); pixel_line(begin, end); + + if(end >= LineLayout::EndOfSync) delegate_.set_row_preset(false); } else if(line < FrameLayout::EndOfBottomBorder) { + if(!begin && line == FrameLayout::EndOfPixels) { + delegate_.set_field_sync(true); + } border_line(begin, end); } else if(line < FrameLayout::EndOfFrontPorch) { porch_line(begin, end); } else if(line < FrameLayout::EndOfSync) { sync_line(begin, end); } else if(line < FrameLayout::EndOfBackPorch) { + if(!begin && line == FrameLayout::EndOfSync) { + delegate_.set_field_sync(false); + } porch_line(begin, end); } else { border_line(begin, end); } + + if(end >= LineLayout::EndOfSync) delegate_.set_hsync(false); }, [&] { reset(); @@ -269,39 +291,39 @@ void MC6847::run_for(const Cycles cycles) { ); } -template -Cycles MC6847::next_sequence_point() const { +template +Cycles MC6847::next_sequence_point() const { return MC6847Base::next_sequence_point(position_.subsegment()); } -template -bool MC6847::hsync() const { +template +bool MC6847::hsync() const { return MC6847Base::hsync(position_.subsegment()); } -template -bool MC6847::vsync() const { +template +bool MC6847::vsync() const { const auto segment = position_.segment(); return segment >= FrameLayout::EndOfFrontPorch && segment < FrameLayout::EndOfSync; } -template -void MC6847::set_scan_target(Outputs::Display::ScanTarget *const target) { +template +void MC6847::set_scan_target(Outputs::Display::ScanTarget *const target) { crt_.set_scan_target(target); } -template -Outputs::Display::ScanStatus MC6847::get_scaled_scan_status() const { +template +Outputs::Display::ScanStatus MC6847::get_scaled_scan_status() const { return crt_.get_scaled_scan_status(); } -template -void MC6847::set_display_type(const Outputs::Display::DisplayType display_type) { +template +void MC6847::set_display_type(const Outputs::Display::DisplayType display_type) { crt_.set_display_type(display_type); } -template -Outputs::Display::DisplayType MC6847::get_display_type() const { +template +Outputs::Display::DisplayType MC6847::get_display_type() const { return crt_.get_display_type(); } diff --git a/Machines/Tandy/CoCo/CoCo.cpp b/Machines/Tandy/CoCo/CoCo.cpp index d0317494d..2fa3b9c38 100644 --- a/Machines/Tandy/CoCo/CoCo.cpp +++ b/Machines/Tandy/CoCo/CoCo.cpp @@ -124,7 +124,7 @@ public: pia1_handler_(*this), pia1_(pia1_handler_), sam_(memory_), - m6847_(sam_), + m6847_(sam_, sam_), tape_player_(int(ClockRate)), audio_(audio_queue_, MaxDACLevel), speaker_(audio_) @@ -669,6 +669,10 @@ private: return graphics_address_; } + void set_hsync(bool) {} + void set_field_sync(bool) {} + void set_row_preset(bool) {} + private: MemoryMap &memory_; @@ -694,6 +698,7 @@ private: Motorola::MC6847::MC6847< Motorola::MC6847::FrameTiming::NTSC, SAM, + SAM, ModeMapper >, Cycles,