VirtualC64 v5.0 beta
Commodore 64 Emulator
Loading...
Searching...
No Matches
TimeDelayed.h
1// -----------------------------------------------------------------------------
2// This file is part of VirtualC64
3//
4// Copyright (C) Dirk W. Hoffmann. www.dirkwhoffmann.de
5// This FILE is dual-licensed. You are free to choose between:
6//
7// - The GNU General Public License v3 (or any later version)
8// - The Mozilla Public License v2
9//
10// SPDX-License-Identifier: GPL-3.0-or-later OR MPL-2.0
11// -----------------------------------------------------------------------------
12
13#pragma once
14
15#include "Macros.h"
16#include "Serializable.h"
17#include <algorithm>
18
19namespace vc64 {
20
21template <class T, isize delay> class TimeDelayed : public Serializable {
22
23 static constexpr isize capacity = delay + 1;
24
25 /* Value pipeline (history buffer)
26 *
27 * pipeline[0] : Value that was written at time timeStamp
28 * pipeline[n] : Value that was written at time timeStamp - n
29 */
30 T pipeline[capacity];
31
32 // Remembers the time of the most recent call to write()
33 i64 timeStamp = 0;
34
35 // Pointer to the reference clock
36 i64 *clock = nullptr;
37
38
39 //
40 // Initializing
41 //
42
43public:
44
45 TimeDelayed(i64 *clock) {
46
47 timeStamp = 0;
48 this->clock = clock;
49 clear();
50 }
51
52 TimeDelayed() : TimeDelayed(nullptr) { };
53
54 TimeDelayed<T,delay>& operator= (const TimeDelayed<T,delay>& other) {
55
56 std::copy(std::begin(other.pipeline), std::end(other.pipeline), std::begin(pipeline));
57 timeStamp = other.timeStamp;
58
59 return *this;
60 }
61
62 // Sets the reference clock (either the C64 clock or a drive clock)
63 void setClock(i64 *clock) { this->clock = clock; }
64
65 // Overwrites all pipeline entries with a reset value
66 void reset(T value) {
67 for (isize i = 0; i < capacity; i++) pipeline[i] = value;
68 timeStamp = 0;
69 }
70
71 // Zeroes out all pipeline entries
72 void clear() { reset((T)0); }
73
74 // Checks if the pipeline is zeroed out
75 bool isClear() {
76 for (isize i = 0; i < capacity; i++) if (pipeline[i]) return false;
77 return true;
78 }
79
80
81 //
82 // Serializing
83 //
84
85public:
86
87 template <class W>
88 void serialize(W& worker)
89 {
90 worker
91
92 << pipeline
93 << timeStamp;
94
95 } SERIALIZERS(serialize);
96
97
98 //
99 // Accessing
100 //
101
102 // Write a value into the pipeline
103 void write(T value) { writeWithDelay(value, 0); }
104
105 // Work horse for writing a value
106 void writeWithDelay(T value, u8 waitCycles) {
107
108 i64 referenceTime = *clock + waitCycles;
109
110 // Shift pipeline
111 i64 diff = referenceTime - timeStamp;
112 for (isize i = capacity - 1; i >= 0; i--) {
113 pipeline[i] = (i - diff > 0) ? pipeline[i - diff] : pipeline[0];
114 }
115
116 // Assign new value
117 timeStamp = referenceTime;
118 pipeline[0] = value;
119 }
120
121 // Reads the most recent pipeline element
122 T current() const { return pipeline[0]; }
123
124 // Reads a value from the pipeline with the standard delay
125 T delayed() const {
126 i64 offset = timeStamp - *clock + delay;
127 if (likely(offset <= 0)) {
128 return pipeline[0];
129 } else {
130 return pipeline[offset];
131 }
132 }
133
134 // Reads a value from the pipeline with a custom delay
135 T readWithDelay(u8 d) const {
136 assert(d <= this->capacity);
137 return pipeline[std::max(0LL, timeStamp - *clock + d)];
138 }
139};
140
141}
VirtualC64 project namespace.
Definition CmdQueue.cpp:16