|
1 /* |
|
2 * QEMU ETRAX Interrupt Controller. |
|
3 * |
|
4 * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB. |
|
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 #include <stdio.h> |
|
26 #include "hw.h" |
|
27 #include "etraxfs.h" |
|
28 |
|
29 #define D(x) |
|
30 |
|
31 struct fs_pic_state_t |
|
32 { |
|
33 CPUState *env; |
|
34 |
|
35 uint32_t rw_mask; |
|
36 /* Active interrupt lines. */ |
|
37 uint32_t r_vect; |
|
38 /* Active lines, gated through the mask. */ |
|
39 uint32_t r_masked_vect; |
|
40 uint32_t r_nmi; |
|
41 uint32_t r_guru; |
|
42 }; |
|
43 |
|
44 static uint32_t pic_readb (void *opaque, target_phys_addr_t addr) |
|
45 { |
|
46 return 0; |
|
47 } |
|
48 static uint32_t pic_readw (void *opaque, target_phys_addr_t addr) |
|
49 { |
|
50 return 0; |
|
51 } |
|
52 |
|
53 static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) |
|
54 { |
|
55 struct fs_pic_state_t *fs = opaque; |
|
56 uint32_t rval; |
|
57 |
|
58 switch (addr) |
|
59 { |
|
60 case 0x0: |
|
61 rval = fs->rw_mask; |
|
62 break; |
|
63 case 0x4: |
|
64 rval = fs->r_vect; |
|
65 break; |
|
66 case 0x8: |
|
67 rval = fs->r_masked_vect; |
|
68 break; |
|
69 case 0xc: |
|
70 rval = fs->r_nmi; |
|
71 break; |
|
72 case 0x10: |
|
73 rval = fs->r_guru; |
|
74 break; |
|
75 default: |
|
76 cpu_abort(fs->env, "invalid PIC register.\n"); |
|
77 break; |
|
78 |
|
79 } |
|
80 D(printf("%s %x=%x\n", __func__, addr, rval)); |
|
81 return rval; |
|
82 } |
|
83 |
|
84 static void |
|
85 pic_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) |
|
86 { |
|
87 } |
|
88 |
|
89 static void |
|
90 pic_writew (void *opaque, target_phys_addr_t addr, uint32_t value) |
|
91 { |
|
92 } |
|
93 |
|
94 static void |
|
95 pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value) |
|
96 { |
|
97 struct fs_pic_state_t *fs = opaque; |
|
98 D(printf("%s addr=%x val=%x\n", __func__, addr, value)); |
|
99 switch (addr) |
|
100 { |
|
101 case 0x0: |
|
102 fs->rw_mask = value; |
|
103 break; |
|
104 case 0x4: |
|
105 fs->r_vect = value; |
|
106 break; |
|
107 case 0x8: |
|
108 fs->r_masked_vect = value; |
|
109 break; |
|
110 case 0xc: |
|
111 fs->r_nmi = value; |
|
112 break; |
|
113 case 0x10: |
|
114 fs->r_guru = value; |
|
115 break; |
|
116 default: |
|
117 cpu_abort(fs->env, "invalid PIC register.\n"); |
|
118 break; |
|
119 } |
|
120 } |
|
121 |
|
122 static CPUReadMemoryFunc *pic_read[] = { |
|
123 &pic_readb, |
|
124 &pic_readw, |
|
125 &pic_readl, |
|
126 }; |
|
127 |
|
128 static CPUWriteMemoryFunc *pic_write[] = { |
|
129 &pic_writeb, |
|
130 &pic_writew, |
|
131 &pic_writel, |
|
132 }; |
|
133 |
|
134 void pic_info(void) |
|
135 { |
|
136 } |
|
137 |
|
138 void irq_info(void) |
|
139 { |
|
140 } |
|
141 |
|
142 static void irq_handler(void *opaque, int irq, int level) |
|
143 { |
|
144 struct fs_pic_state_t *fs = (void *)opaque; |
|
145 CPUState *env = fs->env; |
|
146 int i; |
|
147 uint32_t vector = 0; |
|
148 |
|
149 D(printf("%s irq=%d level=%d mask=%x v=%x mv=%x\n", |
|
150 __func__, irq, level, |
|
151 fs->rw_mask, fs->r_vect, fs->r_masked_vect)); |
|
152 |
|
153 irq -= 1; |
|
154 fs->r_vect &= ~(1 << irq); |
|
155 fs->r_vect |= (!!level << irq); |
|
156 fs->r_masked_vect = fs->r_vect & fs->rw_mask; |
|
157 |
|
158 /* The ETRAX interrupt controller signals interrupts to teh core |
|
159 through an interrupt request wire and an irq vector bus. If |
|
160 multiple interrupts are simultaneously active it chooses vector |
|
161 0x30 and lets the sw choose the priorities. */ |
|
162 if (fs->r_masked_vect) { |
|
163 uint32_t mv = fs->r_masked_vect; |
|
164 for (i = 0; i < 31; i++) { |
|
165 if (mv & 1) { |
|
166 vector = 0x31 + i; |
|
167 /* Check for multiple interrupts. */ |
|
168 if (mv > 1) |
|
169 vector = 0x30; |
|
170 break; |
|
171 } |
|
172 mv >>= 1; |
|
173 } |
|
174 if (vector) { |
|
175 env->interrupt_vector = vector; |
|
176 D(printf("%s vector=%x\n", __func__, vector)); |
|
177 cpu_interrupt(env, CPU_INTERRUPT_HARD); |
|
178 } |
|
179 } else { |
|
180 env->interrupt_vector = 0; |
|
181 cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); |
|
182 D(printf("%s reset irqs\n", __func__)); |
|
183 } |
|
184 } |
|
185 |
|
186 static void nmi_handler(void *opaque, int irq, int level) |
|
187 { |
|
188 struct fs_pic_state_t *fs = (void *)opaque; |
|
189 CPUState *env = fs->env; |
|
190 uint32_t mask; |
|
191 |
|
192 mask = 1 << irq; |
|
193 if (level) |
|
194 fs->r_nmi |= mask; |
|
195 else |
|
196 fs->r_nmi &= ~mask; |
|
197 |
|
198 if (fs->r_nmi) |
|
199 cpu_interrupt(env, CPU_INTERRUPT_NMI); |
|
200 else |
|
201 cpu_reset_interrupt(env, CPU_INTERRUPT_NMI); |
|
202 } |
|
203 |
|
204 static void guru_handler(void *opaque, int irq, int level) |
|
205 { |
|
206 struct fs_pic_state_t *fs = (void *)opaque; |
|
207 CPUState *env = fs->env; |
|
208 cpu_abort(env, "%s unsupported exception\n", __func__); |
|
209 |
|
210 } |
|
211 |
|
212 |
|
213 struct etraxfs_pic *etraxfs_pic_init(CPUState *env, target_phys_addr_t base) |
|
214 { |
|
215 struct fs_pic_state_t *fs = NULL; |
|
216 struct etraxfs_pic *pic = NULL; |
|
217 int intr_vect_regs; |
|
218 |
|
219 pic = qemu_mallocz(sizeof *pic); |
|
220 pic->internal = fs = qemu_mallocz(sizeof *fs); |
|
221 if (!fs || !pic) |
|
222 goto err; |
|
223 |
|
224 fs->env = env; |
|
225 pic->irq = qemu_allocate_irqs(irq_handler, fs, 30); |
|
226 pic->nmi = qemu_allocate_irqs(nmi_handler, fs, 2); |
|
227 pic->guru = qemu_allocate_irqs(guru_handler, fs, 1); |
|
228 |
|
229 intr_vect_regs = cpu_register_io_memory(0, pic_read, pic_write, fs); |
|
230 cpu_register_physical_memory(base, 0x14, intr_vect_regs); |
|
231 |
|
232 return pic; |
|
233 err: |
|
234 free(pic); |
|
235 free(fs); |
|
236 return NULL; |
|
237 } |