root / hw / sun4c_intctl.c @ e94bbefe
History | View | Annotate | Download (5.7 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 | ee76f82e | blueswir1 | #include "hw.h" |
25 | ee76f82e | blueswir1 | #include "sun4m.h" |
26 | ee76f82e | blueswir1 | #include "console.h" |
27 | ee76f82e | blueswir1 | //#define DEBUG_IRQ_COUNT
|
28 | ee76f82e | blueswir1 | //#define DEBUG_IRQ
|
29 | ee76f82e | blueswir1 | |
30 | ee76f82e | blueswir1 | #ifdef DEBUG_IRQ
|
31 | ee76f82e | blueswir1 | #define DPRINTF(fmt, args...) \
|
32 | ee76f82e | blueswir1 | do { printf("IRQ: " fmt , ##args); } while (0) |
33 | ee76f82e | blueswir1 | #else
|
34 | ee76f82e | blueswir1 | #define DPRINTF(fmt, args...)
|
35 | ee76f82e | blueswir1 | #endif
|
36 | ee76f82e | blueswir1 | |
37 | ee76f82e | blueswir1 | /*
|
38 | ee76f82e | blueswir1 | * Registers of interrupt controller in sun4c.
|
39 | ee76f82e | blueswir1 | *
|
40 | ee76f82e | blueswir1 | */
|
41 | ee76f82e | blueswir1 | |
42 | ee76f82e | blueswir1 | #define MAX_PILS 16 |
43 | ee76f82e | blueswir1 | |
44 | ee76f82e | blueswir1 | typedef struct Sun4c_INTCTLState { |
45 | ee76f82e | blueswir1 | #ifdef DEBUG_IRQ_COUNT
|
46 | ee76f82e | blueswir1 | uint64_t irq_count; |
47 | ee76f82e | blueswir1 | #endif
|
48 | ee76f82e | blueswir1 | qemu_irq *cpu_irqs; |
49 | ee76f82e | blueswir1 | const uint32_t *intbit_to_level;
|
50 | ee76f82e | blueswir1 | uint32_t pil_out; |
51 | ee76f82e | blueswir1 | uint8_t reg; |
52 | ee76f82e | blueswir1 | uint8_t pending; |
53 | ee76f82e | blueswir1 | } Sun4c_INTCTLState; |
54 | ee76f82e | blueswir1 | |
55 | ee76f82e | blueswir1 | #define INTCTL_MAXADDR 0 |
56 | ee76f82e | blueswir1 | #define INTCTL_SIZE (INTCTL_MAXADDR + 1) |
57 | ee76f82e | blueswir1 | |
58 | ee76f82e | blueswir1 | static void sun4c_check_interrupts(void *opaque); |
59 | ee76f82e | blueswir1 | |
60 | ee76f82e | blueswir1 | static uint32_t sun4c_intctl_mem_readb(void *opaque, target_phys_addr_t addr) |
61 | ee76f82e | blueswir1 | { |
62 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
63 | ee76f82e | blueswir1 | uint32_t ret; |
64 | ee76f82e | blueswir1 | |
65 | ee76f82e | blueswir1 | ret = s->reg; |
66 | ee76f82e | blueswir1 | DPRINTF("read reg 0x" TARGET_FMT_plx " = %x\n", addr, ret); |
67 | ee76f82e | blueswir1 | |
68 | ee76f82e | blueswir1 | return ret;
|
69 | ee76f82e | blueswir1 | } |
70 | ee76f82e | blueswir1 | |
71 | ee76f82e | blueswir1 | static void sun4c_intctl_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
72 | ee76f82e | blueswir1 | { |
73 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
74 | ee76f82e | blueswir1 | |
75 | ee76f82e | blueswir1 | DPRINTF("write reg 0x" TARGET_FMT_plx " = %x\n", addr, val); |
76 | ee76f82e | blueswir1 | val &= 0xbf;
|
77 | ee76f82e | blueswir1 | s->reg = val; |
78 | ee76f82e | blueswir1 | sun4c_check_interrupts(s); |
79 | ee76f82e | blueswir1 | } |
80 | ee76f82e | blueswir1 | |
81 | ee76f82e | blueswir1 | static CPUReadMemoryFunc *sun4c_intctl_mem_read[3] = { |
82 | ee76f82e | blueswir1 | sun4c_intctl_mem_readb, |
83 | 7c560456 | blueswir1 | NULL,
|
84 | 7c560456 | blueswir1 | NULL,
|
85 | ee76f82e | blueswir1 | }; |
86 | ee76f82e | blueswir1 | |
87 | ee76f82e | blueswir1 | static CPUWriteMemoryFunc *sun4c_intctl_mem_write[3] = { |
88 | ee76f82e | blueswir1 | sun4c_intctl_mem_writeb, |
89 | 7c560456 | blueswir1 | NULL,
|
90 | 7c560456 | blueswir1 | NULL,
|
91 | ee76f82e | blueswir1 | }; |
92 | ee76f82e | blueswir1 | |
93 | ee76f82e | blueswir1 | void sun4c_pic_info(void *opaque) |
94 | ee76f82e | blueswir1 | { |
95 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
96 | ee76f82e | blueswir1 | |
97 | ee76f82e | blueswir1 | term_printf("master: pending 0x%2.2x, enabled 0x%2.2x\n", s->pending, s->reg);
|
98 | ee76f82e | blueswir1 | } |
99 | ee76f82e | blueswir1 | |
100 | ee76f82e | blueswir1 | void sun4c_irq_info(void *opaque) |
101 | ee76f82e | blueswir1 | { |
102 | ee76f82e | blueswir1 | #ifndef DEBUG_IRQ_COUNT
|
103 | ee76f82e | blueswir1 | term_printf("irq statistic code not compiled.\n");
|
104 | ee76f82e | blueswir1 | #else
|
105 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
106 | ee76f82e | blueswir1 | int64_t count; |
107 | ee76f82e | blueswir1 | |
108 | ee76f82e | blueswir1 | term_printf("IRQ statistics:\n");
|
109 | ee76f82e | blueswir1 | count = s->irq_count[i]; |
110 | ee76f82e | blueswir1 | if (count > 0) |
111 | ee76f82e | blueswir1 | term_printf("%2d: %" PRId64 "\n", i, count); |
112 | ee76f82e | blueswir1 | #endif
|
113 | ee76f82e | blueswir1 | } |
114 | ee76f82e | blueswir1 | |
115 | ee76f82e | blueswir1 | static const uint32_t intbit_to_level[] = { 0, 1, 4, 6, 8, 10, 0, 14, }; |
116 | ee76f82e | blueswir1 | |
117 | ee76f82e | blueswir1 | static void sun4c_check_interrupts(void *opaque) |
118 | ee76f82e | blueswir1 | { |
119 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
120 | ee76f82e | blueswir1 | uint32_t pil_pending; |
121 | ee76f82e | blueswir1 | unsigned int i; |
122 | ee76f82e | blueswir1 | |
123 | ee76f82e | blueswir1 | DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
|
124 | ee76f82e | blueswir1 | pil_pending = 0;
|
125 | ee76f82e | blueswir1 | if (s->pending && !(s->reg & 0x80000000)) { |
126 | ee76f82e | blueswir1 | for (i = 0; i < 8; i++) { |
127 | ee76f82e | blueswir1 | if (s->pending & (1 << i)) |
128 | ee76f82e | blueswir1 | pil_pending |= 1 << intbit_to_level[i];
|
129 | ee76f82e | blueswir1 | } |
130 | ee76f82e | blueswir1 | } |
131 | ee76f82e | blueswir1 | |
132 | ee76f82e | blueswir1 | for (i = 0; i < MAX_PILS; i++) { |
133 | ee76f82e | blueswir1 | if (pil_pending & (1 << i)) { |
134 | ee76f82e | blueswir1 | if (!(s->pil_out & (1 << i))) |
135 | ee76f82e | blueswir1 | qemu_irq_raise(s->cpu_irqs[i]); |
136 | ee76f82e | blueswir1 | } else {
|
137 | ee76f82e | blueswir1 | if (s->pil_out & (1 << i)) |
138 | ee76f82e | blueswir1 | qemu_irq_lower(s->cpu_irqs[i]); |
139 | ee76f82e | blueswir1 | } |
140 | ee76f82e | blueswir1 | } |
141 | ee76f82e | blueswir1 | s->pil_out = pil_pending; |
142 | ee76f82e | blueswir1 | } |
143 | ee76f82e | blueswir1 | |
144 | ee76f82e | blueswir1 | /*
|
145 | ee76f82e | blueswir1 | * "irq" here is the bit number in the system interrupt register
|
146 | ee76f82e | blueswir1 | */
|
147 | ee76f82e | blueswir1 | static void sun4c_set_irq(void *opaque, int irq, int level) |
148 | ee76f82e | blueswir1 | { |
149 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
150 | ee76f82e | blueswir1 | uint32_t mask = 1 << irq;
|
151 | ee76f82e | blueswir1 | uint32_t pil = intbit_to_level[irq]; |
152 | ee76f82e | blueswir1 | |
153 | ee76f82e | blueswir1 | DPRINTF("Set irq %d -> pil %d level %d\n", irq, pil,
|
154 | ee76f82e | blueswir1 | level); |
155 | ee76f82e | blueswir1 | if (pil > 0) { |
156 | ee76f82e | blueswir1 | if (level) {
|
157 | ee76f82e | blueswir1 | #ifdef DEBUG_IRQ_COUNT
|
158 | ee76f82e | blueswir1 | s->irq_count[pil]++; |
159 | ee76f82e | blueswir1 | #endif
|
160 | ee76f82e | blueswir1 | s->pending |= mask; |
161 | ee76f82e | blueswir1 | } else {
|
162 | ee76f82e | blueswir1 | s->pending &= ~mask; |
163 | ee76f82e | blueswir1 | } |
164 | ee76f82e | blueswir1 | sun4c_check_interrupts(s); |
165 | ee76f82e | blueswir1 | } |
166 | ee76f82e | blueswir1 | } |
167 | ee76f82e | blueswir1 | |
168 | ee76f82e | blueswir1 | static void sun4c_intctl_save(QEMUFile *f, void *opaque) |
169 | ee76f82e | blueswir1 | { |
170 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
171 | ee76f82e | blueswir1 | |
172 | ee76f82e | blueswir1 | qemu_put_8s(f, &s->reg); |
173 | ee76f82e | blueswir1 | qemu_put_8s(f, &s->pending); |
174 | ee76f82e | blueswir1 | } |
175 | ee76f82e | blueswir1 | |
176 | ee76f82e | blueswir1 | static int sun4c_intctl_load(QEMUFile *f, void *opaque, int version_id) |
177 | ee76f82e | blueswir1 | { |
178 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
179 | ee76f82e | blueswir1 | |
180 | ee76f82e | blueswir1 | if (version_id != 1) |
181 | ee76f82e | blueswir1 | return -EINVAL;
|
182 | ee76f82e | blueswir1 | |
183 | ee76f82e | blueswir1 | qemu_get_8s(f, &s->reg); |
184 | ee76f82e | blueswir1 | qemu_get_8s(f, &s->pending); |
185 | ee76f82e | blueswir1 | sun4c_check_interrupts(s); |
186 | ee76f82e | blueswir1 | |
187 | ee76f82e | blueswir1 | return 0; |
188 | ee76f82e | blueswir1 | } |
189 | ee76f82e | blueswir1 | |
190 | ee76f82e | blueswir1 | static void sun4c_intctl_reset(void *opaque) |
191 | ee76f82e | blueswir1 | { |
192 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s = opaque; |
193 | ee76f82e | blueswir1 | |
194 | ee76f82e | blueswir1 | s->reg = 1;
|
195 | ee76f82e | blueswir1 | s->pending = 0;
|
196 | ee76f82e | blueswir1 | sun4c_check_interrupts(s); |
197 | ee76f82e | blueswir1 | } |
198 | ee76f82e | blueswir1 | |
199 | ee76f82e | blueswir1 | void *sun4c_intctl_init(target_phys_addr_t addr, qemu_irq **irq,
|
200 | ee76f82e | blueswir1 | qemu_irq *parent_irq) |
201 | ee76f82e | blueswir1 | { |
202 | ee76f82e | blueswir1 | int sun4c_intctl_io_memory;
|
203 | ee76f82e | blueswir1 | Sun4c_INTCTLState *s; |
204 | ee76f82e | blueswir1 | |
205 | ee76f82e | blueswir1 | s = qemu_mallocz(sizeof(Sun4c_INTCTLState));
|
206 | ee76f82e | blueswir1 | if (!s)
|
207 | ee76f82e | blueswir1 | return NULL; |
208 | ee76f82e | blueswir1 | |
209 | ee76f82e | blueswir1 | sun4c_intctl_io_memory = cpu_register_io_memory(0, sun4c_intctl_mem_read,
|
210 | ee76f82e | blueswir1 | sun4c_intctl_mem_write, s); |
211 | ee76f82e | blueswir1 | cpu_register_physical_memory(addr, INTCTL_SIZE, sun4c_intctl_io_memory); |
212 | ee76f82e | blueswir1 | s->cpu_irqs = parent_irq; |
213 | ee76f82e | blueswir1 | |
214 | ee76f82e | blueswir1 | register_savevm("sun4c_intctl", addr, 1, sun4c_intctl_save, |
215 | ee76f82e | blueswir1 | sun4c_intctl_load, s); |
216 | ee76f82e | blueswir1 | |
217 | ee76f82e | blueswir1 | qemu_register_reset(sun4c_intctl_reset, s); |
218 | ee76f82e | blueswir1 | *irq = qemu_allocate_irqs(sun4c_set_irq, s, 8);
|
219 | ee76f82e | blueswir1 | |
220 | ee76f82e | blueswir1 | sun4c_intctl_reset(s); |
221 | ee76f82e | blueswir1 | return s;
|
222 | ee76f82e | blueswir1 | } |