Merge pull request #1813 from TomHarte/6847Delegate

Add external delegate signalling to 6847.
This commit is contained in:
Thomas Harte authored and GitHub committed 2026-05-12 17:53:35 -04:00
commit 10597ed830
3 files changed
+75 -37

No files matched your search

+19 -8
View File
@@ -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<uint32_t *>(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];
+50 -28
View File
@@ -39,13 +39,6 @@ template <FrameTiming timing> struct FrameLayout {
static_assert(FrameLayout<FrameTiming::NTSC>::EndOfField == 262, "NTSC frames should be 262 lines long");
static_assert(FrameLayout<FrameTiming::PALPaddedVsync>::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 <FrameTiming timing, typename MemoryAccessT, typename ModeMapperT = NullMapper>
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<LineLayout::EndOfLine, FrameLayout<timing>::EndOfField> position_{2};
DelegateT &delegate_;
};
// MARK: - Implementation.
template <FrameTiming timing, typename MemoryAccessT, typename ModeMapperT>
MC6847<timing, MemoryAccessT, ModeMapperT>::MC6847(MemoryAccessT &memory) :
template <FrameTiming timing, typename MemoryAccessT, typename DelegateT, typename ModeMapperT>
MC6847<timing, MemoryAccessT, DelegateT, ModeMapperT>::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 <FrameTiming timing, typename MemoryAccessT, typename ModeMapperT>
void MC6847<timing, MemoryAccessT, ModeMapperT>::run_for(const Cycles cycles) {
template <FrameTiming timing, typename MemoryAccessT, typename DelegateT, typename ModeMapperT>
void MC6847<timing, MemoryAccessT, DelegateT, ModeMapperT>::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<int>(),
[&] (const int line, const int begin, const int end) {
if(!begin) delegate_.set_hsync(true);
if(line < FrameLayout<timing>::EndOfPixels) {
if(!begin && !address_.row()) delegate_.set_row_preset(true);
Numeric::clamp<LineLayout::EndOfLeftBorder, LineLayout::EndOfPixels>(
begin,
end,
@@ -251,17 +263,27 @@ void MC6847<timing, MemoryAccessT, ModeMapperT>::run_for(const Cycles cycles) {
}
);
pixel_line(begin, end);
if(end >= LineLayout::EndOfSync) delegate_.set_row_preset(false);
} else if(line < FrameLayout<timing>::EndOfBottomBorder) {
if(!begin && line == FrameLayout<timing>::EndOfPixels) {
delegate_.set_field_sync(true);
}
border_line(begin, end);
} else if(line < FrameLayout<timing>::EndOfFrontPorch) {
porch_line(begin, end);
} else if(line < FrameLayout<timing>::EndOfSync) {
sync_line(begin, end);
} else if(line < FrameLayout<timing>::EndOfBackPorch) {
if(!begin && line == FrameLayout<timing>::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<timing, MemoryAccessT, ModeMapperT>::run_for(const Cycles cycles) {
);
}
template <FrameTiming timing, typename MemoryAccessT, typename ModeMapperT>
Cycles MC6847<timing, MemoryAccessT, ModeMapperT>::next_sequence_point() const {
template <FrameTiming timing, typename MemoryAccessT, typename DelegateT, typename ModeMapperT>
Cycles MC6847<timing, MemoryAccessT, DelegateT, ModeMapperT>::next_sequence_point() const {
return MC6847Base::next_sequence_point(position_.subsegment());
}
template <FrameTiming timing, typename MemoryAccessT, typename ModeMapperT>
bool MC6847<timing, MemoryAccessT, ModeMapperT>::hsync() const {
template <FrameTiming timing, typename MemoryAccessT, typename DelegateT, typename ModeMapperT>
bool MC6847<timing, MemoryAccessT, DelegateT, ModeMapperT>::hsync() const {
return MC6847Base::hsync(position_.subsegment());
}
template <FrameTiming timing, typename MemoryAccessT, typename ModeMapperT>
bool MC6847<timing, MemoryAccessT, ModeMapperT>::vsync() const {
template <FrameTiming timing, typename MemoryAccessT, typename DelegateT, typename ModeMapperT>
bool MC6847<timing, MemoryAccessT, DelegateT, ModeMapperT>::vsync() const {
const auto segment = position_.segment();
return segment >= FrameLayout<timing>::EndOfFrontPorch && segment < FrameLayout<timing>::EndOfSync;
}
template <FrameTiming timing, typename MemoryAccessT, typename ModeMapperT>
void MC6847<timing, MemoryAccessT, ModeMapperT>::set_scan_target(Outputs::Display::ScanTarget *const target) {
template <FrameTiming timing, typename MemoryAccessT, typename DelegateT, typename ModeMapperT>
void MC6847<timing, MemoryAccessT, DelegateT, ModeMapperT>::set_scan_target(Outputs::Display::ScanTarget *const target) {
crt_.set_scan_target(target);
}
template <FrameTiming timing, typename MemoryAccessT, typename ModeMapperT>
Outputs::Display::ScanStatus MC6847<timing, MemoryAccessT, ModeMapperT>::get_scaled_scan_status() const {
template <FrameTiming timing, typename MemoryAccessT, typename DelegateT, typename ModeMapperT>
Outputs::Display::ScanStatus MC6847<timing, MemoryAccessT, DelegateT, ModeMapperT>::get_scaled_scan_status() const {
return crt_.get_scaled_scan_status();
}
template <FrameTiming timing, typename MemoryAccessT, typename ModeMapperT>
void MC6847<timing, MemoryAccessT, ModeMapperT>::set_display_type(const Outputs::Display::DisplayType display_type) {
template <FrameTiming timing, typename MemoryAccessT, typename DelegateT, typename ModeMapperT>
void MC6847<timing, MemoryAccessT, DelegateT, ModeMapperT>::set_display_type(const Outputs::Display::DisplayType display_type) {
crt_.set_display_type(display_type);
}
template <FrameTiming timing, typename MemoryAccessT, typename ModeMapperT>
Outputs::Display::DisplayType MC6847<timing, MemoryAccessT, ModeMapperT>::get_display_type() const {
template <FrameTiming timing, typename MemoryAccessT, typename DelegateT, typename ModeMapperT>
Outputs::Display::DisplayType MC6847<timing, MemoryAccessT, DelegateT, ModeMapperT>::get_display_type() const {
return crt_.get_display_type();
}
+6 -1
View File
@@ -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,