mirror of
https://github.com/dingusdev/dingusppc.git
synced 2026-04-20 18:17:02 +00:00
ppc: Timing calculation changes.
Note: all timings are relative to virtual time which is 16 ns per instruction. 8 ns per instruction is too fast for the PDM 'mach' gestalt calculation in firmware. - For MPC601, bit 7 of RTC and DEC changes at 7.8336 MHz so bit 0 would change at 1.0027008 GHz. Therefore multiply time base frequency by 128. For MPC601, DEC now changes at 1.0027008 GHz instead of 7.8336 MHz. - Add tbr_freq_shift for cases where time base frequency exceeds 1GHz. - Change calc_rtcl_value to use time base frequency. For MPC601, RTC now changes at 1.0027008 GHz instead 1GHz. - For MPC601, the 7 least significant bits of DEC are not implemented so make them not getable or setable.
This commit is contained in:
@@ -177,6 +177,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 uint32_t tbr_freq_shift;
|
||||
extern uint64_t tbr_period_ns;
|
||||
extern uint32_t rtc_lo, rtc_hi;
|
||||
|
||||
|
||||
+23
-3
@@ -92,6 +92,7 @@ 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 (999.999999 MHz maximum).
|
||||
uint32_t tbr_freq_shift; // If 32 bits is not sufficient, then include a shift.
|
||||
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
|
||||
@@ -826,12 +827,31 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, bool do_include_6
|
||||
#endif
|
||||
g_nanoseconds_base = cpu_now_ns();
|
||||
g_icycles = 0;
|
||||
//icnt_factor = 6;
|
||||
icnt_factor = 4;
|
||||
|
||||
// // // PDM cpu clock calculated at 0x403036CC in r3
|
||||
// icnt_factor = 11; // 1 instruction = 2048 ns = 0.488 MHz // 00068034 = 0.426036 MHz = 2347.219 ns // floppy doesn't work
|
||||
// icnt_factor = 10; // 1 instruction = 1024 ns = 0.977 MHz // 000D204C = 0.860236 MHz = 1162.471 ns // [0..10] MHz = invalid clock for PDM gestalt calculation
|
||||
// icnt_factor = 9; // 1 instruction = 512 ns = 1.953 MHz // 001A6081 = 1.728641 MHz = 578.489 ns // [0..10] MHz = invalid clock for PDM gestalt calculation
|
||||
// icnt_factor = 8; // 1 instruction = 256 ns = 3.906 MHz // 0034E477 = 3.466359 MHz = 288.487 ns // [0..10] MHz = invalid clock for PDM gestalt calculation
|
||||
// icnt_factor = 7; // 1 instruction = 128 ns = 7.813 MHz // 0069E54C = 6.939980 MHz = 144.092 ns // [0..10] MHz = invalid clock for PDM gestalt calculation
|
||||
// icnt_factor = 6; // 1 instruction = 64 ns = 15.625 MHz // 00D3E6F5 = 13.887221 MHz = 72.008 ns // (10..60] = 50, (60..73] = 66, (73..100] = 80 MHz
|
||||
// icnt_factor = 5; // 1 instruction = 32 ns = 31.250 MHz // 01A7B672 = 27.768434 MHz = 36.012 ns //
|
||||
icnt_factor = 4; // 1 instruction = 16 ns = 62.500 MHz // 034F0F0F = 55.512847 MHz = 18.013 ns // 6100/60 in Apple System Profiler
|
||||
// icnt_factor = 3; // 1 instruction = 8 ns = 125.000 MHz // 069E1E1E = 111.025694 MHz = 9.006 ns // (100...) MHz = invalid clock for PDM gestalt calculation
|
||||
// icnt_factor = 2; // 1 instruction = 4 ns = 250.000 MHz // 0D3C3C3C = 222.051388 MHz = 4.503 ns // (100...) MHz = invalid clock for PDM gestalt calculation
|
||||
// icnt_factor = 1; // 1 instruction = 2 ns = 500.000 MHz // 1A611A7B = 442.571387 MHz = 2.259 ns // (100...) MHz = invalid clock for PDM gestalt calculation
|
||||
// icnt_factor = 0; // 1 instruction = 1 ns = 1500.000 MHz // 3465B2D9 = 879.080153 MHz = 1.137 ns // (100...) MHz = invalid clock for PDM gestalt calculation
|
||||
|
||||
tbr_wr_timestamp = 0;
|
||||
rtc_timestamp = 0;
|
||||
tbr_wr_value = 0;
|
||||
tbr_freq_ghz = (tb_freq << 32) / NS_PER_SEC;
|
||||
if (is_601)
|
||||
tb_freq <<= 7;
|
||||
tbr_freq_shift = 0;
|
||||
uint64_t x;
|
||||
for (x = (tb_freq << 32) / NS_PER_SEC; x >> 32; x >>= 1)
|
||||
tbr_freq_shift++;
|
||||
tbr_freq_ghz = (uint32_t)x;
|
||||
tbr_period_ns = ((uint64_t)NS_PER_SEC << 32) / tb_freq;
|
||||
|
||||
exec_flags = 0;
|
||||
|
||||
+42
-9
@@ -819,6 +819,7 @@ void dppc_interpreter::ppc_mtmsr(uint32_t opcode) {
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline void calc_rtcl_value()
|
||||
{
|
||||
uint64_t new_ts = get_virt_time_ns();
|
||||
@@ -832,22 +833,47 @@ static inline void calc_rtcl_value()
|
||||
}
|
||||
rtc_timestamp = new_ts;
|
||||
}
|
||||
#else
|
||||
static inline void calc_rtcl_value()
|
||||
{
|
||||
uint64_t adj;
|
||||
uint32_t adj_lo;
|
||||
uint64_t new_ts = get_virt_time_ns();
|
||||
uint64_t diff = new_ts - rtc_timestamp;
|
||||
_u32xu64(tbr_freq_ghz, diff, adj, adj_lo);
|
||||
if (tbr_freq_shift)
|
||||
adj = (adj << tbr_freq_shift) + (adj_lo >> (32 - tbr_freq_shift));
|
||||
uint64_t rtc_l = adj + rtc_lo;
|
||||
if (rtc_l >= ONE_BILLION_NS) { // check RTCL overflow
|
||||
rtc_hi += (uint32_t)(rtc_l / ONE_BILLION_NS);
|
||||
rtc_lo = rtc_l % ONE_BILLION_NS;
|
||||
}
|
||||
else {
|
||||
rtc_lo = (uint32_t)rtc_l;
|
||||
}
|
||||
rtc_timestamp = new_ts;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint64_t calc_tbr_value()
|
||||
{
|
||||
uint64_t tbr_inc;
|
||||
uint32_t tbr_inc_lo;
|
||||
uint64_t adj;
|
||||
uint32_t adj_lo;
|
||||
uint64_t diff = get_virt_time_ns() - tbr_wr_timestamp;
|
||||
_u32xu64(tbr_freq_ghz, diff, tbr_inc, tbr_inc_lo);
|
||||
return (tbr_wr_value + tbr_inc);
|
||||
_u32xu64(tbr_freq_ghz, diff, adj, adj_lo);
|
||||
if (tbr_freq_shift)
|
||||
adj = (adj << tbr_freq_shift) + (adj_lo >> (32 - tbr_freq_shift));
|
||||
return (tbr_wr_value + adj);
|
||||
}
|
||||
|
||||
static inline uint32_t calc_dec_value() {
|
||||
uint64_t dec_adj;
|
||||
uint32_t dec_adj_lo;
|
||||
uint64_t adj;
|
||||
uint32_t adj_lo;
|
||||
uint64_t diff = get_virt_time_ns() - dec_wr_timestamp;
|
||||
_u32xu64(tbr_freq_ghz, diff, dec_adj, dec_adj_lo);
|
||||
return (dec_wr_value - static_cast<uint32_t>(dec_adj));
|
||||
_u32xu64(tbr_freq_ghz, diff, adj, adj_lo);
|
||||
if (tbr_freq_shift)
|
||||
adj = (adj << tbr_freq_shift) + (adj_lo >> (32 - tbr_freq_shift));
|
||||
return (dec_wr_value - static_cast<uint32_t>(adj));
|
||||
}
|
||||
|
||||
static void update_timebase(uint64_t mask, uint64_t new_val)
|
||||
@@ -943,8 +969,13 @@ void dppc_interpreter::ppc_mfspr(uint32_t opcode) {
|
||||
}
|
||||
// fallthrough
|
||||
case SPR::DEC_S:
|
||||
ppc_state.gpr[reg_d] = ppc_state.spr[SPR::DEC_S] = calc_dec_value();
|
||||
{
|
||||
uint32_t val = calc_dec_value();
|
||||
if (is_601)
|
||||
val &= ~0x7F;
|
||||
ppc_state.gpr[reg_d] = ppc_state.spr[SPR::DEC_S] = val;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// FIXME: Unknown SPR should be noop or illegal instruction.
|
||||
ppc_state.gpr[reg_d] = ppc_state.spr[ref_spr];
|
||||
@@ -1000,6 +1031,8 @@ void dppc_interpreter::ppc_mtspr(uint32_t opcode) {
|
||||
ppc_state.spr[RTCU_S] = rtc_hi = val;
|
||||
break;
|
||||
case SPR::DEC_S:
|
||||
if (is_601)
|
||||
val &= ~0x7F;
|
||||
ppc_state.spr[DEC_S] = val;
|
||||
update_decrementer(val);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user