diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index 4c97219f8c..c769fcc138 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -681,6 +681,16 @@ static void typhoon_set_timer_irq(void *opaque, int irq, int level) } } +static void typhoon_alarm_timer(void *opaque) +{ + TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3); + int cpu = (uintptr_t)opaque & 3; + + /* Set the ITI bit for this cpu. */ + s->cchip.misc |= 1 << (cpu + 4); + cpu_interrupt(s->cchip.cpu[cpu], CPU_INTERRUPT_TIMER); +} + PCIBus *typhoon_init(ram_addr_t ram_size, qemu_irq *p_rtc_irq, CPUState *cpus[4], pci_map_irq_fn sys_map_irq) { @@ -692,6 +702,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, qemu_irq *p_rtc_irq, PCIHostState *p; TyphoonState *s; PCIBus *b; + int i; dev = qdev_create(NULL, "typhoon-pcihost"); qdev_init_nofail(dev); @@ -700,7 +711,15 @@ PCIBus *typhoon_init(ram_addr_t ram_size, qemu_irq *p_rtc_irq, s = container_of(p, TyphoonState, host); /* Remember the CPUs so that we can deliver interrupts to them. */ - memcpy(s->cchip.cpu, cpus, 4 * sizeof(CPUState *)); + for (i = 0; i < 4; i++) { + CPUState *env = cpus[i]; + s->cchip.cpu[i] = env; + if (env) { + env->alarm_timer = qemu_new_timer_ns(rtc_clock, + typhoon_alarm_timer, + (void *)((uintptr_t)s + i)); + } + } *p_rtc_irq = *qemu_allocate_irqs(typhoon_set_timer_irq, s, 1); diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index c2e7bb31ef..9d61d45ab6 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -265,6 +265,10 @@ struct CPUAlphaState { uint64_t scratch[24]; #endif + /* This alarm doesn't exist in real hardware; we wish it did. */ + struct QEMUTimer *alarm_timer; + uint64_t alarm_expire; + #if TARGET_LONG_BITS > HOST_LONG_BITS /* temporary fixed-point registers * used to emulate 64 bits target on 32 bits hosts diff --git a/target-alpha/helper.h b/target-alpha/helper.h index c352c2493e..b693ceea97 100644 --- a/target-alpha/helper.h +++ b/target-alpha/helper.h @@ -113,7 +113,11 @@ DEF_HELPER_2(stq_c_phys, i64, i64, i64) DEF_HELPER_FLAGS_0(tbia, TCG_CALL_CONST, void) DEF_HELPER_FLAGS_1(tbis, TCG_CALL_CONST, void, i64) + DEF_HELPER_1(halt, void, i64); + +DEF_HELPER_FLAGS_0(get_time, TCG_CALL_CONST, i64) +DEF_HELPER_FLAGS_1(set_alarm, TCG_CALL_CONST, void, i64) #endif #include "def-helper.h" diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index 1896ab8b00..cc102dbd63 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -1228,6 +1228,21 @@ void helper_halt(uint64_t restart) qemu_system_shutdown_request(); } } + +uint64_t helper_get_time(void) +{ + return qemu_get_clock_ns(rtc_clock); +} + +void helper_set_alarm(uint64_t expire) +{ + if (expire) { + env->alarm_expire = expire; + qemu_mod_timer(env->alarm_timer, expire); + } else { + qemu_del_timer(env->alarm_timer); + } +} #endif /*****************************************************************************/ diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 0acbd682d3..a961159d5d 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -1590,18 +1590,34 @@ static int cpu_pr_data(int pr) return offsetof(CPUAlphaState, shadow[pr - 32]); case 40 ... 63: return offsetof(CPUAlphaState, scratch[pr - 40]); + + case 251: + return offsetof(CPUAlphaState, alarm_expire); } return 0; } -static void gen_mfpr(int ra, int regno) +static ExitStatus gen_mfpr(int ra, int regno) { int data = cpu_pr_data(regno); /* In our emulated PALcode, these processor registers have no side effects from reading. */ if (ra == 31) { - return; + return NO_EXIT; + } + + if (regno == 250) { + /* WALL_TIME */ + if (use_icount) { + gen_io_start(); + gen_helper_get_time(cpu_ir[ra]); + gen_io_end(); + return EXIT_PC_STALE; + } else { + gen_helper_get_time(cpu_ir[ra]); + return NO_EXIT; + } } /* The basic registers are data only, and unknown registers @@ -1615,6 +1631,7 @@ static void gen_mfpr(int ra, int regno) } else { tcg_gen_ld_i64(cpu_ir[ra], cpu_env, data); } + return NO_EXIT; } static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno) @@ -1650,6 +1667,11 @@ static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno) gen_helper_halt(tmp); return EXIT_PC_STALE; + case 251: + /* ALARM */ + gen_helper_set_alarm(tmp); + break; + default: /* The basic registers are data only, and unknown registers are read-zero, write-ignore. */ @@ -2772,8 +2794,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) /* HW_MFPR (PALcode) */ #ifndef CONFIG_USER_ONLY if (ctx->tb->flags & TB_FLAGS_PAL_MODE) { - gen_mfpr(ra, insn & 0xffff); - break; + return gen_mfpr(ra, insn & 0xffff); } #endif goto invalid_opc;