libsidplayfp  0.3.5
mos6526.h
1 /***************************************************************************
2  mos6526.h - CIA timer to produce interrupts
3  -------------------
4  begin : Wed Jun 7 2000
5  copyright : (C) 2000 by Simon White
6  email : s_a_white@email.com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #ifndef MOS6526_H
19 #define MOS6526_H
20 
21 #include "sidplayfp/component.h"
22 #include "sidplayfp/event.h"
23 
24 class MOS6526;
25 
32 class Timer : private Event {
33 
34 protected:
35  static const int_least32_t CIAT_CR_START = 0x01;
36  static const int_least32_t CIAT_STEP = 0x04;
37  static const int_least32_t CIAT_CR_ONESHOT = 0x08;
38  static const int_least32_t CIAT_CR_FLOAD = 0x10;
39  static const int_least32_t CIAT_PHI2IN = 0x20;
40  static const int_least32_t CIAT_CR_MASK = CIAT_CR_START | CIAT_CR_ONESHOT | CIAT_CR_FLOAD | CIAT_PHI2IN;
41 
42  static const int_least32_t CIAT_COUNT2 = 0x100;
43  static const int_least32_t CIAT_COUNT3 = 0x200;
44 
45  static const int_least32_t CIAT_ONESHOT0 = 0x08 << 8;
46  static const int_least32_t CIAT_ONESHOT = 0x08 << 16;
47  static const int_least32_t CIAT_LOAD1 = 0x10 << 8;
48  static const int_least32_t CIAT_LOAD = 0x10 << 16;
49 
50  static const int_least32_t CIAT_OUT = 0x80000000;
51 
52 private:
56  EventContext &event_context;
57 
66  event_clock_t ciaEventPauseTime;
67 
71  uint_least16_t timer;
72 
76  uint_least16_t latch;
77 
81  bool pbToggle;
82 
86  uint8_t lastControlValue;
87 
88  EventCallback<Timer> m_cycleSkippingEvent;
89 
90 protected:
95 
99  int_least32_t state;
100 
101 private:
105  void cycleSkippingEvent(void);
106 
110  void clock();
111 
117  inline void reschedule();
118 
122  void event();
123 
127  virtual void underFlow() =0;
128 
132  virtual void serialPort() {};
133 
134 protected:
142  Timer(const char* name, EventContext *context, MOS6526* parent) :
143  Event(name),
144  event_context(*context),
145  timer(0),
146  latch(0),
147  pbToggle(false),
148  lastControlValue(0),
149  m_cycleSkippingEvent("Skip CIA clock decrement cycles", *this, &Timer::cycleSkippingEvent),
150  parent(parent),
151  state(0) {}
152 
153 public:
160  void setControlRegister(const uint8_t cr);
161 
167  void syncWithCpu();
168 
174  void wakeUpAfterSyncWithCpu();
175 
179  void reset();
180 
187  void latchLo(const uint8_t data);
188 
195  void latchHi(const uint8_t data);
196 
203  inline void setPbToggle(const bool state) { pbToggle = state; }
204 
210  inline int_least32_t getState() const { return state; }
211 
217  inline uint_least16_t getTimer() const { return timer; }
218 
225  inline bool getPb(const uint8_t reg) const { return (reg & 0x04) ? pbToggle : (state & CIAT_OUT); }
226 };
227 
234 class TimerA : public Timer {
235 private:
239  void underFlow();
240 
241  void serialPort();
242 
243 public:
248  Timer("CIA Timer A", context, parent) {}
249 };
250 
257 class TimerB : public Timer {
258 private:
259  void underFlow();
260 
261 public:
266  Timer("CIA Timer B", context, parent) {}
267 
271  void cascade() {
272  /* we pretend that we are CPU doing a write to ctrl register */
273  syncWithCpu();
274  state |= CIAT_STEP;
276  }
277 
283  bool started() const { return (state & CIAT_CR_START) != 0; }
284 };
285 
292 class MOS6526: public component
293 {
294  friend class TimerA;
295  friend class TimerB;
296 
297 private:
298  static const char *credit;
299 
300 protected:
304  uint8_t regs[0x10];
305 
306  // Ports
307  uint8_t &pra, &prb, &ddra, &ddrb;
308 
313  TimerB timerB;
314 
315  // Serial Data Registers
316  uint8_t sdr_out;
317  bool sdr_buffered;
318  int sdr_count;
319 
321  uint8_t icr;
322 
324  uint8_t idr;
325 
330 
331  // TOD
332  bool m_todlatched;
333  bool m_todstopped;
334  uint8_t m_todclock[4], m_todalarm[4], m_todlatch[4];
335  event_clock_t m_todCycles, m_todPeriod;
336 
339 
340  // Events
341  EventCallback<MOS6526> bTickEvent;
342  EventCallback<MOS6526> todEvent;
343  EventCallback<MOS6526> triggerEvent;
344 
345 protected:
350  MOS6526(EventContext *context);
351 
365  void bTick(void);
366 
370  void tod(void);
371 
375  void trigger(void);
376 
380  void underflowA(void);
381 
385  void underflowB(void);
386 
392  void trigger(const uint8_t interruptMask);
393 
397  void clear(void);
398 
402  void serialPort();
403 
410  virtual void interrupt(bool state) = 0;
411 
412  virtual void portA() {}
413  virtual void portB() {}
414 
415 public:
419  virtual void reset(void);
420 
427  uint8_t read(uint_least8_t addr);
428 
437  void write(uint_least8_t addr, uint8_t data);
438 
444  const char *credits(void) { return credit; }
445 
451  void clock(float64_t clock);
452 };
453 
454 #endif // MOS6526_H