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:
parent
e6578defcd
commit
b82bef95f3
@ -9,40 +9,68 @@
|
|||||||
#ifndef ClockReceiver_hpp
|
#ifndef ClockReceiver_hpp
|
||||||
#define ClockReceiver_hpp
|
#define ClockReceiver_hpp
|
||||||
|
|
||||||
/*! Describes an integer number of whole cycles — pairs of clock signal transitions. */
|
template <class T> class WrappedInt {
|
||||||
class Cycles {
|
|
||||||
public:
|
public:
|
||||||
Cycles(int l) : length_(l) {}
|
WrappedInt(int l) : length_(l) {}
|
||||||
Cycles(const Cycles &cycles) : length_(int(cycles)) {}
|
WrappedInt() : length_(0) {}
|
||||||
Cycles() : length_(0) {}
|
|
||||||
operator int() const { return length_; }
|
|
||||||
|
|
||||||
Cycles &operator =(const Cycles &cycles) {
|
inline T &operator =(const T &rhs) {
|
||||||
length_ = cycles.length_;
|
length_ = rhs.length_;
|
||||||
return *this;
|
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_;
|
int length_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! Describes an integer number of half cycles — single clock signal transitions. */
|
/*! Describes an integer number of whole cycles — pairs of clock signal transitions. */
|
||||||
class HalfCycles {
|
class Cycles: public WrappedInt<Cycles> {
|
||||||
public:
|
public:
|
||||||
HalfCycles(int l) : length_(l) {}
|
Cycles(int l) : WrappedInt<Cycles>(l) {}
|
||||||
HalfCycles(const Cycles &cycles) : length_(int(cycles) << 1) {}
|
Cycles() : WrappedInt<Cycles>() {}
|
||||||
HalfCycles(const HalfCycles &half_cycles) : length_(int(half_cycles)) {}
|
Cycles(const Cycles &cycles) : WrappedInt<Cycles>(cycles.length_) {}
|
||||||
HalfCycles() : length_(0) {}
|
};
|
||||||
|
|
||||||
HalfCycles &operator =(const HalfCycles &half_cycles) {
|
/*! Describes an integer number of half cycles — single clock signal transitions. */
|
||||||
length_ = half_cycles.length_;
|
class HalfCycles: public WrappedInt<HalfCycles> {
|
||||||
return *this;
|
public:
|
||||||
}
|
HalfCycles(int l) : WrappedInt<HalfCycles>(l) {}
|
||||||
|
HalfCycles() : WrappedInt<HalfCycles>() {}
|
||||||
|
|
||||||
operator int() const { return length_; }
|
HalfCycles(const Cycles &cycles) : WrappedInt<HalfCycles>(cycles.as_int() << 1) {}
|
||||||
|
HalfCycles(const HalfCycles &half_cycles) : WrappedInt<HalfCycles>(half_cycles.length_) {}
|
||||||
private:
|
|
||||||
int length_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -58,7 +86,7 @@ template <class T> class ClockReceiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void run_for(const HalfCycles &half_cycles) {
|
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;
|
half_cycle_carry = cycles & 1;
|
||||||
run_for(Cycles(cycles >> 1));
|
run_for(Cycles(cycles >> 1));
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ void VideoOutput::run_for(const Cycles &cycles) {
|
|||||||
#define clamp(action) \
|
#define clamp(action) \
|
||||||
if(cycles_run_for <= number_of_cycles) { action; } else cycles_run_for = number_of_cycles;
|
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) {
|
while(number_of_cycles) {
|
||||||
int h_counter = counter_ & 63;
|
int h_counter = counter_ & 63;
|
||||||
int cycles_run_for = 0;
|
int cycles_run_for = 0;
|
||||||
|
@ -31,7 +31,7 @@ Video::Video() :
|
|||||||
|
|
||||||
void Video::run_for(const HalfCycles &half_cycles) {
|
void Video::run_for(const HalfCycles &half_cycles) {
|
||||||
// Just keep a running total of the amount of time that remains owed to the CRT.
|
// 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() {
|
void Video::flush() {
|
||||||
|
@ -30,34 +30,34 @@ Machine::Machine() :
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) {
|
int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) {
|
||||||
int previous_counter = horizontal_counter_;
|
HalfCycles previous_counter = horizontal_counter_;
|
||||||
horizontal_counter_ += cycle.length;
|
horizontal_counter_ += cycle.length;
|
||||||
|
|
||||||
if(previous_counter < vsync_start_cycle_ && horizontal_counter_ >= vsync_start_cycle_) {
|
if(previous_counter < vsync_start_ && horizontal_counter_ >= vsync_start_) {
|
||||||
video_->run_for(Cycles(vsync_start_cycle_ - previous_counter));
|
video_->run_for(vsync_start_ - previous_counter);
|
||||||
set_hsync(true);
|
set_hsync(true);
|
||||||
line_counter_ = (line_counter_ + 1) & 7;
|
line_counter_ = (line_counter_ + 1) & 7;
|
||||||
if(nmi_is_enabled_) {
|
if(nmi_is_enabled_) {
|
||||||
set_non_maskable_interrupt_line(true);
|
set_non_maskable_interrupt_line(true);
|
||||||
}
|
}
|
||||||
video_->run_for(Cycles(horizontal_counter_ - vsync_start_cycle_));
|
video_->run_for(horizontal_counter_ - vsync_start_);
|
||||||
} else if(previous_counter < vsync_end_cycle_ && horizontal_counter_ >= vsync_end_cycle_) {
|
} else if(previous_counter < vsync_end_ && horizontal_counter_ >= vsync_end_) {
|
||||||
video_->run_for(Cycles(vsync_end_cycle_ - previous_counter));
|
video_->run_for(vsync_end_ - previous_counter);
|
||||||
set_hsync(false);
|
set_hsync(false);
|
||||||
if(nmi_is_enabled_) {
|
if(nmi_is_enabled_) {
|
||||||
set_non_maskable_interrupt_line(false);
|
set_non_maskable_interrupt_line(false);
|
||||||
set_wait_line(false);
|
set_wait_line(false);
|
||||||
}
|
}
|
||||||
video_->run_for(Cycles(horizontal_counter_ - vsync_end_cycle_));
|
video_->run_for(horizontal_counter_ - vsync_end_);
|
||||||
} else {
|
} else {
|
||||||
video_->run_for(cycle.length);
|
video_->run_for(cycle.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_zx81_) horizontal_counter_ %= 207;
|
if(is_zx81_) horizontal_counter_ %= HalfCycles(Cycles(207));
|
||||||
if(!tape_advance_delay_) {
|
if(!tape_advance_delay_) {
|
||||||
tape_player_.run_for_cycles(cycle.length);
|
tape_player_.run_for_cycles(cycle.length.as_int());
|
||||||
} else {
|
} 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()) {
|
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;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typer_) typer_->update(cycle.length);
|
if(typer_) typer_->update(cycle.length.as_int());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -215,16 +215,16 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target) {
|
|||||||
rom_ = zx81_rom_;
|
rom_ = zx81_rom_;
|
||||||
tape_trap_address_ = 0x37c;
|
tape_trap_address_ = 0x37c;
|
||||||
tape_return_address_ = 0x380;
|
tape_return_address_ = 0x380;
|
||||||
vsync_start_cycle_ = 16;
|
vsync_start_ = HalfCycles(32);
|
||||||
vsync_end_cycle_ = 32;
|
vsync_end_ = HalfCycles(64);
|
||||||
automatic_tape_motor_start_address_ = 0x0340;
|
automatic_tape_motor_start_address_ = 0x0340;
|
||||||
automatic_tape_motor_end_address_ = 0x03c3;
|
automatic_tape_motor_end_address_ = 0x03c3;
|
||||||
} else {
|
} else {
|
||||||
rom_ = zx80_rom_;
|
rom_ = zx80_rom_;
|
||||||
tape_trap_address_ = 0x220;
|
tape_trap_address_ = 0x220;
|
||||||
tape_return_address_ = 0x248;
|
tape_return_address_ = 0x248;
|
||||||
vsync_start_cycle_ = 13;
|
vsync_start_ = HalfCycles(26);
|
||||||
vsync_end_cycle_ = 33;
|
vsync_end_ = HalfCycles(66);
|
||||||
automatic_tape_motor_start_address_ = 0x0206;
|
automatic_tape_motor_start_address_ = 0x0206;
|
||||||
automatic_tape_motor_end_address_ = 0x024d;
|
automatic_tape_motor_end_address_ = 0x024d;
|
||||||
}
|
}
|
||||||
|
@ -103,17 +103,18 @@ class Machine:
|
|||||||
Storage::Tape::BinaryTapePlayer tape_player_;
|
Storage::Tape::BinaryTapePlayer tape_player_;
|
||||||
Storage::Tape::ZX8081::Parser parser_;
|
Storage::Tape::ZX8081::Parser parser_;
|
||||||
|
|
||||||
int horizontal_counter_;
|
|
||||||
bool is_zx81_;
|
bool is_zx81_;
|
||||||
bool nmi_is_enabled_;
|
bool nmi_is_enabled_;
|
||||||
int vsync_start_cycle_, vsync_end_cycle_;
|
|
||||||
|
HalfCycles vsync_start_, vsync_end_;
|
||||||
|
HalfCycles horizontal_counter_;
|
||||||
|
|
||||||
uint8_t latched_video_byte_;
|
uint8_t latched_video_byte_;
|
||||||
bool has_latched_video_byte_;
|
bool has_latched_video_byte_;
|
||||||
|
|
||||||
bool use_fast_tape_hack_;
|
bool use_fast_tape_hack_;
|
||||||
bool use_automatic_tape_motor_control_;
|
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;
|
if(number_of_cycles <= 0) break;
|
||||||
|
|
||||||
checkSchedule();
|
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) {
|
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 carry_result_; // the carry flag is set if bit 0 of carry_result_ is set
|
||||||
uint8_t halt_mask_;
|
uint8_t halt_mask_;
|
||||||
|
|
||||||
int number_of_cycles_;
|
Cycles number_of_cycles_;
|
||||||
|
|
||||||
enum Interrupt: uint8_t {
|
enum Interrupt: uint8_t {
|
||||||
IRQ = 0x01,
|
IRQ = 0x01,
|
||||||
@ -429,7 +429,7 @@ template <class T> class Processor: public ClockReceiver<Processor<T>> {
|
|||||||
target.instructions[c] = &target.all_operations[destination];
|
target.instructions[c] = &target.all_operations[destination];
|
||||||
for(size_t t = 0; t < lengths[c];) {
|
for(size_t t = 0; t < lengths[c];) {
|
||||||
// Skip zero-length bus cycles.
|
// 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++;
|
t++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -766,7 +766,6 @@ template <class T> class Processor: public ClockReceiver<Processor<T>> {
|
|||||||
public:
|
public:
|
||||||
Processor() :
|
Processor() :
|
||||||
halt_mask_(0xff),
|
halt_mask_(0xff),
|
||||||
number_of_cycles_(0),
|
|
||||||
interrupt_mode_(0),
|
interrupt_mode_(0),
|
||||||
wait_line_(false),
|
wait_line_(false),
|
||||||
request_status_(Interrupt::PowerOn),
|
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; \
|
scheduled_program_counter_ = base_page_.fetch_decode_execute_data; \
|
||||||
}
|
}
|
||||||
|
|
||||||
number_of_cycles_ += int(cycles);
|
number_of_cycles_ += cycles;
|
||||||
if(!scheduled_program_counter_) {
|
if(!scheduled_program_counter_) {
|
||||||
advance_operation();
|
advance_operation();
|
||||||
}
|
}
|
||||||
@ -888,7 +887,7 @@ template <class T> class Processor: public ClockReceiver<Processor<T>> {
|
|||||||
|
|
||||||
while(bus_request_line_) {
|
while(bus_request_line_) {
|
||||||
static PartialMachineCycle bus_acknowledge_cycle = {PartialMachineCycle::BusAcknowledge, 1, nullptr, nullptr, false};
|
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_) {
|
if(!number_of_cycles_) {
|
||||||
static_cast<T *>(this)->flush();
|
static_cast<T *>(this)->flush();
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user