mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-06-02 05:41:39 +00:00
Implement MPC601 style RTC.
This commit is contained in:
parent
4525fd50cc
commit
1d86375061
|
@ -33,7 +33,8 @@ using namespace std;
|
||||||
|
|
||||||
#define MIN_TIMEOUT_NS 200
|
#define MIN_TIMEOUT_NS 200
|
||||||
|
|
||||||
#define NS_PER_SEC 1E9
|
#define NS_PER_SEC 1E9
|
||||||
|
#define ONE_BILLION_NS 0x3B9ACA00UL
|
||||||
|
|
||||||
#define USECS_TO_NSECS(us) (us) * 1000
|
#define USECS_TO_NSECS(us) (us) * 1000
|
||||||
|
|
||||||
|
|
|
@ -84,22 +84,27 @@ extern SetPRS ppc_state;
|
||||||
|
|
||||||
/** symbolic names for frequently used SPRs */
|
/** symbolic names for frequently used SPRs */
|
||||||
enum SPR : int {
|
enum SPR : int {
|
||||||
MQ = 0,
|
MQ = 0,
|
||||||
XER = 1,
|
XER = 1,
|
||||||
LR = 8,
|
RTCU_U = 4, // user RTCU
|
||||||
CTR = 9,
|
RTCL_U = 5, // user RTCL
|
||||||
DSISR = 18,
|
LR = 8,
|
||||||
DAR = 19,
|
CTR = 9,
|
||||||
DEC = 22,
|
DSISR = 18,
|
||||||
SDR1 = 25,
|
DAR = 19,
|
||||||
SRR0 = 26,
|
RTCU_S = 20, // supervisor RTCU
|
||||||
SRR1 = 27,
|
RTCL_S = 21, // supervisor RTCL
|
||||||
PVR = 287
|
DEC = 22,
|
||||||
|
SDR1 = 25,
|
||||||
|
SRR0 = 26,
|
||||||
|
SRR1 = 27,
|
||||||
|
TBL_U = 268, // user mode TBL
|
||||||
|
TBU_U = 269, // user mode TBU
|
||||||
|
TBL_S = 284, // supervisor TBL
|
||||||
|
TBU_S = 285, // supervisor TBU
|
||||||
|
PVR = 287
|
||||||
};
|
};
|
||||||
|
|
||||||
/** symbolic names for frequently used SPRs */
|
|
||||||
enum TBR : int { TBL = 0, TBU = 1 };
|
|
||||||
|
|
||||||
/** symbolic names for common PPC processors */
|
/** symbolic names for common PPC processors */
|
||||||
enum PPC_VER : uint32_t {
|
enum PPC_VER : uint32_t {
|
||||||
MPC601 = 0x00010001,
|
MPC601 = 0x00010001,
|
||||||
|
@ -154,6 +159,7 @@ extern uint64_t timebase_counter;
|
||||||
extern uint64_t tbr_wr_timestamp;
|
extern uint64_t tbr_wr_timestamp;
|
||||||
extern uint64_t tbr_wr_value;
|
extern uint64_t tbr_wr_value;
|
||||||
extern uint64_t tbr_freq_hz;
|
extern uint64_t tbr_freq_hz;
|
||||||
|
extern uint32_t rtc_lo, rtc_hi;
|
||||||
|
|
||||||
// Additional steps to prevent overflow?
|
// Additional steps to prevent overflow?
|
||||||
extern int32_t add_result;
|
extern int32_t add_result;
|
||||||
|
@ -321,7 +327,7 @@ extern uint64_t exceptions_processed;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Function prototypes
|
// Function prototypes
|
||||||
extern void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version);
|
extern void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, uint64_t tb_freq);
|
||||||
extern void ppc_mmu_init(uint32_t cpu_version);
|
extern void ppc_mmu_init(uint32_t cpu_version);
|
||||||
|
|
||||||
void ppc_illegalop();
|
void ppc_illegalop();
|
||||||
|
|
|
@ -65,11 +65,13 @@ uint64_t g_icycles;
|
||||||
int icnt_factor;
|
int icnt_factor;
|
||||||
|
|
||||||
/* global variables related to the timebase facility */
|
/* global variables related to the timebase facility */
|
||||||
uint64_t tbr_wr_timestamp; // stores vCPU virtual time of the last TBR write
|
uint64_t tbr_wr_timestamp; // stores vCPU virtual time of the last TBR/RTC write
|
||||||
uint64_t tbr_wr_value; // last value written to the TBR
|
uint64_t tbr_wr_value; // last value written to the TBR
|
||||||
uint64_t tbr_freq_hz; // TBR driving frequency in Hz
|
uint64_t tbr_freq_hz; // TBR/RTC driving frequency in Hz
|
||||||
uint64_t timebase_counter; // internal timebase counter
|
uint64_t timebase_counter; // internal timebase counter
|
||||||
uint32_t decr; // current value of PPC DEC register
|
uint32_t decr; // current value of PPC DEC register
|
||||||
|
uint32_t rtc_lo; // MPC601 RTC lower, counts nanoseconds
|
||||||
|
uint32_t rtc_hi; // MPC601 RTC upper, counts seconds
|
||||||
|
|
||||||
#ifdef CPU_PROFILING
|
#ifdef CPU_PROFILING
|
||||||
|
|
||||||
|
@ -734,13 +736,12 @@ void initialize_ppc_opcode_tables() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version) {
|
void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, uint64_t tb_freq)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
mem_ctrl_instance = mem_ctrl;
|
mem_ctrl_instance = mem_ctrl;
|
||||||
|
|
||||||
//test_timebase_update();
|
|
||||||
|
|
||||||
initialize_ppc_opcode_tables();
|
initialize_ppc_opcode_tables();
|
||||||
|
|
||||||
// initialize emulator timers
|
// initialize emulator timers
|
||||||
|
@ -752,7 +753,7 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version) {
|
||||||
icnt_factor = 4;
|
icnt_factor = 4;
|
||||||
tbr_wr_timestamp = 0;
|
tbr_wr_timestamp = 0;
|
||||||
tbr_wr_value = 0;
|
tbr_wr_value = 0;
|
||||||
tbr_freq_hz = 16705000; // FIXME: this should be set properly during machine initialization
|
tbr_freq_hz = tb_freq;
|
||||||
|
|
||||||
exec_flags = 0;
|
exec_flags = 0;
|
||||||
|
|
||||||
|
|
|
@ -847,6 +847,20 @@ void dppc_interpreter::ppc_mtmsr() {
|
||||||
mmu_change_mode();
|
mmu_change_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint64_t calc_rtcl_value()
|
||||||
|
{
|
||||||
|
uint64_t diff = get_virt_time_ns() - tbr_wr_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_l = rtc_lo;
|
||||||
|
}
|
||||||
|
return rtc_l & 0x3FFFFF80UL;
|
||||||
|
}
|
||||||
|
|
||||||
void dppc_interpreter::ppc_mfspr() {
|
void dppc_interpreter::ppc_mfspr() {
|
||||||
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 31) << 5) | ((ppc_cur_instruction >> 16) & 31);
|
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 31) << 5) | ((ppc_cur_instruction >> 16) & 31);
|
||||||
|
|
||||||
|
@ -855,8 +869,17 @@ void dppc_interpreter::ppc_mfspr() {
|
||||||
num_supervisor_instrs++;
|
num_supervisor_instrs++;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
reg_d = (ppc_cur_instruction >> 21) & 31;
|
|
||||||
ppc_state.gpr[reg_d] = ppc_state.spr[ref_spr];
|
switch (ref_spr) {
|
||||||
|
case SPR::RTCL_U:
|
||||||
|
ppc_state.spr[SPR::RTCL_U] = calc_rtcl_value();
|
||||||
|
break;
|
||||||
|
case SPR::RTCU_U:
|
||||||
|
ppc_state.spr[SPR::RTCL_U] = rtc_hi;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ppc_state.gpr[(ppc_cur_instruction >> 21) & 31] = ppc_state.spr[ref_spr];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t calc_tbr_value()
|
static inline uint64_t calc_tbr_value()
|
||||||
|
@ -871,7 +894,6 @@ static void update_timebase(uint64_t mask, uint64_t new_val)
|
||||||
uint64_t tbr_value = calc_tbr_value();
|
uint64_t tbr_value = calc_tbr_value();
|
||||||
tbr_wr_value = (tbr_value & mask) | new_val;
|
tbr_wr_value = (tbr_value & mask) | new_val;
|
||||||
tbr_wr_timestamp = get_virt_time_ns();
|
tbr_wr_timestamp = get_virt_time_ns();
|
||||||
LOG_F(9, "New TBR value = 0x%llu", tbr_wr_value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dppc_interpreter::ppc_mtspr() {
|
void dppc_interpreter::ppc_mtspr() {
|
||||||
|
@ -884,20 +906,30 @@ void dppc_interpreter::ppc_mtspr() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ref_spr != 287) {
|
uint32_t val = ppc_state.gpr[reg_s];
|
||||||
ppc_state.spr[ref_spr] = ppc_state.gpr[reg_s];
|
|
||||||
|
if (ref_spr != SPR::PVR) { // prevent writes to the read-only PVR
|
||||||
|
ppc_state.spr[ref_spr] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref_spr == SPR::SDR1) {
|
if (ref_spr == SPR::SDR1) { // adapt to SDR1 changes
|
||||||
mmu_pat_ctx_changed();
|
mmu_pat_ctx_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ref_spr) {
|
switch (ref_spr) {
|
||||||
case 284:
|
case SPR::RTCL_S:
|
||||||
update_timebase(0xFFFFFFFF00000000ULL, ppc_state.gpr[reg_s]);
|
rtc_lo = val & 0x3FFFFF80UL;
|
||||||
|
tbr_wr_timestamp = get_virt_time_ns();
|
||||||
break;
|
break;
|
||||||
case 285:
|
case SPR::RTCU_S:
|
||||||
update_timebase(0x00000000FFFFFFFFULL, (uint64_t)(ppc_state.gpr[reg_s]) << 32);
|
rtc_hi = val;
|
||||||
|
tbr_wr_timestamp = get_virt_time_ns();
|
||||||
|
break;
|
||||||
|
case SPR::TBL_S:
|
||||||
|
update_timebase(0xFFFFFFFF00000000ULL, val);
|
||||||
|
break;
|
||||||
|
case SPR::TBU_S:
|
||||||
|
update_timebase(0x00000000FFFFFFFFULL, (uint64_t)(val) << 32);
|
||||||
break;
|
break;
|
||||||
case 528:
|
case 528:
|
||||||
case 529:
|
case 529:
|
||||||
|
@ -928,10 +960,10 @@ void dppc_interpreter::ppc_mftb() {
|
||||||
uint64_t tbr_value = calc_tbr_value();
|
uint64_t tbr_value = calc_tbr_value();
|
||||||
|
|
||||||
switch (ref_spr) {
|
switch (ref_spr) {
|
||||||
case 268:
|
case SPR::TBL_U:
|
||||||
ppc_state.gpr[reg_d] = tbr_value & 0xFFFFFFFFUL;
|
ppc_state.gpr[reg_d] = tbr_value & 0xFFFFFFFFUL;
|
||||||
break;
|
break;
|
||||||
case 269:
|
case SPR::TBU_U:
|
||||||
ppc_state.gpr[reg_d] = (tbr_value >> 32) & 0xFFFFFFFFUL;
|
ppc_state.gpr[reg_d] = (tbr_value >> 32) & 0xFFFFFFFFUL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -101,7 +101,7 @@ int create_gossamer(std::string& id) {
|
||||||
18, dynamic_cast<PCIDevice*>(gMachineObj->get_comp_by_name("ATIRage")));
|
18, dynamic_cast<PCIDevice*>(gMachineObj->get_comp_by_name("ATIRage")));
|
||||||
|
|
||||||
/* Init virtual CPU and request MPC750 CPU aka G3 */
|
/* Init virtual CPU and request MPC750 CPU aka G3 */
|
||||||
ppc_cpu_init(grackle_obj, PPC_VER::MPC750);
|
ppc_cpu_init(grackle_obj, PPC_VER::MPC750, 16705000ULL);
|
||||||
|
|
||||||
// post-initialize all devices
|
// post-initialize all devices
|
||||||
if (gMachineObj->postinit_devices()) {
|
if (gMachineObj->postinit_devices()) {
|
||||||
|
|
|
@ -89,7 +89,7 @@ int create_pdm(std::string& id) {
|
||||||
gMachineObj->add_component("SCSI0", new ScsiBus);
|
gMachineObj->add_component("SCSI0", new ScsiBus);
|
||||||
|
|
||||||
/* Init virtual CPU and request MPC601 */
|
/* Init virtual CPU and request MPC601 */
|
||||||
ppc_cpu_init(hmc_obj, PPC_VER::MPC601);
|
ppc_cpu_init(hmc_obj, PPC_VER::MPC601, 7812500ULL);
|
||||||
|
|
||||||
// post-initialize all devices
|
// post-initialize all devices
|
||||||
if (gMachineObj->postinit_devices()) {
|
if (gMachineObj->postinit_devices()) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user