Commit e5b39b1ee2635b85534b5a2f54f2307210294c32

Authored by dmakow
1 parent fd35d26c

Removed Windows end characters

Showing 1 changed file with 524 additions and 524 deletions
hw/at91_pio.c
1 -/*  
2 - * AT91 Parallel I/O Controller  
3 - *  
4 - * Copyright (c) 2009 Filip Navara  
5 - *  
6 - * Permission is hereby granted, free of charge, to any person obtaining a copy  
7 - * of this software and associated documentation files (the "Software"), to deal  
8 - * in the Software without restriction, including without limitation the rights  
9 - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
10 - * copies of the Software, and to permit persons to whom the Software is  
11 - * furnished to do so, subject to the following conditions:  
12 - *  
13 - * The above copyright notice and this permission notice shall be included in  
14 - * all copies or substantial portions of the Software.  
15 - *  
16 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
17 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
18 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL  
19 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
20 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
21 - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN  
22 - * THE SOFTWARE.  
23 - */  
24 -  
25 -/* TODO: Glitch-filter, multi-driver (ie. open drain) */  
26 -  
27 -#include "sysbus.h"  
28 -  
29 -//#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)  
30 -#define DPRINTF(fmt, ...) do { } while (0)  
31 -  
32 -/* Segment Display */  
33 -#define SEGTOP // displayed at the top of the terminal window  
34 -#define SEGPUTCHAR(com, pin, offset, symb) \  
35 -if (!(s->odsr & (1 << com)) && (s->odsr & (1 << pin))) segline[offset] = symb  
36 -#ifdef SEGTOP  
37 - #define SEGPRINT printf("\x1B[%d;60H%s", ln++, segline)  
38 -#else  
39 - #define SEGPRINT printf("\x1B[20C%s\n", segline)  
40 -#endif  
41 -  
42 -  
43 -/*  
44 - * Input/Output GPIO pins:  
45 - * 32x PIO device  
46 - * 32x peripheral A  
47 - * 32x peripheral B  
48 - */  
49 -  
50 -#define PIO_SIZE 0x200  
51 -#define PIO_PINS 32  
52 -  
53 -#define PIO_PER 0x00 /* PIO Enable Register */  
54 -#define PIO_PDR 0x04 /* PIO Disable Register */  
55 -#define PIO_PSR 0x08 /* PIO Status Register */  
56 -#define PIO_OER 0x10 /* Output Enable Register */  
57 -#define PIO_ODR 0x14 /* Output Disable Register */  
58 -#define PIO_OSR 0x18 /* Output Status Register */  
59 -#define PIO_IFER 0x20 /* Input Filter Enable Register */  
60 -#define PIO_IFDR 0x24 /* Input Filter Disable Register */  
61 -#define PIO_IFSR 0x28 /* Input Filter Status Register */  
62 -#define PIO_SODR 0x30 /* Set Output Data Register */  
63 -#define PIO_CODR 0x34 /* Clear Output Data Register */  
64 -#define PIO_ODSR 0x38 /* Output Data Status Register */  
65 -#define PIO_PDSR 0x3c /* Pin Data Status Register */  
66 -#define PIO_IER 0x40 /* Interrupt Enable Register */  
67 -#define PIO_IDR 0x44 /* Interrupt Disable Register */  
68 -#define PIO_IMR 0x48 /* Interrupt Mask Register */  
69 -#define PIO_ISR 0x4c /* Interrupt Status Register */  
70 -#define PIO_MDER 0x50 /* Multi-driver Enable Register */  
71 -#define PIO_MDDR 0x54 /* Multi-driver Disable Register */  
72 -#define PIO_MDSR 0x58 /* Multi-driver Status Register */  
73 -#define PIO_PPUDR 0x60 /* Pull-up Disable Register */  
74 -#define PIO_PPUER 0x64 /* Pull-up Enable Register */  
75 -#define PIO_PPUSR 0x68 /* Pull-up Status Register */  
76 -#define PIO_ASR 0x70 /* Select A Register */  
77 -#define PIO_BSR 0x74 /* Select B Register */  
78 -#define PIO_ABSR 0x78 /* AB Select Status Register */  
79 -#define PIO_OWER 0xa0 /* Output Write Enable Register */  
80 -#define PIO_OWDR 0xa4 /* Output Write Disable Register */  
81 -#define PIO_OWSR 0xa8 /* Output Write Status Register */  
82 -  
83 -typedef struct PIOState {  
84 - SysBusDevice busdev;  
85 - qemu_irq out[PIO_PINS * 3];  
86 - qemu_irq parent_irq;  
87 - uint32_t psr;  
88 - uint32_t osr;  
89 - uint32_t ifsr;  
90 - uint32_t odsr;  
91 - uint32_t pdsr;  
92 - uint32_t imr;  
93 - uint32_t isr;  
94 - uint32_t mdsr;  
95 - uint32_t ppusr;  
96 - uint32_t absr;  
97 - uint32_t owsr;  
98 - /* Mask of unknown state of PIO pins, needed for pull-up resistor  
99 - implementation */  
100 - uint32_t unknown_state;  
101 - int portid;  
102 -} PIOState;  
103 -  
104 -void at91_pio_set_pin(void *opaque, int pin, int level)  
105 -{  
106 - DPRINTF("In at91_pio_set_pin, opaque=%p, pin=%d, level=%d\n", opaque, pin, level);  
107 - PIOState *s = opaque;  
108 - int mask = 1 << (pin % PIO_PINS);  
109 - int input_set = pin / PIO_PINS;  
110 - int output_set = !!(s->absr & mask);  
111 - uint32_t saved_pdsr;  
112 -  
113 - if (input_set == 0) {  
114 - /* PIO pin -> Peripheral / IO */  
115 -  
116 - DPRINTF("In at91_pio_set_pin, s->osr=%08x, s->psr=%08x, mask=%08x\n",s->osr, s->psr, mask);  
117 -  
118 - /* Skip input if output mode is enabled for the pin */  
119 - if (s->osr & mask)  
120 - return;  
121 -  
122 - if (s->psr & mask) {  
123 - saved_pdsr = s->pdsr;  
124 - s->pdsr &= ~mask;  
125 - s->unknown_state &= ~mask;  
126 - if (level == -1) {  
127 - s->unknown_state |= mask;  
128 - } else if (level) {  
129 - DPRINTF("In at91_pio_set_pin, setting level\n");  
130 - s->unknown_state &= ~mask;  
131 - s->pdsr |= mask;  
132 - }  
133 - if (saved_pdsr != s->pdsr) {  
134 - s->isr |= mask;  
135 - qemu_set_irq(s->parent_irq, !!(s->isr & s->imr));  
136 - }  
137 - } else {  
138 - qemu_set_irq(s->out[PIO_PINS + (output_set * PIO_PINS)], level);  
139 - }  
140 - DPRINTF("In at91_pio_set_pin, s->pdsr=%08x\n",s->pdsr);  
141 -  
142 - } else {  
143 - /* Peripheral -> PIO pin */  
144 - if ((~s->psr & mask) && input_set == output_set) {  
145 - qemu_set_irq(s->out[pin & PIO_PINS], level);  
146 - }  
147 - }  
148 -}  
149 -  
150 -static uint32_t at91_pio_mem_read(void *opaque, target_phys_addr_t offset)  
151 -{  
152 - PIOState *s = opaque;  
153 - int isr;  
154 -  
155 - offset &= PIO_SIZE - 1;  
156 - switch (offset) {  
157 - case PIO_PSR:  
158 - return s->psr;  
159 - case PIO_OSR:  
160 - return s->osr;  
161 - case PIO_IFSR:  
162 - return s->ifsr;  
163 - case PIO_ODSR:  
164 - return s->odsr;  
165 - case PIO_PDSR:  
166 - DPRINTF("In at91_pio_mem_read, reading PDSR, s->pdsr=%08x, s->unknown_state=%08x, retval=%08x\n",  
167 - s->pdsr, s->unknown_state,  
168 - (s->pdsr & ~s->unknown_state) |  
169 - (s->ppusr & s->unknown_state));  
170 - return  
171 - (s->pdsr & ~s->unknown_state) |  
172 - (s->ppusr & s->unknown_state);  
173 - case PIO_IMR:  
174 - return s->imr;  
175 - case PIO_ISR:  
176 - isr = s->isr;  
177 - s->isr = 0;  
178 - qemu_set_irq(s->parent_irq, 0);  
179 - return isr;  
180 - case PIO_MDSR:  
181 - return s->mdsr;  
182 - case PIO_PPUSR:  
183 - return s->ppusr;  
184 - case PIO_ABSR:  
185 - return s->absr;  
186 - case PIO_OWSR:  
187 - return s->owsr;  
188 - default:  
189 - return 0;  
190 - }  
191 -}  
192 -  
193 -static void at91_pio_mem_write(void *opaque, target_phys_addr_t offset,  
194 - uint32_t value)  
195 -{  
196 - PIOState *s = opaque;  
197 - int i;  
198 -  
199 - DPRINTF("Writing PIO: portid=%d, offset=0x%08lx, value=0x%08x\n", s->portid, offset, value);  
200 -  
201 - offset &= PIO_SIZE - 1;  
202 -  
203 - uint32_t prev;  
204 -  
205 - int segdisp_refresh = 0;  
206 -  
207 - switch (offset) {  
208 - case PIO_PER:  
209 - s->psr |= value; //we should also detect LED state change in some cases  
210 - //printf("enabling, psr=0x%08x\n", s->psr);  
211 - break;  
212 - case PIO_PDR:  
213 - s->psr &= ~value;  
214 - //printf("disabling, psr=0x%08x\n", s->psr);  
215 - break;  
216 - case PIO_OER:  
217 - s->osr |= value;  
218 - break;  
219 - case PIO_ODR:  
220 - s->osr &= ~value;  
221 - break;  
222 - case PIO_IFER:  
223 - s->ifsr |= value;  
224 - break;  
225 - case PIO_IFDR:  
226 - s->ifsr &= ~value;  
227 - break;  
228 - case PIO_SODR:  
229 - prev = s->odsr;  
230 - s->odsr |= value;  
231 - for (i = 0; i < PIO_PINS; i++)  
232 - if (value & (1 << i) & s->osr & s->psr)  
233 - {  
234 - qemu_set_irq(s->out[i], 1);  
235 - if ((prev & (1 << i)) != (s->odsr & (1 << i)))  
236 - {  
237 - DPRINTF("Port %c%d set\n",'A' + s->portid, i);  
238 - if (  
239 - (s->portid == 1) && (i >= 20) && (i <= 27)  
240 - && ( !(s->odsr & (1 << 28)) || !(s->odsr & (1 << 30)) )  
241 - && !(s->odsr & (1 << 31))  
242 - )  
243 - segdisp_refresh = 1;  
244 - else if (  
245 - ((s->portid == 1) && ((i == 28) || (i == 30))  
246 - && !(s->odsr & (1 << 31)))  
247 - || ((s->portid == 1) && (i == 31)  
248 - && ( !(s->odsr & (1 << 28)) || !(s->odsr & (1 << 30)) ))  
249 - )  
250 - segdisp_refresh = 1;  
251 - else if ((s->portid == 1) && (i == 8))  
252 - printf("LED1 off\n");  
253 - else if ((s->portid == 2) && (i == 29))  
254 - printf("LED2 off\n");  
255 - }  
256 - }  
257 - break;  
258 - case PIO_CODR:  
259 - prev = s->odsr;  
260 - s->odsr &= ~value;  
261 - for (i = 0; i < PIO_PINS; i++)  
262 - if (value & (1 << i) & s->osr & s->psr)  
263 - {  
264 - qemu_set_irq(s->out[i], 0);  
265 - if ((prev & (1 << i)) != (s->odsr & (1 << i)))  
266 - {  
267 - DPRINTF("Port %c%d reset\n",'A' + s->portid, i);  
268 - if (  
269 - (s->portid == 1) && (i >= 20) && (i <= 27)  
270 - && ( !(s->odsr & (1 << 28)) || !(s->odsr & (1 << 30)) )  
271 - && !(s->odsr & (1 << 31))  
272 - )  
273 - segdisp_refresh = 1;  
274 - else if (  
275 - ((s->portid == 1) && ((i == 28) || (i == 30))  
276 - && !(s->odsr & (1 << 31)))  
277 - || ((s->portid == 1) && (i == 31)  
278 - && ( !(s->odsr & (1 << 28)) || !(s->odsr & (1 << 30)) ))  
279 - )  
280 - segdisp_refresh = 1;  
281 - else if ((s->portid == 1) && (i == 8))  
282 - printf("LED1 on\n");  
283 - else if ((s->portid == 2) && (i == 29))  
284 - printf("LED2 on\n");  
285 - }  
286 - }  
287 - break;  
288 - case PIO_ODSR:  
289 - prev = s->odsr;  
290 - s->odsr = (s->odsr & ~s->owsr) | (value & s->owsr);  
291 - for (i = 0; i < PIO_PINS; i++)  
292 - if (s->owsr & (1 << i))  
293 - {  
294 - qemu_set_irq(s->out[i], !!(value & (1 << i)));  
295 - if ((prev & (1 << i)) != (s->odsr & (1 << i)))  
296 - {  
297 - DPRINTF("Port %c%d written\n",'A' + s->portid, i);  
298 - if (  
299 - (s->portid == 1) && (i >= 20) && (i <= 27)  
300 - && ( !(s->odsr & (1 << 28)) || !(s->odsr & (1 << 30)) )  
301 - && !(s->odsr & (1 << 31))  
302 - )  
303 - segdisp_refresh = 1;  
304 - else if (  
305 - ((s->portid == 1) && ((i == 28) || (i == 30))  
306 - && !(s->odsr & (1 << 31)))  
307 - || ((s->portid == 1) && (i == 31)  
308 - && ( !(s->odsr & (1 << 28)) || !(s->odsr & (1 << 30)) ))  
309 - )  
310 - segdisp_refresh = 1;  
311 - else if ((s->portid == 1) && (i == 8))  
312 - printf("LED1 %s\n", ((s->odsr & (1 << i)) ? "off" : "on"));  
313 - else if ((s->portid == 2) && (i == 29))  
314 - printf("LED2 %s\n", ((s->odsr & (1 << i)) ? "off" : "on"));  
315 - }  
316 - }  
317 - break;  
318 - case PIO_IER:  
319 - s->imr |= value;  
320 - break;  
321 - case PIO_IDR:  
322 - s->imr &= ~value;  
323 - break;  
324 - case PIO_MDER:  
325 - s->mdsr |= value;  
326 - break;  
327 - case PIO_MDDR:  
328 - s->mdsr &= ~value;  
329 - break;  
330 - case PIO_PPUER:  
331 - s->ppusr |= value;  
332 - break;  
333 - case PIO_PPUDR:  
334 - s->ppusr &= ~value;  
335 - break;  
336 - case PIO_ASR:  
337 - s->absr &= ~value;  
338 - break;  
339 - case PIO_BSR:  
340 - s->absr |= value;  
341 - break;  
342 - case PIO_OWER:  
343 - s->owsr |= value;  
344 - break;  
345 - case PIO_OWDR:  
346 - s->owsr &= ~value;  
347 - break;  
348 - default:  
349 - return;  
350 - }  
351 - if (segdisp_refresh)  
352 - {  
353 - // printf("Segment display changed\n");  
354 - char segline[12];  
355 - int ln;  
356 -  
357 -#ifdef SEGTOP  
358 - printf("\x1B[s" "\x1B""7");  
359 -#else  
360 - printf("\n");  
361 -#endif  
362 - printf("\x1B[91m");  
363 -  
364 - strcpy(segline, " ");  
365 - ln = 1;  
366 - SEGPRINT;  
367 - SEGPRINT;  
368 -  
369 - if (s->odsr & (1 << 31))  
370 - {  
371 - while (ln <= 7)  
372 - SEGPRINT;  
373 - }  
374 - else  
375 - {  
376 - strcpy(segline, " ");  
377 - SEGPUTCHAR(28,25,0+1,'-');  
378 - SEGPUTCHAR(28,25,0+2,'-');  
379 - SEGPUTCHAR(30,25,6+1,'-');  
380 - SEGPUTCHAR(30,25,6+2,'-');  
381 - SEGPRINT;  
382 -  
383 - strcpy(segline, " ");  
384 - SEGPUTCHAR(28,27,0+0,'|');  
385 - SEGPUTCHAR(28,24,0+3,'|');  
386 - SEGPUTCHAR(30,27,6+0,'|');  
387 - SEGPUTCHAR(30,24,6+3,'|');  
388 - SEGPRINT;  
389 -  
390 - strcpy(segline, " ");  
391 - SEGPUTCHAR(28,26,0+1,'-');  
392 - SEGPUTCHAR(28,26,0+2,'-');  
393 - SEGPUTCHAR(30,26,6+1,'-');  
394 - SEGPUTCHAR(30,26,6+2,'-');  
395 - SEGPRINT;  
396 -  
397 - strcpy(segline, " ");  
398 - SEGPUTCHAR(28,20,0+0,'|');  
399 - SEGPUTCHAR(28,22,0+3,'|');  
400 - SEGPUTCHAR(30,20,6+0,'|');  
401 - SEGPUTCHAR(30,22,6+3,'|');  
402 - SEGPRINT;  
403 -  
404 - strcpy(segline, " ");  
405 - SEGPUTCHAR(28,21,0+1,'-');  
406 - SEGPUTCHAR(28,21,0+2,'-');  
407 - SEGPUTCHAR(30,21,6+1,'-');  
408 - SEGPUTCHAR(30,21,6+2,'-');  
409 - SEGPUTCHAR(28,23,0+4,'.');  
410 - SEGPUTCHAR(30,23,6+4,'.');  
411 - SEGPRINT;  
412 - }  
413 -  
414 -#ifdef SEGTOP  
415 - printf("\x1B""8" "\x1B[u");  
416 -#else  
417 - printf("\x1B[8A");  
418 -#endif  
419 - printf("\x1B[0m");  
420 - fflush(stdout);  
421 - }  
422 -}  
423 -  
424 -static CPUReadMemoryFunc *at91_pio_readfn[] = {  
425 - at91_pio_mem_read,  
426 - at91_pio_mem_read,  
427 - at91_pio_mem_read,  
428 -};  
429 -  
430 -static CPUWriteMemoryFunc *at91_pio_writefn[] = {  
431 - at91_pio_mem_write,  
432 - at91_pio_mem_write,  
433 - at91_pio_mem_write,  
434 -};  
435 -  
436 -static void at91_pio_save(QEMUFile *f, void *opaque)  
437 -{  
438 - PIOState *s = opaque;  
439 -  
440 - qemu_put_be32(f, s->psr);  
441 - qemu_put_be32(f, s->osr);  
442 - qemu_put_be32(f, s->ifsr);  
443 - qemu_put_be32(f, s->odsr);  
444 - qemu_put_be32(f, s->pdsr);  
445 - qemu_put_be32(f, s->imr);  
446 - qemu_put_be32(f, s->isr);  
447 - qemu_put_be32(f, s->mdsr);  
448 - qemu_put_be32(f, s->ppusr);  
449 - qemu_put_be32(f, s->absr);  
450 - qemu_put_be32(f, s->owsr);  
451 - qemu_put_be32(f, s->unknown_state);  
452 -}  
453 -  
454 -static int at91_pio_load(QEMUFile *f, void *opaque, int version_id)  
455 -{  
456 - PIOState *s = opaque;  
457 -  
458 - if (version_id != 1)  
459 - return -EINVAL;  
460 -  
461 - s->psr = qemu_get_be32(f);  
462 - s->osr = qemu_get_be32(f);  
463 - s->ifsr = qemu_get_be32(f);  
464 - s->odsr = qemu_get_be32(f);  
465 - s->pdsr = qemu_get_be32(f);  
466 - s->imr = qemu_get_be32(f);  
467 - s->isr = qemu_get_be32(f);  
468 - s->mdsr = qemu_get_be32(f);  
469 - s->ppusr = qemu_get_be32(f);  
470 - s->absr = qemu_get_be32(f);  
471 - s->owsr = qemu_get_be32(f);  
472 - s->unknown_state = qemu_get_be32(f);  
473 -  
474 - return 0;  
475 -}  
476 -  
477 -static void at91_pio_reset(void *opaque)  
478 -{  
479 - PIOState *s = opaque;  
480 -  
481 - s->psr = 0xffffffff;  
482 - s->osr = 0;  
483 - s->ifsr = 0;  
484 - s->odsr = 0;  
485 - s->pdsr = 0;  
486 - s->imr = 0;  
487 - s->isr = 0;  
488 - s->mdsr = 0;  
489 - s->ppusr = 0;  
490 - s->absr = 0;  
491 - s->owsr = 0;  
492 - s->unknown_state = 0xffffffff;  
493 -}  
494 -  
495 -void* at91_io_state[5];  
496 -int at91_io_cnt = 0;  
497 -  
498 -static void at91_pio_init(SysBusDevice *dev)  
499 -{  
500 - DPRINTF("at91_pio_init called\n");  
501 - PIOState *s = FROM_SYSBUS(typeof (*s), dev);  
502 - s->portid = at91_io_cnt;  
503 - at91_io_state[at91_io_cnt++] = s;  
504 - int pio_regs;  
505 -  
506 - sysbus_init_irq(dev, &s->parent_irq);  
507 - qdev_init_gpio_in(&dev->qdev, at91_pio_set_pin, PIO_PINS * 3);  
508 - qdev_init_gpio_out(&dev->qdev, s->out, PIO_PINS * 3);  
509 -  
510 - pio_regs = cpu_register_io_memory(at91_pio_readfn, at91_pio_writefn, s);  
511 - sysbus_init_mmio(dev, PIO_SIZE, pio_regs);  
512 -  
513 - at91_pio_reset(s);  
514 - qemu_register_reset(at91_pio_reset, s);  
515 -  
516 - register_savevm("at91_pio", -1, 1, at91_pio_save, at91_pio_load, s);  
517 -}  
518 -  
519 -static void at91_pio_register(void)  
520 -{  
521 - sysbus_register_dev("at91,pio", sizeof(PIOState), at91_pio_init);  
522 -}  
523 -  
524 -device_init(at91_pio_register) 1 +/*
  2 + * AT91 Parallel I/O Controller
  3 + *
  4 + * Copyright (c) 2009 Filip Navara
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +
  25 +/* TODO: Glitch-filter, multi-driver (ie. open drain) */
  26 +
  27 +#include "sysbus.h"
  28 +
  29 +//#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
  30 +#define DPRINTF(fmt, ...) do { } while (0)
  31 +
  32 +/* Segment Display */
  33 +#define SEGTOP // displayed at the top of the terminal window
  34 +#define SEGPUTCHAR(com, pin, offset, symb) \
  35 +if (!(s->odsr & (1 << com)) && (s->odsr & (1 << pin))) segline[offset] = symb
  36 +#ifdef SEGTOP
  37 + #define SEGPRINT printf("\x1B[%d;60H%s", ln++, segline)
  38 +#else
  39 + #define SEGPRINT printf("\x1B[20C%s\n", segline)
  40 +#endif
  41 +
  42 +
  43 +/*
  44 + * Input/Output GPIO pins:
  45 + * 32x PIO device
  46 + * 32x peripheral A
  47 + * 32x peripheral B
  48 + */
  49 +
  50 +#define PIO_SIZE 0x200
  51 +#define PIO_PINS 32
  52 +
  53 +#define PIO_PER 0x00 /* PIO Enable Register */
  54 +#define PIO_PDR 0x04 /* PIO Disable Register */
  55 +#define PIO_PSR 0x08 /* PIO Status Register */
  56 +#define PIO_OER 0x10 /* Output Enable Register */
  57 +#define PIO_ODR 0x14 /* Output Disable Register */
  58 +#define PIO_OSR 0x18 /* Output Status Register */
  59 +#define PIO_IFER 0x20 /* Input Filter Enable Register */
  60 +#define PIO_IFDR 0x24 /* Input Filter Disable Register */
  61 +#define PIO_IFSR 0x28 /* Input Filter Status Register */
  62 +#define PIO_SODR 0x30 /* Set Output Data Register */
  63 +#define PIO_CODR 0x34 /* Clear Output Data Register */
  64 +#define PIO_ODSR 0x38 /* Output Data Status Register */
  65 +#define PIO_PDSR 0x3c /* Pin Data Status Register */
  66 +#define PIO_IER 0x40 /* Interrupt Enable Register */
  67 +#define PIO_IDR 0x44 /* Interrupt Disable Register */
  68 +#define PIO_IMR 0x48 /* Interrupt Mask Register */
  69 +#define PIO_ISR 0x4c /* Interrupt Status Register */
  70 +#define PIO_MDER 0x50 /* Multi-driver Enable Register */
  71 +#define PIO_MDDR 0x54 /* Multi-driver Disable Register */
  72 +#define PIO_MDSR 0x58 /* Multi-driver Status Register */
  73 +#define PIO_PPUDR 0x60 /* Pull-up Disable Register */
  74 +#define PIO_PPUER 0x64 /* Pull-up Enable Register */
  75 +#define PIO_PPUSR 0x68 /* Pull-up Status Register */
  76 +#define PIO_ASR 0x70 /* Select A Register */
  77 +#define PIO_BSR 0x74 /* Select B Register */
  78 +#define PIO_ABSR 0x78 /* AB Select Status Register */
  79 +#define PIO_OWER 0xa0 /* Output Write Enable Register */
  80 +#define PIO_OWDR 0xa4 /* Output Write Disable Register */
  81 +#define PIO_OWSR 0xa8 /* Output Write Status Register */
  82 +
  83 +typedef struct PIOState {
  84 + SysBusDevice busdev;
  85 + qemu_irq out[PIO_PINS * 3];
  86 + qemu_irq parent_irq;
  87 + uint32_t psr;
  88 + uint32_t osr;
  89 + uint32_t ifsr;
  90 + uint32_t odsr;
  91 + uint32_t pdsr;
  92 + uint32_t imr;
  93 + uint32_t isr;
  94 + uint32_t mdsr;
  95 + uint32_t ppusr;
  96 + uint32_t absr;
  97 + uint32_t owsr;
  98 + /* Mask of unknown state of PIO pins, needed for pull-up resistor
  99 + implementation */
  100 + uint32_t unknown_state;
  101 + int portid;
  102 +} PIOState;
  103 +
  104 +void at91_pio_set_pin(void *opaque, int pin, int level)
  105 +{
  106 + DPRINTF("In at91_pio_set_pin, opaque=%p, pin=%d, level=%d\n", opaque, pin, level);
  107 + PIOState *s = opaque;
  108 + int mask = 1 << (pin % PIO_PINS);
  109 + int input_set = pin / PIO_PINS;
  110 + int output_set = !!(s->absr & mask);
  111 + uint32_t saved_pdsr;
  112 +
  113 + if (input_set == 0) {
  114 + /* PIO pin -> Peripheral / IO */
  115 +
  116 + DPRINTF("In at91_pio_set_pin, s->osr=%08x, s->psr=%08x, mask=%08x\n",s->osr, s->psr, mask);
  117 +
  118 + /* Skip input if output mode is enabled for the pin */
  119 + if (s->osr & mask)
  120 + return;
  121 +
  122 + if (s->psr & mask) {
  123 + saved_pdsr = s->pdsr;
  124 + s->pdsr &= ~mask;
  125 + s->unknown_state &= ~mask;
  126 + if (level == -1) {
  127 + s->unknown_state |= mask;
  128 + } else if (level) {
  129 + DPRINTF("In at91_pio_set_pin, setting level\n");
  130 + s->unknown_state &= ~mask;
  131 + s->pdsr |= mask;
  132 + }
  133 + if (saved_pdsr != s->pdsr) {
  134 + s->isr |= mask;
  135 + qemu_set_irq(s->parent_irq, !!(s->isr & s->imr));
  136 + }
  137 + } else {
  138 + qemu_set_irq(s->out[PIO_PINS + (output_set * PIO_PINS)], level);
  139 + }
  140 + DPRINTF("In at91_pio_set_pin, s->pdsr=%08x\n",s->pdsr);
  141 +
  142 + } else {
  143 + /* Peripheral -> PIO pin */
  144 + if ((~s->psr & mask) && input_set == output_set) {
  145 + qemu_set_irq(s->out[pin & PIO_PINS], level);
  146 + }
  147 + }
  148 +}
  149 +
  150 +static uint32_t at91_pio_mem_read(void *opaque, target_phys_addr_t offset)
  151 +{
  152 + PIOState *s = opaque;
  153 + int isr;
  154 +
  155 + offset &= PIO_SIZE - 1;
  156 + switch (offset) {
  157 + case PIO_PSR:
  158 + return s->psr;
  159 + case PIO_OSR:
  160 + return s->osr;
  161 + case PIO_IFSR:
  162 + return s->ifsr;
  163 + case PIO_ODSR:
  164 + return s->odsr;
  165 + case PIO_PDSR:
  166 + DPRINTF("In at91_pio_mem_read, reading PDSR, s->pdsr=%08x, s->unknown_state=%08x, retval=%08x\n",
  167 + s->pdsr, s->unknown_state,
  168 + (s->pdsr & ~s->unknown_state) |
  169 + (s->ppusr & s->unknown_state));
  170 + return
  171 + (s->pdsr & ~s->unknown_state) |
  172 + (s->ppusr & s->unknown_state);
  173 + case PIO_IMR:
  174 + return s->imr;
  175 + case PIO_ISR:
  176 + isr = s->isr;
  177 + s->isr = 0;
  178 + qemu_set_irq(s->parent_irq, 0);
  179 + return isr;
  180 + case PIO_MDSR:
  181 + return s->mdsr;
  182 + case PIO_PPUSR:
  183 + return s->ppusr;
  184 + case PIO_ABSR:
  185 + return s->absr;
  186 + case PIO_OWSR:
  187 + return s->owsr;
  188 + default:
  189 + return 0;
  190 + }
  191 +}
  192 +
  193 +static void at91_pio_mem_write(void *opaque, target_phys_addr_t offset,
  194 + uint32_t value)
  195 +{
  196 + PIOState *s = opaque;
  197 + int i;
  198 +
  199 + DPRINTF("Writing PIO: portid=%d, offset=0x%08lx, value=0x%08x\n", s->portid, offset, value);
  200 +
  201 + offset &= PIO_SIZE - 1;
  202 +
  203 + uint32_t prev;
  204 +
  205 + int segdisp_refresh = 0;
  206 +
  207 + switch (offset) {
  208 + case PIO_PER:
  209 + s->psr |= value; //we should also detect LED state change in some cases
  210 + //printf("enabling, psr=0x%08x\n", s->psr);
  211 + break;
  212 + case PIO_PDR:
  213 + s->psr &= ~value;
  214 + //printf("disabling, psr=0x%08x\n", s->psr);
  215 + break;
  216 + case PIO_OER:
  217 + s->osr |= value;
  218 + break;
  219 + case PIO_ODR:
  220 + s->osr &= ~value;
  221 + break;
  222 + case PIO_IFER:
  223 + s->ifsr |= value;
  224 + break;
  225 + case PIO_IFDR:
  226 + s->ifsr &= ~value;
  227 + break;
  228 + case PIO_SODR:
  229 + prev = s->odsr;
  230 + s->odsr |= value;
  231 + for (i = 0; i < PIO_PINS; i++)
  232 + if (value & (1 << i) & s->osr & s->psr)
  233 + {
  234 + qemu_set_irq(s->out[i], 1);
  235 + if ((prev & (1 << i)) != (s->odsr & (1 << i)))
  236 + {
  237 + DPRINTF("Port %c%d set\n",'A' + s->portid, i);
  238 + if (
  239 + (s->portid == 1) && (i >= 20) && (i <= 27)
  240 + && ( !(s->odsr & (1 << 28)) || !(s->odsr & (1 << 30)) )
  241 + && !(s->odsr & (1 << 31))
  242 + )
  243 + segdisp_refresh = 1;
  244 + else if (
  245 + ((s->portid == 1) && ((i == 28) || (i == 30))
  246 + && !(s->odsr & (1 << 31)))
  247 + || ((s->portid == 1) && (i == 31)
  248 + && ( !(s->odsr & (1 << 28)) || !(s->odsr & (1 << 30)) ))
  249 + )
  250 + segdisp_refresh = 1;
  251 + else if ((s->portid == 1) && (i == 8))
  252 + printf("LED1 off\n");
  253 + else if ((s->portid == 2) && (i == 29))
  254 + printf("LED2 off\n");
  255 + }
  256 + }
  257 + break;
  258 + case PIO_CODR:
  259 + prev = s->odsr;
  260 + s->odsr &= ~value;
  261 + for (i = 0; i < PIO_PINS; i++)
  262 + if (value & (1 << i) & s->osr & s->psr)
  263 + {
  264 + qemu_set_irq(s->out[i], 0);
  265 + if ((prev & (1 << i)) != (s->odsr & (1 << i)))
  266 + {
  267 + DPRINTF("Port %c%d reset\n",'A' + s->portid, i);
  268 + if (
  269 + (s->portid == 1) && (i >= 20) && (i <= 27)
  270 + && ( !(s->odsr & (1 << 28)) || !(s->odsr & (1 << 30)) )
  271 + && !(s->odsr & (1 << 31))
  272 + )
  273 + segdisp_refresh = 1;
  274 + else if (
  275 + ((s->portid == 1) && ((i == 28) || (i == 30))
  276 + && !(s->odsr & (1 << 31)))
  277 + || ((s->portid == 1) && (i == 31)
  278 + && ( !(s->odsr & (1 << 28)) || !(s->odsr & (1 << 30)) ))
  279 + )
  280 + segdisp_refresh = 1;
  281 + else if ((s->portid == 1) && (i == 8))
  282 + printf("LED1 on\n");
  283 + else if ((s->portid == 2) && (i == 29))
  284 + printf("LED2 on\n");
  285 + }
  286 + }
  287 + break;
  288 + case PIO_ODSR:
  289 + prev = s->odsr;
  290 + s->odsr = (s->odsr & ~s->owsr) | (value & s->owsr);
  291 + for (i = 0; i < PIO_PINS; i++)
  292 + if (s->owsr & (1 << i))
  293 + {
  294 + qemu_set_irq(s->out[i], !!(value & (1 << i)));
  295 + if ((prev & (1 << i)) != (s->odsr & (1 << i)))
  296 + {
  297 + DPRINTF("Port %c%d written\n",'A' + s->portid, i);
  298 + if (
  299 + (s->portid == 1) && (i >= 20) && (i <= 27)
  300 + && ( !(s->odsr & (1 << 28)) || !(s->odsr & (1 << 30)) )
  301 + && !(s->odsr & (1 << 31))
  302 + )
  303 + segdisp_refresh = 1;
  304 + else if (
  305 + ((s->portid == 1) && ((i == 28) || (i == 30))
  306 + && !(s->odsr & (1 << 31)))
  307 + || ((s->portid == 1) && (i == 31)
  308 + && ( !(s->odsr & (1 << 28)) || !(s->odsr & (1 << 30)) ))
  309 + )
  310 + segdisp_refresh = 1;
  311 + else if ((s->portid == 1) && (i == 8))
  312 + printf("LED1 %s\n", ((s->odsr & (1 << i)) ? "off" : "on"));
  313 + else if ((s->portid == 2) && (i == 29))
  314 + printf("LED2 %s\n", ((s->odsr & (1 << i)) ? "off" : "on"));
  315 + }
  316 + }
  317 + break;
  318 + case PIO_IER:
  319 + s->imr |= value;
  320 + break;
  321 + case PIO_IDR:
  322 + s->imr &= ~value;
  323 + break;
  324 + case PIO_MDER:
  325 + s->mdsr |= value;
  326 + break;
  327 + case PIO_MDDR:
  328 + s->mdsr &= ~value;
  329 + break;
  330 + case PIO_PPUER:
  331 + s->ppusr |= value;
  332 + break;
  333 + case PIO_PPUDR:
  334 + s->ppusr &= ~value;
  335 + break;
  336 + case PIO_ASR:
  337 + s->absr &= ~value;
  338 + break;
  339 + case PIO_BSR:
  340 + s->absr |= value;
  341 + break;
  342 + case PIO_OWER:
  343 + s->owsr |= value;
  344 + break;
  345 + case PIO_OWDR:
  346 + s->owsr &= ~value;
  347 + break;
  348 + default:
  349 + return;
  350 + }
  351 + if (segdisp_refresh)
  352 + {
  353 + // printf("Segment display changed\n");
  354 + char segline[12];
  355 + int ln;
  356 +
  357 +#ifdef SEGTOP
  358 + printf("\x1B[s" "\x1B""7");
  359 +#else
  360 + printf("\n");
  361 +#endif
  362 + printf("\x1B[91m");
  363 +
  364 + strcpy(segline, " ");
  365 + ln = 1;
  366 + SEGPRINT;
  367 + SEGPRINT;
  368 +
  369 + if (s->odsr & (1 << 31))
  370 + {
  371 + while (ln <= 7)
  372 + SEGPRINT;
  373 + }
  374 + else
  375 + {
  376 + strcpy(segline, " ");
  377 + SEGPUTCHAR(28,25,0+1,'-');
  378 + SEGPUTCHAR(28,25,0+2,'-');
  379 + SEGPUTCHAR(30,25,6+1,'-');
  380 + SEGPUTCHAR(30,25,6+2,'-');
  381 + SEGPRINT;
  382 +
  383 + strcpy(segline, " ");
  384 + SEGPUTCHAR(28,27,0+0,'|');
  385 + SEGPUTCHAR(28,24,0+3,'|');
  386 + SEGPUTCHAR(30,27,6+0,'|');
  387 + SEGPUTCHAR(30,24,6+3,'|');
  388 + SEGPRINT;
  389 +
  390 + strcpy(segline, " ");
  391 + SEGPUTCHAR(28,26,0+1,'-');
  392 + SEGPUTCHAR(28,26,0+2,'-');
  393 + SEGPUTCHAR(30,26,6+1,'-');
  394 + SEGPUTCHAR(30,26,6+2,'-');
  395 + SEGPRINT;
  396 +
  397 + strcpy(segline, " ");
  398 + SEGPUTCHAR(28,20,0+0,'|');
  399 + SEGPUTCHAR(28,22,0+3,'|');
  400 + SEGPUTCHAR(30,20,6+0,'|');
  401 + SEGPUTCHAR(30,22,6+3,'|');
  402 + SEGPRINT;
  403 +
  404 + strcpy(segline, " ");
  405 + SEGPUTCHAR(28,21,0+1,'-');
  406 + SEGPUTCHAR(28,21,0+2,'-');
  407 + SEGPUTCHAR(30,21,6+1,'-');
  408 + SEGPUTCHAR(30,21,6+2,'-');
  409 + SEGPUTCHAR(28,23,0+4,'.');
  410 + SEGPUTCHAR(30,23,6+4,'.');
  411 + SEGPRINT;
  412 + }
  413 +
  414 +#ifdef SEGTOP
  415 + printf("\x1B""8" "\x1B[u");
  416 +#else
  417 + printf("\x1B[8A");
  418 +#endif
  419 + printf("\x1B[0m");
  420 + fflush(stdout);
  421 + }
  422 +}
  423 +
  424 +static CPUReadMemoryFunc *at91_pio_readfn[] = {
  425 + at91_pio_mem_read,
  426 + at91_pio_mem_read,
  427 + at91_pio_mem_read,
  428 +};
  429 +
  430 +static CPUWriteMemoryFunc *at91_pio_writefn[] = {
  431 + at91_pio_mem_write,
  432 + at91_pio_mem_write,
  433 + at91_pio_mem_write,
  434 +};
  435 +
  436 +static void at91_pio_save(QEMUFile *f, void *opaque)
  437 +{
  438 + PIOState *s = opaque;
  439 +
  440 + qemu_put_be32(f, s->psr);
  441 + qemu_put_be32(f, s->osr);
  442 + qemu_put_be32(f, s->ifsr);
  443 + qemu_put_be32(f, s->odsr);
  444 + qemu_put_be32(f, s->pdsr);
  445 + qemu_put_be32(f, s->imr);
  446 + qemu_put_be32(f, s->isr);
  447 + qemu_put_be32(f, s->mdsr);
  448 + qemu_put_be32(f, s->ppusr);
  449 + qemu_put_be32(f, s->absr);
  450 + qemu_put_be32(f, s->owsr);
  451 + qemu_put_be32(f, s->unknown_state);
  452 +}
  453 +
  454 +static int at91_pio_load(QEMUFile *f, void *opaque, int version_id)
  455 +{
  456 + PIOState *s = opaque;
  457 +
  458 + if (version_id != 1)
  459 + return -EINVAL;
  460 +
  461 + s->psr = qemu_get_be32(f);
  462 + s->osr = qemu_get_be32(f);
  463 + s->ifsr = qemu_get_be32(f);
  464 + s->odsr = qemu_get_be32(f);
  465 + s->pdsr = qemu_get_be32(f);
  466 + s->imr = qemu_get_be32(f);
  467 + s->isr = qemu_get_be32(f);
  468 + s->mdsr = qemu_get_be32(f);
  469 + s->ppusr = qemu_get_be32(f);
  470 + s->absr = qemu_get_be32(f);
  471 + s->owsr = qemu_get_be32(f);
  472 + s->unknown_state = qemu_get_be32(f);
  473 +
  474 + return 0;
  475 +}
  476 +
  477 +static void at91_pio_reset(void *opaque)
  478 +{
  479 + PIOState *s = opaque;
  480 +
  481 + s->psr = 0xffffffff;
  482 + s->osr = 0;
  483 + s->ifsr = 0;
  484 + s->odsr = 0;
  485 + s->pdsr = 0;
  486 + s->imr = 0;
  487 + s->isr = 0;
  488 + s->mdsr = 0;
  489 + s->ppusr = 0;
  490 + s->absr = 0;
  491 + s->owsr = 0;
  492 + s->unknown_state = 0xffffffff;
  493 +}
  494 +
  495 +void* at91_io_state[5];
  496 +int at91_io_cnt = 0;
  497 +
  498 +static void at91_pio_init(SysBusDevice *dev)
  499 +{
  500 + DPRINTF("at91_pio_init called\n");
  501 + PIOState *s = FROM_SYSBUS(typeof (*s), dev);
  502 + s->portid = at91_io_cnt;
  503 + at91_io_state[at91_io_cnt++] = s;
  504 + int pio_regs;
  505 +
  506 + sysbus_init_irq(dev, &s->parent_irq);
  507 + qdev_init_gpio_in(&dev->qdev, at91_pio_set_pin, PIO_PINS * 3);
  508 + qdev_init_gpio_out(&dev->qdev, s->out, PIO_PINS * 3);
  509 +
  510 + pio_regs = cpu_register_io_memory(at91_pio_readfn, at91_pio_writefn, s);
  511 + sysbus_init_mmio(dev, PIO_SIZE, pio_regs);
  512 +
  513 + at91_pio_reset(s);
  514 + qemu_register_reset(at91_pio_reset, s);
  515 +
  516 + register_savevm("at91_pio", -1, 1, at91_pio_save, at91_pio_load, s);
  517 +}
  518 +
  519 +static void at91_pio_register(void)
  520 +{
  521 + sysbus_register_dev("at91,pio", sizeof(PIOState), at91_pio_init);
  522 +}
  523 +
  524 +device_init(at91_pio_register)