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
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 Sat Mar 7 2015.