From dd1fc711c727bf34ecf1caa4ba4c8f14fafdff1e Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Thu, 18 Jun 2020 07:37:44 +0200 Subject: [PATCH] PowerPC: partially implement thermal related SPRs Doesn't support triggering interrupts when the thermal threshold is exceeded, but allows polling for temperature information. The THRM[123] registers are documented in most PPC datasheets, see e.g. this PPC750CX one: http://datasheets.chipdb.org/IBM/PowerPC/750/750cx_um3-17-05.pdf --- Source/Core/Core/PowerPC/Gekko.h | 36 +++++++++++++++++++ .../Interpreter_SystemRegisters.cpp | 31 ++++++++++++++++ Source/Core/Core/PowerPC/PowerPC.h | 3 ++ 3 files changed, 70 insertions(+) diff --git a/Source/Core/Core/PowerPC/Gekko.h b/Source/Core/Core/PowerPC/Gekko.h index b11a7565f0..590bd5c3ea 100644 --- a/Source/Core/Core/PowerPC/Gekko.h +++ b/Source/Core/Core/PowerPC/Gekko.h @@ -744,6 +744,38 @@ union UReg_BAT_Lo explicit UReg_BAT_Lo(u32 hex_) : Hex{hex_} {} }; +union UReg_THRM12 +{ + struct + { + u32 V : 1; // Valid + u32 TIE : 1; // Thermal Interrupt Enable + u32 TID : 1; // Thermal Interrupt Direction + u32 : 20; + u32 THRESHOLD : 7; // Temperature Threshold, 0-127°C + u32 TIV : 1; // Thermal Interrupt Valid + u32 TIN : 1; // Thermal Interrupt + }; + u32 Hex = 0; + + UReg_THRM12() = default; + explicit UReg_THRM12(u32 hex_) : Hex{hex_} {} +}; + +union UReg_THRM3 +{ + struct + { + u32 E : 1; // Enable + u32 SITV : 13; // Sample Interval Timer Value + u32 : 18; + }; + u32 Hex = 0; + + UReg_THRM3() = default; + explicit UReg_THRM3(u32 hex_) : Hex{hex_} {} +}; + union UReg_PTE { struct @@ -854,6 +886,10 @@ enum SPR_MMCR1 = 956, SPR_PMC3 = 957, SPR_PMC4 = 958, + + SPR_THRM1 = 1020, + SPR_THRM2 = 1021, + SPR_THRM3 = 1022, }; // Exceptions diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp index d40462c7b5..7a5c0455b5 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp @@ -459,6 +459,37 @@ void Interpreter::mtspr(UGeckoInstruction inst) PowerPC::IBATUpdated(); } break; + + case SPR_THRM1: + case SPR_THRM2: + case SPR_THRM3: + { + // We update both THRM1 and THRM2 when either of the 3 thermal control + // registers are updated. THRM1 and THRM2 are independent, but THRM3 has + // settings that impact both. + // + // TODO: Support thermal interrupts when enabled. + constexpr u32 SIMULATED_TEMP = 42; // °C + + auto UpdateThermalReg = [](UReg_THRM12* reg) { + if (!THRM3.E || !reg->V) + { + reg->TIV = 0; + } + else + { + reg->TIV = 1; + if (reg->TID) + reg->TIN = SIMULATED_TEMP < reg->THRESHOLD; + else + reg->TIN = SIMULATED_TEMP > reg->THRESHOLD; + } + }; + + UpdateThermalReg(&THRM1); + UpdateThermalReg(&THRM2); + break; + } } } diff --git a/Source/Core/Core/PowerPC/PowerPC.h b/Source/Core/Core/PowerPC/PowerPC.h index fe1e11ef03..9d551de056 100644 --- a/Source/Core/Core/PowerPC/PowerPC.h +++ b/Source/Core/Core/PowerPC/PowerPC.h @@ -220,6 +220,9 @@ void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst); #define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL]) #define MMCR0 ((UReg_MMCR0&)PowerPC::ppcState.spr[SPR_MMCR0]) #define MMCR1 ((UReg_MMCR1&)PowerPC::ppcState.spr[SPR_MMCR1]) +#define THRM1 ((UReg_THRM12&)PowerPC::ppcState.spr[SPR_THRM1]) +#define THRM2 ((UReg_THRM12&)PowerPC::ppcState.spr[SPR_THRM2]) +#define THRM3 ((UReg_THRM3&)PowerPC::ppcState.spr[SPR_THRM3]) #define PC PowerPC::ppcState.pc #define NPC PowerPC::ppcState.npc #define FPSCR PowerPC::ppcState.fpscr