libsidplayfp  2.0.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 
34 namespace libsidplayfp
35 {
36 
37 class MOS6526;
38 
42 class Timer : private Event
43 {
44 protected:
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 
62 private:
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 
90 protected:
93 
95  int_least32_t state;
96 
97 private:
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 
130 protected:
138  Timer(const char* name, EventScheduler &scheduler, MOS6526 &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 
149 public:
155  void setControlRegister(uint8_t cr);
156 
162  void syncWithCpu();
163 
169  void wakeUpAfterSyncWithCpu();
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 
223 void 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
libsidplayfp::Timer::reset
void reset()
Definition: timer.cpp:131
libsidplayfp::MOS6526
Definition: mos6526.h:182
libsidplayfp::EventScheduler
Definition: EventScheduler.h:62
libsidplayfp::Timer::getState
int_least32_t getState() const
Definition: timer.h:205
libsidplayfp::Timer::getPb
bool getPb(uint8_t reg) const
Definition: timer.h:220
libsidplayfp::Timer::wakeUpAfterSyncWithCpu
void wakeUpAfterSyncWithCpu()
Definition: timer.cpp:60
libsidplayfp::Timer::latchHi
void latchHi(uint8_t data)
Definition: timer.cpp:149
libsidplayfp::EventScheduler::getTime
event_clock_t getTime(event_phase_t phase) const
Definition: EventScheduler.h:162
libsidplayfp::Timer::state
int_least32_t state
CRA/CRB control register / state.
Definition: timer.h:95
libsidplayfp::Timer::syncWithCpu
void syncWithCpu()
Definition: timer.cpp:37
libsidplayfp::Timer
Definition: timer.h:43
libsidplayfp::Timer::setPbToggle
void setPbToggle(bool state)
Definition: timer.h:198
libsidplayfp::Timer::setControlRegister
void setControlRegister(uint8_t cr)
Definition: timer.cpp:30
libsidplayfp::Timer::getTimer
uint_least16_t getTimer() const
Definition: timer.h:212
libsidplayfp::Timer::Timer
Timer(const char *name, EventScheduler &scheduler, MOS6526 &parent)
Definition: timer.h:138
libsidplayfp::Timer::parent
MOS6526 & parent
Pointer to the MOS6526 which this Timer belongs to.
Definition: timer.h:92
libsidplayfp::Timer::latchLo
void latchLo(uint8_t data)
Definition: timer.cpp:142
libsidplayfp::Event
Definition: Event.h:39
libsidplayfp::EventCallback
Definition: EventCallback.h:36