mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-05-31 23:41:32 +00:00
commit
f27dd94945
49
core/mathutils.h
Normal file
49
core/mathutils.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||
Copyright (C) 2018-22 divingkatae and maximum
|
||||
(theweirdo) spatium
|
||||
|
||||
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MATH_UTILS_H
|
||||
#define MATH_UTILS_H
|
||||
|
||||
inline void _u32xu64(uint32_t a, uint64_t b, uint32_t &hi, uint64_t &lo)
|
||||
{
|
||||
uint64_t p0 = (b & 0xffffffff) * a;
|
||||
uint64_t p1 = (b >> 32) * a;
|
||||
lo = p0 + (p1 << 32);
|
||||
hi = (p1 >> 32) + (lo < p0);
|
||||
}
|
||||
|
||||
inline void _u32xu64(uint32_t a, uint64_t b, uint64_t &hi, uint32_t &lo)
|
||||
{
|
||||
uint64_t p0 = (b & 0xffffffff) * a;
|
||||
uint64_t p1 = (b >> 32) * a;
|
||||
lo = p0;
|
||||
hi = (p0 >> 32) + p1;
|
||||
}
|
||||
|
||||
inline void _u64xu64(uint64_t a, uint64_t b, uint64_t &hi, uint64_t &lo)
|
||||
{
|
||||
uint32_t p0h; uint64_t p0l; _u32xu64(b, a, p0h, p0l);
|
||||
uint64_t p1h; uint32_t p1l; _u32xu64(b >> 32, a, p1h, p1l);
|
||||
lo = p0l + ((uint64_t)p1l << 32);
|
||||
hi = p0h + p1h + (lo < p0l);
|
||||
}
|
||||
|
||||
#endif // MATH_UTILS_H
|
|
@ -159,8 +159,9 @@ 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 tbr_freq_ghz;
|
||||
extern uint32_t rtc_lo, rtc_hi;
|
||||
|
||||
// Additional steps to prevent overflow?
|
||||
|
|
|
@ -66,9 +66,10 @@ 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
|
||||
uint32_t tbr_freq_ghz; // TBR/RTC driving frequency in GHz expressed as a 32 bit fraction less than 1.0.
|
||||
uint64_t timebase_counter; // internal timebase counter
|
||||
uint32_t decr; // current value of PPC DEC register
|
||||
uint32_t rtc_lo; // MPC601 RTC lower, counts nanoseconds
|
||||
|
@ -763,8 +764,9 @@ 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;
|
||||
tbr_freq_ghz = (tb_freq << 32) / NS_PER_SEC;
|
||||
|
||||
exec_flags = 0;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
// General opcodes for the processor - ppcopcodes.cpp
|
||||
|
||||
#include <core/timermanager.h>
|
||||
#include <core/mathutils.h>
|
||||
#include "ppcemu.h"
|
||||
#include "ppcmmu.h"
|
||||
#include <array>
|
||||
|
@ -855,18 +856,18 @@ void dppc_interpreter::ppc_mtmsr() {
|
|||
}
|
||||
}
|
||||
|
||||
static inline uint64_t calc_rtcl_value()
|
||||
static inline void 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);
|
||||
uint64_t new_ts = get_virt_time_ns();
|
||||
uint64_t rtc_l = new_ts - rtc_timestamp + rtc_lo;
|
||||
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;
|
||||
else {
|
||||
rtc_lo = rtc_l;
|
||||
}
|
||||
rtc_timestamp = new_ts;
|
||||
}
|
||||
|
||||
void dppc_interpreter::ppc_mfspr() {
|
||||
|
@ -880,10 +881,12 @@ void dppc_interpreter::ppc_mfspr() {
|
|||
|
||||
switch (ref_spr) {
|
||||
case SPR::RTCL_U:
|
||||
ppc_state.spr[SPR::RTCL_U] = calc_rtcl_value();
|
||||
calc_rtcl_value();
|
||||
ppc_state.spr[SPR::RTCL_U] = rtc_lo & 0x3FFFFF80UL;
|
||||
break;
|
||||
case SPR::RTCU_U:
|
||||
ppc_state.spr[SPR::RTCL_U] = rtc_hi;
|
||||
calc_rtcl_value();
|
||||
ppc_state.spr[SPR::RTCU_U] = rtc_hi;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -893,7 +896,7 @@ void dppc_interpreter::ppc_mfspr() {
|
|||
static inline uint64_t calc_tbr_value()
|
||||
{
|
||||
uint64_t diff = get_virt_time_ns() - tbr_wr_timestamp;
|
||||
uint64_t tbr_inc = diff * tbr_freq_hz / NS_PER_SEC;
|
||||
uint64_t tbr_inc; uint32_t tbr_inc_lo; _u32xu64(tbr_freq_ghz, diff, tbr_inc, tbr_inc_lo);
|
||||
return (tbr_wr_value + tbr_inc);
|
||||
}
|
||||
|
||||
|
@ -926,12 +929,12 @@ void dppc_interpreter::ppc_mtspr() {
|
|||
|
||||
switch (ref_spr) {
|
||||
case SPR::RTCL_S:
|
||||
calc_rtcl_value();
|
||||
rtc_lo = val & 0x3FFFFF80UL;
|
||||
tbr_wr_timestamp = get_virt_time_ns();
|
||||
break;
|
||||
case SPR::RTCU_S:
|
||||
calc_rtcl_value();
|
||||
rtc_hi = val;
|
||||
tbr_wr_timestamp = get_virt_time_ns();
|
||||
break;
|
||||
case SPR::TBL_S:
|
||||
update_timebase(0xFFFFFFFF00000000ULL, val);
|
||||
|
|
Loading…
Reference in New Issue
Block a user