libsidplayfp 2.15.0
timer.h
1/*
2 * This file is part of libsidplayfp, a SID player engine.
3 *
4 * Copyright 2011-2013 Leandro Nini <drfiemost@users.sourceforge.net>
5 * Copyright 2007-2010 Antti Lankila
6 * Copyright 2000 Simon White
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#ifndef TIMER_H
24#define TIMER_H
25
26#include <stdint.h>
27
28#include "Event.h"
29#include "EventCallback.h"
30#include "EventScheduler.h"
31
32#include "sidcxx11.h"
33
34namespace libsidplayfp
35{
36
37class MOS652X;
38
42class Timer : private Event
43{
44protected:
45 static constexpr int_least32_t CIAT_CR_START = 0x01;
46 static constexpr int_least32_t CIAT_STEP = 0x04;
47 static constexpr int_least32_t CIAT_CR_ONESHOT = 0x08;
48 static constexpr int_least32_t CIAT_CR_FLOAD = 0x10;
49 static constexpr int_least32_t CIAT_PHI2IN = 0x20;
50 static constexpr int_least32_t CIAT_CR_MASK = CIAT_CR_START | CIAT_CR_ONESHOT | CIAT_CR_FLOAD | CIAT_PHI2IN;
51
52 static constexpr int_least32_t CIAT_COUNT2 = 0x100;
53 static constexpr int_least32_t CIAT_COUNT3 = 0x200;
54
55 static constexpr int_least32_t CIAT_ONESHOT0 = 0x08 << 8;
56 static constexpr int_least32_t CIAT_ONESHOT = 0x08 << 16;
57 static constexpr int_least32_t CIAT_LOAD1 = 0x10 << 8;
58 static constexpr int_least32_t CIAT_LOAD = 0x10 << 16;
59
60 static constexpr int_least32_t CIAT_OUT = 0x80000000;
61
62private:
63 EventCallback<Timer> m_cycleSkippingEvent;
64
66 EventScheduler &eventScheduler;
67
76 event_clock_t ciaEventPauseTime;
77
79 bool pbToggle = false;
80
82 uint_least16_t timer = 0;
83
85 uint_least16_t latch = 0;
86
88 uint8_t lastControlValue = 0;
89
90protected:
93
95 int_least32_t state = 0;
96
97private:
101 void cycleSkippingEvent();
102
106 void clock();
107
113 inline void reschedule();
114
118 void event() override;
119
123 virtual void underFlow() =0;
124
128 virtual void serialPort() {}
129
130protected:
138 Timer(const char* name, EventScheduler &scheduler, MOS652X &parent) :
139 Event(name),
140 m_cycleSkippingEvent("Skip CIA clock decrement cycles", *this, &Timer::cycleSkippingEvent),
141 eventScheduler(scheduler),
142 parent(parent) {}
143
144public:
150 void setControlRegister(uint8_t cr);
151
157 void syncWithCpu();
158
165
169 void reset();
170
177 void latchLo(uint8_t data);
178
185 void latchHi(uint8_t data);
186
193 inline void setPbToggle(bool state) { pbToggle = state; }
194
200 inline int_least32_t getState() const { return state; }
201
207 inline uint_least16_t getTimer() const { return timer; }
208
215 inline bool getPb(uint8_t reg) const { return (reg & 0x04) ? pbToggle : (state & CIAT_OUT); }
216};
217
218void Timer::reschedule()
219{
220 // There are only two subcases to consider.
221 //
222 // - are we counting, and if so, are we going to
223 // continue counting?
224 // - have we stopped, and are there no conditions to force a new beginning?
225 //
226 // Additionally, there are numerous flags that are present only in passing manner,
227 // but which we need to let cycle through the CIA state machine.
228 const int_least32_t unwanted = CIAT_OUT | CIAT_CR_FLOAD | CIAT_LOAD1 | CIAT_LOAD;
229 if ((state & unwanted) != 0)
230 {
231 eventScheduler.schedule(*this, 1);
232 return;
233 }
234
235 if ((state & CIAT_COUNT3) != 0)
236 {
237 // Test the conditions that keep COUNT2 and thus COUNT3 alive, and also
238 // ensure that all of them are set indicating steady state operation.
239
240 const int_least32_t wanted = CIAT_CR_START | CIAT_PHI2IN | CIAT_COUNT2 | CIAT_COUNT3;
241 if (timer > 2 && (state & wanted) == wanted)
242 {
243 // we executed this cycle, therefore the pauseTime is +1. If we are called
244 // to execute on the very next clock, we need to get 0 because there's
245 // another timer-- in it.
246 ciaEventPauseTime = eventScheduler.getTime(EVENT_CLOCK_PHI1) + 1;
247 // execute event slightly before the next underflow.
248 eventScheduler.schedule(m_cycleSkippingEvent, timer - 1);
249 return;
250 }
251
252 // play safe, keep on ticking.
253 eventScheduler.schedule(*this, 1);
254 }
255 else
256 {
257 // Test conditions that result in CIA activity in next clocks.
258 // If none, stop.
259 const int_least32_t unwanted1 = CIAT_CR_START | CIAT_PHI2IN;
260 const int_least32_t unwanted2 = CIAT_CR_START | CIAT_STEP;
261
262 if ((state & unwanted1) == unwanted1
263 || (state & unwanted2) == unwanted2)
264 {
265 eventScheduler.schedule(*this, 1);
266 return;
267 }
268
269 ciaEventPauseTime = -1;
270 }
271}
272
273}
274
275#endif // TIMER_H
Definition EventCallback.h:36
Definition EventScheduler.h:62
event_clock_t getTime(event_phase_t phase) const
Definition EventScheduler.h:158
Definition Event.h:39
const char * name() const
Definition Event.h:72
Definition mos652x.h:154
Definition timer.h:43
void reset()
Definition timer.cpp:131
uint_least16_t getTimer() const
Definition timer.h:207
bool getPb(uint8_t reg) const
Definition timer.h:215
void wakeUpAfterSyncWithCpu()
Definition timer.cpp:60
int_least32_t getState() const
Definition timer.h:200
void syncWithCpu()
Definition timer.cpp:37
Timer(const char *name, EventScheduler &scheduler, MOS652X &parent)
Definition timer.h:138
int_least32_t state
CRA/CRB control register / state.
Definition timer.h:95
void latchHi(uint8_t data)
Definition timer.cpp:149
MOS652X & parent
Pointer to the MOS6526 which this Timer belongs to.
Definition timer.h:92
void latchLo(uint8_t data)
Definition timer.cpp:142
void setPbToggle(bool state)
Definition timer.h:193
void setControlRegister(uint8_t cr)
Definition timer.cpp:30