Make accessing RTC or TBR not affect the other

Fixed an issue where the following would cause inconsistent results (tb in the left column would sometimes decrement instead of always incrementing):
2 0 do 2 0 do cr tb@ 8 u.r ." ." 8 u.r loop 2 0 do cr 12 spaces rtc@ 8 u.r ." ." 8 u.r loop 2 0 do cr tb@ 8 u.r ." ." 8 u.r space rtc@ 8 u.r ." ." 8 u.r loop loop

RTC and TBR could not be used simultaneously because they are both incremented by an amount based on the last time stamp but that time stamp can be changed by accessing either RTC or TBR. The solution is to have a different time stamp for each.
This commit is contained in:
joevt 2022-09-15 20:21:54 -07:00
parent ce925f5e56
commit 01d7d6bac3
3 changed files with 8 additions and 5 deletions

View File

@ -159,6 +159,7 @@ extern uint32_t opcode_value; // used for interpreting opcodes
extern uint64_t timebase_counter;
extern uint64_t tbr_wr_timestamp;
extern uint64_t rtc_timestamp;
extern uint64_t tbr_wr_value;
extern uint64_t tbr_freq_hz;
extern uint32_t rtc_lo, rtc_hi;

View File

@ -66,7 +66,8 @@ uint64_t g_icycles;
int icnt_factor;
/* global variables related to the timebase facility */
uint64_t tbr_wr_timestamp; // stores vCPU virtual time of the last TBR/RTC write
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
uint64_t tbr_freq_hz; // TBR/RTC driving frequency in Hz
uint64_t timebase_counter; // internal timebase counter
@ -763,6 +764,7 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, uint64_t tb_freq)
g_icycles = 0;
icnt_factor = 4;
tbr_wr_timestamp = 0;
rtc_timestamp = 0;
tbr_wr_value = 0;
tbr_freq_hz = tb_freq;

View File

@ -857,13 +857,13 @@ void dppc_interpreter::ppc_mtmsr() {
static inline uint64_t calc_rtcl_value()
{
uint64_t diff = get_virt_time_ns() - tbr_wr_timestamp;
uint64_t diff = get_virt_time_ns() - rtc_timestamp;
uint64_t rtc_inc = diff * tbr_freq_hz / NS_PER_SEC;
uint64_t rtc_l = rtc_lo + (rtc_inc << 7);
if (rtc_l >= ONE_BILLION_NS) { // check RTCL overflow
rtc_hi += rtc_l / ONE_BILLION_NS;
rtc_lo = rtc_l % ONE_BILLION_NS;
tbr_wr_timestamp = get_virt_time_ns();
rtc_timestamp = get_virt_time_ns();
rtc_l = rtc_lo;
}
return rtc_l & 0x3FFFFF80UL;
@ -927,11 +927,11 @@ void dppc_interpreter::ppc_mtspr() {
switch (ref_spr) {
case SPR::RTCL_S:
rtc_lo = val & 0x3FFFFF80UL;
tbr_wr_timestamp = get_virt_time_ns();
rtc_timestamp = get_virt_time_ns();
break;
case SPR::RTCU_S:
rtc_hi = val;
tbr_wr_timestamp = get_virt_time_ns();
rtc_timestamp = get_virt_time_ns();
break;
case SPR::TBL_S:
update_timebase(0xFFFFFFFF00000000ULL, val);