From b82bef95f382261b20543253216aea187967a370 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 24 Jul 2017 20:10:05 -0400 Subject: [PATCH] Decided to follow through on `Cycles` and `HalfCycles` as complete integer-alikes. Which means giving them the interesting range of operators. Also killed the implicit conversion to int as likely to lead to type confusion. --- Components/ClockReceiver.hpp | 76 ++++++++++++++++++++++++------------ Machines/Oric/Video.cpp | 2 +- Machines/ZX8081/Video.cpp | 2 +- Machines/ZX8081/ZX8081.cpp | 30 +++++++------- Machines/ZX8081/ZX8081.hpp | 7 ++-- Processors/6502/6502.hpp | 2 +- Processors/Z80/Z80.hpp | 9 ++--- 7 files changed, 78 insertions(+), 50 deletions(-) diff --git a/Components/ClockReceiver.hpp b/Components/ClockReceiver.hpp index 6334889e9..4b9513a14 100644 --- a/Components/ClockReceiver.hpp +++ b/Components/ClockReceiver.hpp @@ -9,40 +9,68 @@ #ifndef ClockReceiver_hpp #define ClockReceiver_hpp -/*! Describes an integer number of whole cycles — pairs of clock signal transitions. */ -class Cycles { +template class WrappedInt { public: - Cycles(int l) : length_(l) {} - Cycles(const Cycles &cycles) : length_(int(cycles)) {} - Cycles() : length_(0) {} - operator int() const { return length_; } + WrappedInt(int l) : length_(l) {} + WrappedInt() : length_(0) {} - Cycles &operator =(const Cycles &cycles) { - length_ = cycles.length_; + inline T &operator =(const T &rhs) { + length_ = rhs.length_; return *this; } - private: + inline T &operator +=(const T &rhs) { + length_ += rhs.length_; + return *static_cast(this); + } + + inline T &operator -=(const T &rhs) { + length_ -= rhs.length_; + return *static_cast(this); + } + + inline T &operator %=(const T &rhs) { + length_ %= rhs.length_; + return *static_cast(this); + } + + inline T operator +(const T &rhs) const { return T(length_ + rhs.length_); } + inline T operator -(const T &rhs) const { return T(length_ - rhs.length_); } + + inline bool operator <(const T &rhs) const { return length_ < rhs.length_; } + inline bool operator >(const T &rhs) const { return length_ > rhs.length_; } + inline bool operator <=(const T &rhs) const { return length_ <= rhs.length_; } + inline bool operator >=(const T &rhs) const { return length_ >= rhs.length_; } + inline bool operator ==(const T &rhs) const { return length_ == rhs.length_; } + inline bool operator !=(const T &rhs) const { return length_ != rhs.length_; } + + inline bool operator !() const { return !length_; } + + inline int as_int() const { return length_; } + + // operator int() is deliberately not provided, to avoid accidental subtitution of + // classes that use this template. + + protected: int length_; }; -/*! Describes an integer number of half cycles — single clock signal transitions. */ -class HalfCycles { +/*! Describes an integer number of whole cycles — pairs of clock signal transitions. */ +class Cycles: public WrappedInt { public: - HalfCycles(int l) : length_(l) {} - HalfCycles(const Cycles &cycles) : length_(int(cycles) << 1) {} - HalfCycles(const HalfCycles &half_cycles) : length_(int(half_cycles)) {} - HalfCycles() : length_(0) {} + Cycles(int l) : WrappedInt(l) {} + Cycles() : WrappedInt() {} + Cycles(const Cycles &cycles) : WrappedInt(cycles.length_) {} +}; - HalfCycles &operator =(const HalfCycles &half_cycles) { - length_ = half_cycles.length_; - return *this; - } +/*! Describes an integer number of half cycles — single clock signal transitions. */ +class HalfCycles: public WrappedInt { + public: + HalfCycles(int l) : WrappedInt(l) {} + HalfCycles() : WrappedInt() {} - operator int() const { return length_; } - - private: - int length_; + HalfCycles(const Cycles &cycles) : WrappedInt(cycles.as_int() << 1) {} + HalfCycles(const HalfCycles &half_cycles) : WrappedInt(half_cycles.length_) {} }; /*! @@ -58,7 +86,7 @@ template class ClockReceiver { } void run_for(const HalfCycles &half_cycles) { - int cycles = int(half_cycles) + half_cycle_carry; + int cycles = half_cycles.as_int() + half_cycle_carry; half_cycle_carry = cycles & 1; run_for(Cycles(cycles >> 1)); } diff --git a/Machines/Oric/Video.cpp b/Machines/Oric/Video.cpp index 4acf619af..2e455d873 100644 --- a/Machines/Oric/Video.cpp +++ b/Machines/Oric/Video.cpp @@ -81,7 +81,7 @@ void VideoOutput::run_for(const Cycles &cycles) { #define clamp(action) \ if(cycles_run_for <= number_of_cycles) { action; } else cycles_run_for = number_of_cycles; - int number_of_cycles = int(cycles); + int number_of_cycles = cycles.as_int(); while(number_of_cycles) { int h_counter = counter_ & 63; int cycles_run_for = 0; diff --git a/Machines/ZX8081/Video.cpp b/Machines/ZX8081/Video.cpp index 766c6a1f6..a5443f7e2 100644 --- a/Machines/ZX8081/Video.cpp +++ b/Machines/ZX8081/Video.cpp @@ -31,7 +31,7 @@ Video::Video() : void Video::run_for(const HalfCycles &half_cycles) { // Just keep a running total of the amount of time that remains owed to the CRT. - cycles_since_update_ += (unsigned int)int(half_cycles); + cycles_since_update_ += (unsigned int)half_cycles.as_int(); } void Video::flush() { diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index ccaf83b8a..5641ee94b 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -30,34 +30,34 @@ Machine::Machine() : } int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { - int previous_counter = horizontal_counter_; + HalfCycles previous_counter = horizontal_counter_; horizontal_counter_ += cycle.length; - if(previous_counter < vsync_start_cycle_ && horizontal_counter_ >= vsync_start_cycle_) { - video_->run_for(Cycles(vsync_start_cycle_ - previous_counter)); + if(previous_counter < vsync_start_ && horizontal_counter_ >= vsync_start_) { + video_->run_for(vsync_start_ - previous_counter); set_hsync(true); line_counter_ = (line_counter_ + 1) & 7; if(nmi_is_enabled_) { set_non_maskable_interrupt_line(true); } - video_->run_for(Cycles(horizontal_counter_ - vsync_start_cycle_)); - } else if(previous_counter < vsync_end_cycle_ && horizontal_counter_ >= vsync_end_cycle_) { - video_->run_for(Cycles(vsync_end_cycle_ - previous_counter)); + video_->run_for(horizontal_counter_ - vsync_start_); + } else if(previous_counter < vsync_end_ && horizontal_counter_ >= vsync_end_) { + video_->run_for(vsync_end_ - previous_counter); set_hsync(false); if(nmi_is_enabled_) { set_non_maskable_interrupt_line(false); set_wait_line(false); } - video_->run_for(Cycles(horizontal_counter_ - vsync_end_cycle_)); + video_->run_for(horizontal_counter_ - vsync_end_); } else { video_->run_for(cycle.length); } - if(is_zx81_) horizontal_counter_ %= 207; + if(is_zx81_) horizontal_counter_ %= HalfCycles(Cycles(207)); if(!tape_advance_delay_) { - tape_player_.run_for_cycles(cycle.length); + tape_player_.run_for_cycles(cycle.length.as_int()); } else { - tape_advance_delay_ = std::max(tape_advance_delay_ - cycle.length, 0); + tape_advance_delay_ = std::max(tape_advance_delay_ - cycle.length, HalfCycles(0)); } if(nmi_is_enabled_ && !get_halt_line() && get_non_maskable_interrupt_line()) { @@ -180,7 +180,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { default: break; } - if(typer_) typer_->update(cycle.length); + if(typer_) typer_->update(cycle.length.as_int()); return 0; } @@ -215,16 +215,16 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target) { rom_ = zx81_rom_; tape_trap_address_ = 0x37c; tape_return_address_ = 0x380; - vsync_start_cycle_ = 16; - vsync_end_cycle_ = 32; + vsync_start_ = HalfCycles(32); + vsync_end_ = HalfCycles(64); automatic_tape_motor_start_address_ = 0x0340; automatic_tape_motor_end_address_ = 0x03c3; } else { rom_ = zx80_rom_; tape_trap_address_ = 0x220; tape_return_address_ = 0x248; - vsync_start_cycle_ = 13; - vsync_end_cycle_ = 33; + vsync_start_ = HalfCycles(26); + vsync_end_ = HalfCycles(66); automatic_tape_motor_start_address_ = 0x0206; automatic_tape_motor_end_address_ = 0x024d; } diff --git a/Machines/ZX8081/ZX8081.hpp b/Machines/ZX8081/ZX8081.hpp index e6b460c4e..031ce8b7e 100644 --- a/Machines/ZX8081/ZX8081.hpp +++ b/Machines/ZX8081/ZX8081.hpp @@ -103,17 +103,18 @@ class Machine: Storage::Tape::BinaryTapePlayer tape_player_; Storage::Tape::ZX8081::Parser parser_; - int horizontal_counter_; bool is_zx81_; bool nmi_is_enabled_; - int vsync_start_cycle_, vsync_end_cycle_; + + HalfCycles vsync_start_, vsync_end_; + HalfCycles horizontal_counter_; uint8_t latched_video_byte_; bool has_latched_video_byte_; bool use_fast_tape_hack_; bool use_automatic_tape_motor_control_; - int tape_advance_delay_; + HalfCycles tape_advance_delay_; }; } diff --git a/Processors/6502/6502.hpp b/Processors/6502/6502.hpp index 8eb871286..256aedc5e 100644 --- a/Processors/6502/6502.hpp +++ b/Processors/6502/6502.hpp @@ -340,7 +340,7 @@ template class Processor: public ProcessorBase, public ClockReceiver

0) { diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 6de70af79..f9709da44 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -183,7 +183,7 @@ template class Processor: public ClockReceiver> { uint8_t carry_result_; // the carry flag is set if bit 0 of carry_result_ is set uint8_t halt_mask_; - int number_of_cycles_; + Cycles number_of_cycles_; enum Interrupt: uint8_t { IRQ = 0x01, @@ -429,7 +429,7 @@ template class Processor: public ClockReceiver> { target.instructions[c] = &target.all_operations[destination]; for(size_t t = 0; t < lengths[c];) { // Skip zero-length bus cycles. - if(table[c][t].type == MicroOp::BusOperation && table[c][t].machine_cycle.length == 0) { + if(table[c][t].type == MicroOp::BusOperation && table[c][t].machine_cycle.length.as_int() == 0) { t++; continue; } @@ -766,7 +766,6 @@ template class Processor: public ClockReceiver> { public: Processor() : halt_mask_(0xff), - number_of_cycles_(0), interrupt_mode_(0), wait_line_(false), request_status_(Interrupt::PowerOn), @@ -879,7 +878,7 @@ template class Processor: public ClockReceiver> { scheduled_program_counter_ = base_page_.fetch_decode_execute_data; \ } - number_of_cycles_ += int(cycles); + number_of_cycles_ += cycles; if(!scheduled_program_counter_) { advance_operation(); } @@ -888,7 +887,7 @@ template class Processor: public ClockReceiver> { while(bus_request_line_) { static PartialMachineCycle bus_acknowledge_cycle = {PartialMachineCycle::BusAcknowledge, 1, nullptr, nullptr, false}; - number_of_cycles_ -= static_cast(this)->perform_machine_cycle(bus_acknowledge_cycle) + 1; + number_of_cycles_ -= Cycles(static_cast(this)->perform_machine_cycle(bus_acknowledge_cycle) + 1); if(!number_of_cycles_) { static_cast(this)->flush(); return;