root / hw / sun4c_intctl.c @ 03f48b07
History | View | Annotate | Download (6.1 kB)
1 | ee76f82e | blueswir1 | /*
|
---|---|---|---|
2 | ee76f82e | blueswir1 | * QEMU Sparc Sun4c interrupt controller emulation
|
3 | ee76f82e | blueswir1 | *
|
4 | ee76f82e | blueswir1 | * Based on slavio_intctl, copyright (c) 2003-2005 Fabrice Bellard
|
5 | ee76f82e | blueswir1 | *
|
6 | ee76f82e | blueswir1 | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | ee76f82e | blueswir1 | * of this software and associated documentation files (the "Software"), to deal
|
8 | ee76f82e | blueswir1 | * in the Software without restriction, including without limitation the rights
|
9 | ee76f82e | blueswir1 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | ee76f82e | blueswir1 | * copies of the Software, and to permit persons to whom the Software is
|
11 | ee76f82e | blueswir1 | * furnished to do so, subject to the following conditions:
|
12 | ee76f82e | blueswir1 | *
|
13 | ee76f82e | blueswir1 | * The above copyright notice and this permission notice shall be included in
|
14 | ee76f82e | blueswir1 | * all copies or substantial portions of the Software.
|
15 | ee76f82e | blueswir1 | *
|
16 | ee76f82e | blueswir1 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | ee76f82e | blueswir1 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | ee76f82e | blueswir1 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | ee76f82e | blueswir1 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | ee76f82e | blueswir1 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | ee76f82e | blueswir1 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | ee76f82e | blueswir1 | * THE SOFTWARE.
|
23 | ee76f82e | blueswir1 | */
|
24 | e32cba29 | Blue Swirl | |
25 | ee76f82e | blueswir1 | #include "hw.h" |
26 | ee76f82e | blueswir1 | #include "sun4m.h" |
27 | 376253ec | aliguori | #include "monitor.h" |
28 | e32cba29 | Blue Swirl | #include "sysbus.h" |
29 | e32cba29 | Blue Swirl | |
30 | ee76f82e | blueswir1 | //#define DEBUG_IRQ_COUNT
|
31 | ee76f82e | blueswir1 | //#define DEBUG_IRQ
|
32 | ee76f82e | blueswir1 | |
33 | ee76f82e | blueswir1 | #ifdef DEBUG_IRQ
|
34 | 001faf32 | Blue Swirl | #define DPRINTF(fmt, ...) \
|
35 | 001faf32 | Blue Swirl | do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0) |
36 | ee76f82e | blueswir1 | #else
|
37 | 001faf32 | Blue Swirl | #define DPRINTF(fmt, ...)
|
38 | ee76f82e | blueswir1 | #endif
|
39 | ee76f82e | blueswir1 | |
40 | ee76f82e | blueswir1 | /*
|
41 | ee76f82e | blueswir1 | * Registers of interrupt controller in sun4c.
|
42 | ee76f82e | blueswir1 | *
|
43 | ee76f82e | blueswir1 | */
|
44 | ee76f82e | blueswir1 | |
45 | ee76f82e | blueswir1 | #define MAX_PILS 16 |
46 | ee76f82e | blueswir1 | |
47 | ee76f82e | blueswir1 | typedef struct Sun4c_INTCTLState { |
48 | e32cba29 | Blue Swirl | SysBusDevice busdev; |
49 | 1ce2c9cd | Avi Kivity | MemoryRegion iomem; |
50 | ee76f82e | blueswir1 | #ifdef DEBUG_IRQ_COUNT
|
51 | ee76f82e | blueswir1 | uint64_t irq_count; |
52 | ee76f82e | blueswir1 | #endif
|
53 | e32cba29 | Blue Swirl | qemu_irq cpu_irqs[MAX_PILS]; |
54 | ee76f82e | blueswir1 | const uint32_t *intbit_to_level;
|
55 | ee76f82e | blueswir1 | uint32_t pil_out; |
56 | ee76f82e | blueswir1 | uint8_t reg; |
57 | ee76f82e | blueswir1 | uint8_t pending; |
58 | ee76f82e | blueswir1 | } Sun4c_INTCTLState; |
59 | ee76f82e | blueswir1 | |
60 | e64d7d59 | blueswir1 | #define INTCTL_SIZE 1 |
61 | ee76f82e | blueswir1 | |
62 | ee76f82e | blueswir1 | static void sun4c_check_interrupts(void *opaque); |
63 | ee76f82e | blueswir1 | |
64 | 1ce2c9cd | Avi Kivity | static uint64_t sun4c_intctl_mem_read(void *opaque, target_phys_addr_t addr, |
65 | 1ce2c9cd | Avi Kivity | unsigned size)
|
66 | ee76f82e | blueswir1 | { |
67 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
68 | ee76f82e | blueswir1 | uint32_t ret; |
69 | ee76f82e | blueswir1 | |
70 | ee76f82e | blueswir1 | ret = s->reg; |
71 | ee76f82e | blueswir1 | DPRINTF("read reg 0x" TARGET_FMT_plx " = %x\n", addr, ret); |
72 | ee76f82e | blueswir1 | |
73 | ee76f82e | blueswir1 | return ret;
|
74 | ee76f82e | blueswir1 | } |
75 | ee76f82e | blueswir1 | |
76 | 1ce2c9cd | Avi Kivity | static void sun4c_intctl_mem_write(void *opaque, target_phys_addr_t addr, |
77 | 1ce2c9cd | Avi Kivity | uint64_t val, unsigned size)
|
78 | ee76f82e | blueswir1 | { |
79 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
80 | ee76f82e | blueswir1 | |
81 | 1ce2c9cd | Avi Kivity | DPRINTF("write reg 0x" TARGET_FMT_plx " = %x\n", addr, (unsigned)val); |
82 | ee76f82e | blueswir1 | val &= 0xbf;
|
83 | ee76f82e | blueswir1 | s->reg = val; |
84 | ee76f82e | blueswir1 | sun4c_check_interrupts(s); |
85 | ee76f82e | blueswir1 | } |
86 | ee76f82e | blueswir1 | |
87 | 1ce2c9cd | Avi Kivity | static const MemoryRegionOps sun4c_intctl_mem_ops = { |
88 | 1ce2c9cd | Avi Kivity | .read = sun4c_intctl_mem_read, |
89 | 1ce2c9cd | Avi Kivity | .write = sun4c_intctl_mem_write, |
90 | 1ce2c9cd | Avi Kivity | .endianness = DEVICE_NATIVE_ENDIAN, |
91 | 1ce2c9cd | Avi Kivity | .valid = { |
92 | 1ce2c9cd | Avi Kivity | .min_access_size = 1,
|
93 | 1ce2c9cd | Avi Kivity | .max_access_size = 1,
|
94 | 1ce2c9cd | Avi Kivity | }, |
95 | ee76f82e | blueswir1 | }; |
96 | ee76f82e | blueswir1 | |
97 | 376253ec | aliguori | void sun4c_pic_info(Monitor *mon, void *opaque) |
98 | ee76f82e | blueswir1 | { |
99 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
100 | ee76f82e | blueswir1 | |
101 | 376253ec | aliguori | monitor_printf(mon, "master: pending 0x%2.2x, enabled 0x%2.2x\n",
|
102 | 376253ec | aliguori | s->pending, s->reg); |
103 | ee76f82e | blueswir1 | } |
104 | ee76f82e | blueswir1 | |
105 | 376253ec | aliguori | void sun4c_irq_info(Monitor *mon, void *opaque) |
106 | ee76f82e | blueswir1 | { |
107 | ee76f82e | blueswir1 | #ifndef DEBUG_IRQ_COUNT
|
108 | 376253ec | aliguori | monitor_printf(mon, "irq statistic code not compiled.\n");
|
109 | ee76f82e | blueswir1 | #else
|
110 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
111 | ee76f82e | blueswir1 | int64_t count; |
112 | ee76f82e | blueswir1 | |
113 | 376253ec | aliguori | monitor_printf(mon, "IRQ statistics:\n");
|
114 | 0bf9e31a | Blue Swirl | count = s->irq_count; |
115 | ee76f82e | blueswir1 | if (count > 0) |
116 | 0bf9e31a | Blue Swirl | monitor_printf(mon, " %" PRId64 "\n", count); |
117 | ee76f82e | blueswir1 | #endif
|
118 | ee76f82e | blueswir1 | } |
119 | ee76f82e | blueswir1 | |
120 | ee76f82e | blueswir1 | static const uint32_t intbit_to_level[] = { 0, 1, 4, 6, 8, 10, 0, 14, }; |
121 | ee76f82e | blueswir1 | |
122 | ee76f82e | blueswir1 | static void sun4c_check_interrupts(void *opaque) |
123 | ee76f82e | blueswir1 | { |
124 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
125 | ee76f82e | blueswir1 | uint32_t pil_pending; |
126 | ee76f82e | blueswir1 | unsigned int i; |
127 | ee76f82e | blueswir1 | |
128 | ee76f82e | blueswir1 | pil_pending = 0;
|
129 | ee76f82e | blueswir1 | if (s->pending && !(s->reg & 0x80000000)) { |
130 | ee76f82e | blueswir1 | for (i = 0; i < 8; i++) { |
131 | ee76f82e | blueswir1 | if (s->pending & (1 << i)) |
132 | ee76f82e | blueswir1 | pil_pending |= 1 << intbit_to_level[i];
|
133 | ee76f82e | blueswir1 | } |
134 | ee76f82e | blueswir1 | } |
135 | ee76f82e | blueswir1 | |
136 | ee76f82e | blueswir1 | for (i = 0; i < MAX_PILS; i++) { |
137 | ee76f82e | blueswir1 | if (pil_pending & (1 << i)) { |
138 | ee76f82e | blueswir1 | if (!(s->pil_out & (1 << i))) |
139 | ee76f82e | blueswir1 | qemu_irq_raise(s->cpu_irqs[i]); |
140 | ee76f82e | blueswir1 | } else {
|
141 | ee76f82e | blueswir1 | if (s->pil_out & (1 << i)) |
142 | ee76f82e | blueswir1 | qemu_irq_lower(s->cpu_irqs[i]); |
143 | ee76f82e | blueswir1 | } |
144 | ee76f82e | blueswir1 | } |
145 | ee76f82e | blueswir1 | s->pil_out = pil_pending; |
146 | ee76f82e | blueswir1 | } |
147 | ee76f82e | blueswir1 | |
148 | ee76f82e | blueswir1 | /*
|
149 | ee76f82e | blueswir1 | * "irq" here is the bit number in the system interrupt register
|
150 | ee76f82e | blueswir1 | */
|
151 | ee76f82e | blueswir1 | static void sun4c_set_irq(void *opaque, int irq, int level) |
152 | ee76f82e | blueswir1 | { |
153 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
154 | ee76f82e | blueswir1 | uint32_t mask = 1 << irq;
|
155 | ee76f82e | blueswir1 | uint32_t pil = intbit_to_level[irq]; |
156 | ee76f82e | blueswir1 | |
157 | ee76f82e | blueswir1 | DPRINTF("Set irq %d -> pil %d level %d\n", irq, pil,
|
158 | ee76f82e | blueswir1 | level); |
159 | ee76f82e | blueswir1 | if (pil > 0) { |
160 | ee76f82e | blueswir1 | if (level) {
|
161 | ee76f82e | blueswir1 | #ifdef DEBUG_IRQ_COUNT
|
162 | 0bf9e31a | Blue Swirl | s->irq_count++; |
163 | ee76f82e | blueswir1 | #endif
|
164 | ee76f82e | blueswir1 | s->pending |= mask; |
165 | ee76f82e | blueswir1 | } else {
|
166 | ee76f82e | blueswir1 | s->pending &= ~mask; |
167 | ee76f82e | blueswir1 | } |
168 | ee76f82e | blueswir1 | sun4c_check_interrupts(s); |
169 | ee76f82e | blueswir1 | } |
170 | ee76f82e | blueswir1 | } |
171 | ee76f82e | blueswir1 | |
172 | 9902571d | Blue Swirl | static const VMStateDescription vmstate_sun4c_intctl = { |
173 | 9902571d | Blue Swirl | .name ="sun4c_intctl",
|
174 | 9902571d | Blue Swirl | .version_id = 1,
|
175 | 9902571d | Blue Swirl | .minimum_version_id = 1,
|
176 | 9902571d | Blue Swirl | .minimum_version_id_old = 1,
|
177 | 9902571d | Blue Swirl | .fields = (VMStateField []) { |
178 | 9902571d | Blue Swirl | VMSTATE_UINT8(reg, Sun4c_INTCTLState), |
179 | 9902571d | Blue Swirl | VMSTATE_UINT8(pending, Sun4c_INTCTLState), |
180 | 9902571d | Blue Swirl | VMSTATE_END_OF_LIST() |
181 | 9902571d | Blue Swirl | } |
182 | 9902571d | Blue Swirl | }; |
183 | ee76f82e | blueswir1 | |
184 | 9a2070d3 | Blue Swirl | static void sun4c_intctl_reset(DeviceState *d) |
185 | ee76f82e | blueswir1 | { |
186 | 9a2070d3 | Blue Swirl | Sun4c_INTCTLState *s = container_of(d, Sun4c_INTCTLState, busdev.qdev); |
187 | ee76f82e | blueswir1 | |
188 | ee76f82e | blueswir1 | s->reg = 1;
|
189 | ee76f82e | blueswir1 | s->pending = 0;
|
190 | ee76f82e | blueswir1 | } |
191 | ee76f82e | blueswir1 | |
192 | 81a322d4 | Gerd Hoffmann | static int sun4c_intctl_init1(SysBusDevice *dev) |
193 | e32cba29 | Blue Swirl | { |
194 | e32cba29 | Blue Swirl | Sun4c_INTCTLState *s = FROM_SYSBUS(Sun4c_INTCTLState, dev); |
195 | e32cba29 | Blue Swirl | unsigned int i; |
196 | ee76f82e | blueswir1 | |
197 | 1ce2c9cd | Avi Kivity | memory_region_init_io(&s->iomem, &sun4c_intctl_mem_ops, s, |
198 | 1ce2c9cd | Avi Kivity | "intctl", INTCTL_SIZE);
|
199 | 750ecd44 | Avi Kivity | sysbus_init_mmio(dev, &s->iomem); |
200 | e32cba29 | Blue Swirl | qdev_init_gpio_in(&dev->qdev, sun4c_set_irq, 8);
|
201 | e32cba29 | Blue Swirl | |
202 | e32cba29 | Blue Swirl | for (i = 0; i < MAX_PILS; i++) { |
203 | e32cba29 | Blue Swirl | sysbus_init_irq(dev, &s->cpu_irqs[i]); |
204 | e32cba29 | Blue Swirl | } |
205 | 9a2070d3 | Blue Swirl | |
206 | 81a322d4 | Gerd Hoffmann | return 0; |
207 | ee76f82e | blueswir1 | } |
208 | e32cba29 | Blue Swirl | |
209 | 999e12bb | Anthony Liguori | static void sun4c_intctl_class_init(ObjectClass *klass, void *data) |
210 | 999e12bb | Anthony Liguori | { |
211 | 39bffca2 | Anthony Liguori | DeviceClass *dc = DEVICE_CLASS(klass); |
212 | 999e12bb | Anthony Liguori | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
213 | 999e12bb | Anthony Liguori | |
214 | 999e12bb | Anthony Liguori | k->init = sun4c_intctl_init1; |
215 | 39bffca2 | Anthony Liguori | dc->reset = sun4c_intctl_reset; |
216 | 39bffca2 | Anthony Liguori | dc->vmsd = &vmstate_sun4c_intctl; |
217 | 999e12bb | Anthony Liguori | } |
218 | 999e12bb | Anthony Liguori | |
219 | 39bffca2 | Anthony Liguori | static TypeInfo sun4c_intctl_info = {
|
220 | 39bffca2 | Anthony Liguori | .name = "sun4c_intctl",
|
221 | 39bffca2 | Anthony Liguori | .parent = TYPE_SYS_BUS_DEVICE, |
222 | 39bffca2 | Anthony Liguori | .instance_size = sizeof(Sun4c_INTCTLState),
|
223 | 39bffca2 | Anthony Liguori | .class_init = sun4c_intctl_class_init, |
224 | e32cba29 | Blue Swirl | }; |
225 | e32cba29 | Blue Swirl | |
226 | 83f7d43a | Andreas Färber | static void sun4c_intctl_register_types(void) |
227 | e32cba29 | Blue Swirl | { |
228 | 39bffca2 | Anthony Liguori | type_register_static(&sun4c_intctl_info); |
229 | e32cba29 | Blue Swirl | } |
230 | e32cba29 | Blue Swirl | |
231 | 83f7d43a | Andreas Färber | type_init(sun4c_intctl_register_types) |