Main Page

- Main Page
- Related Pages
- Files

- File List
- Globals

timers.c
Go to the documentation of this file.
1 /*
2 * $Id: timers.c,v 1.15 2004/03/13 19:55:34 troth Exp $
3 *
4 ****************************************************************************
5 *
6 * simulavr - A simulator for the Atmel AVR family of microcontrollers.
7 * Copyright (C) 2001, 2002, 2003, 2004 Theodore A. Roth
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 ****************************************************************************
24 */
25
26 /**
27 * \file timers.c
28 * \brief Module to simulate the AVR's on-board timer/counters.
29 *
30 * This currently only implements the timer/counter 0.
31 */
32
33 #include <config.h>
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "avrerror.h"
40 #include "avrmalloc.h"
41 #include "avrclass.h"
42 #include "utils.h"
43 #include "callback.h"
44 #include "op_names.h"
45
46 #include "storage.h"
47 #include "flash.h"
48
49 #include "vdevs.h"
50 #include "memory.h"
51 #include "stack.h"
52 #include "register.h"
53 #include "sram.h"
54 #include "eeprom.h"
55 #include "timers.h"
56 #include "ports.h"
57
58 #include "avrcore.h"
59
60 #include "intvects.h"
61
62 #ifndef DOXYGEN
63
64 /* *INDENT-OFF* */
65
66 Timer16Def global_timer16_defs[] = {
67 {
68 .timer_name = "Timer1",
69 .tcnth_name = "TCNT1H",
70 .tcntl_name = "TCNT1L",
71 .tccra_name = "TCCR1A",
72 .tccrb_name = "TCCR1B",
73 .base = 0x4c,
74 .tof = bit_TOV1,
75 .ocf_a = bit_OCF1A,
76 .ocf_b = bit_OCF1B,
77 .ocf_c = 8
78 }
79 };
80
81 OCReg16Def global_ocreg16_defs[] = {
82 {
83 .ocrdev_name = "OCR1A",
84 .ocrl_name = "OCR1AL",
85 .ocrh_name = "OCR1AH",
86 .base = 0x4a
87 },
88 {
89 .ocrdev_name = "OCR1B",
90 .ocrl_name = "OCR1BL",
91 .ocrh_name = "OCR1BH",
92 .base = 0x48
93 },
94 {
95 .ocrdev_name = "OCR1C",
96 .ocrl_name = "OCR1CL",
97 .ocrh_name = "OCR1CH",
98 .base = 0x78},
99 {
100 .ocrdev_name = "OCR3A",
101 .ocrl_name = "OCR3AL",
102 .ocrh_name = "OCR3A",
103 .base = 0x86
104 },
105 {
106 .ocrdev_name = "OCR3B",
107 .ocrl_name = "OCR3BL",
108 .ocrh_name = "OCR3BH",
109 .base = 0x84
110 },
111 {
112 .ocrdev_name = "OCR3C",
113 .ocrl_name = "OCR3CL",
114 .ocrh_name = "OCR3CH",
115 .base = 0x82
116 }
117 };
118 /* *INDENT-ON* */
119
120 #endif /* not DOXYGEN */
121
122 /****************************************************************************\
123 *
124 * Timer/Counter 0
125 *
126 \****************************************************************************/
127
128 static void timer_iadd_addr (VDevice *vdev, int addr, char *name,
129 int rel_addr, void *data);
130 static uint8_t timer_intr_read (VDevice *dev, int addr);
131 static void timer_intr_write (VDevice *dev, int addr, uint8_t val);
132 static void timer_intr_reset (VDevice *dev);
133 static int timer_intr_cb (uint64_t time, AvrClass *data);
134
135 /** \brief Allocate a new timer interrupt */
136
137 VDevice *
138 timer_int_create (int addr, char *name, int rel_addr, void *data)
139 {
140 uint8_t *func_mask = (uint8_t *) data;
141 if (data)
142 return (VDevice *)timer_intr_new (addr, name, *func_mask);
143 else
144 avr_error ("Attempted timer interrupt create with NULL data pointer");
145 return 0;
146 }
147
148 TimerIntr_T *
149 timer_intr_new (int addr, char *name, uint8_t func_mask)
150 {
151 TimerIntr_T *ti;
152
153 ti = avr_new (TimerIntr_T, 1);
154 timer_intr_construct (ti, addr, name, func_mask);
155 class_overload_destroy ((AvrClass *)ti, timer_intr_destroy);
156
157 return ti;
158 }
159
160 /** \brief Constructor for timer interrupt object. */
161
162 void
163 timer_intr_construct (TimerIntr_T *ti, int addr, char *name,
164 uint8_t func_mask)
165 {
166 if (ti == NULL)
167 avr_error ("passed null ptr");
168
169 vdev_construct ((VDevice *)ti, timer_intr_read, timer_intr_write,
170 timer_intr_reset, timer_iadd_addr);
171
172 ti->func_mask = func_mask;
173
174 timer_iadd_addr ((VDevice *)ti, addr, name, 0, NULL);
175
176 timer_intr_reset ((VDevice *)ti);
177 }
178
179 static void
180 timer_iadd_addr (VDevice *vdev, int addr, char *name, int rel_addr,
181 void *data)
182 {
183 TimerIntr_T *ti = (TimerIntr_T *)vdev;
184
185 if (strncmp ("TIFR", name, 4) == 0)
186 {
187 ti->tifr_addr = addr;
188 }
189
190 else if (strncmp ("TIMSK", name, 5) == 0)
191 {
192 ti->timsk_addr = addr;
193 }
194
195 else
196 {
197 avr_error ("invalid Timer Interrupt register name: '%s' @ 0x%04x",
198 name, addr);
199 }
200 }
201
202 /** \brief Destructor for timer interrupt object. */
203
204 void
205 timer_intr_destroy (void *ti)
206 {
207 if (ti == NULL)
208 return;
209
210 vdev_destroy (ti);
211 }
212
213 static uint8_t
214 timer_intr_read (VDevice *dev, int addr)
215 {
216 TimerIntr_T *ti = (TimerIntr_T *)dev;
217
218 if (addr == ti->timsk_addr)
219 {
220 return (ti->timsk & ti->func_mask);
221 }
222
223 else if (addr == ti->tifr_addr)
224 {
225 return (ti->tifr & ti->func_mask);
226 }
227
228 else
229 {
230 avr_error ("Bad address: 0x%04x", addr);
231 }
232
233 return 0; /* will never get here */
234 }
235
236 static void
237 timer_intr_write (VDevice *dev, int addr, uint8_t val)
238 {
239 TimerIntr_T *ti = (TimerIntr_T *)dev;
240 CallBack *cb;
241
242 if (addr == ti->timsk_addr)
243 {
244 ti->timsk = (val & ti->func_mask);
245 if (ti->timsk == 0)
246 {
247 ti->intr_cb = NULL; /* no interrupt are enabled, remove the
248 callback */
249 }
250 else if (ti->intr_cb == NULL)
251 {
252 /* we need to install the intr_cb function */
253 cb = callback_new (timer_intr_cb, (AvrClass *)ti);
254 ti->intr_cb = cb;
255 avr_core_async_cb_add ((AvrCore *)vdev_get_core (dev), cb);
256 }
257 }
258
259 else if (addr == ti->tifr_addr)
260 {
261 ti->tifr &= ~(val & ti->func_mask);
262 }
263
264 else
265 {
266 avr_error ("Bad address: 0x%04x", addr);
267 }
268 }
269
270 static void
271 timer_intr_reset (VDevice *dev)
272 {
273 TimerIntr_T *ti = (TimerIntr_T *)dev;
274
275 ti->intr_cb = NULL;
276
277 ti->timsk = 0;
278 ti->tifr = 0;
279 }
280
281 static int
282 timer_intr_cb (uint64_t time, AvrClass *data)
283 {
284 TimerIntr_T *ti = (TimerIntr_T *)data;
285 uint8_t intrs = ti->timsk & ti->tifr & ti->func_mask;
286
287 if (ti->intr_cb == NULL)
288 return CB_RET_REMOVE;
289
290 if (intrs)
291 {
292 AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)ti);
293
294 /*
295 * FIXME: Once an irq has been raised, the flag should be cleared,
296 * _BUT_ should it be done here? Might be a problem if there are
297 * many interrupts pending and then the user wants to clear one.
298 */
299
300 if (intrs & mask_TOV0)
301 {
302 avr_core_irq_raise (core, irq_vect_table_index (TIMER0_OVF));
303 ti->tifr &= ~mask_TOV0;
304 }
305 else if (intrs & mask_ICF1)
306 {
307 avr_core_irq_raise (core, irq_vect_table_index (TIMER1_CAPT));
308 ti->tifr &= ~mask_ICF1;
309 }
310 else if (intrs & mask_OCF1B)
311 {
312 avr_core_irq_raise (core, irq_vect_table_index (TIMER1_COMPB));
313 ti->tifr &= ~mask_OCF1B;
314 }
315 else if (intrs & mask_OCF1A)
316 {
317 avr_core_irq_raise (core, irq_vect_table_index (TIMER1_COMPA));
318 ti->tifr &= ~mask_OCF1A;
319 }
320 else if (intrs & mask_TOV1)
321 {
322 avr_core_irq_raise (core, irq_vect_table_index (TIMER1_OVF));
323 ti->tifr &= ~mask_TOV1;
324 }
325 else
326 {
327 avr_error ("An invalid interrupt was flagged");
328 }
329 }
330
331 return CB_RET_RETAIN;
332 }
333
334 /****************************************************************************\
335 *
336 * Timer/Counter 0
337 *
338 \****************************************************************************/
339
340 static void timer0_add_addr (VDevice *vdev, int addr, char *name,
341 int rel_addr, void *data);
342 static uint8_t timer0_read (VDevice *dev, int addr);
343 static void timer0_write (VDevice *dev, int addr, uint8_t val);
344 static void timer0_reset (VDevice *dev);
345 static int timer0_clk_incr_cb (uint64_t ck, AvrClass *data);
346
347 /** \brief Allocate a new timer/counter 0. */
348
349 VDevice *
350 timer0_create (int addr, char *name, int rel_addr, void *data)
351 {
352 return (VDevice *)timer0_new (addr, name, rel_addr);
353 }
354
355 Timer0_T *
356 timer0_new (int addr, char *name, int rel_addr)
357 {
358 Timer0_T *timer;
359
360 timer = avr_new (Timer0_T, 1);
361 timer0_construct (timer, addr, name, rel_addr);
362 class_overload_destroy ((AvrClass *)timer, timer0_destroy);
363
364 return timer;
365 }
366
367 /** \brief Constructor for timer/counter 0 object. */
368
369 void
370 timer0_construct (Timer0_T *timer, int addr, char *name, int rel_addr)
371 {
372 if (timer == NULL)
373 avr_error ("passed null ptr");
374
375 vdev_construct ((VDevice *)timer, timer0_read, timer0_write, timer0_reset,
376 timer0_add_addr);
377
378 timer0_add_addr ((VDevice *)timer, addr, name, 0, NULL);
379 if (rel_addr)
380 timer->related_addr = rel_addr;
381 timer0_reset ((VDevice *)timer);
382 }
383
384 /** \brief Destructor for timer/counter 0 object. */
385
386 void
387 timer0_destroy (void *timer)
388 {
389 if (timer == NULL)
390 return;
391
392 vdev_destroy (timer);
393 }
394
395 static void
396 timer0_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
397 void *data)
398 {
399 Timer0_T *ti = (Timer0_T *)vdev;
400
401 if (strncmp ("TCNT", name, 4) == 0)
402 {
403 ti->tcnt_addr = addr;
404 }
405
406 else if (strncmp ("TCCR", name, 4) == 0)
407 {
408 ti->tccr_addr = addr;
409 }
410
411 else
412 {
413 avr_error ("invalid Timer register name: '%s' @ 0x%04x", name, addr);
414 }
415 }
416
417 static uint8_t
418 timer0_read (VDevice *dev, int addr)
419 {
420 Timer0_T *timer = (Timer0_T *)dev;
421
422 if (addr == timer->tcnt_addr)
423 return timer->tcnt;
424
425 else if (addr == timer->tccr_addr)
426 return timer->tccr;
427
428 else
429 {
430 avr_error ("Bad address: 0x%04x", addr);
431 }
432
433 return 0; /* will never get here */
434 }
435
436 static void
437 timer0_write (VDevice *dev, int addr, uint8_t val)
438 {
439 Timer0_T *timer = (Timer0_T *)dev;
440 CallBack *cb;
441
442 if (addr == timer->tcnt_addr)
443 {
444 timer->tcnt = val;
445 }
446
447 else if (addr == timer->tccr_addr)
448 {
449 /*
450 * When the user writes toe TCCR, a callback is installed for either
451 * clock generated increments or externally generated increments. The
452 * two incrememtor callback are mutally exclusive, only one or the
453 * other can be installed at any given instant.
454 */
455
456 /* timer 0 only has clock select function. */
457 timer->tccr = val & mask_CS;
458
459 switch (timer->tccr)
460 {
461 case CS_STOP:
462 /* stop either of the installed callbacks */
463 timer->clk_cb = timer->ext_cb = NULL;
464 timer->divisor = 0;
465 return;
466 case CS_EXT_FALL:
467 case CS_EXT_RISE:
468 /* FIXME: not implemented yet */
469 avr_error ("external timer/counter sources is not implemented"
470 " yet");
471 return;
472 case CS_CK:
473 timer->divisor = 1;
474 break;
475 case CS_CK_8:
476 timer->divisor = 8;
477 break;
478 case CS_CK_64:
479 timer->divisor = 64;
480 break;
481 case CS_CK_256:
482 timer->divisor = 256;
483 break;
484 case CS_CK_1024:
485 timer->divisor = 1024;
486 break;
487 default:
488 avr_error ("The impossible happened!");
489 }
490 /* remove external incrementor if installed */
491 if (timer->ext_cb)
492 timer->ext_cb = NULL;
493
494 /* install the clock incrementor callback (with flair!) */
495 if (timer->clk_cb == NULL)
496 {
497 cb = callback_new (timer0_clk_incr_cb, (AvrClass *)timer);
498 timer->clk_cb = cb;
499 avr_core_clk_cb_add ((AvrCore *)vdev_get_core ((VDevice *)timer),
500 cb);
501 }
502 }
503
504 else
505 {
506 avr_error ("Bad address: 0x%04x", addr);
507 }
508 }
509
510 static void
511 timer0_reset (VDevice *dev)
512 {
513 Timer0_T *timer = (Timer0_T *)dev;
514
515 timer->clk_cb = NULL;
516 timer->ext_cb = NULL;
517
518 timer->tccr = 0;
519 timer->tcnt = 0;
520
521 timer->divisor = 0;
522 }
523
524 static int
525 timer0_clk_incr_cb (uint64_t ck, AvrClass *data)
526 {
527 Timer0_T *timer = (Timer0_T *)data;
528 uint8_t last = timer->tcnt;
529 TimerIntr_T *ti;
530
531 ti = (TimerIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
532 vdev_get_core ((VDevice *)
533 timer),
534 timer->related_addr);
535
536 if (timer->clk_cb == NULL)
537 return CB_RET_REMOVE;
538
539 if (timer->divisor <= 0)
540 avr_error ("Bad divisor value: %d", timer->divisor);
541
542 /* Increment clock if ck is a mutliple of divisor. Since divisor is always
543 a power of 2, it's much faster to do the bitwise AND instead of using
544 the integer modulus operator (%). */
545 timer->tcnt += ((ck & (timer->divisor - 1)) == 0);
546
547 /* Check if tcnt rolled over and if so, set the overflow flag. If
548 overflow interrupts are set? what if they aren't? This is set
549 irregardless of whether SREG-I or TOIE0 are set (overflow interrupt
550 enabled) and thus allows the interrupt to be pending until manually
551 cleared (writing a one to the TOV0 flag) or interrupts are enabled. My
552 interpretation of the datasheets. See datasheet discussion of TIFR.
553 TRoth */
554 if ((timer->tcnt == 0) && (timer->tcnt != last))
555 ti->tifr |= mask_TOV0;
556
557 return CB_RET_RETAIN;
558 }
559
560 /****************************************************************************\
561 *
562 * Timer/Counter 1/3 (16 bit)
563 *
564 \****************************************************************************/
565
566 /** \name 16 Bit Timer Functions */
567
568 /*@{*/
569
570 static void timer16_add_addr (VDevice *vdev, int addr, char *name,
571 int rel_addr, void *data);
572 static void timer16_destroy (void *timer);
573 static uint8_t timer16_read (VDevice *dev, int addr);
574 static void timer16_write (VDevice *dev, int addr, uint8_t val);
575 static void timer16_reset (VDevice *dev);
576 static int timer16_clk_incr_cb (uint64_t time, AvrClass *data);
577 static void timer16_handle_tccr_write (Timer16_T *timer);
578
579 /** \brief Allocate a new 16 bit timer/counter. */
580
581 VDevice *
582 timer16_create (int addr, char *name, int rel_addr, void *data)
583 {
584 uint8_t *def_data = (uint8_t *) data;
585 if (data)
586 return (VDevice *)timer16_new (addr, name, rel_addr,
587 global_timer16_defs[*def_data]);
588 else
589 avr_error ("Attempted timer 16 create with NULL data pointer");
590 return 0;
591 }
592
593 Timer16_T *
594 timer16_new (int addr, char *name, int rel_addr, Timer16Def timerdef)
595 {
596 Timer16_T *timer;
597
598 timer = avr_new (Timer16_T, 1);
599 timer16_construct (timer, addr, name, rel_addr, timerdef);
600 class_overload_destroy ((AvrClass *)timer, timer16_destroy);
601
602 return timer;
603 }
604
605 /** \brief Constructor for 16 bit timer/counter object. */
606
607 void
608 timer16_construct (Timer16_T *timer, int addr, char *name, int rel_addr,
609 Timer16Def timerdef)
610 {
611 if (timer == NULL)
612 avr_error ("passed null ptr");
613
614 vdev_construct ((VDevice *)timer, timer16_read, timer16_write,
615 timer16_reset, timer16_add_addr);
616
617 timer->timerdef = timerdef;
618
619 timer16_add_addr ((VDevice *)timer, addr, name, 0, NULL);
620 if (rel_addr)
621 timer->related_addr = rel_addr;
622 timer16_reset ((VDevice *)timer);
623 }
624
625 static void
626 timer16_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
627 void *data)
628 {
629 Timer16_T *ti = (Timer16_T *)vdev;
630
631 if (strncmp ("TCNTL", name, 5) == 0)
632 {
633 ti->tcntl_addr = addr;
634 }
635
636 else if (strncmp ("TCNTH", name, 5) == 0)
637 {
638 ti->tcnth_addr = addr;
639 }
640
641 else if (strncmp ("TCCRA", name, 5) == 0)
642 {
643 ti->tccra_addr = addr;
644 }
645
646 else if (strncmp ("TCCRB", name, 5) == 0)
647 {
648 ti->tccrb_addr = addr;
649 }
650
651 else if (strncmp ("TCCRC", name, 5) == 0)
652 {
653 ti->tccrc_addr = addr;
654 }
655
656 else
657 {
658 avr_error ("invalid Timer16 register name: '%s' @ 0x%04x", name,
659 addr);
660 }
661 }
662
663 static void
664 timer16_destroy (void *timer)
665 {
666 if (timer == NULL)
667 return;
668
669 vdev_destroy (timer);
670 }
671
672 static uint8_t
673 timer16_read (VDevice *dev, int addr)
674 {
675 Timer16_T *timer = (Timer16_T *)dev;
676
677 if (addr == timer->tcntl_addr)
678 {
679 timer->TEMP = (uint8_t) ((timer->tcnt) >> 8);
680 return (timer->tcnt) & 0xFF;
681 }
682
683 else if (addr == timer->tcnth_addr)
684 {
685 return timer->TEMP;
686 }
687
688 else if (addr == timer->tccra_addr)
689 {
690 return timer->tccra;
691 }
692
693 else if (addr == timer->tccrb_addr)
694 {
695 return timer->tccrb;
696 }
697
698 else if (addr == timer->tccrc_addr)
699 {
700 return timer->tccrc;
701 }
702
703 else
704 {
705 avr_error ("Bad address: 0x%04x", addr);
706 }
707
708 return 0; /* will never get here */
709 }
710
711 static void
712 timer16_write (VDevice *dev, int addr, uint8_t val)
713 {
714 Timer16_T *timer = (Timer16_T *)dev;
715
716 if (addr == timer->tcntl_addr)
717 {
718 timer->tcnt = (((timer->TEMP) << 8) & 0xFF00) | val;
719 }
720
721 else if (addr == timer->tcnth_addr)
722 {
723 timer->TEMP = val;
724 }
725
726 else if (addr == timer->tccra_addr)
727 {
728 timer->tccra = val;
729 timer16_handle_tccr_write (timer);
730 }
731
732 else if (addr == timer->tccrb_addr)
733 {
734 timer->tccrb = val;
735 timer16_handle_tccr_write (timer);
736 }
737
738 else if (addr == timer->tccrc_addr)
739 {
740 timer->tccrc = val;
741 timer16_handle_tccr_write (timer);
742 }
743
744 else
745 {
746 avr_error ("Bad address: 0x%04x", addr);
747 }
748 }
749
750 static void
751 timer16_reset (VDevice *dev)
752 {
753 Timer16_T *timer = (Timer16_T *)dev;
754
755 timer->clk_cb = NULL;
756 timer->ext_cb = NULL;
757
758 timer->tccra = 0;
759 timer->tccrb = 0;
760 timer->tccrc = 0;
761 timer->tcnt = 0;
762
763 timer->divisor = 0;
764 }
765
766 static void
767 timer_intr_set_flag (TimerIntr_T *ti, uint8_t bitnr)
768 {
769 ti->tifr |= bitnr;
770 }
771
772 static int
773 timer16_clk_incr_cb (uint64_t ck, AvrClass *data)
774 {
775 Timer16_T *timer = (Timer16_T *)data;
776 uint16_t last = timer->tcnt;
777
778 if (!timer->ti)
779 timer->ti =
780 (TimerIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
781 vdev_get_core ((VDevice
782 *)
783 timer),
784 timer->related_addr);
785
786 if (timer->clk_cb == NULL)
787 return CB_RET_REMOVE;
788
789 /* Increment clock if ck is a mutliple of divisor. Since divisor is always
790 a power of 2, it's much faster to do the bitwise AND instead of using
791 the integer modulus operator (%). */
792 timer->tcnt += ((ck & (timer->divisor - 1)) == 0);
793
794 if (timer->divisor <= 0)
795 avr_error ("Bad divisor value: %d", timer->divisor);
796
797 /* The following things only have to be checked if the counter value has
798 changed */
799 if (timer->tcnt != last)
800 {
801 /* An overflow occurred */
802 if (timer->tcnt == 0)
803 timer_intr_set_flag (timer->ti, mask_TOV1);
804
805 /* The counter value matches one of the ocr values */
806 if (timer->ocra && (timer->tcnt == timer->ocra->ocr))
807 {
808 timer_intr_set_flag (timer->ti, mask_OCF1A);
809 }
810
811 if (timer->ocrb && (timer->tcnt == timer->ocrb->ocr))
812 {
813 timer_intr_set_flag (timer->ti, mask_OCF1B);
814 }
815 }
816 return CB_RET_RETAIN;
817 }
818
819 #if 0
820 static void
821 timer_intr_clear_flag (TimerIntr_T *ti, uint8_t bitnr)
822 {
823 ti->tifr &= ~(bitnr);
824 }
825 #endif
826
827 static void
828 timer16_handle_tccr_write (Timer16_T *timer)
829 {
830 int cs;
831 CallBack *cb;
832 /*
833 * When the user writes toe TCCR, a callback is installed for either
834 * clock generated increments or externally generated increments. The
835 * two incrememtor callback are mutally exclusive, only one or the
836 * other can be installed at any given instant.
837 */
838
839 cs = timer->tccrb & 0x07;
840
841 switch (cs)
842 {
843 case CS_STOP:
844 /* stop either of the installed callbacks */
845 timer->clk_cb = timer->ext_cb = NULL;
846 timer->divisor = 0;
847 return;
848 case CS_EXT_FALL:
849 case CS_EXT_RISE:
850 /* FIXME: not implemented yet */
851 avr_error ("external timer/counter sources is not implemented"
852 "yet");
853 return;
854 case CS_CK:
855 timer->divisor = 1;
856 break;
857 case CS_CK_8:
858 timer->divisor = 8;
859 break;
860 case CS_CK_64:
861 timer->divisor = 64;
862 break;
863 case CS_CK_256:
864 timer->divisor = 256;
865 break;
866 case CS_CK_1024:
867 timer->divisor = 1024;
868 break;
869 default:
870 avr_error ("The impossible happened!");
871 }
872 /* remove external incrementor if installed */
873 if (timer->ext_cb)
874 timer->ext_cb = NULL;
875
876 /* install the clock incrementor callback (with flair!) */
877 if (timer->clk_cb == NULL)
878 {
879 cb = callback_new (timer16_clk_incr_cb, (AvrClass *)timer);
880 timer->clk_cb = cb;
881 avr_core_clk_cb_add ((AvrCore *)vdev_get_core ((VDevice *)timer), cb);
882 }
883 }
884
885 /*@}*/
886
887 /****************************************************************************\
888 *
889 * Timer16OCR(VDevice) : 16bit - Timer/Counter - Output Compare Register
890 *
891 \****************************************************************************/
892
893 /** \name 16 Bit Output Compare Register Functions */
894
895 /*@{*/
896
897 static void ocr_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
898 void *data);
899 static void ocreg16_destroy (void *ocr);
900 static uint8_t ocreg16_read (VDevice *dev, int addr);
901 static void ocreg16_write (VDevice *dev, int addr, uint8_t val);
902 static void ocreg16_reset (VDevice *dev);
903
904 /** \brief Allocate a new 16 bit Output Compare Register
905 * \param ocrdef The definition struct for the \a OCR to be created
906 */
907
908 VDevice *
909 ocreg16_create (int addr, char *name, int rel_addr, void *data)
910 {
911 uint8_t *def_data = (uint8_t *) data;
912 if (data)
913 return (VDevice *)ocreg16_new (addr, name,
914 global_ocreg16_defs[*def_data]);
915 else
916 avr_error ("Attempted OCReg create with NULL data pointer");
917 return 0;
918 }
919
920 OCReg16_T *
921 ocreg16_new (int addr, char *name, OCReg16Def ocrdef)
922 {
923 OCReg16_T *ocreg;
924
925 ocreg = avr_new (OCReg16_T, 1);
926 ocreg16_construct (ocreg, addr, name, ocrdef);
927 class_overload_destroy ((AvrClass *)ocreg, ocreg16_destroy);
928
929 return ocreg;
930 }
931
932 /** \brief Constructor for 16 bit Output Compare Register object. */
933
934 void
935 ocreg16_construct (OCReg16_T *ocreg, int addr, char *name, OCReg16Def ocrdef)
936 {
937 if (ocreg == NULL)
938 avr_error ("passed null ptr");
939
940 vdev_construct ((VDevice *)ocreg, ocreg16_read, ocreg16_write,
941 ocreg16_reset, ocr_add_addr);
942
943 ocreg->ocrdef = ocrdef;
944
945 ocr_add_addr ((VDevice *)ocreg, addr, name, 0, NULL);
946 ocreg16_reset ((VDevice *)ocreg);
947 }
948
949 static void
950 ocr_add_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
951 {
952 OCReg16_T *ocreg = (OCReg16_T *)vdev;
953
954 if ((strncmp ("OCRAL", name, 5) == 0) || (strncmp ("OCRBL", name, 5) == 0)
955 || (strncmp ("OCRCL", name, 5) == 0))
956 {
957 ocreg->ocrl_addr = addr;
958 }
959
960 else if ((strncmp ("OCRAH", name, 5) == 0)
961 || (strncmp ("OCRBH", name, 5) == 0)
962 || (strncmp ("OCRCH", name, 5) == 0))
963
964 {
965 ocreg->ocrh_addr = addr;
966 }
967
968 else
969 {
970 avr_error ("invalid Timer16 register name: '%s' @ 0x%04x", name,
971 addr);
972 }
973 }
974
975 static void
976 ocreg16_destroy (void *ocreg)
977 {
978 if (ocreg == NULL)
979 return;
980
981 vdev_destroy (ocreg);
982 }
983
984 static uint8_t
985 ocreg16_read (VDevice *dev, int addr)
986 {
987 OCReg16_T *ocreg = (OCReg16_T *)dev;
988
989 if (addr == ocreg->ocrl_addr)
990 {
991 return (ocreg->ocr) & 0xFF;
992 }
993
994 else if (addr == ocreg->ocrh_addr)
995 {
996 return (ocreg->ocr) >> 8;
997 }
998
999 else
1000 {
1001 avr_error ("Bad address: 0x%04x", addr);
1002 }
1003
1004 return 0;
1005 }
1006
1007 static void
1008 ocreg16_write (VDevice *dev, int addr, uint8_t val)
1009 {
1010 OCReg16_T *ocreg = (OCReg16_T *)dev;
1011
1012 if (addr == ocreg->ocrl_addr)
1013 {
1014 ocreg->ocr = (((ocreg->TEMP) << 8) & 0xFF00) | val;
1015 }
1016
1017 else if (addr == ocreg->ocrh_addr)
1018 {
1019 ocreg->TEMP = val;
1020 }
1021
1022 else
1023 {
1024 avr_error ("Bad address: 0x%04x", addr);
1025 }
1026 }
1027
1028 static void
1029 ocreg16_reset (VDevice *dev)
1030 {
1031 OCReg16_T *ocreg = (OCReg16_T *)dev;
1032
1033 ocreg->ocr = 0;
1034 }
1035
1036 /*@}*/

Automatically generated by Doxygen 1.8.2 on Mon Aug 18 2014.