sim_core.c: extended data type to 32 bits for eicall/eijmp instruction.
[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 <ctype.h>
27 #include <stdint.h>
28 #include "sim_io.h"
29
30 int
31 avr_ioctl(
32                 avr_t *avr,
33                 uint32_t ctl,
34                 void * io_param)
35 {
36         avr_io_t * port = avr->io_port;
37         int res = -1;
38         while (port && res == -1) {
39                 if (port->ioctl)
40                         res = port->ioctl(port, ctl, io_param);
41                 port = port->next;
42         }
43         return res;
44 }
45
46 void
47 avr_register_io(
48                 avr_t *avr,
49                 avr_io_t * io)
50 {
51         io->next = avr->io_port;
52         io->avr = avr;
53         avr->io_port = io;
54 }
55
56 void
57 avr_register_io_read(
58                 avr_t *avr,
59                 avr_io_addr_t addr,
60                 avr_io_read_t readp,
61                 void * param)
62 {
63         avr_io_addr_t a = AVR_DATA_TO_IO(addr);
64         if (avr->io[a].r.param || avr->io[a].r.c) {
65                 if (avr->io[a].r.param != param || avr->io[a].r.c != readp) {
66                         AVR_LOG(avr, LOG_ERROR, "IO: avr_register_io_read(): Already registered, refusing to override.\n");
67                         AVR_LOG(avr, LOG_ERROR, "IO: 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 = (intptr_t)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         if (a >= MAX_IOs) {
101                 AVR_LOG(avr, LOG_ERROR, "IO: avr_register_io_write(): IO address 0x%04x out of range (max 0x%04x).\n",
102                                         a, MAX_IOs);
103                 abort();
104         }
105         /*
106          * Verifying that some other piece of code is not installed to watch write
107          * on this address. If there is, this code installs a "dispatcher" callback
108          * instead to handle multiple clients, otherwise, it continues as usual
109          */
110         if (avr->io[a].w.param || avr->io[a].w.c) {
111                 if (avr->io[a].w.param != param || avr->io[a].w.c != writep) {
112                         // if the muxer not already installed, allocate a new slot
113                         if (avr->io[a].w.c != _avr_io_mux_write) {
114                                 int no = avr->io_shared_io_count++;
115                                 if (avr->io_shared_io_count > 4) {
116                                         AVR_LOG(avr, LOG_ERROR, "IO: avr_register_io_write(): Too many shared IO registers.\n");
117                                         abort();
118                                 }
119                                 AVR_LOG(avr, LOG_TRACE, "IO: avr_register_io_write(%04x): Installing muxer on register.\n", addr);
120                                 avr->io_shared_io[no].used = 1;
121                                 avr->io_shared_io[no].io[0].param = avr->io[a].w.param;
122                                 avr->io_shared_io[no].io[0].c = avr->io[a].w.c;
123                                 avr->io[a].w.param = (void*)(intptr_t)no;
124                                 avr->io[a].w.c = _avr_io_mux_write;
125                         }
126                         int no = (intptr_t)avr->io[a].w.param;
127                         int d = avr->io_shared_io[no].used++;
128                         if (avr->io_shared_io[no].used > 4) {
129                                 AVR_LOG(avr, LOG_ERROR, "IO: avr_register_io_write(): Too many callbacks on %04x.\n", addr);
130                                 abort();
131                         }
132                         avr->io_shared_io[no].io[d].param = param;
133                         avr->io_shared_io[no].io[d].c = writep;
134                 }
135         }
136
137         avr->io[a].w.param = param;
138         avr->io[a].w.c = writep;
139 }
140
141 avr_irq_t *
142 avr_io_getirq(
143                 avr_t * avr,
144                 uint32_t ctl,
145                 int index)
146 {
147         avr_io_t * port = avr->io_port;
148         while (port) {
149                 if (port->irq && port->irq_ioctl_get == ctl && port->irq_count > index)
150                         return port->irq + index;
151                 port = port->next;
152         }
153         return NULL;
154         
155 }
156
157 avr_irq_t *
158 avr_iomem_getirq(
159                 avr_t * avr,
160                 avr_io_addr_t addr,
161                 const char * name,
162                 int index)
163 {
164         if (index > 8)
165                 return NULL;
166         avr_io_addr_t a = AVR_DATA_TO_IO(addr);
167         if (avr->io[a].irq == NULL) {
168                 /*
169                  * Prepare an array of names for the io IRQs. Ideally we'd love to have
170                  * a proper name for these, but it's not possible at this time.
171                  */
172                 char names[9 * 20];
173                 char * d = names;
174                 const char * namep[9];
175                 for (int ni = 0; ni < 9; ni++) {
176                         if (ni < 8)
177                                 sprintf(d, "=avr.io%04x.%d", addr, ni);
178                         else
179                                 sprintf(d, "8=avr.io%04x.all", addr);
180                         namep[ni] = d;
181                         d += strlen(d) + 1;
182                 }
183                 avr->io[a].irq = avr_alloc_irq(&avr->irq_pool, 0, 9, namep);
184                 // mark the pin ones as filtered, so they only are raised when changing
185                 for (int i = 0; i < 8; i++)
186                         avr->io[a].irq[i].flags |= IRQ_FLAG_FILTERED;
187         }
188         // if given a name, replace the default one...
189         if (name) {
190                 int l = strlen(name);
191                 char n[l + 10];
192                 sprintf(n, "avr.io.%s", name);
193                 free((void*)avr->io[a].irq[index].name);
194                 avr->io[a].irq[index].name = strdup(n);
195         }
196         return avr->io[a].irq + index;
197 }
198
199 avr_irq_t *
200 avr_io_setirqs(
201                 avr_io_t * io,
202                 uint32_t ctl,
203                 int count,
204                 avr_irq_t * irqs )
205 {
206         // allocate this module's IRQ
207         io->irq_count = count;
208
209         if (!irqs) {
210                 const char ** irq_names = NULL;
211
212                 if (io->irq_names) {
213                         irq_names = malloc(count * sizeof(char*));
214                         memset(irq_names, 0, count * sizeof(char*));
215                         char buf[64];
216                         for (int i = 0; i < count; i++) {
217                                 /*
218                                  * this bit takes the io module 'kind' ("port")
219                                  * the IRQ name ("=0") and the last character of the ioctl ('p','o','r','A')
220                                  * to create a full name "=porta.0"
221                                  */
222                                 char * dst = buf;
223                                 // copy the 'flags' of the name out
224                                 const char * kind = io->irq_names[i];
225                                 while (isdigit(*kind))
226                                         *dst++ = *kind++;
227                                 while (!isalpha(*kind))
228                                         *dst++ = *kind++;
229                                 // add avr name
230 //                              strcpy(dst, io->avr->mmcu);
231                                 strcpy(dst, "avr");
232                                 dst += strlen(dst);
233                                 *dst ++ = '.';
234                                 // add module 'kind'
235                                 strcpy(dst, io->kind);
236                                 dst += strlen(dst);
237                                 // add port name, if any
238                                 if ((ctl & 0xff) > ' ')
239                                         *dst ++ = tolower(ctl & 0xff);
240                                 *dst ++ = '.';
241                                 // add the rest of the irq name
242                                 strcpy(dst, kind);
243                                 dst += strlen(dst);
244                                 *dst = 0;
245
246 //                              printf("%s\n", buf);
247                                 irq_names[i] = strdup(buf);
248                         }
249                 }
250                 irqs = avr_alloc_irq(&io->avr->irq_pool, 0,
251                                                 count, irq_names);
252                 if (irq_names) {
253                         for (int i = 0; i < count; i++)
254                                 free((char*)irq_names[i]);
255                         free((char*)irq_names);
256                 }
257         }
258
259         io->irq = irqs;
260         io->irq_ioctl_get = ctl;
261         return io->irq;
262 }
263
264 static void
265 avr_deallocate_io(
266                 avr_io_t * io)
267 {
268         if (io->dealloc)
269                 io->dealloc(io);
270         avr_free_irq(io->irq, io->irq_count);
271         io->irq_count = 0;
272         io->irq_ioctl_get = 0;
273         io->avr = NULL;
274         io->next = NULL;
275 }
276
277 void
278 avr_deallocate_ios(
279                 avr_t * avr)
280 {
281         avr_io_t * port = avr->io_port;
282         while (port) {
283                 avr_io_t * next = port->next;
284                 avr_deallocate_io(port);
285                 port = next;
286         }
287         avr->io_port = NULL;
288 }