Decrementer exception changes.

This commit is contained in:
joevt 2023-08-07 11:11:02 -07:00 committed by Maxim Poliakovski
parent d2e7c9a5df
commit 300965ab10
4 changed files with 54 additions and 2 deletions

View File

@ -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

View File

@ -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. */
}
}

View File

@ -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;

View File

@ -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