libsidplayfp 1.0.3
|
00001 /* 00002 * This file is part of libsidplayfp, a SID player engine. 00003 * 00004 * Copyright 2011-2013 Leandro Nini <drfiemost@users.sourceforge.net> 00005 * Copyright 2007-2010 Antti Lankila 00006 * Copyright 2000 Simon White 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 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 /* There are only two subcases to consider. 00236 * 00237 * - are we counting, and if so, are we going to 00238 * continue counting? 00239 * - have we stopped, and are there no conditions to force a new beginning? 00240 * 00241 * Additionally, there are numerous flags that are present only in passing manner, 00242 * but which we need to let cycle through the CIA state machine. 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 /* Test the conditions that keep COUNT2 and thus COUNT3 alive, and also 00254 * ensure that all of them are set indicating steady state operation. */ 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 /* we executed this cycle, therefore the pauseTime is +1. If we are called 00260 * to execute on the very next clock, we need to get 0 because there's 00261 * another timer-- in it. */ 00262 ciaEventPauseTime = event_context.getTime(EVENT_CLOCK_PHI1) + 1; 00263 /* execute event slightly before the next underflow. */ 00264 event_context.schedule(m_cycleSkippingEvent, timer - 1); 00265 return; 00266 } 00267 00268 /* play safe, keep on ticking. */ 00269 event_context.schedule(*this, 1); 00270 } 00271 else 00272 { 00273 /* Test conditions that result in CIA activity in next clocks. 00274 * If none, stop. */ 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