1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-25 18:30:07 +00:00

Ensures proper manipulation of scan_statuses, leading to the correct result out of a CRTMachine.

Possibly with the exception of the TMS, as I appear to have uncovered an unrelated issue there.
This commit is contained in:
Thomas Harte 2020-01-21 22:28:25 -05:00
parent e7fff6e123
commit a71c5946f0
33 changed files with 95 additions and 57 deletions

View File

@ -83,9 +83,9 @@ template <class BusHandler> class MOS6560 {
speaker_.set_input_rate(static_cast<float>(clock_rate / 4.0));
}
void set_scan_target(Outputs::Display::ScanTarget *scan_target) { crt_.set_scan_target(scan_target); }
Outputs::Display::ScanStatus get_scan_status() const { return crt_.get_scan_status(); }
void set_display_type(Outputs::Display::DisplayType display_type) { crt_.set_display_type(display_type); }
void set_scan_target(Outputs::Display::ScanTarget *scan_target) { crt_.set_scan_target(scan_target); }
Outputs::Display::ScanStatus get_scaled_scan_status() const { return crt_.get_scaled_scan_status() / 4.0f; }
void set_display_type(Outputs::Display::DisplayType display_type) { crt_.set_display_type(display_type); }
Outputs::Speaker::Speaker *get_speaker() { return &speaker_; }
void set_high_frequency_cutoff(float cutoff) {

View File

@ -117,8 +117,8 @@ void TMS9918::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
crt_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus TMS9918::get_scan_status() const {
return crt_.get_scan_status();
Outputs::Display::ScanStatus TMS9918::get_scaled_scan_status() const {
return crt_.get_scaled_scan_status();
}
void TMS9918::set_display_type(Outputs::Display::DisplayType display_type) {

View File

@ -45,7 +45,7 @@ class TMS9918: public Base {
void set_scan_target(Outputs::Display::ScanTarget *);
/// Gets the current scan status.
Outputs::Display::ScanStatus get_scan_status() const;
Outputs::Display::ScanStatus get_scaled_scan_status() const;
/*! Sets the type of display the CRT will request. */
void set_display_type(Outputs::Display::DisplayType);

View File

@ -336,8 +336,8 @@ class CRTCBusHandler {
}
/// @returns The current scan status.
Outputs::Display::ScanStatus get_scan_status() const {
return crt_.get_scan_status();
Outputs::Display::ScanStatus get_scaled_scan_status() const {
return crt_.get_scaled_scan_status() / 64.0f;
}
/// Sets the type of display.
@ -1012,8 +1012,8 @@ template <bool has_fdc> class ConcreteMachine:
}
/// A CRTMachine function; returns the current scan status.
Outputs::Display::ScanStatus get_scan_status() const final {
return crtc_bus_handler_.get_scan_status();
Outputs::Display::ScanStatus get_scaled_scan_status() const final {
return crtc_bus_handler_.get_scaled_scan_status();
}
/// A CRTMachine function; sets the output display type.

View File

@ -421,8 +421,8 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
video_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus get_scan_status() const final {
return video_.get_scan_status();
Outputs::Display::ScanStatus get_scaled_scan_status() const final {
return video_.get_scaled_scan_status();
}
/// Sets the type of display.

View File

@ -47,8 +47,8 @@ void VideoBase::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
crt_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus VideoBase::get_scan_status() const {
return crt_.get_scan_status();
Outputs::Display::ScanStatus VideoBase::get_scaled_scan_status() const {
return crt_.get_scaled_scan_status() / 14.0f;
}
void VideoBase::set_display_type(Outputs::Display::DisplayType display_type) {

View File

@ -41,7 +41,7 @@ class VideoBase {
void set_scan_target(Outputs::Display::ScanTarget *scan_target);
/// Gets the current scan status.
Outputs::Display::ScanStatus get_scan_status() const;
Outputs::Display::ScanStatus get_scaled_scan_status() const;
/// Sets the type of output.
void set_display_type(Outputs::Display::DisplayType);

View File

@ -175,8 +175,8 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
video_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus get_scan_status() const final {
return video_.get_scan_status();
Outputs::Display::ScanStatus get_scaled_scan_status() const final {
return video_.get_scaled_scan_status();
}
Outputs::Speaker::Speaker *get_speaker() override {

View File

@ -37,8 +37,8 @@ void Video::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
crt_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus Video::get_scan_status() const {
return crt_.get_scan_status();
Outputs::Display::ScanStatus Video::get_scaled_scan_status() const {
return crt_.get_scaled_scan_status() / 2.0f;
}
void Video::run_for(HalfCycles duration) {

View File

@ -43,7 +43,7 @@ class Video {
void set_scan_target(Outputs::Display::ScanTarget *scan_target);
/// Gets the current scan status.
Outputs::Display::ScanStatus get_scan_status() const;
Outputs::Display::ScanStatus get_scaled_scan_status() const;
/*!
Produces the next @c duration period of pixels.

View File

@ -161,8 +161,8 @@ class ConcreteMachine:
bus_->tia_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus get_scan_status() const final {
return bus_->tia_.get_scan_status();
Outputs::Display::ScanStatus get_scaled_scan_status() const final {
return bus_->tia_.get_scaled_scan_status() / 3.0f;
}
Outputs::Speaker::Speaker *get_speaker() override {

View File

@ -142,8 +142,8 @@ void TIA::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
crt_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus TIA::get_scan_status() const {
return crt_.get_scan_status();
Outputs::Display::ScanStatus TIA::get_scaled_scan_status() const {
return crt_.get_scaled_scan_status() / 2.0f;
}
void TIA::run_for(const Cycles cycles) {

View File

@ -75,7 +75,7 @@ class TIA {
void set_crt_delegate(Outputs::CRT::Delegate *);
void set_scan_target(Outputs::Display::ScanTarget *);
Outputs::Display::ScanStatus get_scan_status() const;
Outputs::Display::ScanStatus get_scaled_scan_status() const;
private:
Outputs::CRT::CRT crt_;

View File

@ -139,8 +139,8 @@ class ConcreteMachine:
video_->set_scan_target(scan_target);
}
Outputs::Display::ScanStatus get_scan_status() const final {
return video_->get_scan_status();
Outputs::Display::ScanStatus get_scaled_scan_status() const final {
return video_->get_scaled_scan_status();
}
void set_display_type(Outputs::Display::DisplayType display_type) final {

View File

@ -127,8 +127,8 @@ void Video::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
crt_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus Video::get_scan_status() const {
return crt_.get_scan_status();
Outputs::Display::ScanStatus Video::get_scaled_scan_status() const {
return crt_.get_scaled_scan_status() / 2.0f;
}
void Video::set_display_type(Outputs::Display::DisplayType display_type) {

View File

@ -41,7 +41,7 @@ class Video {
void set_scan_target(Outputs::Display::ScanTarget *scan_target);
/// Gets the current scan status.
Outputs::Display::ScanStatus get_scan_status() const;
Outputs::Display::ScanStatus get_scaled_scan_status() const;
/*!
Sets the type of output.

View File

@ -40,7 +40,9 @@ class Machine {
/*!
@returns The current scan status.
*/
virtual Outputs::Display::ScanStatus get_scan_status() const = 0;
virtual Outputs::Display::ScanStatus get_scan_status() const {
return get_scaled_scan_status() / float(clock_rate_);
}
/// @returns The speaker that receives this machine's output, or @c nullptr if this machine is mute.
virtual Outputs::Speaker::Speaker *get_speaker() = 0;
@ -115,6 +117,15 @@ class Machine {
return clock_rate_;
}
virtual Outputs::Display::ScanStatus get_scaled_scan_status() const {
// This deliberately sets up an infinite loop if the user hasn't
// overridden at least one of this or get_scan_status.
//
// Most likely you want to override this, and let the base class
// throw in a divide-by-clock-rate at the end for you.
return get_scan_status();
}
/*!
Maps from Configurable::Display to Outputs::Display::VideoSignal and calls
@c set_display_type with the result.

View File

@ -185,8 +185,8 @@ class ConcreteMachine:
vdp_->set_scan_target(scan_target);
}
Outputs::Display::ScanStatus get_scan_status() const final {
return vdp_->get_scan_status();
Outputs::Display::ScanStatus get_scaled_scan_status() const final {
return vdp_->get_scaled_scan_status();
}
void set_display_type(Outputs::Display::DisplayType display_type) override {

View File

@ -626,8 +626,8 @@ class ConcreteMachine:
mos6560_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus get_scan_status() const final {
return mos6560_.get_scan_status();
Outputs::Display::ScanStatus get_scaled_scan_status() const final {
return mos6560_.get_scaled_scan_status();
}
void set_display_type(Outputs::Display::DisplayType display_type) override final {

View File

@ -383,8 +383,8 @@ class ConcreteMachine:
video_output_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus get_scan_status() const final {
return video_output_.get_scan_status();
Outputs::Display::ScanStatus get_scaled_scan_status() const final {
return video_output_.get_scaled_scan_status();
}
void set_display_type(Outputs::Display::DisplayType display_type) override {

View File

@ -56,8 +56,8 @@ void VideoOutput::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
crt_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus VideoOutput::get_scan_status() const {
return crt_.get_scan_status();
Outputs::Display::ScanStatus VideoOutput::get_scaled_scan_status() const {
return crt_.get_scaled_scan_status() / float(crt_cycles_multiplier);
}
void VideoOutput::set_display_type(Outputs::Display::DisplayType display_type) {

View File

@ -40,7 +40,7 @@ class VideoOutput {
void set_scan_target(Outputs::Display::ScanTarget *scan_target);
/// Gets the current scan status.
Outputs::Display::ScanStatus get_scan_status() const;
Outputs::Display::ScanStatus get_scaled_scan_status() const;
/// Sets the type of output.
void set_display_type(Outputs::Display::DisplayType);

View File

@ -282,8 +282,8 @@ class ConcreteMachine:
vdp_->set_scan_target(scan_target);
}
Outputs::Display::ScanStatus get_scan_status() const final {
return vdp_->get_scan_status();
Outputs::Display::ScanStatus get_scaled_scan_status() const final {
return vdp_->get_scaled_scan_status();
}
void set_display_type(Outputs::Display::DisplayType display_type) override {

View File

@ -177,8 +177,8 @@ class ConcreteMachine:
vdp_->set_scan_target(scan_target);
}
Outputs::Display::ScanStatus get_scan_status() const final {
return vdp_->get_scan_status();
Outputs::Display::ScanStatus get_scaled_scan_status() const final {
return vdp_->get_scaled_scan_status();
}
void set_display_type(Outputs::Display::DisplayType display_type) override {

View File

@ -556,8 +556,8 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
video_output_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus get_scan_status() const final {
return video_output_.get_scan_status();
Outputs::Display::ScanStatus get_scaled_scan_status() const final {
return video_output_.get_scaled_scan_status();
}
void set_display_type(Outputs::Display::DisplayType display_type) final {

View File

@ -56,8 +56,8 @@ void VideoOutput::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
crt_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus VideoOutput::get_scan_status() const {
return crt_.get_scan_status();
Outputs::Display::ScanStatus VideoOutput::get_scaled_scan_status() const {
return crt_.get_scaled_scan_status() / 6.0f;
}
void VideoOutput::set_colour_rom(const std::vector<uint8_t> &rom) {

View File

@ -27,7 +27,7 @@ class VideoOutput {
void set_scan_target(Outputs::Display::ScanTarget *scan_target);
void set_display_type(Outputs::Display::DisplayType display_type);
Outputs::Display::ScanStatus get_scan_status() const;
Outputs::Display::ScanStatus get_scaled_scan_status() const;
private:
uint8_t *ram_;

View File

@ -110,6 +110,6 @@ void Video::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
crt_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus Video::get_scan_status() const {
return crt_.get_scan_status();
Outputs::Display::ScanStatus Video::get_scaled_scan_status() const {
return crt_.get_scaled_scan_status() / 0.5f;
}

View File

@ -44,7 +44,7 @@ class Video {
void set_scan_target(Outputs::Display::ScanTarget *scan_target);
/// Gets the current scan status.
Outputs::Display::ScanStatus get_scan_status() const;
Outputs::Display::ScanStatus get_scaled_scan_status() const;
private:
bool sync_ = false;

View File

@ -318,8 +318,8 @@ template<bool is_zx81> class ConcreteMachine:
video_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus get_scan_status() const final {
return video_.get_scan_status();
Outputs::Display::ScanStatus get_scaled_scan_status() const final {
return video_.get_scaled_scan_status();
}
Outputs::Speaker::Speaker *get_speaker() override final {

View File

@ -468,7 +468,7 @@ Outputs::Display::Rect CRT::get_rect_for_area(int first_line_after_sync, int num
return Outputs::Display::Rect(start_x, start_y, width, height);
}
Outputs::Display::ScanStatus CRT::get_scan_status() const {
Outputs::Display::ScanStatus CRT::get_scaled_scan_status() const {
Outputs::Display::ScanStatus status;
status.field_duration = float(vertical_flywheel_->get_locked_period()) / float(time_multiplier_);
status.field_duration_gradient = float(vertical_flywheel_->get_last_period_adjustment()) / float(time_multiplier_);

View File

@ -274,8 +274,11 @@ class CRT {
/*! Sets the scan target for CRT output. */
void set_scan_target(Outputs::Display::ScanTarget *);
/*! Gets current scan status. */
Outputs::Display::ScanStatus get_scan_status() const;
/*!
Gets current scan status, with time based fields being in the input scale e.g. if you're supplying
86 cycles/line and 98 lines/field then it'll return a field duration of 86*98.
*/
Outputs::Display::ScanStatus get_scaled_scan_status() const;
/*! Sets the display type that will be nominated to the scan target. */
void set_display_type(Outputs::Display::DisplayType);

View File

@ -320,6 +320,30 @@ struct ScanStatus {
/// of the current vertical position — i.e. if current_position = 0.8 then a caller can
/// conclude that the top 80% of the visible part of the display has been painted.
float current_position;
/*!
@returns this ScanStatus, with time-relative fields scaled by dividing them by @c dividend.
*/
ScanStatus operator / (float dividend) {
const ScanStatus result = {
.field_duration = field_duration / dividend,
.field_duration_gradient = field_duration_gradient / dividend,
.current_position = current_position
};
return result;
}
/*!
@returns this ScanStatus, with time-relative fields scaled by multiplying them by @c multiplier.
*/
ScanStatus operator * (float multiplier) {
const ScanStatus result = {
.field_duration = field_duration * multiplier,
.field_duration_gradient = field_duration_gradient * multiplier,
.current_position = current_position
};
return result;
}
};
/*!