From 300965ab10720cd4de300879b85b73a33f56d701 Mon Sep 17 00:00:00 2001 From: joevt Date: Mon, 7 Aug 2023 11:11:02 -0700 Subject: [PATCH] Decrementer exception changes. --- cpu/ppc/ppcemu.h | 2 ++ cpu/ppc/ppcexceptions.cpp | 2 +- cpu/ppc/ppcexec.cpp | 5 ++++- cpu/ppc/ppcopcodes.cpp | 47 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/cpu/ppc/ppcemu.h b/cpu/ppc/ppcemu.h index 816af8d..c327546 100644 --- a/cpu/ppc/ppcemu.h +++ b/cpu/ppc/ppcemu.h @@ -173,6 +173,7 @@ extern uint64_t rtc_timestamp; extern uint64_t tbr_wr_value; extern uint32_t dec_wr_value; extern uint32_t tbr_freq_ghz; +extern uint64_t tbr_period_ns; extern uint32_t rtc_lo, rtc_hi; // Additional steps to prevent overflow? @@ -319,6 +320,7 @@ extern bool grab_return; extern bool power_on; extern bool int_pin; +extern bool dec_exception_pending; extern bool is_601; // For PowerPC 601 Emulation extern bool is_altivec; // For Altivec Emulation diff --git a/cpu/ppc/ppcexceptions.cpp b/cpu/ppc/ppcexceptions.cpp index cec9632..11c6a0c 100644 --- a/cpu/ppc/ppcexceptions.cpp +++ b/cpu/ppc/ppcexceptions.cpp @@ -131,7 +131,7 @@ void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits) { mmu_change_mode(); - if (exception_type != Except_Type::EXC_EXT_INT) { + if (exception_type != Except_Type::EXC_EXT_INT && exception_type != Except_Type::EXC_DECR) { longjmp(exc_env, 2); /* return to the main execution loop. */ } } diff --git a/cpu/ppc/ppcexec.cpp b/cpu/ppc/ppcexec.cpp index 9d7971a..70ac292 100644 --- a/cpu/ppc/ppcexec.cpp +++ b/cpu/ppc/ppcexec.cpp @@ -55,6 +55,7 @@ uint32_t ppc_next_instruction_address; // Used for branching, setting up the unsigned exec_flags; // execution control flags bool int_pin = false; // interrupt request pin state: true - asserted +bool dec_exception_pending = false; /* copy of local variable bb_start_la. Need for correct calculation of CPU cycles after setjmp that clobbers @@ -69,7 +70,8 @@ int icnt_factor; uint64_t tbr_wr_timestamp; // stores vCPU virtual time of the last TBR write uint64_t rtc_timestamp; // stores vCPU virtual time of the last RTC write uint64_t tbr_wr_value; // last value written to the TBR -uint32_t tbr_freq_ghz; // TBR/RTC driving frequency in GHz expressed as a 32 bit fraction less than 1.0. +uint32_t tbr_freq_ghz; // TBR/RTC driving frequency in GHz expressed as a 32 bit fraction less than 1.0 (999.999999 MHz maximum). +uint64_t tbr_period_ns; // TBR/RTC period in ns expressed as a 64 bit value with 32 fractional bits (<1 Hz minimum). uint64_t timebase_counter; // internal timebase counter uint64_t dec_wr_timestamp; // stores vCPU virtual time of the last DEC write uint32_t dec_wr_value; // last value written to the DEC register @@ -768,6 +770,7 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, uint64_t tb_freq) rtc_timestamp = 0; tbr_wr_value = 0; tbr_freq_ghz = (tb_freq << 32) / NS_PER_SEC; + tbr_period_ns = ((uint64_t)NS_PER_SEC << 32) / tb_freq; exec_flags = 0; diff --git a/cpu/ppc/ppcopcodes.cpp b/cpu/ppc/ppcopcodes.cpp index 3960099..07eeabf 100644 --- a/cpu/ppc/ppcopcodes.cpp +++ b/cpu/ppc/ppcopcodes.cpp @@ -851,6 +851,10 @@ void dppc_interpreter::ppc_mtmsr() { if (ppc_state.msr & 0x8000 && int_pin) { LOG_F(WARNING, "MTMSR: CPU INT pending, generate CPU exception"); ppc_exception_handler(Except_Type::EXC_EXT_INT, 0); + } else if ((ppc_state.msr & 0x8000) && dec_exception_pending) { + dec_exception_pending = false; + //LOG_F(WARNING, "MTMSR: decrementer exception triggered"); + ppc_exception_handler(Except_Type::EXC_DECR, 0); } else { mmu_change_mode(); } @@ -894,9 +898,43 @@ static void update_timebase(uint64_t mask, uint64_t new_val) tbr_wr_timestamp = get_virt_time_ns(); } + +static uint32_t decrementer_timer_id = 0; + +static void trigger_decrementer_exception() { + decrementer_timer_id = 0; + dec_wr_value = -1; + dec_wr_timestamp = get_virt_time_ns(); + if (ppc_state.msr & 0x8000) { + dec_exception_pending = false; + //LOG_F(WARNING, "decrementer exception triggered"); + ppc_exception_handler(Except_Type::EXC_DECR, 0); + } + else { + //LOG_F(WARNING, "decrementer exception pending"); + dec_exception_pending = true; + } +} + static void update_decrementer(uint32_t val) { dec_wr_value = val; dec_wr_timestamp = get_virt_time_ns(); + + dec_exception_pending = false; + + if (decrementer_timer_id) { + //LOG_F(WARNING, "decrementer cancel timer"); + TimerManager::get_instance()->cancel_timer(decrementer_timer_id); + } + + uint64_t time_out; + uint32_t time_out_lo; + _u32xu64(val, tbr_period_ns, time_out, time_out_lo); + //LOG_F(WARNING, "decrementer:0x%08X ns:%llu", val, time_out); + decrementer_timer_id = TimerManager::get_instance()->add_oneshot_timer( + time_out, + trigger_decrementer_exception + ); } void dppc_interpreter::ppc_mfspr() { @@ -1401,6 +1439,15 @@ void dppc_interpreter::ppc_rfi() { return; } + if ((ppc_state.msr & 0x8000) && dec_exception_pending) { + dec_exception_pending = false; + //LOG_F(WARNING, "decrementer exception from rfi msr:0x%X", ppc_state.msr); + uint32_t save_srr0 = ppc_state.spr[SPR::SRR0] & 0xFFFFFFFCUL; + ppc_exception_handler(Except_Type::EXC_DECR, 0); + ppc_state.spr[SPR::SRR0] = save_srr0; + return; + } + ppc_next_instruction_address = ppc_state.spr[SPR::SRR0] & 0xFFFFFFFCUL; do_ctx_sync(); // RFI is context synchronizing