|
|
1.1 root 1: /*
2: * QEMU Sparc SLAVIO interrupt controller emulation
3: *
4: * Copyright (c) 2003-2005 Fabrice Bellard
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: #include "vl.h"
25: //#define DEBUG_IRQ_COUNT
26: //#define DEBUG_IRQ
27:
28: #ifdef DEBUG_IRQ
29: #define DPRINTF(fmt, args...) \
30: do { printf("IRQ: " fmt , ##args); } while (0)
31: #else
32: #define DPRINTF(fmt, args...)
33: #endif
34:
35: /*
36: * Registers of interrupt controller in sun4m.
37: *
38: * This is the interrupt controller part of chip STP2001 (Slave I/O), also
39: * produced as NCR89C105. See
40: * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
41: *
42: * There is a system master controller and one for each cpu.
43: *
44: */
45:
46: #define MAX_CPUS 16
47:
48: typedef struct SLAVIO_INTCTLState {
49: uint32_t intreg_pending[MAX_CPUS];
50: uint32_t intregm_pending;
51: uint32_t intregm_disabled;
52: uint32_t target_cpu;
53: #ifdef DEBUG_IRQ_COUNT
54: uint64_t irq_count[32];
55: #endif
56: } SLAVIO_INTCTLState;
57:
58: #define INTCTL_MAXADDR 0xf
59: #define INTCTLM_MAXADDR 0xf
60: static void slavio_check_interrupts(void *opaque);
61:
62: // per-cpu interrupt controller
63: static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
64: {
65: SLAVIO_INTCTLState *s = opaque;
66: uint32_t saddr;
67: int cpu;
68:
69: cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
70: saddr = (addr & INTCTL_MAXADDR) >> 2;
71: switch (saddr) {
72: case 0:
73: return s->intreg_pending[cpu];
74: default:
75: break;
76: }
77: return 0;
78: }
79:
80: static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
81: {
82: SLAVIO_INTCTLState *s = opaque;
83: uint32_t saddr;
84: int cpu;
85:
86: cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
87: saddr = (addr & INTCTL_MAXADDR) >> 2;
88: switch (saddr) {
89: case 1: // clear pending softints
90: if (val & 0x4000)
91: val |= 80000000;
92: val &= 0xfffe0000;
93: s->intreg_pending[cpu] &= ~val;
94: DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
95: break;
96: case 2: // set softint
97: val &= 0xfffe0000;
98: s->intreg_pending[cpu] |= val;
99: DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
100: break;
101: default:
102: break;
103: }
104: }
105:
106: static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
107: slavio_intctl_mem_readl,
108: slavio_intctl_mem_readl,
109: slavio_intctl_mem_readl,
110: };
111:
112: static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
113: slavio_intctl_mem_writel,
114: slavio_intctl_mem_writel,
115: slavio_intctl_mem_writel,
116: };
117:
118: // master system interrupt controller
119: static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
120: {
121: SLAVIO_INTCTLState *s = opaque;
122: uint32_t saddr;
123:
124: saddr = (addr & INTCTLM_MAXADDR) >> 2;
125: switch (saddr) {
126: case 0:
127: return s->intregm_pending & 0x7fffffff;
128: case 1:
129: return s->intregm_disabled;
130: case 4:
131: return s->target_cpu;
132: default:
133: break;
134: }
135: return 0;
136: }
137:
138: static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
139: {
140: SLAVIO_INTCTLState *s = opaque;
141: uint32_t saddr;
142:
143: saddr = (addr & INTCTLM_MAXADDR) >> 2;
144: switch (saddr) {
145: case 2: // clear (enable)
146: // Force clear unused bits
147: val &= ~0x4fb2007f;
148: s->intregm_disabled &= ~val;
149: DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
150: slavio_check_interrupts(s);
151: break;
152: case 3: // set (disable, clear pending)
153: // Force clear unused bits
154: val &= ~0x4fb2007f;
155: s->intregm_disabled |= val;
156: s->intregm_pending &= ~val;
157: DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
158: break;
159: case 4:
160: s->target_cpu = val & (MAX_CPUS - 1);
161: DPRINTF("Set master irq cpu %d\n", s->target_cpu);
162: break;
163: default:
164: break;
165: }
166: }
167:
168: static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
169: slavio_intctlm_mem_readl,
170: slavio_intctlm_mem_readl,
171: slavio_intctlm_mem_readl,
172: };
173:
174: static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
175: slavio_intctlm_mem_writel,
176: slavio_intctlm_mem_writel,
177: slavio_intctlm_mem_writel,
178: };
179:
180: void slavio_pic_info(void *opaque)
181: {
182: SLAVIO_INTCTLState *s = opaque;
183: int i;
184:
185: for (i = 0; i < MAX_CPUS; i++) {
186: term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
187: }
188: term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
189: }
190:
191: void slavio_irq_info(void *opaque)
192: {
193: #ifndef DEBUG_IRQ_COUNT
194: term_printf("irq statistic code not compiled.\n");
195: #else
196: SLAVIO_INTCTLState *s = opaque;
197: int i;
198: int64_t count;
199:
200: term_printf("IRQ statistics:\n");
201: for (i = 0; i < 32; i++) {
202: count = s->irq_count[i];
203: if (count > 0)
204: term_printf("%2d: %lld\n", i, count);
205: }
206: #endif
207: }
208:
209: static const uint32_t intbit_to_level[32] = {
210: 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12,
211: 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0,
212: };
213:
214: static void slavio_check_interrupts(void *opaque)
215: {
216: SLAVIO_INTCTLState *s = opaque;
217: uint32_t pending = s->intregm_pending;
218: unsigned int i, max = 0;
219:
220: pending &= ~s->intregm_disabled;
221:
222: if (pending && !(s->intregm_disabled & 0x80000000)) {
223: for (i = 0; i < 32; i++) {
224: if (pending & (1 << i)) {
225: if (max < intbit_to_level[i])
226: max = intbit_to_level[i];
227: }
228: }
229: if (cpu_single_env->interrupt_index == 0) {
230: DPRINTF("Triggered pil %d\n", max);
231: #ifdef DEBUG_IRQ_COUNT
232: s->irq_count[max]++;
233: #endif
234: cpu_single_env->interrupt_index = TT_EXTINT | max;
235: cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
236: }
237: else
238: DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, cpu_single_env->interrupt_index);
239: }
240: else
241: DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled);
242: }
243:
244: /*
245: * "irq" here is the bit number in the system interrupt register to
246: * separate serial and keyboard interrupts sharing a level.
247: */
248: void slavio_pic_set_irq(void *opaque, int irq, int level)
249: {
250: SLAVIO_INTCTLState *s = opaque;
251:
252: DPRINTF("Set irq %d level %d\n", irq, level);
253: if (irq < 32) {
254: uint32_t mask = 1 << irq;
255: uint32_t pil = intbit_to_level[irq];
256: if (pil > 0) {
257: if (level) {
258: s->intregm_pending |= mask;
259: s->intreg_pending[s->target_cpu] |= 1 << pil;
260: }
261: else {
262: s->intregm_pending &= ~mask;
263: s->intreg_pending[s->target_cpu] &= ~(1 << pil);
264: }
265: }
266: }
267: slavio_check_interrupts(s);
268: }
269:
270: static void slavio_intctl_save(QEMUFile *f, void *opaque)
271: {
272: SLAVIO_INTCTLState *s = opaque;
273: int i;
274:
275: for (i = 0; i < MAX_CPUS; i++) {
276: qemu_put_be32s(f, &s->intreg_pending[i]);
277: }
278: qemu_put_be32s(f, &s->intregm_pending);
279: qemu_put_be32s(f, &s->intregm_disabled);
280: qemu_put_be32s(f, &s->target_cpu);
281: }
282:
283: static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
284: {
285: SLAVIO_INTCTLState *s = opaque;
286: int i;
287:
288: if (version_id != 1)
289: return -EINVAL;
290:
291: for (i = 0; i < MAX_CPUS; i++) {
292: qemu_get_be32s(f, &s->intreg_pending[i]);
293: }
294: qemu_get_be32s(f, &s->intregm_pending);
295: qemu_get_be32s(f, &s->intregm_disabled);
296: qemu_get_be32s(f, &s->target_cpu);
297: return 0;
298: }
299:
300: static void slavio_intctl_reset(void *opaque)
301: {
302: SLAVIO_INTCTLState *s = opaque;
303: int i;
304:
305: for (i = 0; i < MAX_CPUS; i++) {
306: s->intreg_pending[i] = 0;
307: }
308: s->intregm_disabled = ~0xffb2007f;
309: s->intregm_pending = 0;
310: s->target_cpu = 0;
311: }
312:
313: void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
314: {
315: int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
316: SLAVIO_INTCTLState *s;
317:
318: s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
319: if (!s)
320: return NULL;
321:
322: for (i = 0; i < MAX_CPUS; i++) {
323: slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
324: cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory);
325: }
326:
327: slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
328: cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory);
329:
330: register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
331: qemu_register_reset(slavio_intctl_reset, s);
332: slavio_intctl_reset(s);
333: return s;
334: }
335:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.