diff --git a/cpu/ppc/ppcemu.h b/cpu/ppc/ppcemu.h index 539a898..5d2168f 100644 --- a/cpu/ppc/ppcemu.h +++ b/cpu/ppc/ppcemu.h @@ -85,17 +85,18 @@ extern SetPRS ppc_state; /** symbolic names for frequently used SPRs */ enum SPR : int { - MQ = 0, + MQ = 0, // MQ (601) XER = 1, - RTCU_U = 4, // user RTCU - RTCL_U = 5, // user RTCL + RTCU_U = 4, // user mode RTCU (601) + RTCL_U = 5, // user mode RTCL (601) + DEC_U = 6, // user mode decrementer (601) LR = 8, CTR = 9, DSISR = 18, DAR = 19, - RTCU_S = 20, // supervisor RTCU - RTCL_S = 21, // supervisor RTCL - DEC = 22, // decrementer + RTCU_S = 20, // supervisor RTCU (601) + RTCL_S = 21, // supervisor RTCL (601) + DEC_S = 22, // supervisor decrementer SDR1 = 25, SRR0 = 26, SRR1 = 27, diff --git a/cpu/ppc/ppcexec.cpp b/cpu/ppc/ppcexec.cpp index f8a26a4..e1909a9 100644 --- a/cpu/ppc/ppcexec.cpp +++ b/cpu/ppc/ppcexec.cpp @@ -864,8 +864,8 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, bool include_601, /* MPC601 sets MSR[ME] bit during hard reset / Power-On */ ppc_state.msr = (MSR::ME + MSR::IP); } else { - ppc_state.msr = MSR::IP; - ppc_state.spr[SPR::DEC] = 0xFFFFFFFFUL; + ppc_state.msr = MSR::IP; + ppc_state.spr[SPR::DEC_S] = 0xFFFFFFFFUL; } ppc_mmu_init(); @@ -885,10 +885,10 @@ void print_fprs() { } static map SPRName2Num = { - {"XER", SPR::XER}, {"LR", SPR::LR}, {"CTR", SPR::CTR}, - {"DEC", SPR::DEC}, {"PVR", SPR::PVR}, {"SPRG0", SPR::SPRG0}, - {"SPRG1", SPR::SPRG1}, {"SPRG2", SPR::SPRG2}, {"SPRG3", SPR::SPRG3}, - {"SRR0", SPR::SRR0}, {"SRR1", SPR::SRR1}, {"IBAT0U", 528}, + {"XER", SPR::XER}, {"LR", SPR::LR}, {"CTR", SPR::CTR}, + {"DEC", SPR::DEC_S}, {"PVR", SPR::PVR}, {"SPRG0", SPR::SPRG0}, + {"SPRG1", SPR::SPRG1}, {"SPRG2", SPR::SPRG2}, {"SPRG3", SPR::SPRG3}, + {"SRR0", SPR::SRR0}, {"SRR1", SPR::SRR1}, {"IBAT0U", 528}, {"IBAT0L", 529}, {"IBAT1U", 530}, {"IBAT1L", 531}, {"IBAT2U", 532}, {"IBAT2L", 533}, {"IBAT3U", 534}, {"IBAT3L", 535}, {"DBAT0U", 536}, {"DBAT0L", 537}, @@ -897,9 +897,9 @@ static map SPRName2Num = { {"HID0", SPR::HID0}, {"HID1", SPR::HID1}, {"IABR", 1010}, {"DABR", 1013}, {"L2CR", 1017}, {"ICTC", 1019}, {"THRM1", 1020}, {"THRM2", 1021}, {"THRM3", 1022}, - {"PIR", 1023}, {"TBL", SPR::TBL_U}, {"TBU", SPR::TBU_U}, - {"SDR1", SPR::SDR1}, {"MQ", SPR::MQ}, {"RTCU", SPR::RTCU_U}, - {"RTCL", SPR::RTCL_U}, {"DSISR", SPR::DSISR}, {"DAR", SPR::DAR}, + {"PIR", 1023}, {"TBL", SPR::TBL_S}, {"TBU", SPR::TBU_S}, + {"SDR1", SPR::SDR1}, {"MQ", SPR::MQ}, {"RTCU", SPR::RTCU_S}, + {"RTCL", SPR::RTCL_S}, {"DSISR", SPR::DSISR}, {"DAR", SPR::DAR}, {"MMCR0", SPR::MMCR0}, {"PMC1", SPR::PMC1}, {"PMC2", SPR::PMC2}, {"SDA", SPR::SDA}, {"SIA", SPR::SIA}, {"MMCR1", SPR::MMCR1} }; @@ -974,6 +974,13 @@ uint64_t reg_op(string& reg_name, uint64_t val, bool is_write) { reg_num_str = reg_name_u.substr(3); reg_num = (unsigned)stoul(reg_num_str, NULL, 0); if (reg_num < 1024) { + switch (reg_num) { + case SPR::DEC_U : reg_num = SPR::DEC_S ; break; + case SPR::RTCL_U : reg_num = SPR::RTCL_S ; break; + case SPR::RTCU_U : reg_num = SPR::RTCU_S ; break; + case SPR::TBL_U : reg_num = SPR::TBL_S ; break; + case SPR::TBU_U : reg_num = SPR::TBU_S ; break; + } if (is_write) ppc_state.spr[reg_num] = (uint32_t)val; return ppc_state.spr[reg_num]; diff --git a/cpu/ppc/ppcopcodes.cpp b/cpu/ppc/ppcopcodes.cpp index 2830c07..4889f66 100644 --- a/cpu/ppc/ppcopcodes.cpp +++ b/cpu/ppc/ppcopcodes.cpp @@ -898,20 +898,42 @@ void dppc_interpreter::ppc_mfspr() { } switch (ref_spr) { + case SPR::MQ: + if (!is_601) { + ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + } + ppc_state.gpr[reg_d] = ppc_state.spr[ref_spr]; + break; case SPR::RTCL_U: + if (!is_601) { + ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + } calc_rtcl_value(); - ppc_state.spr[SPR::RTCL_U] = rtc_lo & 0x3FFFFF80UL; + ppc_state.gpr[reg_d] = + ppc_state.spr[SPR::RTCL_S] = rtc_lo & 0x3FFFFF80UL; + ppc_state.spr[SPR::RTCU_S] = rtc_hi; break; case SPR::RTCU_U: + if (!is_601) { + ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + } calc_rtcl_value(); - ppc_state.spr[SPR::RTCU_U] = rtc_hi; + ppc_state.gpr[reg_d] = + ppc_state.spr[SPR::RTCU_S] = rtc_hi; + ppc_state.spr[SPR::RTCL_S] = rtc_lo; break; - case SPR::DEC: - ppc_state.spr[SPR::DEC] = calc_dec_value(); + case SPR::DEC_U: + if (!is_601) { + ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + } + // fallthrough + case SPR::DEC_S: + ppc_state.gpr[reg_d] = ppc_state.spr[SPR::DEC_S] = calc_dec_value(); break; + default: + // FIXME: Unknown SPR should be noop or illegal instruction. + ppc_state.gpr[reg_d] = ppc_state.spr[ref_spr]; } - - ppc_state.gpr[reg_d] = ppc_state.spr[ref_spr]; } void dppc_interpreter::ppc_mtspr() { @@ -927,38 +949,54 @@ void dppc_interpreter::ppc_mtspr() { } } - if (ref_spr == SPR::PVR || ( - ref_spr == SPR::MQ && !is_601 - )) { // prevent writes to the read-only registers - return; - } - uint32_t val = ppc_state.gpr[reg_d]; - ppc_state.spr[ref_spr] = val; switch (ref_spr) { + case SPR::MQ: + if (!is_601) { + ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + } + ppc_state.spr[ref_spr] = val; + break; + case SPR::RTCL_U: + case SPR::RTCU_U: + case SPR::DEC_U: + if (!is_601) { + ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + } + break; case SPR::XER: ppc_state.spr[ref_spr] = val & 0xe000ff7f; break; case SPR::SDR1: + ppc_state.spr[ref_spr] = val; mmu_pat_ctx_changed(); // adapt to SDR1 changes break; case SPR::RTCL_S: calc_rtcl_value(); - rtc_lo = val & 0x3FFFFF80UL; + ppc_state.spr[RTCL_S] = rtc_lo = val & 0x3FFFFF80UL; + ppc_state.spr[RTCU_S] = rtc_hi; break; case SPR::RTCU_S: calc_rtcl_value(); - rtc_hi = val; + ppc_state.spr[RTCL_S] = rtc_lo; + ppc_state.spr[RTCU_S] = rtc_hi = val; break; - case SPR::DEC: + case SPR::DEC_S: + ppc_state.spr[DEC_S] = val; update_decrementer(val); break; case SPR::TBL_S: update_timebase(0xFFFFFFFF00000000ULL, val); + ppc_state.spr[TBL_S] = val; + ppc_state.spr[TBU_S] = tbr_wr_value >> 32; break; case SPR::TBU_S: update_timebase(0x00000000FFFFFFFFULL, uint64_t(val) << 32); + ppc_state.spr[TBL_S] = (uint32_t)tbr_wr_value; + ppc_state.spr[TBU_S] = val; + break; + case SPR::PVR: break; case 528: case 529: @@ -968,6 +1006,7 @@ void dppc_interpreter::ppc_mtspr() { case 533: case 534: case 535: + ppc_state.spr[ref_spr] = val; ibat_update(ref_spr); break; case 536: @@ -978,7 +1017,11 @@ void dppc_interpreter::ppc_mtspr() { case 541: case 542: case 543: + ppc_state.spr[ref_spr] = val; dbat_update(ref_spr); + default: + // FIXME: Unknown SPR should be noop or illegal instruction. + ppc_state.spr[ref_spr] = val; } } @@ -990,10 +1033,14 @@ void dppc_interpreter::ppc_mftb() { switch (ref_spr) { case SPR::TBL_U: - ppc_state.gpr[reg_d] = uint32_t(tbr_value); + ppc_state.gpr[reg_d] = + ppc_state.spr[TBL_S] = uint32_t(tbr_value); + ppc_state.spr[TBU_S] = uint32_t(tbr_value >> 32); break; case SPR::TBU_U: - ppc_state.gpr[reg_d] = uint32_t(tbr_value >> 32); + ppc_state.gpr[reg_d] = + ppc_state.spr[TBU_S] = uint32_t(tbr_value >> 32); + ppc_state.spr[TBL_S] = uint32_t(tbr_value); break; default: ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);