mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-11 05:29:43 +00:00
Decrementer exception changes.
This commit is contained in:
parent
d2e7c9a5df
commit
300965ab10
@ -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
|
||||
|
@ -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. */
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user