libsidplayfp  1.4.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 "sidplayfp/event.h"
29 #include "sidplayfp/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 
64  EventContext &event_context;
65 
74  event_clock_t ciaEventPauseTime;
75 
79  uint_least16_t timer;
80 
84  uint_least16_t latch;
85 
89  bool pbToggle;
90 
94  uint8_t lastControlValue;
95 
96 protected:
100  MOS6526* const parent;
101 
105  int_least32_t state;
106 
107 private:
111  void cycleSkippingEvent();
112 
116  void clock();
117 
123  inline void reschedule();
124 
128  void event();
129 
133  virtual void underFlow() =0;
134 
138  virtual void serialPort() {};
139 
140 protected:
148  Timer(const char* name, EventContext *context, MOS6526* parent) :
149  Event(name),
150  m_cycleSkippingEvent("Skip CIA clock decrement cycles", *this, &Timer::cycleSkippingEvent),
151  event_context(*context),
152  timer(0),
153  latch(0),
154  pbToggle(false),
155  lastControlValue(0),
156  parent(parent),
157  state(0) {}
158 
159 public:
166  void setControlRegister(uint8_t cr);
167 
173  void syncWithCpu();
174 
180  void wakeUpAfterSyncWithCpu();
181 
185  void reset();
186 
193  void latchLo(uint8_t data);
194 
201  void latchHi(uint8_t data);
202 
209  inline void setPbToggle(bool state) { pbToggle = state; }
210 
216  inline int_least32_t getState() const { return state; }
217 
223  inline uint_least16_t getTimer() const { return timer; }
224 
231  inline bool getPb(uint8_t reg) const { return (reg & 0x04) ? pbToggle : (state & CIAT_OUT); }
232 };
233 
234 void Timer::reschedule()
235 {
236  /* There are only two subcases to consider.
237  *
238  * - are we counting, and if so, are we going to
239  * continue counting?
240  * - have we stopped, and are there no conditions to force a new beginning?
241  *
242  * Additionally, there are numerous flags that are present only in passing manner,
243  * but which we need to let cycle through the CIA state machine.
244  */
245  const int_least32_t unwanted = CIAT_OUT | CIAT_CR_FLOAD | CIAT_LOAD1 | CIAT_LOAD;
246  if ((state & unwanted) != 0)
247  {
248  event_context.schedule(*this, 1);
249  return;
250  }
251 
252  if ((state & CIAT_COUNT3) != 0)
253  {
254  /* Test the conditions that keep COUNT2 and thus COUNT3 alive, and also
255  * ensure that all of them are set indicating steady state operation. */
256 
257  const int_least32_t wanted = CIAT_CR_START | CIAT_PHI2IN | CIAT_COUNT2 | CIAT_COUNT3;
258  if (timer > 2 && (state & wanted) == wanted)
259  {
260  /* we executed this cycle, therefore the pauseTime is +1. If we are called
261  * to execute on the very next clock, we need to get 0 because there's
262  * another timer-- in it. */
263  ciaEventPauseTime = event_context.getTime(EVENT_CLOCK_PHI1) + 1;
264  /* execute event slightly before the next underflow. */
265  event_context.schedule(m_cycleSkippingEvent, timer - 1);
266  return;
267  }
268 
269  /* play safe, keep on ticking. */
270  event_context.schedule(*this, 1);
271  }
272  else
273  {
274  /* Test conditions that result in CIA activity in next clocks.
275  * If none, stop. */
276  const int_least32_t unwanted1 = CIAT_CR_START | CIAT_PHI2IN;
277  const int_least32_t unwanted2 = CIAT_CR_START | CIAT_STEP;
278 
279  if ((state & unwanted1) == unwanted1
280  || (state & unwanted2) == unwanted2)
281  {
282  event_context.schedule(*this, 1);
283  return;
284  }
285 
286  ciaEventPauseTime = -1;
287  }
288 }
289 
290 #endif // TIMER_H
Definition: mos6526.h:102
void reset()
Definition: timer.cpp:128
void latchLo(uint8_t data)
Definition: timer.cpp:139
void setPbToggle(bool state)
Definition: timer.h:209
bool getPb(uint8_t reg) const
Definition: timer.h:231
Definition: event.h:101
Timer(const char *name, EventContext *context, MOS6526 *parent)
Definition: timer.h:148
int_least32_t getState() const
Definition: timer.h:216
MOS6526 *const parent
Definition: timer.h:100
virtual void schedule(Event &event, event_clock_t cycles, event_phase_t phase)=0
int_least32_t state
Definition: timer.h:105
uint_least16_t getTimer() const
Definition: timer.h:223
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