simavr: Updare simavr core to new IRQ prototypes
[simavr] / simavr / sim / sim_io.c
1 /*
2         sim_io.c
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include "sim_io.h"
27
28 int
29 avr_ioctl(
30                 avr_t *avr,
31                 uint32_t ctl,
32                 void * io_param)
33 {
34         avr_io_t * port = avr->io_port;
35         int res = -1;
36         while (port && res == -1) {
37                 if (port->ioctl)
38                         res = port->ioctl(port, ctl, io_param);
39                 port = port->next;
40         }
41         return res;
42 }
43
44 void
45 avr_register_io(
46                 avr_t *avr,
47                 avr_io_t * io)
48 {
49         io->next = avr->io_port;
50         io->avr = avr;
51         avr->io_port = io;
52 }
53
54 void
55 avr_register_io_read(
56                 avr_t *avr,
57                 avr_io_addr_t addr,
58                 avr_io_read_t readp,
59                 void * param)
60 {
61         avr_io_addr_t a = AVR_DATA_TO_IO(addr);
62         if (avr->io[a].r.param || avr->io[a].r.c) {
63                 if (avr->io[a].r.param != param || avr->io[a].r.c != readp) {
64                         fprintf(stderr,
65                                         "Error: avr_register_io_read(): Already registered, refusing to override.\n");
66                         fprintf(stderr,
67                                         "Error: avr_register_io_read(%04x : %p/%p): %p/%p\n", a,
68                                         avr->io[a].r.c, avr->io[a].r.param, readp, param);
69                         abort();
70                 }
71         }
72         avr->io[a].r.param = param;
73         avr->io[a].r.c = readp;
74 }
75
76 static void
77 _avr_io_mux_write(
78                 avr_t * avr,
79                 avr_io_addr_t addr,
80                 uint8_t v,
81                 void * param)
82 {
83         int io = (int)param;
84         for (int i = 0; i < avr->io_shared_io[io].used; i++) {
85                 avr_io_write_t c = avr->io_shared_io[io].io[i].c;
86                 if (c)
87                         c(avr, addr, v, avr->io_shared_io[io].io[i].param);
88         }
89 }
90
91 void
92 avr_register_io_write(
93                 avr_t *avr,
94                 avr_io_addr_t addr,
95                 avr_io_write_t writep,
96                 void * param)
97 {
98         avr_io_addr_t a = AVR_DATA_TO_IO(addr);
99
100         /*
101          * Verifying that some other piece of code is not installed to watch write
102          * on this address. If there is, this code installs a "dispatcher" callback
103          * instead to handle multiple clients, otherwise, it continues as usual
104          */
105         if (avr->io[a].w.param || avr->io[a].w.c) {
106                 if (avr->io[a].w.param != param || avr->io[a].w.c != writep) {
107                         // if the muxer not already installed, allocate a new slot
108                         if (avr->io[a].w.c != _avr_io_mux_write) {
109                                 int no = avr->io_shared_io_count++;
110                                 if (avr->io_shared_io_count > 4) {
111                                         fprintf(stderr,
112                                                         "Error: avr_register_io_write(): Too many shared IO registers.\n");
113                                         abort();
114                                 }
115                                 fprintf(stderr,
116                                                 "Note: avr_register_io_write(%04x): Installing muxer on register.\n", addr);
117                                 avr->io_shared_io[no].used = 1;
118                                 avr->io_shared_io[no].io[0].param = avr->io[a].w.param;
119                                 avr->io_shared_io[no].io[0].c = avr->io[a].w.c;
120                                 avr->io[a].w.param = (void*)no;
121                                 avr->io[a].w.c = _avr_io_mux_write;
122                         }
123                         int no = (int)avr->io[a].w.param;
124                         int d = avr->io_shared_io[no].used++;
125                         if (avr->io_shared_io[no].used > 4) {
126                                 fprintf(stderr,
127                                                 "Error: avr_register_io_write(): Too many callbacks on %04x.\n", addr);
128                                 abort();
129                         }
130                         avr->io_shared_io[no].io[d].param = param;
131                         avr->io_shared_io[no].io[d].c = writep;
132                 }
133         }
134
135         avr->io[a].w.param = param;
136         avr->io[a].w.c = writep;
137 }
138
139 avr_irq_t *
140 avr_io_getirq(
141                 avr_t * avr,
142                 uint32_t ctl,
143                 int index)
144 {
145         avr_io_t * port = avr->io_port;
146         while (port) {
147                 if (port->irq && port->irq_ioctl_get == ctl && port->irq_count > index)
148                         return port->irq + index;
149                 port = port->next;
150         }
151         return NULL;
152         
153 }
154
155 avr_irq_t *
156 avr_iomem_getirq(
157                 avr_t * avr,
158                 avr_io_addr_t addr,
159                 int index)
160 {
161         avr_io_addr_t a = AVR_DATA_TO_IO(addr);
162         if (avr->io[a].irq == NULL) {
163                 avr->io[a].irq = avr_alloc_irq(&avr->irq_pool, 0, 9, NULL /* TODO: names*/);
164                 // mark the pin ones as filtered, so they only are raised when changing
165                 for (int i = 0; i < 8; i++)
166                         avr->io[a].irq[i].flags |= IRQ_FLAG_FILTERED;
167         }
168         return index < 9 ? avr->io[a].irq + index : NULL;
169 }
170
171 avr_irq_t *
172 avr_io_setirqs(
173                 avr_io_t * io,
174                 uint32_t ctl,
175                 int count,
176                 avr_irq_t * irqs)
177 {
178         // allocate this module's IRQ
179         io->irq_count = count;
180         io->irq = irqs ? irqs :
181                 avr_alloc_irq(&io->avr->irq_pool, 0,
182                                 count, NULL /* TODO: names*/);
183         io->irq_ioctl_get = ctl;
184         return io->irq;
185 }
186
187 static void
188 avr_deallocate_io(
189                 avr_io_t * io)
190 {
191         if (io->dealloc)
192                 io->dealloc(io);
193         avr_free_irq(io->irq, io->irq_count);
194         io->irq_count = 0;
195         io->irq_ioctl_get = 0;
196         io->avr = NULL;
197         io->next = NULL;
198 }
199
200 void
201 avr_deallocate_ios(
202                 avr_t * avr)
203 {
204         avr_io_t * port = avr->io_port;
205         while (port) {
206                 avr_io_t * next = port->next;
207                 avr_deallocate_io(port);
208                 port = next;
209         }
210         avr->io_port = NULL;
211 }