@@ -31,6 +31,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
3131#include < cinttypes>
3232#include < vector>
3333
34+ static int junction_temperature = 24 ;
35+ static TimerInfo thermal_timer;
36+
3437// Extract the registers desired and the values of the registers.
3538
3639// Affects CR Field 0 - For integer operations
@@ -820,6 +823,9 @@ void dppc_interpreter::ppc_mtmsr(uint32_t opcode) {
820823 dec_exception_pending = false ;
821824 // LOG_F(WARNING, "MTMSR: decrementer exception triggered");
822825 ppc_exception_handler (Except_Type::EXC_DECR , 0 );
826+ } else if ((ppc_state.msr & MSR ::EE ) && thrm_exception_pending) {
827+ thrm_exception_pending = false ;
828+ ppc_exception_handler (Except_Type::EXC_THRM_MGMT_INT , 0 );
823829 } else if (ppc_state.msr & MSR ::POW ) [[unlikely]] {
824830 bool enter_sleep = false ;
825831
@@ -980,6 +986,48 @@ static void update_decrementer(bool update_time_stamp, uint32_t oldval, uint32_t
980986 );
981987}
982988
989+ static void update_thermal (uint64_t , uint64_t ) {
990+ thermal_timer.active = 0 ;
991+
992+ uint32_t val = ppc_state.spr [SPR ::THRM3 ];
993+ auto sampled_interval_timer_value = (val >> 1 ) & 0x1FFF ;
994+ auto enabled = val & 1 ;
995+
996+ bool interrupt = false ;
997+ for (int the_reg = 0 ; the_reg < 2 ; the_reg++) {
998+ val = ppc_state.spr [SPR ::THRM1 + the_reg];
999+ uint32_t t_interrupt; // = (val >> 31) & 1;
1000+ uint32_t t_int_valid; // = (val >> 30) & 1;
1001+ uint32_t threshold = (val >> 23 ) & 0x7F ;
1002+ uint32_t t_int_direction = (val >> 2 ) & 1 ;
1003+ uint32_t t_int_enable = (val >> 1 ) & 1 ;
1004+ uint32_t valid = (val >> 0 ) & 1 ;
1005+
1006+ if (!valid) {
1007+ t_interrupt = 0 ;
1008+ t_int_valid = 0 ;
1009+ } else {
1010+ t_interrupt = t_int_direction ?
1011+ junction_temperature < threshold
1012+ :
1013+ junction_temperature > threshold;
1014+ t_int_valid = 1 ;
1015+ interrupt |= t_int_enable && t_interrupt;
1016+ }
1017+ ppc_state.spr [SPR ::THRM1 + the_reg] = (t_interrupt << 31 ) | (t_int_valid << 30 ) | (val & 0x3FFFFFFF );
1018+ }
1019+
1020+ if (interrupt && enabled) {
1021+ if (ppc_state.msr & MSR ::EE ) {
1022+ thrm_exception_pending = false ;
1023+ ppc_exception_handler (Except_Type::EXC_THRM_MGMT_INT , 0 );
1024+ }
1025+ else {
1026+ thrm_exception_pending = true ;
1027+ }
1028+ }
1029+ }
1030+
9831031void dppc_interpreter::ppc_mfspr (uint32_t opcode) {
9841032 ppc_grab_dab (opcode);
9851033 uint32_t ref_spr = (reg_b << 5 ) | reg_a;
@@ -1052,6 +1100,15 @@ void dppc_interpreter::ppc_mfspr(uint32_t opcode) {
10521100 ppc_state.spr [TBL_S ] = uint32_t (tbr_value);
10531101 break ;
10541102 }
1103+ case SPR ::THRM1 :
1104+ case SPR ::THRM2 : {
1105+ uint32_t val = ppc_state.spr [ref_spr];
1106+ ppc_state.gpr [reg_d] = val;
1107+ break ;
1108+ }
1109+ case SPR ::THRM3 :
1110+ ppc_state.gpr [reg_d] = ppc_state.spr [ref_spr];
1111+ break ;
10551112 default :
10561113 // FIXME: Unknown SPR should be noop or illegal instruction.
10571114 ppc_state.gpr [reg_d] = ppc_state.spr [ref_spr];
@@ -1157,6 +1214,25 @@ void dppc_interpreter::ppc_mtspr(uint32_t opcode) {
11571214 ppc_change_endian ((val & 0x10000000 ) != 0 );
11581215 }
11591216 break ;
1217+ case SPR ::THRM1 :
1218+ case SPR ::THRM2 : {
1219+ ppc_state.spr [ref_spr] = val & 0x3F800007 ;
1220+
1221+ if (thermal_timer.active )
1222+ TimerManager::get_instance ()->cancel_timer (thermal_timer);
1223+ TimerManager::get_instance ()->add_oneshot_timer (thermal_timer, USECS_TO_NSECS (20 ), update_thermal);
1224+ break ;
1225+ }
1226+ case SPR ::THRM3 : {
1227+ ppc_state.spr [ref_spr] = val & 0x00003FFF ;
1228+ ppc_state.spr [SPR ::THRM1 ] &= ~(3 <<30 );
1229+ ppc_state.spr [SPR ::THRM2 ] &= ~(3 <<30 );
1230+
1231+ if (thermal_timer.active )
1232+ TimerManager::get_instance ()->cancel_timer (thermal_timer);
1233+ TimerManager::get_instance ()->add_oneshot_timer (thermal_timer, USECS_TO_NSECS (20 ), update_thermal);
1234+ break ;
1235+ }
11601236 default :
11611237 // FIXME: Unknown SPR should be noop or illegal instruction.
11621238 ppc_state.spr [ref_spr] = val;
@@ -1518,14 +1594,18 @@ void dppc_interpreter::ppc_rfi(uint32_t opcode) {
15181594 ppc_msr_did_change (ppc_state.msr , new_msr_val);
15191595
15201596 // setting MSR[EE] may enable pending exceptions
1521- if ((ppc_state.msr & MSR ::EE ) && (int_pin || dec_exception_pending)) {
1597+ if ((ppc_state.msr & MSR ::EE ) && (int_pin || dec_exception_pending || thrm_exception_pending )) {
15221598 uint32_t save_srr0 = ppc_state.spr [SPR ::SRR0 ] & ~3UL ;
15231599 if (int_pin) // check for pending external exceptions (higher priority)
15241600 ppc_exception_handler (Except_Type::EXC_EXT_INT , 0 );
1525- else {
1601+ else if (dec_exception_pending) {
15261602 dec_exception_pending = false ;
15271603 ppc_exception_handler (Except_Type::EXC_DECR , 0 );
15281604 }
1605+ else if (thrm_exception_pending) {
1606+ thrm_exception_pending = false ;
1607+ ppc_exception_handler (Except_Type::EXC_THRM_MGMT_INT , 0 );
1608+ }
15291609 ppc_state.spr [SPR ::SRR0 ] = save_srr0;
15301610 return ;
15311611 }
0 commit comments