Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 20 additions & 28 deletions src/components/scc/tcp4tlm_bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "tcp4tlm_bridge.h"
#include "scc/report.h"
#include "scc/tcp4tlm/messages.h"
#include "scc/wall_time_speed_limiter.h"
#include "tlm/scc/tlm_extensions.h"
#include "tlm/scc/tlm_gp_shared.h"
#include <algorithm>
Expand Down Expand Up @@ -98,6 +99,10 @@ tcp4tlm_bridge::~tcp4tlm_bridge() {
}
}

void tcp4tlm_bridge::before_end_of_elaboration() {
if(wall_time_simulation_speed.get_value())
scc::wall_time_speed_limiter::get(); // initialize module
}
void tcp4tlm_bridge::end_of_elaboration() {
client::host = other_host_name.get_value();
client::port = other_host_port.get_value();
Expand Down Expand Up @@ -270,28 +275,13 @@ void tcp4tlm_bridge::timing_thread() {
const auto usecs_to_sleep = 1000LL;
#if defined __x86_64__
if(!is_connection_server.get_value()) {
while(true) {
wait(1_ms);
auto smsg = tcp4tlm::make_sync_msg(sc_core::sc_time_stamp().value());
client_connection().write_data(smsg);
}
} else if(wall_time_simulation_speed.get_value()) {
SCCDEBUG(SCMOD) << "Running in wall time mode";
auto duration = usecs_to_sleep;
auto checkpoint_us = get_time_of_day_us();
while(true) {
wait(usecs_to_sleep, sc_core::SC_US);
auto act_us = get_time_of_day_us();
auto consumed = act_us - checkpoint_us;
if(consumed > 0 && duration > consumed) {
struct timespec tv;
tv.tv_sec = static_cast<time_t>(duration - consumed) / 1000000;
tv.tv_nsec = static_cast<decltype(tv.tv_nsec)>((duration - consumed) * 1000);
nanosleep(&tv, &tv);
if(!no_systemc_sync.get_value())
while(true) {
wait(1_ms);
auto smsg = tcp4tlm::make_sync_msg(sc_core::sc_time_stamp().value());
client_connection().write_data(smsg);
}
checkpoint_us = get_time_of_day_us();
}
} else {
} else if(!wall_time_simulation_speed.get_value()) {
SCCDEBUG(SCMOD) << "Running in simulated time mode";
while(true) {
while(next_time_stamp.empty()) {
Expand Down Expand Up @@ -395,18 +385,20 @@ void tcp4tlm_bridge::server_receive_completed(con_ptr& con, const tcp4tlm::reque
std::future<bool> fut = task.get_future();
timed_task tup{std::move(task), time_point};
task_que.emplace(std::move(tup));
next_time_stamp.push(time_point);
if(wall_time_simulation_speed.get_value())
next_time_stamp.push(time_point);
fut.wait();
fut.get();
} break;
case tcp4tlm::RequestPayload_SyncMsg: {
SCCTRACE(SCMOD) << "Got SyncMsg";
if(is_connection_server.get_value()) {
const auto* msg = request->payload_as_SyncMsg();
auto time_point = sc_core::sc_time::from_value(msg->time_stamp());
next_time_stamp.push(time_point);
if(wall_time_simulation_speed.get_value()) {
const auto* msg = request->payload_as_SyncMsg();
auto time_point = sc_core::sc_time::from_value(msg->time_stamp());
next_time_stamp.push(time_point);
}
}
// con->async_write(okmsg);
} break;
case tcp4tlm::RequestPayload_SigOpMsg: {
SCCTRACE(SCMOD) << "Got SigOpMsg";
Expand Down Expand Up @@ -458,8 +450,8 @@ void tcp4tlm_bridge::process_task_que() {
timed_task res;
while(true) {
while(task_que.try_get(res)) {
SCCTRACEALL(SCMOD) << "Got a task @" << res.timepoint;
if(no_systemc_sync.get_value() || sc_core::sc_time_stamp() > res.timepoint) {
SCCTRACEALL(SCMOD) << "Got a task for time " << res.timepoint;
if(wall_time_simulation_speed.get_value() || sc_core::sc_time_stamp() > res.timepoint) {
res.t();
} else {
auto time_point = res.timepoint - sc_core::sc_time_stamp();
Expand Down
1 change: 1 addition & 0 deletions src/components/scc/tcp4tlm_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ struct tcp4tlm_bridge : public sc_core::sc_module,
void timing_thread();
void process_task_que();
void process_timed_task_que();
void before_end_of_elaboration() override;
void end_of_elaboration() override;
void start_of_simulation() override;
void end_of_simulation() override;
Expand Down
92 changes: 92 additions & 0 deletions src/sysc/scc/wall_time_speed_limiter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*******************************************************************************
* Copyright 2026 MINRES Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#ifndef _SCC_WALL_TIME_SPEED_LIMITER_H
#define _SCC_WALL_TIME_SPEED_LIMITER_H

#include "report.h"
#include <sys/time.h>
#include <sysc/kernel/sc_module.h>
#include <sysc/kernel/sc_simcontext.h>

/** \ingroup scc-sysc
* @{
*/
/**@{*/
//! @brief SCC SystemC utilities
namespace scc {
/**
* @class wall_time_speed_limiter
* @brief a component traversing the SystemC object hierarchy and tracing the objects
*
*/
struct wall_time_speed_limiter : public sc_core::sc_module {
static wall_time_speed_limiter& get() {
static wall_time_speed_limiter limiter("sped_limiter");
return limiter;
}

private:
wall_time_speed_limiter(sc_core::sc_module_name const& nm)
: sc_module(nm) {
SC_HAS_PROCESS(wall_time_speed_limiter);
SC_THREAD(main_thread);
}

inline long long int get_time_of_day_us() {
timeval checkpoint;
#if defined __x86_64__
gettimeofday(&checkpoint, 0);
return checkpoint.tv_sec * 100000 + checkpoint.tv_usec;
#else
return 0;
#endif
}

void main_thread() {
SCCDEBUG(SCMOD) << "Limiting simulation speed to wall time mode";
const auto interval = 1000LL; // us
#if defined(__x86_64__) || 1
auto time_stamp = get_time_of_day_us();
while(true) {
wait(interval, sc_core::SC_US);
auto consumed = get_time_of_day_us() - time_stamp;
if(consumed > 0 && interval > consumed) {
struct timespec tv;
tv.tv_sec = static_cast<time_t>(interval - consumed) / 1000000;
tv.tv_nsec = static_cast<decltype(tv.tv_nsec)>((interval - consumed) * 1000);
nanosleep(&tv, &tv);
}
time_stamp = get_time_of_day_us();
}
#else
boost::posix_time::ptime checkpoint = std::posix_time::microsec_clock::local_time();
boost::posix_time::time_duration duration = std::posix_time::microsec(interval);
while(true) {
wait(duration, sc_core::SC_US);
boost::posix_time::time_duration consumed = std::posix_time::microsec_clock::local_time() - checkpoint;
if(consumed > 0 && duration > consumed) {
std::this_thread::sleep(duration - consumed);
}
checkpoint = boost::posix_time::microsec_clock::local_time();
}
#endif
}
};

} /* namespace scc */
/** @} */ // end of scc-sysc
#endif /* _SCC_WALL_TIME_SPEED_LIMITER_H */
Loading