libsidplayfp  1.8.3
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 
31 class MOS6526;
32 
38 class Timer : private Event
39 {
40 protected:
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 
58 private:
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 
86 protected:
88  MOS6526* const parent;
89 
91  int_least32_t state;
92 
93 private:
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 
126 protected:
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 
145 public:
151  void setControlRegister(uint8_t cr);
152 
158  void syncWithCpu();
159 
165  void wakeUpAfterSyncWithCpu();
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 
219 void 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: mos6526.h:103
void reset()
Definition: timer.cpp:128
void latchLo(uint8_t data)
Definition: timer.cpp:139
void setPbToggle(bool state)
Definition: timer.h:194
bool getPb(uint8_t reg) const
Definition: timer.h:216
Definition: event.h:107
Timer(const char *name, EventContext *context, MOS6526 *parent)
Definition: timer.h:134
virtual void schedule(Event &event, unsigned int cycles, event_phase_t phase)=0
int_least32_t getState() const
Definition: timer.h:201
MOS6526 *const parent
Pointer to the MOS6526 which this Timer belongs to.
Definition: timer.h:88
int_least32_t state
CRA/CRB control register / state.
Definition: timer.h:91
uint_least16_t getTimer() const
Definition: timer.h:208
void latchHi(uint8_t data)
Definition: timer.cpp:146
Definition: event.h:50
void syncWithCpu()
Definition: timer.cpp:34
virtual event_clock_t getTime(event_phase_t phase) const =0
void wakeUpAfterSyncWithCpu()
Definition: timer.cpp:57
Definition: timer.h:38
void setControlRegister(uint8_t cr)
Definition: timer.cpp:27