Commit fd35d26cc6ee07717a12402cae6d7f2e2e8dddb4

Authored by dmakow
1 parent fbb25edb

Added support for 7-LED display provided by L.Starzak

Showing 1 changed file with 524 additions and 391 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 -  
33 -  
34 -/*  
35 - * Input/Output GPIO pins:  
36 - * 32x PIO device  
37 - * 32x peripheral A  
38 - * 32x peripheral B  
39 - */  
40 -  
41 -#define PIO_SIZE 0x200  
42 -#define PIO_PINS 32  
43 -  
44 -#define PIO_PER 0x00 /* PIO Enable Register */  
45 -#define PIO_PDR 0x04 /* PIO Disable Register */  
46 -#define PIO_PSR 0x08 /* PIO Status Register */  
47 -#define PIO_OER 0x10 /* Output Enable Register */  
48 -#define PIO_ODR 0x14 /* Output Disable Register */  
49 -#define PIO_OSR 0x18 /* Output Status Register */  
50 -#define PIO_IFER 0x20 /* Input Filter Enable Register */  
51 -#define PIO_IFDR 0x24 /* Input Filter Disable Register */  
52 -#define PIO_IFSR 0x28 /* Input Filter Status Register */  
53 -#define PIO_SODR 0x30 /* Set Output Data Register */  
54 -#define PIO_CODR 0x34 /* Clear Output Data Register */  
55 -#define PIO_ODSR 0x38 /* Output Data Status Register */  
56 -#define PIO_PDSR 0x3c /* Pin Data Status Register */  
57 -#define PIO_IER 0x40 /* Interrupt Enable Register */  
58 -#define PIO_IDR 0x44 /* Interrupt Disable Register */  
59 -#define PIO_IMR 0x48 /* Interrupt Mask Register */  
60 -#define PIO_ISR 0x4c /* Interrupt Status Register */  
61 -#define PIO_MDER 0x50 /* Multi-driver Enable Register */  
62 -#define PIO_MDDR 0x54 /* Multi-driver Disable Register */  
63 -#define PIO_MDSR 0x58 /* Multi-driver Status Register */  
64 -#define PIO_PPUDR 0x60 /* Pull-up Disable Register */  
65 -#define PIO_PPUER 0x64 /* Pull-up Enable Register */  
66 -#define PIO_PPUSR 0x68 /* Pull-up Status Register */  
67 -#define PIO_ASR 0x70 /* Select A Register */  
68 -#define PIO_BSR 0x74 /* Select B Register */  
69 -#define PIO_ABSR 0x78 /* AB Select Status Register */  
70 -#define PIO_OWER 0xa0 /* Output Write Enable Register */  
71 -#define PIO_OWDR 0xa4 /* Output Write Disable Register */  
72 -#define PIO_OWSR 0xa8 /* Output Write Status Register */  
73 -  
74 -typedef struct PIOState {  
75 - SysBusDevice busdev;  
76 - qemu_irq out[PIO_PINS * 3];  
77 - qemu_irq parent_irq;  
78 - uint32_t psr;  
79 - uint32_t osr;  
80 - uint32_t ifsr;  
81 - uint32_t odsr;  
82 - uint32_t pdsr;  
83 - uint32_t imr;  
84 - uint32_t isr;  
85 - uint32_t mdsr;  
86 - uint32_t ppusr;  
87 - uint32_t absr;  
88 - uint32_t owsr;  
89 - /* Mask of unknown state of PIO pins, needed for pull-up resistor  
90 - implementation */  
91 - uint32_t unknown_state;  
92 - int portid;  
93 -} PIOState;  
94 -  
95 -void at91_pio_set_pin(void *opaque, int pin, int level)  
96 -{  
97 - DPRINTF("In at91_pio_set_pin, opaque=%p, pin=%d, level=%d\n", opaque, pin, level);  
98 - PIOState *s = opaque;  
99 - int mask = 1 << (pin % PIO_PINS);  
100 - int input_set = pin / PIO_PINS;  
101 - int output_set = !!(s->absr & mask);  
102 - uint32_t saved_pdsr;  
103 -  
104 - if (input_set == 0) {  
105 - /* PIO pin -> Peripheral / IO */  
106 -  
107 - DPRINTF("In at91_pio_set_pin, s->osr=%08x, s->psr=%08x, mask=%08x\n",s->osr, s->psr, mask);  
108 -  
109 - /* Skip input if output mode is enabled for the pin */  
110 - if (s->osr & mask)  
111 - return;  
112 -  
113 - if (s->psr & mask) {  
114 - saved_pdsr = s->pdsr;  
115 - s->pdsr &= ~mask;  
116 - s->unknown_state &= ~mask;  
117 - if (level == -1) {  
118 - s->unknown_state |= mask;  
119 - } else if (level) {  
120 - DPRINTF("In at91_pio_set_pin, setting level\n");  
121 - s->unknown_state &= ~mask;  
122 - s->pdsr |= mask;  
123 - }  
124 - if (saved_pdsr != s->pdsr) {  
125 - s->isr |= mask;  
126 - qemu_set_irq(s->parent_irq, !!(s->isr & s->imr));  
127 - }  
128 - } else {  
129 - qemu_set_irq(s->out[PIO_PINS + (output_set * PIO_PINS)], level);  
130 - }  
131 - DPRINTF("In at91_pio_set_pin, s->pdsr=%08x\n",s->pdsr);  
132 -  
133 - } else {  
134 - /* Peripheral -> PIO pin */  
135 - if ((~s->psr & mask) && input_set == output_set) {  
136 - qemu_set_irq(s->out[pin & PIO_PINS], level);  
137 - }  
138 - }  
139 -}  
140 -  
141 -static uint32_t at91_pio_mem_read(void *opaque, target_phys_addr_t offset)  
142 -{  
143 - PIOState *s = opaque;  
144 - int isr;  
145 -  
146 - offset &= PIO_SIZE - 1;  
147 - switch (offset) {  
148 - case PIO_PSR:  
149 - return s->psr;  
150 - case PIO_OSR:  
151 - return s->osr;  
152 - case PIO_IFSR:  
153 - return s->ifsr;  
154 - case PIO_ODSR:  
155 - return s->odsr;  
156 - case PIO_PDSR:  
157 - DPRINTF("In at91_pio_mem_read, reading PDSR, s->pdsr=%08x, s->unknown_state=%08x, retval=%08x\n",  
158 - s->pdsr, s->unknown_state,  
159 - (s->pdsr & ~s->unknown_state) |  
160 - (s->ppusr & s->unknown_state));  
161 - return  
162 - (s->pdsr & ~s->unknown_state) |  
163 - (s->ppusr & s->unknown_state);  
164 - case PIO_IMR:  
165 - return s->imr;  
166 - case PIO_ISR:  
167 - isr = s->isr;  
168 - s->isr = 0;  
169 - qemu_set_irq(s->parent_irq, 0);  
170 - return isr;  
171 - case PIO_MDSR:  
172 - return s->mdsr;  
173 - case PIO_PPUSR:  
174 - return s->ppusr;  
175 - case PIO_ABSR:  
176 - return s->absr;  
177 - case PIO_OWSR:  
178 - return s->owsr;  
179 - default:  
180 - return 0;  
181 - }  
182 -}  
183 -  
184 -static void at91_pio_mem_write(void *opaque, target_phys_addr_t offset,  
185 - uint32_t value)  
186 -{  
187 - PIOState *s = opaque;  
188 - int i;  
189 -  
190 - DPRINTF("Writing PIO: portid=%d, offset=0x%08lx, value=0x%08x\n", s->portid, offset, value);  
191 -  
192 - offset &= PIO_SIZE - 1;  
193 -  
194 - uint32_t prev;  
195 - switch (offset) {  
196 - case PIO_PER:  
197 - s->psr |= value; //we should also detect LED state change in some cases  
198 - //printf("enabling, psr=0x%08x\n", s->psr);  
199 - break;  
200 - case PIO_PDR:  
201 - s->psr &= ~value;  
202 - //printf("disabling, psr=0x%08x\n", s->psr);  
203 - break;  
204 - case PIO_OER:  
205 - s->osr |= value;  
206 - break;  
207 - case PIO_ODR:  
208 - s->osr &= ~value;  
209 - break;  
210 - case PIO_IFER:  
211 - s->ifsr |= value;  
212 - break;  
213 - case PIO_IFDR:  
214 - s->ifsr &= ~value;  
215 - break;  
216 - case PIO_SODR:  
217 - prev = s->odsr;  
218 - s->odsr |= value;  
219 - for (i = 0; i < PIO_PINS; i++)  
220 - if (value & (1 << i) & s->osr & s->psr)  
221 - {  
222 - qemu_set_irq(s->out[i], 1);  
223 - if((prev & (1 << i)) != (s->odsr & (1 << i)))  
224 - {  
225 - DPRINTF("Port %c%d set\n",'A' + s->portid, i);  
226 - if ((s->portid == 1) && (i == 8))  
227 - printf("LED1 off\n");  
228 - if ((s->portid == 2) && (i == 29))  
229 - printf("LED2 off\n");  
230 - }  
231 - }  
232 - break;  
233 - case PIO_CODR:  
234 - prev = s->odsr;  
235 - s->odsr &= ~value;  
236 - for (i = 0; i < PIO_PINS; i++)  
237 - if (value & (1 << i) & s->osr & s->psr)  
238 - {  
239 - qemu_set_irq(s->out[i], 0);  
240 - if((prev & (1 << i)) != (s->odsr & (1 << i)))  
241 - {  
242 - DPRINTF("Port %c%d reset\n",'A' + s->portid, i);  
243 - if ((s->portid == 1) && (i == 8))  
244 - printf("LED1 on\n");  
245 - if ((s->portid == 2) && (i == 29))  
246 - printf("LED2 on\n");  
247 - }  
248 - }  
249 - break;  
250 - case PIO_ODSR:  
251 - s->odsr = (s->odsr & ~s->owsr) | (value & s->owsr);  
252 - for (i = 0; i < PIO_PINS; i++)  
253 - if (s->owsr & (1 << i))  
254 - qemu_set_irq(s->out[i], !!(value & (1 << i)));  
255 - break;  
256 - case PIO_IER:  
257 - s->imr |= value;  
258 - break;  
259 - case PIO_IDR:  
260 - s->imr &= ~value;  
261 - break;  
262 - case PIO_MDER:  
263 - s->mdsr |= value;  
264 - break;  
265 - case PIO_MDDR:  
266 - s->mdsr &= ~value;  
267 - break;  
268 - case PIO_PPUER:  
269 - s->ppusr |= value;  
270 - break;  
271 - case PIO_PPUDR:  
272 - s->ppusr &= ~value;  
273 - break;  
274 - case PIO_ASR:  
275 - s->absr &= ~value;  
276 - break;  
277 - case PIO_BSR:  
278 - s->absr |= value;  
279 - break;  
280 - case PIO_OWER:  
281 - s->owsr |= value;  
282 - break;  
283 - case PIO_OWDR:  
284 - s->owsr &= ~value;  
285 - break;  
286 - default:  
287 - return;  
288 - }  
289 -}  
290 -  
291 -static CPUReadMemoryFunc *at91_pio_readfn[] = {  
292 - at91_pio_mem_read,  
293 - at91_pio_mem_read,  
294 - at91_pio_mem_read,  
295 -};  
296 -  
297 -static CPUWriteMemoryFunc *at91_pio_writefn[] = {  
298 - at91_pio_mem_write,  
299 - at91_pio_mem_write,  
300 - at91_pio_mem_write,  
301 -};  
302 -  
303 -static void at91_pio_save(QEMUFile *f, void *opaque)  
304 -{  
305 - PIOState *s = opaque;  
306 -  
307 - qemu_put_be32(f, s->psr);  
308 - qemu_put_be32(f, s->osr);  
309 - qemu_put_be32(f, s->ifsr);  
310 - qemu_put_be32(f, s->odsr);  
311 - qemu_put_be32(f, s->pdsr);  
312 - qemu_put_be32(f, s->imr);  
313 - qemu_put_be32(f, s->isr);  
314 - qemu_put_be32(f, s->mdsr);  
315 - qemu_put_be32(f, s->ppusr);  
316 - qemu_put_be32(f, s->absr);  
317 - qemu_put_be32(f, s->owsr);  
318 - qemu_put_be32(f, s->unknown_state);  
319 -}  
320 -  
321 -static int at91_pio_load(QEMUFile *f, void *opaque, int version_id)  
322 -{  
323 - PIOState *s = opaque;  
324 -  
325 - if (version_id != 1)  
326 - return -EINVAL;  
327 -  
328 - s->psr = qemu_get_be32(f);  
329 - s->osr = qemu_get_be32(f);  
330 - s->ifsr = qemu_get_be32(f);  
331 - s->odsr = qemu_get_be32(f);  
332 - s->pdsr = qemu_get_be32(f);  
333 - s->imr = qemu_get_be32(f);  
334 - s->isr = qemu_get_be32(f);  
335 - s->mdsr = qemu_get_be32(f);  
336 - s->ppusr = qemu_get_be32(f);  
337 - s->absr = qemu_get_be32(f);  
338 - s->owsr = qemu_get_be32(f);  
339 - s->unknown_state = qemu_get_be32(f);  
340 -  
341 - return 0;  
342 -}  
343 -  
344 -static void at91_pio_reset(void *opaque)  
345 -{  
346 - PIOState *s = opaque;  
347 -  
348 - s->psr = 0xffffffff;  
349 - s->osr = 0;  
350 - s->ifsr = 0;  
351 - s->odsr = 0;  
352 - s->pdsr = 0;  
353 - s->imr = 0;  
354 - s->isr = 0;  
355 - s->mdsr = 0;  
356 - s->ppusr = 0;  
357 - s->absr = 0;  
358 - s->owsr = 0;  
359 - s->unknown_state = 0xffffffff;  
360 -}  
361 -  
362 -void* at91_io_state[5];  
363 -int at91_io_cnt = 0;  
364 -  
365 -static void at91_pio_init(SysBusDevice *dev)  
366 -{  
367 - DPRINTF("at91_pio_init called\n");  
368 - PIOState *s = FROM_SYSBUS(typeof (*s), dev);  
369 - s->portid = at91_io_cnt;  
370 - at91_io_state[at91_io_cnt++] = s;  
371 - int pio_regs;  
372 -  
373 - sysbus_init_irq(dev, &s->parent_irq);  
374 - qdev_init_gpio_in(&dev->qdev, at91_pio_set_pin, PIO_PINS * 3);  
375 - qdev_init_gpio_out(&dev->qdev, s->out, PIO_PINS * 3);  
376 -  
377 - pio_regs = cpu_register_io_memory(at91_pio_readfn, at91_pio_writefn, s);  
378 - sysbus_init_mmio(dev, PIO_SIZE, pio_regs);  
379 -  
380 - at91_pio_reset(s);  
381 - qemu_register_reset(at91_pio_reset, s);  
382 -  
383 - register_savevm("at91_pio", -1, 1, at91_pio_save, at91_pio_load, s);  
384 -}  
385 -  
386 -static void at91_pio_register(void)  
387 -{  
388 - sysbus_register_dev("at91,pio", sizeof(PIOState), at91_pio_init);  
389 -}  
390 -  
391 -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)