リビジョン | ba4443e1f3f8e5f98fd91d9b977bb4ff61d78028 (tree) |
---|---|
日時 | 2018-12-12 14:23:32 |
作者 | Yoshinori Sato <ysato@user...> |
コミッター | Yoshinori Sato |
fix interrupt handling
@@ -14,13 +14,33 @@ | ||
14 | 14 | #include "hw/intc/rx_icu.h" |
15 | 15 | #include "qemu/error-report.h" |
16 | 16 | |
17 | +#define request(icu, n) (icu->ipr[icu->map[n]] << 8 | n) | |
18 | + | |
19 | + | |
20 | +static qemu_irq* rxicu_pin(RXICUState *icu, int n_IRQ) | |
21 | +{ | |
22 | + if ((icu->fir & 0x8000) && (icu->fir & 0xff) == n_IRQ) | |
23 | + return &icu->_fir; | |
24 | + else | |
25 | + return &icu->_irq; | |
26 | +} | |
27 | + | |
28 | +static void rxicu_request(RXICUState *icu, int n_IRQ) | |
29 | +{ | |
30 | + int enable; | |
31 | + | |
32 | + enable = icu->ier[n_IRQ / 8] & (1 << (n_IRQ & 7)); | |
33 | + if (enable != 0 && icu->req_irq < 0) { | |
34 | + qemu_set_irq(*rxicu_pin(icu, n_IRQ), 0x1000 | request(icu, n_IRQ)); | |
35 | + icu->req_irq = n_IRQ; | |
36 | + } | |
37 | +} | |
38 | + | |
17 | 39 | static void rxicu_set_irq(void *opaque, int n_IRQ, int level) |
18 | 40 | { |
19 | 41 | RXICUState *icu = opaque; |
20 | 42 | struct IRQSource *src; |
21 | - int req; | |
22 | 43 | int issue; |
23 | - qemu_irq *ir; | |
24 | 44 | |
25 | 45 | if (n_IRQ >= 256) { |
26 | 46 | error_report("%s: IRQ %d out of range", __func__, n_IRQ); |
@@ -28,14 +48,8 @@ static void rxicu_set_irq(void *opaque, int n_IRQ, int level) | ||
28 | 48 | } |
29 | 49 | |
30 | 50 | src = &icu->src[n_IRQ]; |
31 | - if ((icu->fir & 0x8000) && (icu->fir & 0xff) == n_IRQ) { | |
32 | - ir = &icu->_fir; | |
33 | - req = 0; | |
34 | - } else { | |
35 | - ir = &icu->_irq; | |
36 | - req = icu->ipr[icu->map[n_IRQ]] << 8 | n_IRQ; | |
37 | - } | |
38 | 51 | |
52 | + level = (level != 0); | |
39 | 53 | switch (src->sense) { |
40 | 54 | case TRG_LEVEL: |
41 | 55 | /* level-sensitive irq */ |
@@ -55,13 +69,43 @@ static void rxicu_set_irq(void *opaque, int n_IRQ, int level) | ||
55 | 69 | src->level = level; |
56 | 70 | break; |
57 | 71 | } |
58 | - if (issue) { | |
59 | - qemu_set_irq(*ir, 0x1000 | req); | |
60 | - icu->ir[n_IRQ] = 1; | |
61 | - } else if (src->sense == TRG_LEVEL) { | |
62 | - qemu_set_irq(*ir, req); | |
72 | + if (issue == 0 && src->sense == TRG_LEVEL) { | |
63 | 73 | icu->ir[n_IRQ] = 0; |
74 | + if (icu->req_irq == n_IRQ) { | |
75 | + qemu_set_irq(*rxicu_pin(icu, n_IRQ), request(icu, n_IRQ)); | |
76 | + icu->req_irq = -1; | |
77 | + } | |
78 | + return; | |
64 | 79 | } |
80 | + if (issue) | |
81 | + rxicu_request(icu, n_IRQ); | |
82 | +} | |
83 | + | |
84 | +static void rxicu_ack_irq(void *opaque, int no, int level) | |
85 | +{ | |
86 | + RXICUState *icu = opaque; | |
87 | + int i; | |
88 | + int n_IRQ; | |
89 | + int max_pri; | |
90 | + | |
91 | + if (icu->req_irq < 0) | |
92 | + return; | |
93 | + if (icu->src[icu->req_irq].sense != TRG_LEVEL) | |
94 | + icu->ir[icu->req_irq] = 0; | |
95 | + icu->req_irq = -1; | |
96 | + | |
97 | + max_pri = 0; | |
98 | + n_IRQ = -1; | |
99 | + for (i = 0; i < 256; i++) { | |
100 | + if (icu->ir[i]) { | |
101 | + if (max_pri < icu->ipr[icu->map[i]]) { | |
102 | + n_IRQ = i; | |
103 | + max_pri = icu->ipr[icu->map[i]]; | |
104 | + } | |
105 | + } | |
106 | + } | |
107 | + if (n_IRQ >= 0) | |
108 | + rxicu_request(icu, n_IRQ); | |
65 | 109 | } |
66 | 110 | |
67 | 111 | static uint64_t icu_read(void *opaque, hwaddr addr, unsigned size) |
@@ -123,13 +167,8 @@ static void icu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) | ||
123 | 167 | if (!error) { |
124 | 168 | switch (offset) { |
125 | 169 | case 0x000 ... 0x0ff: |
126 | - if (icu->src[reg].sense != TRG_LEVEL && val == 0) { | |
170 | + if (icu->src[reg].sense != TRG_LEVEL && val == 0) | |
127 | 171 | icu->ir[reg] = 0; |
128 | - if ((icu->fir & 0xff) == reg) | |
129 | - qemu_set_irq(icu->_fir, 0); | |
130 | - else | |
131 | - qemu_set_irq(icu->_irq, reg); | |
132 | - } | |
133 | 172 | break; |
134 | 173 | case 0x100 ... 0x1ff: |
135 | 174 | icu->dtcer[reg] = val & 1; |
@@ -195,6 +234,7 @@ static void rxicu_realize(DeviceState *dev, Error **errp) | ||
195 | 234 | } else |
196 | 235 | icu->src[i].sense = TRG_PEDGE; |
197 | 236 | } |
237 | + icu->req_irq = -1; | |
198 | 238 | } |
199 | 239 | |
200 | 240 | static void rxicu_init(Object *obj) |
@@ -207,6 +247,7 @@ static void rxicu_init(Object *obj) | ||
207 | 247 | sysbus_init_mmio(d, &icu->memory); |
208 | 248 | |
209 | 249 | qdev_init_gpio_in(DEVICE(d), rxicu_set_irq, 256); |
250 | + qdev_init_gpio_in_named(DEVICE(d), rxicu_ack_irq, "ack", 1); | |
210 | 251 | sysbus_init_irq(d, &icu->_irq); |
211 | 252 | sysbus_init_irq(d, &icu->_fir); |
212 | 253 | sysbus_init_irq(d, &icu->_swi); |
@@ -68,10 +68,6 @@ static RXICUState *register_icu(RX62NState *s) | ||
68 | 68 | |
69 | 69 | icu = SYS_BUS_DEVICE(qdev_create(NULL, TYPE_RXICU)); |
70 | 70 | sysbus_mmio_map(icu, 0, 0x00087000); |
71 | - sysbus_connect_irq(icu, RX_CPU_IRQ, | |
72 | - qdev_get_gpio_in(DEVICE(s->cpu), RX_CPU_IRQ)); | |
73 | - sysbus_connect_irq(icu, RX_CPU_FIR, | |
74 | - qdev_get_gpio_in(DEVICE(s->cpu), RX_CPU_FIR)); | |
75 | 71 | qdev_prop_set_string(DEVICE(icu), "icutype", "icua"); |
76 | 72 | qdev_prop_set_uint32(DEVICE(icu), "len-ipr-map", 256); |
77 | 73 | for (i = 0; i < 256; i++) { |
@@ -164,14 +160,15 @@ static void rx62n_realize(DeviceState *dev, Error **errp) | ||
164 | 160 | |
165 | 161 | if (!s->kernel) |
166 | 162 | rom_add_file_fixed(bios_name, 0xfff80000, 0); |
167 | - else | |
168 | 163 | |
169 | 164 | object_property_set_bool(OBJECT(s->cpu), true, "realized", &err); |
170 | 165 | if (err != NULL) { |
171 | 166 | error_propagate(errp, err); |
172 | 167 | return; |
173 | 168 | } |
169 | + | |
174 | 170 | s->icu = register_icu(s); |
171 | + s->cpu->env.ack = qdev_get_gpio_in_named(DEVICE(s->icu), "ack", 0); | |
175 | 172 | s->tmr[0] = register_tmr(s, 0); |
176 | 173 | s->tmr[1] = register_tmr(s, 1); |
177 | 174 | s->cmt[0] = register_cmt(s, 0); |
@@ -30,6 +30,7 @@ struct RXICUState { | ||
30 | 30 | uint8_t nmier; |
31 | 31 | uint8_t nmiclr; |
32 | 32 | uint8_t nmicr; |
33 | + int req_irq; | |
33 | 34 | qemu_irq _irq; |
34 | 35 | qemu_irq _fir; |
35 | 36 | qemu_irq _swi; |
@@ -120,7 +120,7 @@ typedef struct CPURXState { | ||
120 | 120 | uint32_t in_sleep; |
121 | 121 | uint32_t intlevel; |
122 | 122 | uint32_t irq; |
123 | - uint32_t int_insn_len; | |
123 | + uint32_t sirq; | |
124 | 124 | float_status fp_status; |
125 | 125 | uint32_t op_a1[12]; |
126 | 126 | uint32_t op_a2[12]; |
@@ -131,7 +131,7 @@ typedef struct CPURXState { | ||
131 | 131 | |
132 | 132 | CPU_COMMON |
133 | 133 | |
134 | - void *intc_handle; | |
134 | + void *ack; | |
135 | 135 | } CPURXState; |
136 | 136 | |
137 | 137 | /** |
@@ -177,6 +177,7 @@ void rx_cpu_list(FILE *f, fprintf_function cpu_fprintf); | ||
177 | 177 | void rx_load_image(RXCPU *cpu, const char *filename, |
178 | 178 | uint32_t start, uint32_t size); |
179 | 179 | void rx_cpu_pack_psw(CPURXState *env); |
180 | +void rx_cpu_unpack_psw(CPURXState *env, int all); | |
180 | 181 | |
181 | 182 | #define cpu_signal_handler cpu_rx_signal_handler |
182 | 183 | #define cpu_list rx_cpu_list |
@@ -200,27 +201,6 @@ enum { | ||
200 | 201 | ACCESS_INT = 0x20 |
201 | 202 | }; |
202 | 203 | |
203 | -static inline target_ulong cpu_read_psw(CPURXState *env) | |
204 | -{ | |
205 | - return (env->psw_o << PSW_O) | (env->psw_s << PSW_S) | | |
206 | - (env->psw_z << PSW_Z) | (env->psw_c << PSW_C) | | |
207 | - (env->psw_u << PSW_U) | (env->psw_u << PSW_I) | | |
208 | - (env->psw_u << PSW_PM) | (env->psw_u << PSW_IPL); | |
209 | -} | |
210 | - | |
211 | -static inline void cpu_write_psw(CPURXState *env, target_ulong psw) | |
212 | -{ | |
213 | - env->psw = psw; | |
214 | - env->psw_o = (psw >> PSW_O) & 1; | |
215 | - env->psw_s = (psw >> PSW_S) & 1; | |
216 | - env->psw_z = (psw >> PSW_Z) & 1; | |
217 | - env->psw_c = (psw >> PSW_C) & 1; | |
218 | - env->psw_i = (psw >> PSW_I) & 1; | |
219 | - env->psw_u = (psw >> PSW_U) & 1; | |
220 | - env->psw_pm = (psw >> PSW_PM) & 1; | |
221 | - env->psw_ipl = (psw >> PSW_IPL) & 4; | |
222 | -} | |
223 | - | |
224 | 204 | static inline void cpu_get_tb_cpu_state(CPURXState *env, target_ulong *pc, |
225 | 205 | target_ulong *cs_base, uint32_t *flags) |
226 | 206 | { |
@@ -210,24 +210,20 @@ void rx_cpu_do_interrupt(CPUState *cs) | ||
210 | 210 | CPURXState *env = &cpu->env; |
211 | 211 | int do_irq = cs->interrupt_request & |
212 | 212 | (CPU_INTERRUPT_HARD | CPU_INTERRUPT_SOFT | CPU_INTERRUPT_FIR); |
213 | - int do_exp, irq_vector = -1; | |
214 | - | |
215 | - do_exp = cs->exception_index < 0x100; | |
213 | + int irq_vector = -1; | |
216 | 214 | |
217 | 215 | env->in_sleep = 0; |
218 | 216 | |
219 | - if (!do_irq) { | |
220 | - cs->interrupt_request = 0; | |
221 | - return ; | |
222 | - } | |
223 | 217 | if (do_irq & CPU_INTERRUPT_HARD) { |
224 | 218 | irq_vector = env->irq; |
225 | - if (irq_vector == -1 || env->psw_i == 0) { | |
219 | + if (irq_vector == -1 || | |
220 | + (env->psw_i == 0 && !(do_irq & CPU_INTERRUPT_SOFT))) { | |
226 | 221 | return; /* masked */ |
227 | 222 | } |
223 | + cs->interrupt_request &= ~CPU_INTERRUPT_HARD; | |
228 | 224 | } |
229 | - if (do_irq & CPU_INTERRUPT_SOFT) { | |
230 | - irq_vector = env->irq; | |
225 | + if (irq_vector == -1 && do_irq & CPU_INTERRUPT_SOFT) { | |
226 | + irq_vector = env->sirq; | |
231 | 227 | cs->interrupt_request &= ~CPU_INTERRUPT_SOFT; |
232 | 228 | } |
233 | 229 |
@@ -278,23 +274,24 @@ void rx_cpu_do_interrupt(CPUState *cs) | ||
278 | 274 | env->bpc = env->pc; |
279 | 275 | env->bpsw = env->psw; |
280 | 276 | } |
281 | - env->psw &= ~((1UL << PSW_PM) | (1UL << PSW_I) | (1UL << PSW_U)); | |
282 | 277 | env->psw_pm = env->psw_i = env->psw_u = 0; |
283 | 278 | env->regs[0] = env->isp; |
284 | - if (do_irq & CPU_INTERRUPT_HARD) | |
285 | - env->psw_ipl = env->intlevel; | |
286 | - | |
287 | - if (do_exp) { | |
288 | - uint32_t vec = cs->exception_index; | |
289 | - env->pc = cpu_ldl_all(env, 0xffffffc0 + vec * 4); | |
290 | - return; | |
291 | - } | |
292 | - | |
293 | 279 | if (do_irq) { |
294 | - if (do_irq & CPU_INTERRUPT_FIR) | |
280 | + if (do_irq & CPU_INTERRUPT_FIR) { | |
295 | 281 | env->pc = env->fintv; |
296 | - else | |
297 | - env->pc = cpu_ldl_all(env, env->intb + irq_vector * 4); | |
282 | + env->psw_ipl = 15; | |
283 | + cs->interrupt_request &= ~CPU_INTERRUPT_FIR; | |
284 | + qemu_set_irq(env->ack, 0); | |
285 | + return; | |
286 | + } else if (do_irq & CPU_INTERRUPT_HARD) { | |
287 | + env->psw_ipl = env->intlevel; | |
288 | + qemu_set_irq(env->ack, 0); | |
289 | + } | |
290 | + env->pc = cpu_ldl_all(env, env->intb + irq_vector * 4); | |
291 | + return; | |
292 | + } else { | |
293 | + uint32_t vec = cs->exception_index; | |
294 | + env->pc = cpu_ldl_all(env, 0xffffffc0 + vec * 4); | |
298 | 295 | return; |
299 | 296 | } |
300 | 297 | } |
@@ -306,11 +303,11 @@ bool rx_cpu_exec_interrupt(CPUState *cs, int interrupt_request) | ||
306 | 303 | if (((interrupt_request & CPU_INTERRUPT_HARD) && |
307 | 304 | (env->psw_i && (env->psw_ipl < env->intlevel))) | |
308 | 305 | (interrupt_request & CPU_INTERRUPT_SOFT) || |
309 | - (env->psw_i && (interrupt_request & CPU_INTERRUPT_FIR))) { | |
306 | + (env->psw_i && (interrupt_request & CPU_INTERRUPT_FIR) && | |
307 | + (env->psw_ipl < 15))) { | |
310 | 308 | rx_cpu_do_interrupt(cs); |
311 | 309 | return true; |
312 | 310 | } |
313 | - | |
314 | 311 | return false; |
315 | 312 | } |
316 | 313 |
@@ -365,8 +362,7 @@ void QEMU_NORETURN helper_rxint(CPURXState *env, uint32_t vec) | ||
365 | 362 | CPUState *cs = CPU(rx_env_get_cpu(env)); |
366 | 363 | |
367 | 364 | cs->interrupt_request |= CPU_INTERRUPT_SOFT; |
368 | - env->irq = vec; | |
369 | - printf("int r13=0x%08x, r15=0x%08x\n", env->regs[13], env->regs[15]); | |
365 | + env->sirq = vec; | |
370 | 366 | raise_exception(env, 0x100, 0); |
371 | 367 | } |
372 | 368 |
@@ -375,7 +371,7 @@ void QEMU_NORETURN helper_rxbrk(CPURXState *env) | ||
375 | 371 | CPUState *cs = CPU(rx_env_get_cpu(env)); |
376 | 372 | |
377 | 373 | cs->interrupt_request |= CPU_INTERRUPT_SOFT; |
378 | - env->irq = 0; | |
374 | + env->sirq = 0; | |
379 | 375 | raise_exception(env, 0x100, 0); |
380 | 376 | } |
381 | 377 |