mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-24 12:30:17 +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
|
||||
#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
|
||||
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 { 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_; }
|
||||
|
||||
@ -116,35 +153,20 @@ class HalfCycles: public WrappedInt<HalfCycles> {
|
||||
|
||||
inline HalfCycles(const Cycles &cycles) : WrappedInt<HalfCycles>(cycles.as_int() << 1) {}
|
||||
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
|
||||
automatically to gain run_for(HalfCycles).
|
||||
@ -155,13 +177,12 @@ template <class T> class HalfClockReceiver: public T {
|
||||
|
||||
using T::run_for;
|
||||
inline void run_for(const HalfCycles &half_cycles) {
|
||||
int cycles = half_cycles.as_int() + half_cycle_carry_;
|
||||
half_cycle_carry_ = cycles & 1;
|
||||
T::run_for(Cycles(cycles >> 1));
|
||||
half_cycles_ += half_cycles;
|
||||
T::run_for(half_cycles_.flush_cycles());
|
||||
}
|
||||
|
||||
private:
|
||||
int half_cycle_carry_ = 0;
|
||||
HalfCycles half_cycles_;
|
||||
};
|
||||
|
||||
#endif /* ClockReceiver_hpp */
|
||||
|
@ -351,7 +351,7 @@ void Machine::flush() {
|
||||
#pragma mark - Deferred scheduling
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
@ -363,7 +363,7 @@ inline void Machine::queue_next_display_interrupt() {
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,10 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor<Concrete
|
||||
public:
|
||||
ConcreteAllRAMProcessor() : AllRAMProcessor() {}
|
||||
|
||||
inline Cycles perform_machine_cycle(const PartialMachineCycle &cycle) {
|
||||
inline HalfCycles perform_machine_cycle(const PartialMachineCycle &cycle) {
|
||||
timestamp_ += cycle.length;
|
||||
if(!cycle.is_terminal()) {
|
||||
return Cycles(0);
|
||||
return HalfCycles(0);
|
||||
}
|
||||
|
||||
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_);
|
||||
}
|
||||
|
||||
return Cycles(0);
|
||||
return HalfCycles(0);
|
||||
}
|
||||
|
||||
void run_for(const Cycles &cycles) {
|
||||
|
Loading…
Reference in New Issue
Block a user