Many more changes, timed callbacks etc
[simavr] / simavr / sim / avr_timer8.c
1 /*
2         avr_timer8.c
3
4         Handles the just one mode of the 8 bit AVR timer.
5         Still need to handle all the others!
6
7         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
8
9         This file is part of simavr.
10
11         simavr is free software: you can redistribute it and/or modify
12         it under the terms of the GNU General Public License as published by
13         the Free Software Foundation, either version 3 of the License, or
14         (at your option) any later version.
15
16         simavr is distributed in the hope that it will be useful,
17         but WITHOUT ANY WARRANTY; without even the implied warranty of
18         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19         GNU General Public License for more details.
20
21         You should have received a copy of the GNU General Public License
22         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 #include <stdio.h>
26 #include "avr_timer8.h"
27
28 static avr_cycle_count_t avr_timer8_compa(struct avr_t * avr, avr_cycle_count_t when, void * param)
29 {
30         avr_timer8_t * p = (avr_timer8_t *)param;
31         avr_raise_interrupt(avr, &p->compa);
32         return p->compa_cycles ? when + p->compa_cycles : 0;
33 }
34
35 static avr_cycle_count_t avr_timer8_compb(struct avr_t * avr, avr_cycle_count_t when, void * param)
36 {
37         avr_timer8_t * p = (avr_timer8_t *)param;
38         avr_raise_interrupt(avr, &p->compb);
39         return p->compb_cycles ? when + p->compb_cycles : 0;
40 }
41
42 static uint8_t avr_timer8_tcnt_read(struct avr_t * avr, uint8_t addr, void * param)
43 {
44         //avr_timer8_t * p = (avr_timer8_t *)param;
45         // made to trigger potential watchpoints
46         return avr_core_watch_read(avr, addr);
47 }
48
49 static void avr_timer8_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * param)
50 {
51         avr_timer8_t * p = (avr_timer8_t *)param;
52
53         p->compa_cycles = 0;
54         p->compb_cycles = 0;
55
56         avr_core_watch_write(avr, addr, v);
57         long clock = avr->frequency;
58         if (avr_regbit_get(avr, p->as2))
59                 clock = 32768;
60         uint8_t cs = avr_regbit_get_array(avr, p->cs, ARRAY_SIZE(p->cs));
61         if (cs == 0) {
62                 printf("%s-%c clock turned off\n", __FUNCTION__, p->name);              
63                 avr_cycle_timer_cancel(avr, avr_timer8_compa, p);
64                 avr_cycle_timer_cancel(avr, avr_timer8_compb, p);
65                 return;
66         }
67         uint8_t mode = avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm));
68         uint8_t cs_div = p->cs_div[cs];
69         uint16_t ocra = avr->data[p->r_ocra];
70         uint16_t ocrb = avr->data[p->r_ocrb];
71         long f = clock >> cs_div;
72         long fa = f / (ocra+1), fb = f / (ocrb+1);
73
74 //      printf("%s-%c clock f=%ld cs=%02x (div %d) = %ldhz\n", __FUNCTION__, p->name, clock, cs, 1 << cs_div, f);
75         if (ocra) printf("%s-%c wgm %d OCRA=%3d = %ldhz\n", __FUNCTION__, p->name, mode, ocra, fa);
76         if (ocrb) printf("%s-%c wgm %d OCRB=%3d = %ldhz\n", __FUNCTION__, p->name, mode, ocrb, fb);
77
78         p->compa_cycles = avr_hz_to_cycles(avr, fa);
79         p->compb_cycles = avr_hz_to_cycles(avr, fb);
80         if (p->compa_cycles)
81                 avr_cycle_timer_register(avr, p->compa_cycles, avr_timer8_compa, p);
82         if (p->compb_cycles)
83                 avr_cycle_timer_register(avr, p->compb_cycles, avr_timer8_compb, p);
84 //      printf("%s-%c A %ld/%ld = cycles = %d\n", __FUNCTION__, p->name, (long)avr->frequency, fa, (int)p->compa_cycles);
85 //      printf("%s-%c B %ld/%ld = cycles = %d\n", __FUNCTION__, p->name, (long)avr->frequency, fb, (int)p->compb_cycles);
86 }
87
88 static void avr_timer8_reset(avr_io_t * port)
89 {
90         avr_timer8_t * p = (avr_timer8_t *)port;
91         avr_cycle_timer_cancel(p->io.avr, avr_timer8_compa, p);
92         avr_cycle_timer_cancel(p->io.avr, avr_timer8_compb, p);
93         p->compa_cycles = 0;
94         p->compb_cycles = 0;
95 }
96
97 static  avr_io_t        _io = {
98         .kind = "timer8",
99         .reset = avr_timer8_reset,
100 };
101
102 void avr_timer8_init(avr_t * avr, avr_timer8_t * p)
103 {
104         p->io = _io;
105 //      printf("%s timer%c created\n", __FUNCTION__, p->name);
106
107         avr_register_io(avr, &p->io);
108         avr_register_vector(avr, &p->compa);
109
110         avr_register_io_write(avr, p->cs[0].reg, avr_timer8_write, p);
111         avr_register_io_write(avr, p->r_ocra, avr_timer8_write, p);
112         avr_register_io_write(avr, p->r_ocrb, avr_timer8_write, p);
113
114         avr_register_io_read(avr, p->r_tcnt, avr_timer8_tcnt_read, p);
115 }