mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-13 22:32:03 +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:
parent
e6578defcd
commit
b82bef95f3
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user