diff --git a/Makefile.target b/Makefile.target index 98fe7e12bf..d066cc03db 100644 --- a/Makefile.target +++ b/Makefile.target @@ -445,7 +445,7 @@ ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o -VL_OBJS+= cirrus_vga.o parallel.o +VL_OBJS+= cirrus_vga.o parallel.o ptimer.o else VL_OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o sparc32_dma.o diff --git a/hw/sun4u.c b/hw/sun4u.c index 952beff3cd..a7b9ad8f01 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -282,7 +282,35 @@ void qemu_system_powerdown(void) static void main_cpu_reset(void *opaque) { CPUState *env = opaque; + cpu_reset(env); + ptimer_set_limit(env->tick, 0x7fffffffffffffffULL, 1); + ptimer_run(env->tick, 0); + ptimer_set_limit(env->stick, 0x7fffffffffffffffULL, 1); + ptimer_run(env->stick, 0); + ptimer_set_limit(env->hstick, 0x7fffffffffffffffULL, 1); + ptimer_run(env->hstick, 0); +} + +void tick_irq(void *opaque) +{ + CPUState *env = opaque; + + cpu_interrupt(env, CPU_INTERRUPT_TIMER); +} + +void stick_irq(void *opaque) +{ + CPUState *env = opaque; + + cpu_interrupt(env, CPU_INTERRUPT_TIMER); +} + +void hstick_irq(void *opaque) +{ + CPUState *env = opaque; + + cpu_interrupt(env, CPU_INTERRUPT_TIMER); } static const int ide_iobase[2] = { 0x1f0, 0x170 }; @@ -311,6 +339,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, long prom_offset, initrd_size, kernel_size; PCIBus *pci_bus; const sparc_def_t *def; + QEMUBH *bh; linux_boot = (kernel_filename != NULL); @@ -324,8 +353,20 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, } env = cpu_init(); cpu_sparc_register(env, def); + bh = qemu_bh_new(tick_irq, env); + env->tick = ptimer_init(bh); + ptimer_set_period(env->tick, 1ULL); + + bh = qemu_bh_new(stick_irq, env); + env->stick = ptimer_init(bh); + ptimer_set_period(env->stick, 1ULL); + + bh = qemu_bh_new(hstick_irq, env); + env->hstick = ptimer_init(bh); + ptimer_set_period(env->hstick, 1ULL); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); + main_cpu_reset(env); /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index b067d7b9bd..c5ccd28a82 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -226,10 +226,12 @@ typedef struct CPUSPARCState { uint64_t mgregs[8]; /* mmu general registers */ uint64_t fprs; uint64_t tick_cmpr, stick_cmpr; + void *tick, *stick; uint64_t gsr; uint32_t gl; // UA2005 /* UA 2005 hyperprivileged registers */ uint64_t hpstate, htstate[MAXTL], hintp, htba, hver, hstick_cmpr, ssr; + void *hstick; // UA 2005 #endif #if !defined(TARGET_SPARC64) && !defined(reg_T2) target_ulong t2; @@ -292,6 +294,9 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); void raise_exception(int tt); void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, int is_asi); +void do_tick_set_count(void *opaque, uint64_t count); +uint64_t do_tick_get_count(void *opaque); +void do_tick_set_limit(void *opaque, uint64_t limit); #include "cpu-all.h" diff --git a/target-sparc/op.c b/target-sparc/op.c index 5fbbd6db0f..c0aee8f4ac 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1096,12 +1096,38 @@ void OPPROTO op_wrccr(void) void OPPROTO op_rdtick(void) { - T0 = 0; // XXX read cycle counter and bit 31 + T0 = do_tick_get_count(env->tick); } void OPPROTO op_wrtick(void) { - T0 = 0; // XXX write cycle counter and bit 31 + do_tick_set_count(env->tick, T0); +} + +void OPPROTO op_wrtick_cmpr(void) +{ + do_tick_set_limit(env->tick, T0); +} + +void OPPROTO op_rdstick(void) +{ + T0 = do_tick_get_count(env->stick); +} + +void OPPROTO op_wrstick(void) +{ + do_tick_set_count(env->stick, T0); + do_tick_set_count(env->hstick, T0); +} + +void OPPROTO op_wrstick_cmpr(void) +{ + do_tick_set_limit(env->stick, T0); +} + +void OPPROTO op_wrhstick_cmpr(void) +{ + do_tick_set_limit(env->hstick, T0); } void OPPROTO op_rdtpc(void) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 93f61a8025..b2f982f4ee 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1133,3 +1133,20 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, raise_exception(TT_DATA_ACCESS); } #endif + +#ifdef TARGET_SPARC64 +void do_tick_set_count(void *opaque, uint64_t count) +{ + ptimer_set_count(opaque, -count); +} + +uint64_t do_tick_get_count(void *opaque) +{ + return -ptimer_get_count(opaque); +} + +void do_tick_set_limit(void *opaque, uint64_t limit) +{ + ptimer_set_limit(opaque, -limit, 0); +} +#endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 38d2a13195..8dbe3370fe 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1202,7 +1202,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_T0_reg(rd); break; case 0x18: /* System tick */ - gen_op_rdtick(); // XXX + gen_op_rdstick(); gen_movl_T0_reg(rd); break; case 0x19: /* System tick compare */ @@ -1991,21 +1991,23 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto illegal_insn; #endif - gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr)); + gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr)); + gen_op_wrtick_cmpr(); break; case 0x18: /* System tick */ #if !defined(CONFIG_USER_ONLY) if (!supervisor(dc)) goto illegal_insn; #endif - gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr)); + gen_op_wrstick(); break; case 0x19: /* System tick compare */ #if !defined(CONFIG_USER_ONLY) if (!supervisor(dc)) goto illegal_insn; #endif - gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr)); + gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr)); + gen_op_wrstick_cmpr(); break; case 0x10: /* Performance Control */ @@ -2155,7 +2157,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_movl_env_T0(offsetof(CPUSPARCState, htba)); break; case 31: // hstick_cmpr - gen_op_movl_env_T0(offsetof(CPUSPARCState, hstick_cmpr)); + gen_op_movtl_env_T0(offsetof(CPUSPARCState, hstick_cmpr)); + gen_op_wrhstick_cmpr(); break; case 6: // hver readonly default: