00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef TIMER_H
00024 #define TIMER_H
00025
00026 #include <stdint.h>
00027
00028 #include "sidplayfp/EventScheduler.h"
00029
00030 class MOS6526;
00031
00037 class Timer : private Event
00038 {
00039 protected:
00040 static const int_least32_t CIAT_CR_START = 0x01;
00041 static const int_least32_t CIAT_STEP = 0x04;
00042 static const int_least32_t CIAT_CR_ONESHOT = 0x08;
00043 static const int_least32_t CIAT_CR_FLOAD = 0x10;
00044 static const int_least32_t CIAT_PHI2IN = 0x20;
00045 static const int_least32_t CIAT_CR_MASK = CIAT_CR_START | CIAT_CR_ONESHOT | CIAT_CR_FLOAD | CIAT_PHI2IN;
00046
00047 static const int_least32_t CIAT_COUNT2 = 0x100;
00048 static const int_least32_t CIAT_COUNT3 = 0x200;
00049
00050 static const int_least32_t CIAT_ONESHOT0 = 0x08 << 8;
00051 static const int_least32_t CIAT_ONESHOT = 0x08 << 16;
00052 static const int_least32_t CIAT_LOAD1 = 0x10 << 8;
00053 static const int_least32_t CIAT_LOAD = 0x10 << 16;
00054
00055 static const int_least32_t CIAT_OUT = 0x80000000;
00056
00057 private:
00058 EventCallback<Timer> m_cycleSkippingEvent;
00059
00063 EventContext &event_context;
00064
00073 event_clock_t ciaEventPauseTime;
00074
00078 uint_least16_t timer;
00079
00083 uint_least16_t latch;
00084
00088 bool pbToggle;
00089
00093 uint8_t lastControlValue;
00094
00095 protected:
00099 MOS6526* const parent;
00100
00104 int_least32_t state;
00105
00106 private:
00110 void cycleSkippingEvent();
00111
00115 void clock();
00116
00122 inline void reschedule();
00123
00127 void event();
00128
00132 virtual void underFlow() =0;
00133
00137 virtual void serialPort() {};
00138
00139 protected:
00147 Timer(const char* name, EventContext *context, MOS6526* parent) :
00148 Event(name),
00149 m_cycleSkippingEvent("Skip CIA clock decrement cycles", *this, &Timer::cycleSkippingEvent),
00150 event_context(*context),
00151 timer(0),
00152 latch(0),
00153 pbToggle(false),
00154 lastControlValue(0),
00155 parent(parent),
00156 state(0) {}
00157
00158 public:
00165 void setControlRegister(uint8_t cr);
00166
00172 void syncWithCpu();
00173
00179 void wakeUpAfterSyncWithCpu();
00180
00184 void reset();
00185
00192 void latchLo(uint8_t data);
00193
00200 void latchHi(uint8_t data);
00201
00208 inline void setPbToggle(bool state) { pbToggle = state; }
00209
00215 inline int_least32_t getState() const { return state; }
00216
00222 inline uint_least16_t getTimer() const { return timer; }
00223
00230 inline bool getPb(uint8_t reg) const { return (reg & 0x04) ? pbToggle : (state & CIAT_OUT); }
00231 };
00232
00233 void Timer::reschedule()
00234 {
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244 const int_least32_t unwanted = CIAT_OUT | CIAT_CR_FLOAD | CIAT_LOAD1 | CIAT_LOAD;
00245 if ((state & unwanted) != 0)
00246 {
00247 event_context.schedule(*this, 1);
00248 return;
00249 }
00250
00251 if ((state & CIAT_COUNT3) != 0)
00252 {
00253
00254
00255
00256 const int_least32_t wanted = CIAT_CR_START | CIAT_PHI2IN | CIAT_COUNT2 | CIAT_COUNT3;
00257 if (timer > 2 && (state & wanted) == wanted)
00258 {
00259
00260
00261
00262 ciaEventPauseTime = event_context.getTime(EVENT_CLOCK_PHI1) + 1;
00263
00264 event_context.schedule(m_cycleSkippingEvent, timer - 1);
00265 return;
00266 }
00267
00268
00269 event_context.schedule(*this, 1);
00270 }
00271 else
00272 {
00273
00274
00275 const int_least32_t unwanted1 = CIAT_CR_START | CIAT_PHI2IN;
00276 const int_least32_t unwanted2 = CIAT_CR_START | CIAT_STEP;
00277
00278 if ((state & unwanted1) == unwanted1
00279 || (state & unwanted2) == unwanted2)
00280 {
00281 event_context.schedule(*this, 1);
00282 return;
00283 }
00284
00285 ciaEventPauseTime = -1;
00286 }
00287 }
00288
00289 #endif // TIMER_H