libsidplayfp 1.8.8
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 "sidplayfp/event.h"
29#include "EventScheduler.h"
30
31class MOS6526;
32
38class Timer : private Event
39{
40protected:
41 static const int_least32_t CIAT_CR_START = 0x01;
42 static const int_least32_t CIAT_STEP = 0x04;
43 static const int_least32_t CIAT_CR_ONESHOT = 0x08;
44 static const int_least32_t CIAT_CR_FLOAD = 0x10;
45 static const int_least32_t CIAT_PHI2IN = 0x20;
46 static const int_least32_t CIAT_CR_MASK = CIAT_CR_START | CIAT_CR_ONESHOT | CIAT_CR_FLOAD | CIAT_PHI2IN;
47
48 static const int_least32_t CIAT_COUNT2 = 0x100;
49 static const int_least32_t CIAT_COUNT3 = 0x200;
50
51 static const int_least32_t CIAT_ONESHOT0 = 0x08 << 8;
52 static const int_least32_t CIAT_ONESHOT = 0x08 << 16;
53 static const int_least32_t CIAT_LOAD1 = 0x10 << 8;
54 static const int_least32_t CIAT_LOAD = 0x10 << 16;
55
56 static const int_least32_t CIAT_OUT = 0x80000000;
57
58private:
59 EventCallback<Timer> m_cycleSkippingEvent;
60
62 EventContext &event_context;
63
72 event_clock_t ciaEventPauseTime;
73
75 uint_least16_t timer;
76
78 uint_least16_t latch;
79
81 bool pbToggle;
82
84 uint8_t lastControlValue;
85
86protected:
89
91 int_least32_t state;
92
93private:
97 void cycleSkippingEvent();
98
102 void clock();
103
109 inline void reschedule();
110
114 void event();
115
119 virtual void underFlow() =0;
120
124 virtual void serialPort() {};
125
126protected:
134 Timer(const char* name, EventContext *context, MOS6526* parent) :
135 Event(name),
136 m_cycleSkippingEvent("Skip CIA clock decrement cycles", *this, &Timer::cycleSkippingEvent),
137 event_context(*context),
138 timer(0),
139 latch(0),
140 pbToggle(false),
141 lastControlValue(0),
142 parent(parent),
143 state(0) {}
144
145public:
151 void setControlRegister(uint8_t cr);
152
158 void syncWithCpu();
159
166
170 void reset();
171
178 void latchLo(uint8_t data);
179
186 void latchHi(uint8_t data);
187
194 inline void setPbToggle(bool state) { pbToggle = state; }
195
201 inline int_least32_t getState() const { return state; }
202
208 inline uint_least16_t getTimer() const { return timer; }
209
216 inline bool getPb(uint8_t reg) const { return (reg & 0x04) ? pbToggle : (state & CIAT_OUT); }
217};
218
219void Timer::reschedule()
220{
221 /* There are only two subcases to consider.
222 *
223 * - are we counting, and if so, are we going to
224 * continue counting?
225 * - have we stopped, and are there no conditions to force a new beginning?
226 *
227 * Additionally, there are numerous flags that are present only in passing manner,
228 * but which we need to let cycle through the CIA state machine.
229 */
230 const int_least32_t unwanted = CIAT_OUT | CIAT_CR_FLOAD | CIAT_LOAD1 | CIAT_LOAD;
231 if ((state & unwanted) != 0)
232 {
233 event_context.schedule(*this, 1);
234 return;
235 }
236
237 if ((state & CIAT_COUNT3) != 0)
238 {
239 /* Test the conditions that keep COUNT2 and thus COUNT3 alive, and also
240 * ensure that all of them are set indicating steady state operation. */
241
242 const int_least32_t wanted = CIAT_CR_START | CIAT_PHI2IN | CIAT_COUNT2 | CIAT_COUNT3;
243 if (timer > 2 && (state & wanted) == wanted)
244 {
245 /* we executed this cycle, therefore the pauseTime is +1. If we are called
246 * to execute on the very next clock, we need to get 0 because there's
247 * another timer-- in it. */
248 ciaEventPauseTime = event_context.getTime(EVENT_CLOCK_PHI1) + 1;
249 /* execute event slightly before the next underflow. */
250 event_context.schedule(m_cycleSkippingEvent, timer - 1);
251 return;
252 }
253
254 /* play safe, keep on ticking. */
255 event_context.schedule(*this, 1);
256 }
257 else
258 {
259 /* Test conditions that result in CIA activity in next clocks.
260 * If none, stop. */
261 const int_least32_t unwanted1 = CIAT_CR_START | CIAT_PHI2IN;
262 const int_least32_t unwanted2 = CIAT_CR_START | CIAT_STEP;
263
264 if ((state & unwanted1) == unwanted1
265 || (state & unwanted2) == unwanted2)
266 {
267 event_context.schedule(*this, 1);
268 return;
269 }
270
271 ciaEventPauseTime = -1;
272 }
273}
274
275#endif // TIMER_H
Definition: EventScheduler.h:31
Definition: event.h:108
virtual event_clock_t getTime(event_phase_t phase) const =0
virtual void schedule(Event &event, unsigned int cycles, event_phase_t phase)=0
Definition: event.h:51
Definition: mos6526.h:104
Definition: timer.h:39
int_least32_t getState() const
Definition: timer.h:201
void syncWithCpu()
Definition: timer.cpp:34
Timer(const char *name, EventContext *context, MOS6526 *parent)
Definition: timer.h:134
uint_least16_t getTimer() const
Definition: timer.h:208
bool getPb(uint8_t reg) const
Definition: timer.h:216
void reset()
Definition: timer.cpp:128
void setControlRegister(uint8_t cr)
Definition: timer.cpp:27
void wakeUpAfterSyncWithCpu()
Definition: timer.cpp:57
void setPbToggle(bool state)
Definition: timer.h:194
int_least32_t state
CRA/CRB control register / state.
Definition: timer.h:91
MOS6526 *const parent
Pointer to the MOS6526 which this Timer belongs to.
Definition: timer.h:88
void latchHi(uint8_t data)
Definition: timer.cpp:146
void latchLo(uint8_t data)
Definition: timer.cpp:139