Merge pull request #1813 from TomHarte/6847Delegate
Add external delegate signalling to 6847.
This commit is contained in:
3 files changed
+75
-37
No files matched your search
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user