mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-23 05:29:23 +00:00
Switched definitively to the works-for-now approach of requiring an explicit opt-in where somebody wants to clock a whole-cycle receiver from a half-cycle clock.
This commit is contained in:
parent
847e49ccdf
commit
8361756dc4
@ -9,6 +9,8 @@
|
||||
#ifndef ClockReceiver_hpp
|
||||
#define ClockReceiver_hpp
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
/*!
|
||||
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.
|
||||
@ -118,13 +120,7 @@ class HalfCycles: public WrappedInt<HalfCycles> {
|
||||
inline HalfCycles(const HalfCycles &half_cycles) : WrappedInt<HalfCycles>(half_cycles.length_) {}
|
||||
};
|
||||
|
||||
/*!
|
||||
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
|
||||
methods and to declare that they are `using` the other; buying into the template
|
||||
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
|
||||
@ -150,22 +146,24 @@ class HalfCycles: public WrappedInt<HalfCycles> {
|
||||
of a full cycle. The second will do the second half. Etc.
|
||||
|
||||
*/
|
||||
template <class T> class ClockReceiver {
|
||||
|
||||
/*!
|
||||
If a component implements only run_for(Cycles), an owner can wrap it in HalfClockReceiver
|
||||
automatically to gain run_for(HalfCycles).
|
||||
*/
|
||||
template <class T> class HalfClockReceiver: public T {
|
||||
public:
|
||||
ClockReceiver() : half_cycle_carry_(0) {}
|
||||
|
||||
inline void run_for(const Cycles &cycles) {
|
||||
static_cast<T *>(this)->run_for(HalfCycles(cycles));
|
||||
}
|
||||
using T::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;
|
||||
static_cast<T *>(this)->run_for(Cycles(cycles >> 1));
|
||||
T::run_for(Cycles(cycles >> 1));
|
||||
}
|
||||
|
||||
private:
|
||||
int half_cycle_carry_;
|
||||
int half_cycle_carry_ = 0;
|
||||
};
|
||||
|
||||
#endif /* ClockReceiver_hpp */
|
||||
|
@ -13,8 +13,6 @@
|
||||
#include <typeinfo>
|
||||
#include <cstdio>
|
||||
|
||||
#include "../../ClockReceiver/ClockReceiver.hpp"
|
||||
|
||||
namespace MOS {
|
||||
|
||||
/*!
|
||||
@ -28,7 +26,7 @@ namespace MOS {
|
||||
Consumers should derive their own curiously-recurring-template-pattern subclass,
|
||||
implementing bus communications as required.
|
||||
*/
|
||||
template <class T> class MOS6522: public ClockReceiver<MOS6522<T>> {
|
||||
template <class T> class MOS6522 {
|
||||
private:
|
||||
enum InterruptFlag: uint8_t {
|
||||
CA2ActiveEdge = 1 << 0,
|
||||
|
@ -12,8 +12,6 @@
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
#include "../../ClockReceiver/ClockReceiver.hpp"
|
||||
|
||||
namespace MOS {
|
||||
|
||||
/*!
|
||||
@ -27,7 +25,7 @@ namespace MOS {
|
||||
Consumers should derive their own curiously-recurring-template-pattern subclass,
|
||||
implementing bus communications as required.
|
||||
*/
|
||||
template <class T> class MOS6532: public ClockReceiver<MOS6532<T>> {
|
||||
template <class T> class MOS6532 {
|
||||
public:
|
||||
inline void set_ram(uint16_t address, uint8_t value) { ram_[address&0x7f] = value; }
|
||||
inline uint8_t get_ram(uint16_t address) { return ram_[address & 0x7f]; }
|
||||
@ -106,7 +104,6 @@ template <class T> class MOS6532: public ClockReceiver<MOS6532<T>> {
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
using ClockReceiver<MOS6532<T>>::run_for;
|
||||
inline void run_for(const Cycles &cycles) {
|
||||
unsigned int number_of_cycles = (unsigned int)cycles.as_int();
|
||||
|
||||
|
@ -41,7 +41,7 @@ class Speaker: public ::Outputs::Filter<Speaker> {
|
||||
|
||||
@c set_register and @c get_register provide register access.
|
||||
*/
|
||||
template <class T> class MOS6560: public ClockReceiver<MOS6560<T>> {
|
||||
template <class T> class MOS6560 {
|
||||
public:
|
||||
MOS6560() :
|
||||
crt_(new Outputs::CRT::CRT(65*4, 4, Outputs::CRT::NTSC60, 2)),
|
||||
@ -147,7 +147,6 @@ template <class T> class MOS6560: public ClockReceiver<MOS6560<T>> {
|
||||
}
|
||||
}
|
||||
|
||||
using ClockReceiver<MOS6560<T>>::run_for;
|
||||
/*!
|
||||
Runs for cycles. Derr.
|
||||
*/
|
||||
|
@ -12,11 +12,10 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "../CRTMachine.hpp"
|
||||
#include "../../ClockReceiver/ClockReceiver.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
|
||||
class TIA: public ClockReceiver<TIA> {
|
||||
class TIA {
|
||||
public:
|
||||
TIA();
|
||||
// The supplied hook is for unit testing only; if instantiated with a line_end_function then it will
|
||||
@ -32,7 +31,6 @@ class TIA: public ClockReceiver<TIA> {
|
||||
Advances the TIA by @c cycles. Any queued setters take effect in the first cycle performed.
|
||||
*/
|
||||
void run_for(const Cycles &cycles);
|
||||
using ClockReceiver<TIA>::run_for;
|
||||
void set_output_mode(OutputMode output_mode);
|
||||
|
||||
void set_sync(bool sync);
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "../../Processors/6502/6502.hpp"
|
||||
#include "../../Storage/Tape/Tape.hpp"
|
||||
#include "../../ClockReceiver/ClockReceiver.hpp"
|
||||
|
||||
#include "../ConfigurationTarget.hpp"
|
||||
#include "../CRTMachine.hpp"
|
||||
|
@ -22,7 +22,7 @@ namespace Electron {
|
||||
running either at 40 or 80 columns. Memory is shared between video and CPU; when the video
|
||||
is accessing it the CPU may not.
|
||||
*/
|
||||
class VideoOutput: public ClockReceiver<VideoOutput> {
|
||||
class VideoOutput {
|
||||
public:
|
||||
/*!
|
||||
Instantiates a VideoOutput that will read its pixels from @c memory. The pointer supplied
|
||||
@ -35,7 +35,6 @@ class VideoOutput: public ClockReceiver<VideoOutput> {
|
||||
|
||||
/// Produces the next @c cycles of video output.
|
||||
void run_for(const Cycles &cycles);
|
||||
using ClockReceiver<VideoOutput>::run_for;
|
||||
|
||||
/*!
|
||||
Writes @c value to the register at @c address. May mutate the results of @c get_next_interrupt,
|
||||
|
@ -14,12 +14,11 @@
|
||||
|
||||
namespace Oric {
|
||||
|
||||
class VideoOutput: public ClockReceiver<VideoOutput> {
|
||||
class VideoOutput {
|
||||
public:
|
||||
VideoOutput(uint8_t *memory);
|
||||
std::shared_ptr<Outputs::CRT::CRT> get_crt();
|
||||
void run_for(const Cycles &cycles);
|
||||
using ClockReceiver<VideoOutput>::run_for;
|
||||
void set_colour_rom(const std::vector<uint8_t> &rom);
|
||||
void set_output_device(Outputs::CRT::OutputDevice output_device);
|
||||
|
||||
|
@ -24,7 +24,7 @@ namespace ZX8081 {
|
||||
a 1-bit graphic and output over the next 4 cycles, picking between the white level
|
||||
and the black level.
|
||||
*/
|
||||
class Video: public ClockReceiver<Video> {
|
||||
class Video {
|
||||
public:
|
||||
/// Constructs an instance of the video feed; a CRT is also created.
|
||||
Video();
|
||||
@ -33,7 +33,6 @@ class Video: public ClockReceiver<Video> {
|
||||
|
||||
/// Advances time by @c cycles.
|
||||
void run_for(const HalfCycles &);
|
||||
using ClockReceiver<Video>::run_for;
|
||||
/// Forces output to catch up to the current output position.
|
||||
void flush();
|
||||
|
||||
|
@ -180,7 +180,8 @@ HalfCycles Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &c
|
||||
default: break;
|
||||
}
|
||||
|
||||
if(typer_) typer_->update(cycle.length.as_int());
|
||||
// This will lose some precision; TODO: bring inside the [Half]ClockReceiver domain.
|
||||
if(typer_) typer_->update(cycle.length.as_int() / 2);
|
||||
|
||||
return HalfCycles(0);
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ class Machine:
|
||||
void set_hsync(bool sync);
|
||||
void update_sync();
|
||||
|
||||
Storage::Tape::BinaryTapePlayer tape_player_;
|
||||
HalfClockReceiver<Storage::Tape::BinaryTapePlayer> tape_player_;
|
||||
Storage::Tape::ZX8081::Parser parser_;
|
||||
|
||||
bool is_zx81_;
|
||||
|
@ -135,7 +135,7 @@ class Speaker {
|
||||
|
||||
Call `run_for` to request that the next period of input data is collected.
|
||||
*/
|
||||
template <class T> class Filter: public Speaker, public ClockReceiver<Filter<T>> {
|
||||
template <class T> class Filter: public Speaker {
|
||||
public:
|
||||
~Filter() {
|
||||
_queue->flush();
|
||||
|
@ -128,7 +128,7 @@ class ProcessorBase {
|
||||
that will cause call outs when the program counter reaches those addresses. @c return_from_subroutine can be used to exit from a
|
||||
jammed state.
|
||||
*/
|
||||
template <class T> class Processor: public ProcessorBase, public ClockReceiver<Processor<T>> {
|
||||
template <class T> class Processor: public ProcessorBase {
|
||||
private:
|
||||
const MicroOp *scheduled_program_counter_;
|
||||
|
||||
@ -283,7 +283,6 @@ template <class T> class Processor: public ProcessorBase, public ClockReceiver<P
|
||||
}
|
||||
|
||||
public:
|
||||
using ClockReceiver<Processor<T>>::run_for;
|
||||
/*!
|
||||
Runs the 6502 for a supplied number of cycles.
|
||||
|
||||
|
@ -164,7 +164,7 @@ struct PartialMachineCycle {
|
||||
order to provide the bus on which the Z80 operates and @c flush(), which is called upon completion of a continuous run
|
||||
of cycles to allow a subclass to bring any on-demand activities up to date.
|
||||
*/
|
||||
template <class T> class Processor: public ClockReceiver<Processor<T>> {
|
||||
template <class T> class Processor {
|
||||
private:
|
||||
uint8_t a_;
|
||||
RegisterPair bc_, de_, hl_;
|
||||
@ -849,7 +849,6 @@ template <class T> class Processor: public ClockReceiver<Processor<T>> {
|
||||
copy_program(irq_mode2_program, irq_program_[2]);
|
||||
}
|
||||
|
||||
using ClockReceiver<Processor<T>>::run_for;
|
||||
/*!
|
||||
Runs the Z80 for a supplied number of cycles.
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace Storage {
|
||||
|
||||
class DigitalPhaseLockedLoop: public ClockReceiver<DigitalPhaseLockedLoop> {
|
||||
class DigitalPhaseLockedLoop {
|
||||
public:
|
||||
/*!
|
||||
Instantiates a @c DigitalPhaseLockedLoop.
|
||||
@ -32,7 +32,6 @@ class DigitalPhaseLockedLoop: public ClockReceiver<DigitalPhaseLockedLoop> {
|
||||
@c number_of_cycles The time to run the loop for.
|
||||
*/
|
||||
void run_for(const Cycles &cycles);
|
||||
using ClockReceiver<DigitalPhaseLockedLoop>::run_for;
|
||||
|
||||
/*!
|
||||
Announces a pulse at the current time.
|
||||
|
@ -101,7 +101,6 @@ class TapePlayer: public TimedEventLoop {
|
||||
bool has_tape();
|
||||
std::shared_ptr<Storage::Tape::Tape> get_tape();
|
||||
|
||||
using TimedEventLoop::run_for;
|
||||
void run_for(const Cycles &cycles);
|
||||
|
||||
void run_for_input_pulse();
|
||||
@ -132,7 +131,6 @@ class BinaryTapePlayer: public TapePlayer {
|
||||
void set_tape_output(bool set);
|
||||
bool get_input();
|
||||
|
||||
using TapePlayer::run_for;
|
||||
void run_for(const Cycles &cycles);
|
||||
|
||||
class Delegate {
|
||||
|
@ -10,7 +10,6 @@
|
||||
#define TimedEventLoop_hpp
|
||||
|
||||
#include "Storage.hpp"
|
||||
|
||||
#include "../ClockReceiver/ClockReceiver.hpp"
|
||||
#include "../SignalProcessing/Stepper.hpp"
|
||||
|
||||
@ -38,7 +37,7 @@ namespace Storage {
|
||||
@c reset_timer to initiate a distinctly-timed stream or @c jump_to_next_event to short-circuit the timing
|
||||
loop and fast forward immediately to the next event.
|
||||
*/
|
||||
class TimedEventLoop: public ClockReceiver<TimedEventLoop> {
|
||||
class TimedEventLoop {
|
||||
public:
|
||||
/*!
|
||||
Constructs a timed event loop that will be clocked at @c input_clock_rate.
|
||||
@ -49,7 +48,6 @@ namespace Storage {
|
||||
Advances the event loop by @c number_of_cycles cycles.
|
||||
*/
|
||||
void run_for(const Cycles &cycles);
|
||||
using ClockReceiver<TimedEventLoop>::run_for;
|
||||
|
||||
/*!
|
||||
@returns the number of whole cycles remaining until the next event is triggered.
|
||||
|
Loading…
Reference in New Issue
Block a user