libsidplayfp 2.4.2
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 const int_least32_t CIAT_CR_START = 0x01;
46 static const int_least32_t CIAT_STEP = 0x04;
47 static const int_least32_t CIAT_CR_ONESHOT = 0x08;
48 static const int_least32_t CIAT_CR_FLOAD = 0x10;
49 static const int_least32_t CIAT_PHI2IN = 0x20;
50 static const int_least32_t CIAT_CR_MASK = CIAT_CR_START | CIAT_CR_ONESHOT | CIAT_CR_FLOAD | CIAT_PHI2IN;
51
52 static const int_least32_t CIAT_COUNT2 = 0x100;
53 static const int_least32_t CIAT_COUNT3 = 0x200;
54
55 static const int_least32_t CIAT_ONESHOT0 = 0x08 << 8;
56 static const int_least32_t CIAT_ONESHOT = 0x08 << 16;
57 static const int_least32_t CIAT_LOAD1 = 0x10 << 8;
58 static const int_least32_t CIAT_LOAD = 0x10 << 16;
59
60 static const 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;
80
82 uint_least16_t timer;
83
85 uint_least16_t latch;
86
88 uint8_t lastControlValue;
89
90protected:
93
95 int_least32_t state;
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 pbToggle(false),
143 timer(0),
144 latch(0),
145 lastControlValue(0),
146 parent(parent),
147 state(0) {}
148
149public:
155 void setControlRegister(uint8_t cr);
156
162 void syncWithCpu();
163
170
174 void reset();
175
182 void latchLo(uint8_t data);
183
190 void latchHi(uint8_t data);
191
198 inline void setPbToggle(bool state) { pbToggle = state; }
199
205 inline int_least32_t getState() const { return state; }
206
212 inline uint_least16_t getTimer() const { return timer; }
213
220 inline bool getPb(uint8_t reg) const { return (reg & 0x04) ? pbToggle : (state & CIAT_OUT); }
221};
222
223void Timer::reschedule()
224{
225 // There are only two subcases to consider.
226 //
227 // - are we counting, and if so, are we going to
228 // continue counting?
229 // - have we stopped, and are there no conditions to force a new beginning?
230 //
231 // Additionally, there are numerous flags that are present only in passing manner,
232 // but which we need to let cycle through the CIA state machine.
233 const int_least32_t unwanted = CIAT_OUT | CIAT_CR_FLOAD | CIAT_LOAD1 | CIAT_LOAD;
234 if ((state & unwanted) != 0)
235 {
236 eventScheduler.schedule(*this, 1);
237 return;
238 }
239
240 if ((state & CIAT_COUNT3) != 0)
241 {
242 // Test the conditions that keep COUNT2 and thus COUNT3 alive, and also
243 // ensure that all of them are set indicating steady state operation.
244
245 const int_least32_t wanted = CIAT_CR_START | CIAT_PHI2IN | CIAT_COUNT2 | CIAT_COUNT3;
246 if (timer > 2 && (state & wanted) == wanted)
247 {
248 // we executed this cycle, therefore the pauseTime is +1. If we are called
249 // to execute on the very next clock, we need to get 0 because there's
250 // another timer-- in it.
251 ciaEventPauseTime = eventScheduler.getTime(EVENT_CLOCK_PHI1) + 1;
252 // execute event slightly before the next underflow.
253 eventScheduler.schedule(m_cycleSkippingEvent, timer - 1);
254 return;
255 }
256
257 // play safe, keep on ticking.
258 eventScheduler.schedule(*this, 1);
259 }
260 else
261 {
262 // Test conditions that result in CIA activity in next clocks.
263 // If none, stop.
264 const int_least32_t unwanted1 = CIAT_CR_START | CIAT_PHI2IN;
265 const int_least32_t unwanted2 = CIAT_CR_START | CIAT_STEP;
266
267 if ((state & unwanted1) == unwanted1
268 || (state & unwanted2) == unwanted2)
269 {
270 eventScheduler.schedule(*this, 1);
271 return;
272 }
273
274 ciaEventPauseTime = -1;
275 }
276}
277
278}
279
280#endif // TIMER_H
Definition EventCallback.h:36
Definition EventScheduler.h:62
event_clock_t getTime(event_phase_t phase) const
Definition EventScheduler.h:162
Definition Event.h:39
Definition mos652x.h:154
Definition timer.h:43
void reset()
Definition timer.cpp:131
uint_least16_t getTimer() const
Definition timer.h:212
bool getPb(uint8_t reg) const
Definition timer.h:220
void wakeUpAfterSyncWithCpu()
Definition timer.cpp:60
int_least32_t getState() const
Definition timer.h:205
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:198
void setControlRegister(uint8_t cr)
Definition timer.cpp:30