diff --git a/hw/sun4u.c b/hw/sun4u.c index 00dac2d03e..59418f69e5 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -33,6 +33,15 @@ #include "firmware_abi.h" #include "fw_cfg.h" +//#define DEBUG_IRQ + +#ifdef DEBUG_IRQ +#define DPRINTF(fmt, args...) \ + do { printf("CPUIRQ: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif + #define KERNEL_LOAD_ADDR 0x00404000 #define CMDLINE_ADDR 0x003ff000 #define INITRD_LOAD_ADDR 0x00300000 @@ -47,6 +56,8 @@ #define MAX_IDE_BUS 2 #define BIOS_CFG_IOPORT 0x510 +#define MAX_PILS 16 + struct hwdef { const char * const default_cpu_model; uint16_t machine_id; @@ -201,6 +212,50 @@ void irq_info(void) { } +void cpu_check_irqs(CPUState *env) +{ + uint32_t pil = env->pil_in | (env->softint & ~SOFTINT_TIMER) | + ((env->softint & SOFTINT_TIMER) << 14); + + if (pil && (env->interrupt_index == 0 || + (env->interrupt_index & ~15) == TT_EXTINT)) { + unsigned int i; + + for (i = 15; i > 0; i--) { + if (pil & (1 << i)) { + int old_interrupt = env->interrupt_index; + + env->interrupt_index = TT_EXTINT | i; + if (old_interrupt != env->interrupt_index) { + DPRINTF("Set CPU IRQ %d\n", i); + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } + break; + } + } + } else if (!pil && (env->interrupt_index & ~15) == TT_EXTINT) { + DPRINTF("Reset CPU IRQ %d\n", env->interrupt_index & 15); + env->interrupt_index = 0; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +static void cpu_set_irq(void *opaque, int irq, int level) +{ + CPUState *env = opaque; + + if (level) { + DPRINTF("Raise CPU IRQ %d\n", irq); + env->halted = 0; + env->pil_in |= 1 << irq; + cpu_check_irqs(env); + } else { + DPRINTF("Lower CPU IRQ %d\n", irq); + env->pil_in &= ~(1 << irq); + cpu_check_irqs(env); + } +} + void qemu_system_powerdown(void) { } @@ -222,6 +277,7 @@ static void tick_irq(void *opaque) { CPUState *env = opaque; + env->softint |= SOFTINT_TIMER; cpu_interrupt(env, CPU_INTERRUPT_TIMER); } @@ -229,6 +285,7 @@ static void stick_irq(void *opaque) { CPUState *env = opaque; + env->softint |= SOFTINT_TIMER; cpu_interrupt(env, CPU_INTERRUPT_TIMER); } @@ -236,13 +293,10 @@ static void hstick_irq(void *opaque) { CPUState *env = opaque; + env->softint |= SOFTINT_TIMER; cpu_interrupt(env, CPU_INTERRUPT_TIMER); } -static void dummy_cpu_set_irq(void *opaque, int irq, int level) -{ -} - static const int ide_iobase[2] = { 0x1f0, 0x170 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 }; static const int ide_irq[2] = { 14, 15 }; @@ -383,7 +437,7 @@ static void sun4uv_init(ram_addr_t RAM_size, int vga_ram_size, pci_nic_init(pci_bus, &nd_table[i], -1); } - irq = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, 32); + irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS); if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { fprintf(stderr, "qemu: too many IDE bus\n"); exit(1); diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 87fd3190a3..6faaa6f914 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -329,6 +329,8 @@ typedef struct CPUSPARCState { /* UA 2005 hyperprivileged registers */ uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr; void *hstick; // UA 2005 + uint32_t softint; +#define SOFTINT_TIMER 1 #endif sparc_def_t *def; } CPUSPARCState; diff --git a/target-sparc/helper.h b/target-sparc/helper.h index 9320bc813d..e85ed344b1 100644 --- a/target-sparc/helper.h +++ b/target-sparc/helper.h @@ -31,6 +31,9 @@ DEF_HELPER(target_ulong, helper_cas_asi, (target_ulong addr, \ DEF_HELPER(target_ulong, helper_casx_asi, (target_ulong addr, \ target_ulong val1, \ target_ulong val2, uint32_t asi)) +DEF_HELPER(void, helper_set_softint, (uint64_t value)) +DEF_HELPER(void, helper_clear_softint, (uint64_t value)) +DEF_HELPER(void, helper_write_softint, (uint64_t value)) DEF_HELPER(void, helper_tick_set_count, (void *opaque, uint64_t count)) DEF_HELPER(uint64_t, helper_tick_get_count, (void *opaque)) DEF_HELPER(void, helper_tick_set_limit, (void *opaque, uint64_t limit)) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 163e82b902..7901403e8e 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -2671,6 +2671,21 @@ void helper_retry(void) env->tl--; env->tsptr = &env->ts[env->tl & MAXTL_MASK]; } + +void helper_set_softint(uint64_t value) +{ + env->softint |= (uint32_t)value; +} + +void helper_clear_softint(uint64_t value) +{ + env->softint &= (uint32_t)~value; +} + +void helper_write_softint(uint64_t value) +{ + env->softint = (uint32_t)value; +} #endif void helper_flush(target_ulong addr) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 96dd56faa6..abea2f15a2 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -49,7 +49,7 @@ static TCGv cpu_cond, cpu_src1, cpu_src2, cpu_dst, cpu_addr, cpu_val; #ifdef TARGET_SPARC64 static TCGv cpu_xcc, cpu_asi, cpu_fprs, cpu_gsr; static TCGv cpu_tick_cmpr, cpu_stick_cmpr, cpu_hstick_cmpr; -static TCGv cpu_hintp, cpu_htba, cpu_hver, cpu_ssr, cpu_ver; +static TCGv cpu_hintp, cpu_htba, cpu_hver, cpu_ssr, cpu_ver, cpu_softint; #else static TCGv cpu_wim; #endif @@ -2102,6 +2102,10 @@ static void disas_sparc_insn(DisasContext * dc) goto jmp_insn; gen_movl_TN_reg(rd, cpu_gsr); break; + case 0x16: /* Softint */ + tcg_gen_ext_i32_tl(cpu_dst, cpu_softint); + gen_movl_TN_reg(rd, cpu_dst); + break; case 0x17: /* Tick compare */ gen_movl_TN_reg(rd, cpu_tick_cmpr); break; @@ -2126,7 +2130,6 @@ static void disas_sparc_insn(DisasContext * dc) case 0x12: /* Dispatch Control */ case 0x14: /* Softint set, WO */ case 0x15: /* Softint clear, WO */ - case 0x16: /* Softint write */ #endif default: goto illegal_insn; @@ -3233,6 +3236,27 @@ static void disas_sparc_insn(DisasContext * dc) goto jmp_insn; tcg_gen_xor_tl(cpu_gsr, cpu_src1, cpu_src2); break; + case 0x14: /* Softint set */ + if (!supervisor(dc)) + goto illegal_insn; + tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2); + tcg_gen_helper_0_1(helper_set_softint, + cpu_tmp64); + break; + case 0x15: /* Softint clear */ + if (!supervisor(dc)) + goto illegal_insn; + tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2); + tcg_gen_helper_0_1(helper_clear_softint, + cpu_tmp64); + break; + case 0x16: /* Softint write */ + if (!supervisor(dc)) + goto illegal_insn; + tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2); + tcg_gen_helper_0_1(helper_write_softint, + cpu_tmp64); + break; case 0x17: /* Tick compare */ #if !defined(CONFIG_USER_ONLY) if (!supervisor(dc)) @@ -3292,9 +3316,6 @@ static void disas_sparc_insn(DisasContext * dc) case 0x11: /* Performance Instrumentation Counter */ case 0x12: /* Dispatch Control */ - case 0x14: /* Softint set */ - case 0x15: /* Softint clear */ - case 0x16: /* Softint write */ #endif default: goto illegal_insn; @@ -4952,6 +4973,9 @@ void gen_intermediate_code_init(CPUSPARCState *env) offsetof(CPUState, ssr), "ssr"); cpu_ver = tcg_global_mem_new(TCG_TYPE_TL, TCG_AREG0, offsetof(CPUState, version), "ver"); + cpu_softint = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, + offsetof(CPUState, softint), + "softint"); #else cpu_wim = tcg_global_mem_new(TCG_TYPE_I32, TCG_AREG0, offsetof(CPUState, wim),