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)
... ...