1#include "sc_time_syncronizer.h"
2#include "global_time_keeper.h"
5#include <tlm_utils/tlm_quantumkeeper.h>
12 sc_core::sc_register_stage_callback(*
this, sc_core::SC_POST_END_OF_ELABORATION | sc_core::SC_POST_START_OF_SIMULATION |
13 sc_core::SC_PRE_TIMESTEP);
14 sc_core::sc_spawn_options opt;
16 sc_core::sc_spawn([
this]() { sc_method(); },
nullptr, &opt);
19bool sc_time_syncronizer::process_pending_tasks() {
20 auto res = this->gtk.get_sc_time_ticks();
21 auto& pending_tasks = this->gtk.pending_tasks;
22 if(pending_tasks.size()) {
23 while(pending_tasks.size()) {
24 auto res = pending_tasks.front();
25 auto idx = std::get<0>(*res);
26 auto t = std::get<1>(*res);
27 if(t > sc_core::sc_time_stamp().value()) {
28 auto d = sc_core::sc_time::from_value(t) - sc_core::sc_time_stamp();
29#ifdef DEBUG_MT_SCHEDULING
30 SCCDEBUG(__PRETTY_FUNCTION__) <<
"scheduling task from client " << idx <<
" with t=" << t <<
" with delay " << d;
32 notify_task(idx, std::move(std::get<2>(*res)), d);
34#ifdef DEBUG_MT_SCHEDULING
35 SCCDEBUG(__PRETTY_FUNCTION__) <<
"scheduling task from client " << idx <<
" with t=" << t <<
" now";
37 notify_task(idx, std::move(std::get<2>(*res)), sc_core::SC_ZERO_TIME);
46void sc_time_syncronizer::sc_method() {
47 if(process_pending_tasks()) {
48 sc_core::next_trigger(sc_core::SC_ZERO_TIME);
51 if(state == sync_state::INITIAL)
52 state = sync_state::PROCESSING;
54 auto time_to_next_evt = sc_core::sc_time_to_pending_activity();
56 auto time_to_next_evt = sc_core::sc_time_to_pending_activity(sc_core::sc_get_curr_simcontext());
58 if(sc_core::sc_get_curr_simcontext()->pending_activity_at_current_time()) {
59#ifdef DEBUG_MT_SCHEDULING
60 SCCTRACEALL(__PRETTY_FUNCTION__) <<
"yield to next delta cycle (pending activity time: " << time_to_next_evt <<
")";
62 sc_core::next_trigger(sc_core::SC_ZERO_TIME);
65 if(!sc_is_free_running) {
66 auto min_time = sc_core::sc_time::from_value(gtk.get_client_min_time_ticks());
67 auto abs_time_of_next_evt = sc_core::sc_time_stamp() + time_to_next_evt;
68 if(min_time < abs_time_of_next_evt) {
69 if(min_time > sc_core::sc_time_stamp()) {
70#ifdef DEBUG_MT_SCHEDULING
71 SCCTRACEALL(__PRETTY_FUNCTION__) <<
"advancing SC time lockstepped to " << min_time;
73 sc_core::next_trigger(min_time - sc_core::sc_time_stamp());
77 std::this_thread::yield();
79 sc_core::next_trigger(sc_core::SC_ZERO_TIME);
82#ifdef DEBUG_MT_SCHEDULING
83 SCCTRACEALL(__PRETTY_FUNCTION__) <<
"advancing SC time lockstepped to " << abs_time_of_next_evt;
85 sc_core::next_trigger(time_to_next_evt);
88 if(state == sync_state::PROCESSING) {
89 state = sync_state::ARMED;
90 sc_core::next_trigger(sc_core::SC_ZERO_TIME);
95 auto next_time_point = sc_core::sc_time_stamp() + time_to_next_evt;
96 if(next_time_point.value() == std::numeric_limits<uint64_t>::max()) {
97 time_to_next_evt = tlm_utils::tlm_quantumkeeper::get_global_quantum();
98 if(time_to_next_evt == sc_core::SC_ZERO_TIME)
99 time_to_next_evt = 1_us;
101#ifdef DEBUG_MT_SCHEDULING
102 SCCTRACEALL(__PRETTY_FUNCTION__) <<
"advancing SC time free running to " << next_time_point;
104 sc_core::next_trigger(time_to_next_evt);
107void sc_time_syncronizer::stage_callback(
const sc_core::sc_stage& stage) {
109 case sc_core::SC_PRE_TIMESTEP: {
110 sc_core::sc_time next_time;
111 if(sc_core::sc_get_curr_simcontext()->next_time(next_time)) {
112 gtk.update_sc_time_ticks(next_time.value());
113 while(gtk.get_sc_time_ticks() != next_time.value())
114 std::this_thread::yield();
116 state = sync_state::INITIAL;
117#ifdef DEBUG_MT_SCHEDULING
118 SCCTRACEALL(__PRETTY_FUNCTION__) <<
"advancing SystemC kernel time to " << next_time <<
", get_min_time()=" << get_min_time()
119 <<
", sc_is_free_running=" << sc_is_free_running;
122 case sc_core::SC_POST_END_OF_ELABORATION:
125 case sc_core::SC_POST_START_OF_SIMULATION:
126 gtk.update_sc_time_ticks(sc_core::sc_time_stamp().value());
the global time keeper, a singleton