Commit 4de9b249d37c1b382cc3e5a21fad1b4a11cec2fa
1 parent
30c4bbac
Reworking MIPS interrupt handling, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2350 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
13 changed files
with
76 additions
and
75 deletions
Makefile.target
| @@ -376,7 +376,7 @@ VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o | @@ -376,7 +376,7 @@ VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o | ||
| 376 | CPPFLAGS += -DHAS_AUDIO | 376 | CPPFLAGS += -DHAS_AUDIO |
| 377 | endif | 377 | endif |
| 378 | ifeq ($(TARGET_ARCH), mips) | 378 | ifeq ($(TARGET_ARCH), mips) |
| 379 | -VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o dma.o vga.o serial.o i8254.o i8259.o | 379 | +VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o |
| 380 | VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o | 380 | VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o |
| 381 | VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) | 381 | VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) |
| 382 | DEFINES += -DHAS_AUDIO | 382 | DEFINES += -DHAS_AUDIO |
cpu-exec.c
| @@ -535,7 +535,6 @@ int cpu_exec(CPUState *env1) | @@ -535,7 +535,6 @@ int cpu_exec(CPUState *env1) | ||
| 535 | env->exception_index = EXCP_EXT_INTERRUPT; | 535 | env->exception_index = EXCP_EXT_INTERRUPT; |
| 536 | env->error_code = 0; | 536 | env->error_code = 0; |
| 537 | do_interrupt(env); | 537 | do_interrupt(env); |
| 538 | - env->interrupt_request &= ~CPU_INTERRUPT_HARD; | ||
| 539 | #if defined(__sparc__) && !defined(HOST_SOLARIS) | 538 | #if defined(__sparc__) && !defined(HOST_SOLARIS) |
| 540 | tmp_T0 = 0; | 539 | tmp_T0 = 0; |
| 541 | #else | 540 | #else |
hw/gt64xxx.c
| 1 | /* | 1 | /* |
| 2 | * QEMU GT64120 PCI host | 2 | * QEMU GT64120 PCI host |
| 3 | * | 3 | * |
| 4 | - * Copyright (c) 2006 Aurelien Jarno | 4 | + * Copyright (c) 2006,2007 Aurelien Jarno |
| 5 | * | 5 | * |
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | 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 | 7 | * of this software and associated documentation files (the "Software"), to deal |
| @@ -433,7 +433,8 @@ static uint32_t gt64120_readl (void *opaque, | @@ -433,7 +433,8 @@ static uint32_t gt64120_readl (void *opaque, | ||
| 433 | val = s->regs[saddr]; | 433 | val = s->regs[saddr]; |
| 434 | break; | 434 | break; |
| 435 | case GT_PCI0_IACK: | 435 | case GT_PCI0_IACK: |
| 436 | - val = pic_intack_read(isa_pic); | 436 | + /* Read the IRQ number */ |
| 437 | + val = pic_read_irq(isa_pic); | ||
| 437 | break; | 438 | break; |
| 438 | 439 | ||
| 439 | /* SDRAM Parameters */ | 440 | /* SDRAM Parameters */ |
hw/i8259.c
| @@ -161,6 +161,13 @@ void pic_update_irq(PicState2 *s) | @@ -161,6 +161,13 @@ void pic_update_irq(PicState2 *s) | ||
| 161 | #endif | 161 | #endif |
| 162 | s->irq_request(s->irq_request_opaque, 1); | 162 | s->irq_request(s->irq_request_opaque, 1); |
| 163 | } | 163 | } |
| 164 | + | ||
| 165 | +/* all targets should do this rather than acking the IRQ in the cpu */ | ||
| 166 | +#if defined(TARGET_MIPS) | ||
| 167 | + else { | ||
| 168 | + s->irq_request(s->irq_request_opaque, 0); | ||
| 169 | + } | ||
| 170 | +#endif | ||
| 164 | } | 171 | } |
| 165 | 172 | ||
| 166 | #ifdef DEBUG_IRQ_LATENCY | 173 | #ifdef DEBUG_IRQ_LATENCY |
hw/mips_int.c
0 → 100644
| 1 | +#include "vl.h" | ||
| 2 | +#include "cpu.h" | ||
| 3 | + | ||
| 4 | +/* Raise IRQ to CPU if necessary. It must be called every time the active | ||
| 5 | + IRQ may change */ | ||
| 6 | +void cpu_mips_update_irq(CPUState *env) | ||
| 7 | +{ | ||
| 8 | + if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && | ||
| 9 | + (env->CP0_Status & (1 << CP0St_IE)) && | ||
| 10 | + !(env->hflags & MIPS_HFLAG_EXL) && | ||
| 11 | + !(env->hflags & MIPS_HFLAG_ERL) && | ||
| 12 | + !(env->hflags & MIPS_HFLAG_DM)) { | ||
| 13 | + if (! (env->interrupt_request & CPU_INTERRUPT_HARD)) { | ||
| 14 | + cpu_interrupt(env, CPU_INTERRUPT_HARD); | ||
| 15 | + } | ||
| 16 | + } else { | ||
| 17 | + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); | ||
| 18 | + } | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +void cpu_mips_irq_request(void *opaque, int irq, int level) | ||
| 22 | +{ | ||
| 23 | + CPUState *env = first_cpu; | ||
| 24 | + | ||
| 25 | + uint32_t mask; | ||
| 26 | + | ||
| 27 | + if (irq >= 16) | ||
| 28 | + return; | ||
| 29 | + | ||
| 30 | + mask = 1 << (irq + CP0Ca_IP); | ||
| 31 | + | ||
| 32 | + if (level) { | ||
| 33 | + env->CP0_Cause |= mask; | ||
| 34 | + } else { | ||
| 35 | + env->CP0_Cause &= ~mask; | ||
| 36 | + } | ||
| 37 | + cpu_mips_update_irq(env); | ||
| 38 | +} | ||
| 39 | + |
hw/mips_malta.c
| @@ -54,16 +54,10 @@ typedef struct { | @@ -54,16 +54,10 @@ typedef struct { | ||
| 54 | 54 | ||
| 55 | static PITState *pit; | 55 | static PITState *pit; |
| 56 | 56 | ||
| 57 | +/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */ | ||
| 57 | static void pic_irq_request(void *opaque, int level) | 58 | static void pic_irq_request(void *opaque, int level) |
| 58 | { | 59 | { |
| 59 | - CPUState *env = first_cpu; | ||
| 60 | - if (level) { | ||
| 61 | - env->CP0_Cause |= 0x00000400; | ||
| 62 | - cpu_interrupt(env, CPU_INTERRUPT_HARD); | ||
| 63 | - } else { | ||
| 64 | - env->CP0_Cause &= ~0x00000400; | ||
| 65 | - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); | ||
| 66 | - } | 60 | + cpu_mips_irq_request(opaque, 2, level); |
| 67 | } | 61 | } |
| 68 | 62 | ||
| 69 | /* Malta FPGA */ | 63 | /* Malta FPGA */ |
hw/mips_r4k.c
| @@ -38,14 +38,7 @@ static PITState *pit; /* PIT i8254 */ | @@ -38,14 +38,7 @@ static PITState *pit; /* PIT i8254 */ | ||
| 38 | /*The PIC is attached to the MIPS CPU INT0 pin */ | 38 | /*The PIC is attached to the MIPS CPU INT0 pin */ |
| 39 | static void pic_irq_request(void *opaque, int level) | 39 | static void pic_irq_request(void *opaque, int level) |
| 40 | { | 40 | { |
| 41 | - CPUState *env = first_cpu; | ||
| 42 | - if (level) { | ||
| 43 | - env->CP0_Cause |= 0x00000400; | ||
| 44 | - cpu_interrupt(env, CPU_INTERRUPT_HARD); | ||
| 45 | - } else { | ||
| 46 | - env->CP0_Cause &= ~0x00000400; | ||
| 47 | - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); | ||
| 48 | - } | 41 | + cpu_mips_irq_request(opaque, 2, level); |
| 49 | } | 42 | } |
| 50 | 43 | ||
| 51 | static void mips_qemu_writel (void *opaque, target_phys_addr_t addr, | 44 | static void mips_qemu_writel (void *opaque, target_phys_addr_t addr, |
hw/mips_timer.c
| @@ -57,8 +57,7 @@ void cpu_mips_store_count (CPUState *env, uint32_t value) | @@ -57,8 +57,7 @@ void cpu_mips_store_count (CPUState *env, uint32_t value) | ||
| 57 | void cpu_mips_store_compare (CPUState *env, uint32_t value) | 57 | void cpu_mips_store_compare (CPUState *env, uint32_t value) |
| 58 | { | 58 | { |
| 59 | cpu_mips_update_count(env, cpu_mips_get_count(env), value); | 59 | cpu_mips_update_count(env, cpu_mips_get_count(env), value); |
| 60 | - env->CP0_Cause &= ~0x00008000; | ||
| 61 | - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); | 60 | + cpu_mips_irq_request(env, 7, 0); |
| 62 | } | 61 | } |
| 63 | 62 | ||
| 64 | static void mips_timer_cb (void *opaque) | 63 | static void mips_timer_cb (void *opaque) |
| @@ -72,8 +71,7 @@ static void mips_timer_cb (void *opaque) | @@ -72,8 +71,7 @@ static void mips_timer_cb (void *opaque) | ||
| 72 | } | 71 | } |
| 73 | #endif | 72 | #endif |
| 74 | cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare); | 73 | cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare); |
| 75 | - env->CP0_Cause |= 0x00008000; | ||
| 76 | - cpu_interrupt(env, CPU_INTERRUPT_HARD); | 74 | + cpu_mips_irq_request(env, 7, 1); |
| 77 | } | 75 | } |
| 78 | 76 | ||
| 79 | void cpu_mips_clock_init (CPUState *env) | 77 | void cpu_mips_clock_init (CPUState *env) |
target-mips/cpu.h
| @@ -158,6 +158,7 @@ struct CPUMIPSState { | @@ -158,6 +158,7 @@ struct CPUMIPSState { | ||
| 158 | #define CP0Ca_IV 23 | 158 | #define CP0Ca_IV 23 |
| 159 | #define CP0Ca_WP 22 | 159 | #define CP0Ca_WP 22 |
| 160 | #define CP0Ca_IP 8 | 160 | #define CP0Ca_IP 8 |
| 161 | +#define CP0Ca_IP_mask 0x0000FF00 | ||
| 161 | #define CP0Ca_EC 2 | 162 | #define CP0Ca_EC 2 |
| 162 | target_ulong CP0_EPC; | 163 | target_ulong CP0_EPC; |
| 163 | int32_t CP0_PRid; | 164 | int32_t CP0_PRid; |
target-mips/exec.h
| @@ -164,6 +164,7 @@ uint32_t cpu_mips_get_random (CPUState *env); | @@ -164,6 +164,7 @@ uint32_t cpu_mips_get_random (CPUState *env); | ||
| 164 | uint32_t cpu_mips_get_count (CPUState *env); | 164 | uint32_t cpu_mips_get_count (CPUState *env); |
| 165 | void cpu_mips_store_count (CPUState *env, uint32_t value); | 165 | void cpu_mips_store_count (CPUState *env, uint32_t value); |
| 166 | void cpu_mips_store_compare (CPUState *env, uint32_t value); | 166 | void cpu_mips_store_compare (CPUState *env, uint32_t value); |
| 167 | +void cpu_mips_update_irq(CPUState *env); | ||
| 167 | void cpu_mips_clock_init (CPUState *env); | 168 | void cpu_mips_clock_init (CPUState *env); |
| 168 | void cpu_mips_tlb_flush (CPUState *env, int flush_global); | 169 | void cpu_mips_tlb_flush (CPUState *env, int flush_global); |
| 169 | 170 |
target-mips/op.c
| @@ -1357,7 +1357,7 @@ void op_mtc0_compare (void) | @@ -1357,7 +1357,7 @@ void op_mtc0_compare (void) | ||
| 1357 | 1357 | ||
| 1358 | void op_mtc0_status (void) | 1358 | void op_mtc0_status (void) |
| 1359 | { | 1359 | { |
| 1360 | - uint32_t val, old, mask; | 1360 | + uint32_t val, old; |
| 1361 | 1361 | ||
| 1362 | val = (int32_t)T0 & 0xFA78FF01; | 1362 | val = (int32_t)T0 & 0xFA78FF01; |
| 1363 | old = env->CP0_Status; | 1363 | old = env->CP0_Status; |
| @@ -1374,21 +1374,9 @@ void op_mtc0_status (void) | @@ -1374,21 +1374,9 @@ void op_mtc0_status (void) | ||
| 1374 | else | 1374 | else |
| 1375 | env->hflags &= ~MIPS_HFLAG_EXL; | 1375 | env->hflags &= ~MIPS_HFLAG_EXL; |
| 1376 | env->CP0_Status = val; | 1376 | env->CP0_Status = val; |
| 1377 | - /* If we unmasked an asserted IRQ, raise it */ | ||
| 1378 | - mask = 0x0000FF00; | ||
| 1379 | if (loglevel & CPU_LOG_TB_IN_ASM) | 1377 | if (loglevel & CPU_LOG_TB_IN_ASM) |
| 1380 | CALL_FROM_TB2(do_mtc0_status_debug, old, val); | 1378 | CALL_FROM_TB2(do_mtc0_status_debug, old, val); |
| 1381 | - if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) && | ||
| 1382 | - !(env->hflags & MIPS_HFLAG_EXL) && | ||
| 1383 | - !(env->hflags & MIPS_HFLAG_ERL) && | ||
| 1384 | - !(env->hflags & MIPS_HFLAG_DM) && | ||
| 1385 | - (env->CP0_Status & env->CP0_Cause & mask)) { | ||
| 1386 | - env->interrupt_request |= CPU_INTERRUPT_HARD; | ||
| 1387 | - if (logfile) | ||
| 1388 | - CALL_FROM_TB0(do_mtc0_status_irqraise_debug); | ||
| 1389 | - } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) { | ||
| 1390 | - env->interrupt_request &= ~CPU_INTERRUPT_HARD; | ||
| 1391 | - } | 1379 | + CALL_FROM_TB1(cpu_mips_update_irq, env); |
| 1392 | RETURN(); | 1380 | RETURN(); |
| 1393 | } | 1381 | } |
| 1394 | 1382 | ||
| @@ -1415,22 +1403,13 @@ void op_mtc0_srsmap (void) | @@ -1415,22 +1403,13 @@ void op_mtc0_srsmap (void) | ||
| 1415 | 1403 | ||
| 1416 | void op_mtc0_cause (void) | 1404 | void op_mtc0_cause (void) |
| 1417 | { | 1405 | { |
| 1418 | - uint32_t val, old; | 1406 | + env->CP0_Cause = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x00C00300); |
| 1419 | 1407 | ||
| 1420 | - val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x00C00300); | ||
| 1421 | - old = env->CP0_Cause; | ||
| 1422 | - env->CP0_Cause = val; | ||
| 1423 | -#if 0 | ||
| 1424 | - { | ||
| 1425 | - int i, mask; | ||
| 1426 | - /* Check if we ever asserted a software IRQ */ | ||
| 1427 | - for (i = 0; i < 2; i++) { | ||
| 1428 | - mask = 0x100 << i; | ||
| 1429 | - if ((val & mask) & !(old & mask)) | ||
| 1430 | - CALL_FROM_TB1(mips_set_irq, i); | ||
| 1431 | - } | 1408 | + /* Handle the software interrupt as an hardware one, as they |
| 1409 | + are very similar */ | ||
| 1410 | + if (T0 & CP0Ca_IP_mask) { | ||
| 1411 | + CALL_FROM_TB1(cpu_mips_update_irq, env); | ||
| 1432 | } | 1412 | } |
| 1433 | -#endif | ||
| 1434 | RETURN(); | 1413 | RETURN(); |
| 1435 | } | 1414 | } |
| 1436 | 1415 | ||
| @@ -2074,36 +2053,17 @@ void op_pmon (void) | @@ -2074,36 +2053,17 @@ void op_pmon (void) | ||
| 2074 | 2053 | ||
| 2075 | void op_di (void) | 2054 | void op_di (void) |
| 2076 | { | 2055 | { |
| 2077 | - uint32_t val; | ||
| 2078 | - | ||
| 2079 | T0 = env->CP0_Status; | 2056 | T0 = env->CP0_Status; |
| 2080 | - val = T0 & ~(1 << CP0St_IE); | ||
| 2081 | - if (val != T0) { | ||
| 2082 | - env->interrupt_request &= ~CPU_INTERRUPT_HARD; | ||
| 2083 | - env->CP0_Status = val; | ||
| 2084 | - } | 2057 | + env->CP0_Status = T0 & ~(1 << CP0St_IE); |
| 2058 | + CALL_FROM_TB1(cpu_mips_update_irq, env); | ||
| 2085 | RETURN(); | 2059 | RETURN(); |
| 2086 | } | 2060 | } |
| 2087 | 2061 | ||
| 2088 | void op_ei (void) | 2062 | void op_ei (void) |
| 2089 | { | 2063 | { |
| 2090 | - uint32_t val; | ||
| 2091 | - | ||
| 2092 | T0 = env->CP0_Status; | 2064 | T0 = env->CP0_Status; |
| 2093 | - val = T0 | (1 << CP0St_IE); | ||
| 2094 | - if (val != T0) { | ||
| 2095 | - const uint32_t mask = 0x0000FF00; | ||
| 2096 | - | ||
| 2097 | - env->CP0_Status = val; | ||
| 2098 | - if (!(env->hflags & MIPS_HFLAG_EXL) && | ||
| 2099 | - !(env->hflags & MIPS_HFLAG_ERL) && | ||
| 2100 | - !(env->hflags & MIPS_HFLAG_DM) && | ||
| 2101 | - (env->CP0_Status & env->CP0_Cause & mask)) { | ||
| 2102 | - env->interrupt_request |= CPU_INTERRUPT_HARD; | ||
| 2103 | - if (logfile) | ||
| 2104 | - CALL_FROM_TB0(do_mtc0_status_irqraise_debug); | ||
| 2105 | - } | ||
| 2106 | - } | 2065 | + env->CP0_Status = T0 | (1 << CP0St_IE); |
| 2066 | + CALL_FROM_TB1(cpu_mips_update_irq, env); | ||
| 2107 | RETURN(); | 2067 | RETURN(); |
| 2108 | } | 2068 | } |
| 2109 | 2069 |
target-mips/op_helper.c
| @@ -265,6 +265,11 @@ void cpu_mips_store_compare(CPUState *env, uint32_t value) | @@ -265,6 +265,11 @@ void cpu_mips_store_compare(CPUState *env, uint32_t value) | ||
| 265 | cpu_abort(env, "mtc0 compare\n"); | 265 | cpu_abort(env, "mtc0 compare\n"); |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | +void cpu_mips_update_irq(CPUState *env) | ||
| 269 | +{ | ||
| 270 | + cpu_abort(env, "mtc0 status / mtc0 cause\n"); | ||
| 271 | +} | ||
| 272 | + | ||
| 268 | void do_mtc0_status_debug(uint32_t old, uint32_t val) | 273 | void do_mtc0_status_debug(uint32_t old, uint32_t val) |
| 269 | { | 274 | { |
| 270 | cpu_abort(env, "mtc0 status debug\n"); | 275 | cpu_abort(env, "mtc0 status debug\n"); |
vl.h
| @@ -1067,6 +1067,9 @@ extern QEMUMachine mips_machine; | @@ -1067,6 +1067,9 @@ extern QEMUMachine mips_machine; | ||
| 1067 | /* mips_malta.c */ | 1067 | /* mips_malta.c */ |
| 1068 | extern QEMUMachine mips_malta_machine; | 1068 | extern QEMUMachine mips_malta_machine; |
| 1069 | 1069 | ||
| 1070 | +/* mips_int */ | ||
| 1071 | +extern void cpu_mips_irq_request(void *opaque, int irq, int level); | ||
| 1072 | + | ||
| 1070 | /* mips_timer.c */ | 1073 | /* mips_timer.c */ |
| 1071 | extern void cpu_mips_clock_init(CPUState *); | 1074 | extern void cpu_mips_clock_init(CPUState *); |
| 1072 | extern void cpu_mips_irqctrl_init (void); | 1075 | extern void cpu_mips_irqctrl_init (void); |