OXYGENHUB
◆ main openmsx / src / serial / ClockPin.cc
2.7 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "ClockPin.hh"
2
3
#include "serialize.hh"
4
5
#include <cassert>
6
7
namespace openmsx {
8
9
ClockPin::ClockPin(Scheduler& scheduler_, ClockPinListener* listener_)
10
	: Schedulable(scheduler_), listener(listener_)
11
{
12
}
13
14
void ClockPin::setState(bool newStatus, EmuTime time)
15
{
16
	periodic = false;
17
	if (signalEdge) {
18
		unschedule();
19
	}
20
	if (signalEdge && !status && newStatus) {
21
		// pos edge
22
		status = newStatus;
23
		if (listener) {
24
			listener->signalPosEdge(*this, time);
25
		}
26
	} else {
27
		status = newStatus;
28
	}
29
	if (listener) {
30
		listener->signal(*this, time);
31
	}
32
}
33
34
void ClockPin::setPeriodicState(EmuDuration total,
35
	EmuDuration hi, EmuTime time)
36
{
37
	referenceTime = time;
38
	totalDur = total;
39
	hiDur = hi;
40
41
	if (listener) {
42
		if (periodic) {
43
			unschedule();
44
		}
45
		periodic = true;
46
		if (signalEdge) {
47
			executeUntil(time);
48
		}
49
		listener->signal(*this, time);
50
	} else {
51
		periodic = true;
52
	}
53
}
54
55
56
bool ClockPin::getState(EmuTime time) const
57
{
58
	if (!periodic) {
59
		return status;
60
	} else {
61
		return ((time - referenceTime) % totalDur) < hiDur;
62
	}
63
}
64
65
EmuDuration ClockPin::getTotalDuration() const
66
{
67
	assert(periodic);
68
	return totalDur;
69
}
70
71
EmuDuration ClockPin::getHighDuration() const
72
{
73
	assert(periodic);
74
	return hiDur;
75
}
76
77
unsigned ClockPin::getTicksBetween(EmuTime begin, EmuTime end) const
78
{
79
	assert(begin <= end);
80
	if (!periodic) {
81
		return 0;
82
	}
83
	if (totalDur > EmuDuration::zero()) {
84
		auto a = (begin < referenceTime)
85
		       ? 0
86
		       : (begin - referenceTime) / totalDur;
87
		auto b = (end   - referenceTime) / totalDur;
88
		return b - a;
89
	} else {
90
		return 0;
91
	}
92
}
93
94
95
void ClockPin::generateEdgeSignals(bool wanted, EmuTime time)
96
{
97
	if (signalEdge != wanted) {
98
		signalEdge = wanted;
99
		if (periodic) {
100
			if (signalEdge) {
101
				EmuTime tmp(referenceTime);
102
				while (tmp < time) {
103
					tmp += totalDur;
104
				}
105
				if (listener) {
106
					schedule(tmp);
107
				}
108
			} else {
109
				unschedule();
110
			}
111
		}
112
	}
113
}
114
115
void ClockPin::unschedule()
116
{
117
	removeSyncPoint();
118
}
119
120
void ClockPin::schedule(EmuTime time)
121
{
122
	assert(signalEdge && periodic && listener);
123
	setSyncPoint(time);
124
}
125
126
void ClockPin::executeUntil(EmuTime time)
127
{
128
	assert(signalEdge && periodic && listener);
129
	listener->signalPosEdge(*this, time);
130
	if (signalEdge && (totalDur > EmuDuration::zero())) {
131
		schedule(time + totalDur);
132
	}
133
}
134
135
136
template<typename Archive>
137
void ClockPin::serialize(Archive& ar, unsigned /*version*/)
138
{
139
	ar.template serializeBase<Schedulable>(*this);
140
	ar.serialize("totalDur",      totalDur,
141
	             "hiDur",         hiDur,
142
	             "referenceTime", referenceTime,
143
	             "periodic",      periodic,
144
	             "status",        status,
145
	             "signalEdge",    signalEdge);
146
}
147
INSTANTIATE_SERIALIZE_METHODS(ClockPin);
148
149
} // namespace openmsx