mirror of
https://github.com/TomHarte/CLK.git
synced 2024-09-16 08:56:51 +00:00
Added some documentation, got explicit again about cycle/half-cycle intermingling, and added flush
as what amounts to divide(1)
, for cleaner usage without a clock divider.
This commit is contained in:
parent
cfbd62a5dc
commit
545683df6f
@ -9,6 +9,10 @@
|
|||||||
#ifndef ClockReceiver_hpp
|
#ifndef ClockReceiver_hpp
|
||||||
#define ClockReceiver_hpp
|
#define ClockReceiver_hpp
|
||||||
|
|
||||||
|
/*!
|
||||||
|
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.
|
||||||
|
*/
|
||||||
template <class T> class WrappedInt {
|
template <class T> class WrappedInt {
|
||||||
public:
|
public:
|
||||||
inline WrappedInt(int l) : length_(l) {}
|
inline WrappedInt(int l) : length_(l) {}
|
||||||
@ -68,12 +72,27 @@ template <class T> class WrappedInt {
|
|||||||
inline operator bool() const { return !!length_; }
|
inline operator bool() const { return !!length_; }
|
||||||
|
|
||||||
inline int as_int() const { return length_; }
|
inline int as_int() const { return length_; }
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Severs from @c this the effect of dividing by @c divisor — @c this will end up with
|
||||||
|
the value of @c this modulo @c divisor and @c divided by @c divisor is returned.
|
||||||
|
*/
|
||||||
inline T divide(const T &divisor) {
|
inline T divide(const T &divisor) {
|
||||||
T result(length_ / divisor.length_);
|
T result(length_ / divisor.length_);
|
||||||
length_ %= divisor.length_;
|
length_ %= divisor.length_;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Flushes the value in @c this. The current value is returned, and the internal value
|
||||||
|
is reset to zero.
|
||||||
|
*/
|
||||||
|
inline T flush() {
|
||||||
|
T result(length_);
|
||||||
|
length_ = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// operator int() is deliberately not provided, to avoid accidental subtitution of
|
// operator int() is deliberately not provided, to avoid accidental subtitution of
|
||||||
// classes that use this template.
|
// classes that use this template.
|
||||||
|
|
||||||
@ -81,7 +100,7 @@ template <class T> class WrappedInt {
|
|||||||
int length_;
|
int length_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! Describes an integer number of whole cycles — pairs of clock signal transitions. */
|
/// Describes an integer number of whole cycles — pairs of clock signal transitions.
|
||||||
class Cycles: public WrappedInt<Cycles> {
|
class Cycles: public WrappedInt<Cycles> {
|
||||||
public:
|
public:
|
||||||
inline Cycles(int l) : WrappedInt<Cycles>(l) {}
|
inline Cycles(int l) : WrappedInt<Cycles>(l) {}
|
||||||
@ -89,7 +108,7 @@ class Cycles: public WrappedInt<Cycles> {
|
|||||||
inline Cycles(const Cycles &cycles) : WrappedInt<Cycles>(cycles.length_) {}
|
inline Cycles(const Cycles &cycles) : WrappedInt<Cycles>(cycles.length_) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! Describes an integer number of half cycles — single clock signal transitions. */
|
/// Describes an integer number of half cycles — single clock signal transitions.
|
||||||
class HalfCycles: public WrappedInt<HalfCycles> {
|
class HalfCycles: public WrappedInt<HalfCycles> {
|
||||||
public:
|
public:
|
||||||
inline HalfCycles(int l) : WrappedInt<HalfCycles>(l) {}
|
inline HalfCycles(int l) : WrappedInt<HalfCycles>(l) {}
|
||||||
@ -102,23 +121,51 @@ class HalfCycles: public WrappedInt<HalfCycles> {
|
|||||||
/*!
|
/*!
|
||||||
ClockReceiver is a template for components that receove a clock, measured either
|
ClockReceiver is a template for components that receove a clock, measured either
|
||||||
in cycles or in half cycles. They are expected to implement either of the run_for
|
in cycles or in half cycles. They are expected to implement either of the run_for
|
||||||
methods; buying into the template means that the other run_for will automatically
|
methods and to declare that they are `using` the other; buying into the template
|
||||||
map appropriately to the implemented one, so callers may use either.
|
means that the other run_for will automatically map appropriately to the implemented
|
||||||
|
one, so callers may use either.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
template <class T> class ClockReceiver {
|
template <class T> class ClockReceiver {
|
||||||
public:
|
public:
|
||||||
|
ClockReceiver() : half_cycle_carry_(0) {}
|
||||||
|
|
||||||
inline void run_for(const Cycles &cycles) {
|
inline void run_for(const Cycles &cycles) {
|
||||||
static_cast<T *>(this)->run_for(HalfCycles(cycles));
|
static_cast<T *>(this)->run_for(HalfCycles(cycles));
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
int cycles = half_cycles.as_int() + half_cycle_carry_;
|
||||||
half_cycle_carry = cycles & 1;
|
half_cycle_carry_ = cycles & 1;
|
||||||
run_for(Cycles(cycles >> 1));
|
static_cast<T *>(this)->run_for(Cycles(cycles >> 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int half_cycle_carry;
|
int half_cycle_carry_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* ClockReceiver_hpp */
|
#endif /* ClockReceiver_hpp */
|
||||||
|
Loading…
Reference in New Issue
Block a user