mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-10 13:29:38 +00:00
Add timers management.
This commit is contained in:
parent
8efc61e1b9
commit
339db4a078
@ -56,6 +56,7 @@ if (DPPC_68K_DEBUGGER)
|
|||||||
add_subdirectory(thirdparty/capstone EXCLUDE_FROM_ALL)
|
add_subdirectory(thirdparty/capstone EXCLUDE_FROM_ALL)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory("${PROJECT_SOURCE_DIR}/core")
|
||||||
add_subdirectory("${PROJECT_SOURCE_DIR}/cpu/ppc/")
|
add_subdirectory("${PROJECT_SOURCE_DIR}/cpu/ppc/")
|
||||||
add_subdirectory("${PROJECT_SOURCE_DIR}/debugger/")
|
add_subdirectory("${PROJECT_SOURCE_DIR}/debugger/")
|
||||||
add_subdirectory("${PROJECT_SOURCE_DIR}/devices/")
|
add_subdirectory("${PROJECT_SOURCE_DIR}/devices/")
|
||||||
@ -80,6 +81,7 @@ add_subdirectory(thirdparty/cubeb EXCLUDE_FROM_ALL)
|
|||||||
set(CLI11_ROOT ${PROJECT_SOURCE_DIR}/thirdparty/CLI11)
|
set(CLI11_ROOT ${PROJECT_SOURCE_DIR}/thirdparty/CLI11)
|
||||||
|
|
||||||
include_directories("${PROJECT_SOURCE_DIR}"
|
include_directories("${PROJECT_SOURCE_DIR}"
|
||||||
|
"${PROJECT_SOURCE_DIR}/core"
|
||||||
"${PROJECT_SOURCE_DIR}/devices"
|
"${PROJECT_SOURCE_DIR}/devices"
|
||||||
"${PROJECT_SOURCE_DIR}/cpu/ppc"
|
"${PROJECT_SOURCE_DIR}/cpu/ppc"
|
||||||
"${PROJECT_SOURCE_DIR}/debugger"
|
"${PROJECT_SOURCE_DIR}/debugger"
|
||||||
@ -100,8 +102,9 @@ file(GLOB SOURCES "${PROJECT_SOURCE_DIR}/*.cpp"
|
|||||||
|
|
||||||
file(GLOB TEST_SOURCES "${PROJECT_SOURCE_DIR}/cpu/ppc/test/*.cpp")
|
file(GLOB TEST_SOURCES "${PROJECT_SOURCE_DIR}/cpu/ppc/test/*.cpp")
|
||||||
|
|
||||||
add_executable(dingusppc ${SOURCES} $<TARGET_OBJECTS:debugger>
|
add_executable(dingusppc ${SOURCES} $<TARGET_OBJECTS:core>
|
||||||
$<TARGET_OBJECTS:cpu_ppc>
|
$<TARGET_OBJECTS:cpu_ppc>
|
||||||
|
$<TARGET_OBJECTS:debugger>
|
||||||
$<TARGET_OBJECTS:devices>
|
$<TARGET_OBJECTS:devices>
|
||||||
$<TARGET_OBJECTS:execution>
|
$<TARGET_OBJECTS:execution>
|
||||||
$<TARGET_OBJECTS:machines>
|
$<TARGET_OBJECTS:machines>
|
||||||
|
8
core/CMakeLists.txt
Normal file
8
core/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
include_directories("${PROJECT_SOURCE_DIR}"
|
||||||
|
"${PROJECT_SOURCE_DIR}/thirdparty/loguru/"
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
|
||||||
|
|
||||||
|
add_library(core OBJECT ${SOURCES})
|
||||||
|
target_link_libraries(core)
|
127
core/timermanager.cpp
Normal file
127
core/timermanager.cpp
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Timer management system. */
|
||||||
|
|
||||||
|
#include <loguru.hpp>
|
||||||
|
#include "timermanager.h"
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
TimerManager* TimerManager::timer_manager;
|
||||||
|
|
||||||
|
uint32_t TimerManager::add_oneshot_timer(uint64_t timeout, timer_cb cb)
|
||||||
|
{
|
||||||
|
if (!timeout || timeout <= MIN_TIMEOUT_NS) {
|
||||||
|
LOG_F(WARNING, "One-shot timer too short, timeout=%llu ns", timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
TimerInfo* ti = new TimerInfo;
|
||||||
|
|
||||||
|
ti->id = ++this->id;
|
||||||
|
ti->timeout_ns = this->get_time_now() + timeout;
|
||||||
|
ti->interval_ns = 0;
|
||||||
|
ti->cb = cb;
|
||||||
|
|
||||||
|
std::shared_ptr<TimerInfo> timer_desc(ti);
|
||||||
|
|
||||||
|
// add new timer to the timer queue
|
||||||
|
this->timer_queue.push(timer_desc);
|
||||||
|
|
||||||
|
// notify listeners about changes in the timer queue
|
||||||
|
this->notify_timer_changes();
|
||||||
|
|
||||||
|
return ti->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t TimerManager::add_cyclic_timer(uint64_t interval, timer_cb cb)
|
||||||
|
{
|
||||||
|
if (!interval || interval <= MIN_TIMEOUT_NS) {
|
||||||
|
LOG_F(WARNING, "Cyclic timer interval too short, timeout=%llu ns", interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
TimerInfo* ti = new TimerInfo;
|
||||||
|
|
||||||
|
ti->id = ++this->id;
|
||||||
|
ti->timeout_ns = this->get_time_now() + interval;
|
||||||
|
ti->interval_ns = interval;
|
||||||
|
ti->cb = cb;
|
||||||
|
|
||||||
|
std::shared_ptr<TimerInfo> timer_desc(ti);
|
||||||
|
|
||||||
|
// add new timer to the timer queue
|
||||||
|
this->timer_queue.push(timer_desc);
|
||||||
|
|
||||||
|
// notify listeners about changes in the timer queue
|
||||||
|
this->notify_timer_changes();
|
||||||
|
|
||||||
|
return ti->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimerManager::cancel_timer(uint32_t id)
|
||||||
|
{
|
||||||
|
TimerInfo* cur_timer = this->timer_queue.top().get();
|
||||||
|
if (cur_timer->id == id) {
|
||||||
|
this->timer_queue.pop();
|
||||||
|
} else {
|
||||||
|
this->timer_queue.remove_by_id(id);
|
||||||
|
}
|
||||||
|
this->notify_timer_changes();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t TimerManager::process_timers(uint64_t time_now)
|
||||||
|
{
|
||||||
|
TimerInfo* cur_timer;
|
||||||
|
|
||||||
|
if (this->timer_queue.empty()) {
|
||||||
|
return 0ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// scan for expired timers
|
||||||
|
cur_timer = this->timer_queue.top().get();
|
||||||
|
while (cur_timer->timeout_ns <= time_now ||
|
||||||
|
cur_timer->timeout_ns <= (time_now + MIN_TIMEOUT_NS)) {
|
||||||
|
// invoke timer callback
|
||||||
|
cur_timer->cb();
|
||||||
|
|
||||||
|
// re-arm cyclic timers
|
||||||
|
if (cur_timer->interval_ns) {
|
||||||
|
auto new_timer = this->timer_queue.top();
|
||||||
|
new_timer->timeout_ns = time_now + cur_timer->interval_ns;
|
||||||
|
this->timer_queue.pop();
|
||||||
|
this->timer_queue.push(new_timer);
|
||||||
|
} else {
|
||||||
|
// remove one-shot timers from queue
|
||||||
|
this->timer_queue.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// process next timer
|
||||||
|
if (this->timer_queue.empty()) {
|
||||||
|
return 0ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_timer = this->timer_queue.top().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return time slice in nanoseconds until next timer's expiry
|
||||||
|
return cur_timer->timeout_ns - time_now;
|
||||||
|
}
|
115
core/timermanager.h
Normal file
115
core/timermanager.h
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
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 TIMER_MANAGER_H
|
||||||
|
#define TIMER_MANAGER_H
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <queue>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define MIN_TIMEOUT_NS 200
|
||||||
|
|
||||||
|
#define NS_PER_SEC 1E9
|
||||||
|
|
||||||
|
#define USECS_TO_NSECS(us) (us) * 1000
|
||||||
|
|
||||||
|
typedef function<void()> timer_cb;
|
||||||
|
|
||||||
|
/** Extend std::priority_queue as suggested here:
|
||||||
|
https://stackoverflow.com/a/36711682
|
||||||
|
to be able to remove arbitrary elements.
|
||||||
|
*/
|
||||||
|
template <typename T, class Container = std::vector<T>, class Compare = std::less<typename Container::value_type>>
|
||||||
|
class my_priority_queue : public std::priority_queue<T, Container, Compare> {
|
||||||
|
public:
|
||||||
|
bool remove_by_id(const uint32_t id){
|
||||||
|
auto it = std::find_if(
|
||||||
|
this->c.begin(), this->c.end(), [id](const T& el) { return el->id == id; });
|
||||||
|
if (it != this->c.end()) {
|
||||||
|
this->c.erase(it);
|
||||||
|
std::make_heap(this->c.begin(), this->c.end(), this->comp);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct TimerInfo {
|
||||||
|
uint32_t id;
|
||||||
|
uint64_t timeout_ns; // timer expiry
|
||||||
|
uint64_t interval_ns; // 0 for one-shot timers
|
||||||
|
timer_cb cb; // timer callback
|
||||||
|
} TimerInfo;
|
||||||
|
|
||||||
|
// Custom comparator for sorting our timer queue in ascending order
|
||||||
|
class MyGtComparator {
|
||||||
|
public:
|
||||||
|
bool operator()(const shared_ptr<TimerInfo>& l, const shared_ptr<TimerInfo>& r) {
|
||||||
|
return l.get()->timeout_ns > r.get()->timeout_ns;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TimerManager {
|
||||||
|
public:
|
||||||
|
static TimerManager* get_instance() {
|
||||||
|
if (!timer_manager) {
|
||||||
|
timer_manager = new TimerManager();
|
||||||
|
}
|
||||||
|
return timer_manager;
|
||||||
|
};
|
||||||
|
|
||||||
|
// callback ´for retrieving current time
|
||||||
|
void set_time_now_cb(const function<uint64_t()> &cb) {
|
||||||
|
this->get_time_now = cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
// callback for acknowledging time changes
|
||||||
|
void set_notify_changes_cb(const timer_cb &cb) {
|
||||||
|
this->notify_timer_changes = cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
// creating and cancelling timers
|
||||||
|
uint32_t add_oneshot_timer(uint64_t timeout, timer_cb cb);
|
||||||
|
uint32_t add_cyclic_timer(uint64_t interval, timer_cb cb);
|
||||||
|
void cancel_timer(uint32_t id);
|
||||||
|
|
||||||
|
uint64_t process_timers(uint64_t time_now);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static TimerManager* timer_manager;
|
||||||
|
TimerManager(){}; // private constructor to implement a singleton
|
||||||
|
|
||||||
|
uint32_t id = 0;
|
||||||
|
|
||||||
|
// timer queue
|
||||||
|
my_priority_queue<shared_ptr<TimerInfo>, vector<shared_ptr<TimerInfo>>, MyGtComparator> timer_queue;
|
||||||
|
|
||||||
|
function<uint64_t()> get_time_now;
|
||||||
|
function<void()> notify_timer_changes;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TIMER_MANAGER_H
|
@ -202,7 +202,8 @@ enum class BB_end_kind {
|
|||||||
BB_NONE = 0, /* no basic block end is reached */
|
BB_NONE = 0, /* no basic block end is reached */
|
||||||
BB_BRANCH = 1, /* a branch instruction is encountered */
|
BB_BRANCH = 1, /* a branch instruction is encountered */
|
||||||
BB_EXCEPTION, /* an exception is occured */
|
BB_EXCEPTION, /* an exception is occured */
|
||||||
BB_RFI /* the rfi instruction is encountered */
|
BB_RFI, /* the rfi instruction is encountered */
|
||||||
|
BB_TIMER, /* timer queue changed */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CR_select : int32_t {
|
enum CR_select : int32_t {
|
||||||
@ -297,7 +298,6 @@ extern BB_end_kind bb_kind;
|
|||||||
|
|
||||||
extern jmp_buf exc_env;
|
extern jmp_buf exc_env;
|
||||||
|
|
||||||
extern bool grab_exception;
|
|
||||||
extern bool grab_return;
|
extern bool grab_return;
|
||||||
|
|
||||||
extern bool power_on;
|
extern bool power_on;
|
||||||
|
@ -19,19 +19,21 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <core/timermanager.h>
|
||||||
|
#include <loguru.hpp>
|
||||||
|
#include "ppcemu.h"
|
||||||
|
#include "ppcmmu.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <loguru.hpp>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "ppcemu.h"
|
|
||||||
#include "ppcmmu.h"
|
|
||||||
|
|
||||||
#define NEW_TBR_UPDATE_ALGO
|
#define NEW_TBR_UPDATE_ALGO
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -46,7 +48,6 @@ SetPRS ppc_state;
|
|||||||
bool rc_flag = 0; // Record flag
|
bool rc_flag = 0; // Record flag
|
||||||
bool oe_flag = 0; // Overflow flag
|
bool oe_flag = 0; // Overflow flag
|
||||||
|
|
||||||
bool grab_exception;
|
|
||||||
bool grab_return;
|
bool grab_return;
|
||||||
bool grab_breakpoint;
|
bool grab_breakpoint;
|
||||||
|
|
||||||
@ -298,12 +299,22 @@ uint64_t get_virt_time_ns()
|
|||||||
return g_icycles << icnt_factor;
|
return g_icycles << icnt_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_events()
|
uint64_t process_events()
|
||||||
{
|
{
|
||||||
// dummy implementation that schedules execution
|
uint64_t slice_ns = TimerManager::get_instance()->process_timers(get_virt_time_ns());
|
||||||
// of another 10.000 instructions
|
if (slice_ns == 0) {
|
||||||
|
// execute 10.000 cycles
|
||||||
|
// if there are no pending timers
|
||||||
return g_icycles + 10000;
|
return g_icycles + 10000;
|
||||||
}
|
}
|
||||||
|
return g_icycles + ((slice_ns + (1 << icnt_factor)) >> icnt_factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void force_cycle_counter_reload()
|
||||||
|
{
|
||||||
|
// tell the interpreter loop to reload cycle counter
|
||||||
|
bb_kind = BB_end_kind::BB_TIMER;
|
||||||
|
}
|
||||||
|
|
||||||
/** Execute PPC code as long as power is on. */
|
/** Execute PPC code as long as power is on. */
|
||||||
#if 0
|
#if 0
|
||||||
@ -399,8 +410,15 @@ static void ppc_exec_inner()
|
|||||||
if (bb_kind != BB_end_kind::BB_NONE) { // execution block ended ?
|
if (bb_kind != BB_end_kind::BB_NONE) { // execution block ended ?
|
||||||
if (!power_on)
|
if (!power_on)
|
||||||
break;
|
break;
|
||||||
// check the reason for the block end
|
// reload cycle counter if requested
|
||||||
//eb_last = false;
|
if (bb_kind == BB_end_kind::BB_TIMER) {
|
||||||
|
max_cycles = process_events();
|
||||||
|
ppc_state.pc += 4;
|
||||||
|
pc_real += 4;
|
||||||
|
ppc_set_cur_instruction(pc_real);
|
||||||
|
bb_kind = BB_end_kind::BB_NONE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// define next execution block
|
// define next execution block
|
||||||
eb_start = ppc_next_instruction_address;
|
eb_start = ppc_next_instruction_address;
|
||||||
eb_end = (eb_start + PAGE_SIZE) & PAGE_MASK;
|
eb_end = (eb_start + PAGE_SIZE) & PAGE_MASK;
|
||||||
@ -486,7 +504,11 @@ void ppc_exec_single()
|
|||||||
mmu_translate_imem(ppc_state.pc);
|
mmu_translate_imem(ppc_state.pc);
|
||||||
ppc_main_opcode();
|
ppc_main_opcode();
|
||||||
if (bb_kind != BB_end_kind::BB_NONE) {
|
if (bb_kind != BB_end_kind::BB_NONE) {
|
||||||
|
if (bb_kind == BB_end_kind::BB_TIMER) {
|
||||||
|
ppc_state.pc += 4;
|
||||||
|
} else {
|
||||||
ppc_state.pc = ppc_next_instruction_address;
|
ppc_state.pc = ppc_next_instruction_address;
|
||||||
|
}
|
||||||
bb_kind = BB_end_kind::BB_NONE;
|
bb_kind = BB_end_kind::BB_NONE;
|
||||||
} else {
|
} else {
|
||||||
ppc_state.pc += 4;
|
ppc_state.pc += 4;
|
||||||
@ -585,8 +607,15 @@ static void ppc_exec_until_inner(const uint32_t goal_addr)
|
|||||||
|
|
||||||
//if (eb_last) {
|
//if (eb_last) {
|
||||||
if (bb_kind != BB_end_kind::BB_NONE) { // execution block ended ?
|
if (bb_kind != BB_end_kind::BB_NONE) { // execution block ended ?
|
||||||
// check the reason for the block end
|
// reload cycle counter if requested
|
||||||
//eb_last = false;
|
if (bb_kind == BB_end_kind::BB_TIMER) {
|
||||||
|
max_cycles = process_events();
|
||||||
|
ppc_state.pc += 4;
|
||||||
|
pc_real += 4;
|
||||||
|
ppc_set_cur_instruction(pc_real);
|
||||||
|
bb_kind = BB_end_kind::BB_NONE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// define next execution block
|
// define next execution block
|
||||||
eb_start = ppc_next_instruction_address;
|
eb_start = ppc_next_instruction_address;
|
||||||
eb_end = (eb_start + PAGE_SIZE) & PAGE_MASK;
|
eb_end = (eb_start + PAGE_SIZE) & PAGE_MASK;
|
||||||
@ -719,8 +748,15 @@ static void ppc_exec_dbg_inner(const uint32_t start_addr, const uint32_t size)
|
|||||||
|
|
||||||
//if (eb_last) {
|
//if (eb_last) {
|
||||||
if (bb_kind != BB_end_kind::BB_NONE) { // execution block ended ?
|
if (bb_kind != BB_end_kind::BB_NONE) { // execution block ended ?
|
||||||
// check the reason for the block end
|
// reload cycle counter if requested
|
||||||
//eb_last = false;
|
if (bb_kind == BB_end_kind::BB_TIMER) {
|
||||||
|
max_cycles = process_events();
|
||||||
|
ppc_state.pc += 4;
|
||||||
|
pc_real += 4;
|
||||||
|
ppc_set_cur_instruction(pc_real);
|
||||||
|
bb_kind = BB_end_kind::BB_NONE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// define next execution block
|
// define next execution block
|
||||||
eb_start = ppc_next_instruction_address;
|
eb_start = ppc_next_instruction_address;
|
||||||
eb_end = (eb_start + PAGE_SIZE) & PAGE_MASK;
|
eb_end = (eb_start + PAGE_SIZE) & PAGE_MASK;
|
||||||
@ -1016,6 +1052,10 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version) {
|
|||||||
tbr_factor = 4;
|
tbr_factor = 4;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// initialize emulator timers
|
||||||
|
TimerManager::get_instance()->set_time_now_cb(&get_virt_time_ns);
|
||||||
|
TimerManager::get_instance()->set_notify_changes_cb(&force_cycle_counter_reload);
|
||||||
|
|
||||||
// initialize time base facility
|
// initialize time base facility
|
||||||
g_icycles = 0;
|
g_icycles = 0;
|
||||||
icnt_factor = 4;
|
icnt_factor = 4;
|
||||||
|
@ -21,6 +21,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
// General opcodes for the processor - ppcopcodes.cpp
|
// General opcodes for the processor - ppcopcodes.cpp
|
||||||
|
|
||||||
|
#include <core/timermanager.h>
|
||||||
#include "ppcemu.h"
|
#include "ppcemu.h"
|
||||||
#include "ppcmmu.h"
|
#include "ppcmmu.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
@ -858,8 +859,6 @@ void dppc_interpreter::ppc_mfspr() {
|
|||||||
ppc_state.gpr[reg_d] = ppc_state.spr[ref_spr];
|
ppc_state.gpr[reg_d] = ppc_state.spr[ref_spr];
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NS_PER_SEC 1E9
|
|
||||||
|
|
||||||
static inline uint64_t calc_tbr_value()
|
static inline uint64_t calc_tbr_value()
|
||||||
{
|
{
|
||||||
uint64_t diff = get_virt_time_ns() - tbr_wr_timestamp;
|
uint64_t diff = get_virt_time_ns() - tbr_wr_timestamp;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user