mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-27 01:31:42 +00:00
Revoked the operator bool() on WrappedInt as providing an indirect means for implicit but incorrect assignment to unwrapped ints. Got explicit about run_for
intention and simplified HalfClockReceiver slightly by building a lossy and a flushing conversion to Cycles into HalfCycles. Adapted the all-RAM Z80 properly to return HalfCycles.
This commit is contained in:
parent
b9f4f7a530
commit
9ef232157b
@ -9,6 +9,43 @@
|
|||||||
#ifndef ClockReceiver_hpp
|
#ifndef ClockReceiver_hpp
|
||||||
#define ClockReceiver_hpp
|
#define ClockReceiver_hpp
|
||||||
|
|
||||||
|
/*
|
||||||
|
Informal pattern for all classes that run from a clock cycle:
|
||||||
|
|
||||||
|
Each will implement either or both of run_for(Cycles) and run_for(HalfCycles), as
|
||||||
|
is appropriate.
|
||||||
|
|
||||||
|
Callers that are accumulating HalfCycles but want to talk to receivers that implement
|
||||||
|
only run_for(Cycles) can use HalfCycle.flush_cycles if they have appropriate storage, or
|
||||||
|
can wrap the receiver in HalfClockReceiver in order automatically to bind half-cycle
|
||||||
|
storage to it.
|
||||||
|
|
||||||
|
Alignment rule:
|
||||||
|
|
||||||
|
run_for(Cycles) may be called only after an even number of half cycles. E.g. the following
|
||||||
|
sequence will have undefined results:
|
||||||
|
|
||||||
|
run_for(HalfCycles(1))
|
||||||
|
run_for(Cycles(1))
|
||||||
|
|
||||||
|
An easy way to ensure this as a caller is to pick only one of run_for(Cycles) and
|
||||||
|
run_for(HalfCycles) to use.
|
||||||
|
|
||||||
|
Reasoning:
|
||||||
|
|
||||||
|
Users of this template may with to implement run_for(Cycles) and run_for(HalfCycles)
|
||||||
|
where there is a need to implement at half-cycle precision but a faster execution
|
||||||
|
path can be offered for full-cycle precision. Those users are permitted to assume
|
||||||
|
phase in run_for(Cycles) and should do so to be compatible with callers that use
|
||||||
|
only run_for(Cycles).
|
||||||
|
|
||||||
|
Corollary:
|
||||||
|
|
||||||
|
Starting from nothing, the first run_for(HalfCycles(1)) will do the **first** half
|
||||||
|
of a full cycle. The second will do the second half. Etc.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Provides a class that wraps a plain int, providing most of the basic arithmetic and
|
Provides a class that wraps a plain int, providing most of the basic arithmetic and
|
||||||
Boolean operators, but forcing callers and receivers to be explicit as to usage.
|
Boolean operators, but forcing callers and receivers to be explicit as to usage.
|
||||||
@ -69,7 +106,7 @@ template <class T> class WrappedInt {
|
|||||||
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 bool operator !() const { return !length_; }
|
||||||
inline operator bool() const { return !!length_; }
|
// bool operator () is not supported because it offers an implicit cast to int, which is prone silently to permit misuse
|
||||||
|
|
||||||
inline int as_int() const { return length_; }
|
inline int as_int() const { return length_; }
|
||||||
|
|
||||||
@ -116,35 +153,20 @@ class HalfCycles: public WrappedInt<HalfCycles> {
|
|||||||
|
|
||||||
inline HalfCycles(const Cycles &cycles) : WrappedInt<HalfCycles>(cycles.as_int() << 1) {}
|
inline HalfCycles(const Cycles &cycles) : WrappedInt<HalfCycles>(cycles.as_int() << 1) {}
|
||||||
inline HalfCycles(const HalfCycles &half_cycles) : WrappedInt<HalfCycles>(half_cycles.length_) {}
|
inline HalfCycles(const HalfCycles &half_cycles) : WrappedInt<HalfCycles>(half_cycles.length_) {}
|
||||||
|
|
||||||
|
/// @returns The number of whole cycles completely covered by this span of half cycles.
|
||||||
|
inline Cycles cycles() {
|
||||||
|
return Cycles(length_ >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
///Flushes the whole cycles in @c this, subtracting that many from the total stored here.
|
||||||
|
inline Cycles flush_cycles() {
|
||||||
|
Cycles result(length_ >> 1);
|
||||||
|
length_ &= 1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
Alignment rule:
|
|
||||||
|
|
||||||
run_for(Cycles) may be called only at the start of a cycle. E.g. the following
|
|
||||||
sequence will have undefined results:
|
|
||||||
|
|
||||||
run_for(HalfCycles(1))
|
|
||||||
run_for(Cycles(1))
|
|
||||||
|
|
||||||
An easy way to ensure this as a caller is to pick only one of run_for(Cycles) and
|
|
||||||
run_for(HalfCycles) to use.
|
|
||||||
|
|
||||||
Reasoning:
|
|
||||||
|
|
||||||
Users of this template may with to implement run_for(Cycles) and run_for(HalfCycles)
|
|
||||||
where there is a need to implement at half-cycle precision but a faster execution
|
|
||||||
path can be offered for full-cycle precision. Those users are permitted to assume
|
|
||||||
phase in run_for(Cycles) and should do so to be compatible with callers that use
|
|
||||||
only run_for(Cycles).
|
|
||||||
|
|
||||||
Corollary:
|
|
||||||
|
|
||||||
Starting from nothing, the first run_for(HalfCycles(1)) will do the **first** half
|
|
||||||
of a full cycle. The second will do the second half. Etc.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
If a component implements only run_for(Cycles), an owner can wrap it in HalfClockReceiver
|
If a component implements only run_for(Cycles), an owner can wrap it in HalfClockReceiver
|
||||||
automatically to gain run_for(HalfCycles).
|
automatically to gain run_for(HalfCycles).
|
||||||
@ -155,13 +177,12 @@ template <class T> class HalfClockReceiver: public T {
|
|||||||
|
|
||||||
using T::run_for;
|
using T::run_for;
|
||||||
inline void run_for(const HalfCycles &half_cycles) {
|
inline void run_for(const HalfCycles &half_cycles) {
|
||||||
int cycles = half_cycles.as_int() + half_cycle_carry_;
|
half_cycles_ += half_cycles;
|
||||||
half_cycle_carry_ = cycles & 1;
|
T::run_for(half_cycles_.flush_cycles());
|
||||||
T::run_for(Cycles(cycles >> 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int half_cycle_carry_ = 0;
|
HalfCycles half_cycles_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* ClockReceiver_hpp */
|
#endif /* ClockReceiver_hpp */
|
||||||
|
@ -351,7 +351,7 @@ void Machine::flush() {
|
|||||||
#pragma mark - Deferred scheduling
|
#pragma mark - Deferred scheduling
|
||||||
|
|
||||||
inline void Machine::update_display() {
|
inline void Machine::update_display() {
|
||||||
if(cycles_since_display_update_) {
|
if(cycles_since_display_update_ > 0) {
|
||||||
video_output_->run_for(cycles_since_display_update_.flush());
|
video_output_->run_for(cycles_since_display_update_.flush());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -363,7 +363,7 @@ inline void Machine::queue_next_display_interrupt() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void Machine::update_audio() {
|
inline void Machine::update_audio() {
|
||||||
if(cycles_since_audio_update_) {
|
if(cycles_since_audio_update_ > 0) {
|
||||||
speaker_->run_for(cycles_since_audio_update_.divide(Cycles(Speaker::clock_rate_divider)));
|
speaker_->run_for(cycles_since_audio_update_.divide(Cycles(Speaker::clock_rate_divider)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,10 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor<Concrete
|
|||||||
public:
|
public:
|
||||||
ConcreteAllRAMProcessor() : AllRAMProcessor() {}
|
ConcreteAllRAMProcessor() : AllRAMProcessor() {}
|
||||||
|
|
||||||
inline Cycles perform_machine_cycle(const PartialMachineCycle &cycle) {
|
inline HalfCycles perform_machine_cycle(const PartialMachineCycle &cycle) {
|
||||||
timestamp_ += cycle.length;
|
timestamp_ += cycle.length;
|
||||||
if(!cycle.is_terminal()) {
|
if(!cycle.is_terminal()) {
|
||||||
return Cycles(0);
|
return HalfCycles(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t address = cycle.address ? *cycle.address : 0x0000;
|
uint16_t address = cycle.address ? *cycle.address : 0x0000;
|
||||||
@ -60,7 +60,7 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor<Concrete
|
|||||||
delegate_->z80_all_ram_processor_did_perform_bus_operation(*this, cycle.operation, address, cycle.value ? *cycle.value : 0x00, timestamp_);
|
delegate_->z80_all_ram_processor_did_perform_bus_operation(*this, cycle.operation, address, cycle.value ? *cycle.value : 0x00, timestamp_);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Cycles(0);
|
return HalfCycles(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_for(const Cycles &cycles) {
|
void run_for(const Cycles &cycles) {
|
||||||
|
Loading…
Reference in New Issue
Block a user