1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-14 13:33:42 +00:00

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.

This commit is contained in:
Thomas Harte 2017-07-24 20:10:05 -04:00
parent e6578defcd
commit b82bef95f3
7 changed files with 78 additions and 50 deletions

View File

@ -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 T> 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<T *>(this);
}
inline T &operator -=(const T &rhs) {
length_ -= rhs.length_;
return *static_cast<T *>(this);
}
inline T &operator %=(const T &rhs) {
length_ %= rhs.length_;
return *static_cast<T *>(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<Cycles> {
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<Cycles>(l) {}
Cycles() : WrappedInt<Cycles>() {}
Cycles(const Cycles &cycles) : WrappedInt<Cycles>(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<HalfCycles> {
public:
HalfCycles(int l) : WrappedInt<HalfCycles>(l) {}
HalfCycles() : WrappedInt<HalfCycles>() {}
operator int() const { return length_; }
private:
int length_;
HalfCycles(const Cycles &cycles) : WrappedInt<HalfCycles>(cycles.as_int() << 1) {}
HalfCycles(const HalfCycles &half_cycles) : WrappedInt<HalfCycles>(half_cycles.length_) {}
};
/*!
@ -58,7 +86,7 @@ template <class T> 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));
}

View File

@ -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;

View File

@ -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() {

View File

@ -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;
}

View File

@ -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_;
};
}

View File

@ -340,7 +340,7 @@ template <class T> class Processor: public ProcessorBase, public ClockReceiver<P
if(number_of_cycles <= 0) break;
checkSchedule();
int number_of_cycles = int(cycles) + cycles_left_to_run_;
int number_of_cycles = cycles.as_int() + cycles_left_to_run_;
while(number_of_cycles > 0) {

View File

@ -183,7 +183,7 @@ template <class T> class Processor: public ClockReceiver<Processor<T>> {
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 T> class Processor: public ClockReceiver<Processor<T>> {
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 T> class Processor: public ClockReceiver<Processor<T>> {
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 T> class Processor: public ClockReceiver<Processor<T>> {
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 T> class Processor: public ClockReceiver<Processor<T>> {
while(bus_request_line_) {
static PartialMachineCycle bus_acknowledge_cycle = {PartialMachineCycle::BusAcknowledge, 1, nullptr, nullptr, false};
number_of_cycles_ -= static_cast<T *>(this)->perform_machine_cycle(bus_acknowledge_cycle) + 1;
number_of_cycles_ -= Cycles(static_cast<T *>(this)->perform_machine_cycle(bus_acknowledge_cycle) + 1);
if(!number_of_cycles_) {
static_cast<T *>(this)->flush();
return;