1
0
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:
Thomas Harte 2017-07-27 07:40:02 -04:00
parent 847e49ccdf
commit 8361756dc4
17 changed files with 29 additions and 47 deletions

View File

@ -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 */

View File

@ -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,

View File

@ -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();

View File

@ -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.
*/

View File

@ -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);

View File

@ -11,6 +11,7 @@
#include "../../Processors/6502/6502.hpp"
#include "../../Storage/Tape/Tape.hpp"
#include "../../ClockReceiver/ClockReceiver.hpp"
#include "../ConfigurationTarget.hpp"
#include "../CRTMachine.hpp"

View File

@ -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,

View File

@ -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);

View File

@ -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();

View File

@ -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);
}

View File

@ -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_;

View File

@ -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();

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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 {

View File

@ -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.