Bug fix: check if vm exists
[avr-sim.git] / Timer16.cpp
blobc0be1b8c3f432b99263332a25d1e01410d8938c5
1 #include "Timer16.h"
2 #include "Registers.h"
3 #include "Bus.h"
4 #include "ImplementationException.h"
6 enum {
7 bit_CS0 = 0, /* timer/counter clock select bit 0 */
8 bit_CS1 = 1,
9 bit_CS2 = 2,
10 bit_ICES = 6, /* input capture edge select */
11 bit_ICNC = 7, /* input capture noise canceler (4 CKs) */
14 enum {
15 mask_CS0 = 1 << bit_CS0,
16 mask_CS1 = 1 << bit_CS1,
17 mask_CS2 = 1 << bit_CS2,
18 mask_ICES = 1 << bit_ICES,
19 mask_ICNC = 1 << bit_ICNC,
20 mask_CS = (mask_CS0 | mask_CS1 | mask_CS2),
23 enum {
24 CS_STOP = 0x00, /* Stop, the Timer/Counter is stopped */
25 CS_CK = 0x01, /* CK */
26 CS_CK_8 = 0x02, /* CK/8 */
27 CS_CK_64 = 0x03, /* CK/64 */
28 CS_CK_256 = 0x04, /* CK/256 */
29 CS_CK_1024 = 0x05, /* CK/1024 */
30 CS_EXT_FALL = 0x06, /* External Pin Tn, falling edge */
31 CS_EXT_RISE = 0x07, /* External Pin Tn, rising edge */
34 enum {
35 bit_WGM1 = 3,
36 bit_WGM0 = 6,
37 bit_FOC = 7,
38 bit_COM0 = 4,
39 bit_COM1 = 5
42 enum {
43 WGM1 = (1<<bit_WGM1),
44 WGM0 = (1<<bit_WGM0),
45 FOC = (1<<bit_FOC),
46 COM0 = (1<<bit_COM0),
47 COM1 = (1<<bit_COM1),
48 mask_WGM = (WGM1|WGM0),
49 mask_COM = (COM1|COM0),
52 enum {
53 MODE_NORMAL = 0,
54 MODE_PWM_8 = 1,
55 MODE_PWM_9 = 2,
56 MODE_PWM_10 = 3,
57 MODE_CTC_OCR = 4,
58 MODE_FASTPWM_8 = 5,
59 MODE_FASTPWM_9 = 6,
60 MODE_FASTPWM_10 = 7,
61 MODE_PWM_PNF_ICR = 8,
62 MODE_PWM_PNF_OCR = 9,
63 MODE_PWM_ICR = 10,
64 MODE_PWM_OCR = 11,
65 MODE_CTC_ICR = 12,
66 MODE_FASTPWM_ICR = 14,
67 MODE_FASTPWM_OCR = 15
70 enum {
71 COM_NORMAL = 0,
72 COM_TOGGLE = COM0,
73 COM_CLEAR = COM1,
74 COM_SET = COM0|COM1
78 namespace avr {
80 #define overflow() *tifr |= tovmask
81 #define compareMatch() *tifr |= ocfmask
83 class OutputCompareUnit16 : public Hardware {
84 public:
85 OutputCompareUnit16();
87 public:
88 void flush();
89 word value() const { return ocrBuf; }
90 void forceOutputCompare(word tcnt);
91 void compareMatchOutput(word tcnt);
93 private:
94 word ocrBuf;
95 unsigned char compareMode;
97 private:
98 IORegister *ocrl;
99 IORegister *ocrh;
102 void OutputCompareUnit16::flush() {
103 ocrBuf = (ocrh->get() << 8) || ocrl->get();
106 void OutputCompareUnit16::forceOutputCompare(word tcnt) {
107 compareMatchOutput( tcnt );
110 // compareMode = val & mask_COM;
112 void OutputCompareUnit16::compareMatchOutput(word tcnt) {
113 // the non-PWM modes are NORMAL and CTC
114 // under NORMAL, there is no pin action for a compare match
115 // under CTC, the action is to clear the pin.
116 if( tcnt == ocrBuf ) {
117 switch( compareMode ) {
118 case COM_NORMAL:
119 break;
121 case COM_TOGGLE:
122 //outputComparePin.toggle();
123 break;
125 case COM_CLEAR:
126 //outputComparePin.low();
127 break;
129 case COM_SET:
130 //outputComparePin.high();
131 break;
134 //compareMatch();
138 bool Timer16::attachReg(const char *name, IORegister *reg) {
139 if( strcmp(name, "tcntl") == 0 ) {
140 tcntl = reg;
141 reg->registerHW(this);
142 } else if( strcmp(name, "tcnth") == 0 )
143 tcnth = reg;
144 else if( strcmp(name, "tccr") == 0 ) {
145 tccr = reg;
146 reg->registerHW(this);
147 } else if( strcmp(name, "tifr") == 0 )
148 tifr = reg;
149 else
150 return false;
152 return true;
155 void Timer16::regChanged( IORegister *reg ) {
156 if( reg == tccr ) {
157 unsigned char val = tccr->get();
158 setClock(val);
160 unsigned char timerModeNew = val & mask_WGM;
161 if( timerMode != timerModeNew )
162 direction = +1;
163 timerMode = timerModeNew;
165 if( val & FOC )
166 ;//for(int cntr = 0; cntr < compareUnits.size(); cntr++ )
167 // TODO compareUnits[cntr].forceOutputCompare(tcnt);
168 } else if( reg == tcntl ) {
169 tcnt |= (tcnth->get()<<8) | tcntl->get();
170 blockCompareMatch = true;
174 void Timer16::setClock(unsigned char tccr) {
175 byte clk = tccr & mask_CS;
176 switch( clk ) {
177 case CS_STOP:
178 bus.clearBreak(this);
179 return;
181 case CS_CK:
182 period = 1;
183 break;
185 case CS_CK_8:
186 period = 8;
187 break;
189 case CS_CK_64:
190 period = 64;
191 break;
193 case CS_CK_256:
194 period = 256;
195 break;
197 case CS_CK_1024:
198 period = 1024;
199 break;
201 case CS_EXT_FALL:
202 case CS_EXT_RISE:
203 throw util::ImplementationException(
204 "external timer/counter sources not implemented" );
207 bus.setBreakDelta(period, this);
210 void Timer16::step() {
211 static const word TOP[] = {
212 0xffff, 0x00ff, 0x01ff, 0x03ff, 0, 0x0ff, 0x01ff, 0x03ff
214 static const word MAX = 0xffff;
216 word compareI = 0;
217 word compareA = 0;
219 word tcntSave = tcnt;
220 bool tov = false;
222 switch( timerMode ) {
223 case MODE_NORMAL:
224 if( tcnt == TOP[timerMode] ) {
225 tov = true;
226 tcnt = 0;
228 break;
230 case MODE_PWM_8:
231 case MODE_PWM_9:
232 case MODE_PWM_10:
233 if( (tcnt == TOP[timerMode]) && (direction == +1) ) {
234 direction = -1;
235 flushOCRn();
236 } else if( (tcnt == 0) && (direction == -1) ) {
237 direction = +1;
238 tov = true;
240 break;
242 case MODE_CTC_OCR:
243 if( tcnt == compareA ) {
244 tcnt = 0;
245 } else if( tcnt == MAX ) {
246 tov = true;
248 break;
250 case MODE_FASTPWM_8:
251 case MODE_FASTPWM_9:
252 case MODE_FASTPWM_10:
253 if( tcnt == TOP[timerMode] ) {
254 tcnt = 0;
255 flushOCRn();
256 tov = true;
258 break;
260 case MODE_PWM_PNF_ICR:
261 if( (tcnt == compareI) && (direction == +1) ) {
262 direction = -1;
263 } else if( (tcnt == 0) && (direction == -1) ) {
264 direction = +1;
265 flushOCRn();
266 tov = true;
268 break;
270 case MODE_PWM_PNF_OCR:
271 if( (tcnt == compareA) && (direction == +1) ) {
272 direction = -1;
273 } else if( (tcnt == 0) && (direction == -1) ) {
274 direction = +1;
275 flushOCRn();
276 tov = true;
278 break;
280 case MODE_PWM_ICR:
281 if( (tcnt == compareI) && (direction == +1) ) {
282 direction = -1;
283 flushOCRn();
284 } else if( (tcnt == 0) && (direction == -1) ) {
285 direction = +1;
286 tov = true;
288 break;
290 case MODE_PWM_OCR:
291 if( (tcnt == compareI) && (direction == +1) ) {
292 direction = -1;
293 flushOCRn();
294 } else if( (tcnt == 0) && (direction == -1) ) {
295 direction = +1;
296 tov = true;
298 break;
300 case MODE_CTC_ICR:
301 if( tcnt == compareI ) {
302 tcnt = 0;
303 } else if( tcnt == MAX ) {
304 tov = true;
306 break;
308 case MODE_FASTPWM_ICR:
309 if( tcnt == compareI ) {
310 tcnt = 0;
311 tov = true;
312 flushOCRn();
314 break;
316 case MODE_FASTPWM_OCR:
317 if( tcnt == compareI ) {
318 tcnt = 0;
319 tov = true;
320 flushOCRn();
322 break;
325 tcnt += direction;
327 if( ! blockCompareMatch )
328 ;//for(int cntr = 0; cntr < compareUnits.size(); cntr++ )
329 // TODO compareUnits[cntr].compare(tcntSave);
330 blockCompareMatch = false;
332 tcntl->set( tcnt & 0xff );
333 tcnth->set( (tcnt >> 8) & 0xff );
334 bus.setBreakDelta(period, this);
337 void Timer16::flushOCRn() {
338 // TODO
339 //for(int cntr = 0; cntr < compareUnits.size(); cntr++ )
340 // compareUnits[cntr].flush();