# 介绍
本文为实现 SystemC 响应异步事件 解决方案。
应用场景:
SystemC 是一个支持系统事务级、行为级建模的开源的 C++ library;
我们将 SystemC 仿真的模拟叫做模拟器。在很多场景下,模拟器要保持 alive,等待异步 async 事件,做出对应的处理。例如设计一个 SystemC 消费者模拟器,而生产者程序不属于 SystemC 仿真范畴,消费者模拟器需要一直保持等待,并在出现数据后进行处理。
世界上没有东西是完美的啊,倒不如说,同时拥有光明和阴影才是完美的,这样的你才是真正的你。
------ 大家好啊 我是 暮冬 Z 羡慕
以上应用场景应当很常见,但是无论中文网站搜索、SystemC 社区、谷歌搜索、Stack Overflow 等,都没有合适的解决方案。笔者在综合了解相关问题及做了不少尝试后,给出了较为合适的解决方案。感兴趣的伙伴可以查看以下相关帖子:
https://workspace.accellera.org/document/dl/10932
https://forums.accellera.org/topic/29-async_request_update-example/
https://stackoverflow.com/questions/49814756/async-request-update-example-in-systemc
# 解决方案:
#include <systemc.h> | |
#include <pthread.h> | |
#include <unistd.h> | |
using namespace std; | |
class ThreadSafeEventIf : public sc_interface { | |
virtual void notify(sc_time delay = SC_ZERO_TIME) = 0; | |
virtual const sc_event &default_event(void) const = 0; | |
protected: | |
virtual void update(void) = 0; | |
}; | |
class ThreadSafeEvent : public sc_prim_channel, public ThreadSafeEventIf { | |
public: | |
ThreadSafeEvent(const char *name = ""): event(name) {} | |
void notify(sc_time delay = SC_ZERO_TIME) { | |
this->delay = delay; | |
async_request_update(); | |
} | |
const sc_event &default_event(void) const { | |
return event; | |
} | |
protected: | |
virtual void update(void) { | |
event.notify(delay); | |
} | |
sc_event event; | |
sc_time delay; | |
}; | |
sc_event GenScEvent; | |
sc_event workingFinishEvent; // finish event | |
int workingFlag = 0; // maybe dnot need a lock | |
SC_MODULE(Foo) { | |
public: | |
SC_CTOR(Foo) { | |
SC_THREAD(main); | |
SC_METHOD(eventTriggered); | |
sensitive << threadSafeEvent; | |
dont_initialize(); | |
SC_METHOD(stopTriggered); | |
sensitive << threadStopEvent; | |
dont_initialize(); | |
} | |
private: | |
void main() { //extra forever thread to avoid simulation exit | |
while (true) { | |
usleep(0.05*1000*1000); // check if there is any instruction every one sec. | |
wait(SC_ZERO_TIME); | |
if(workingFlag){ // check working | |
wait(workingFinishEvent); // wait the working finish | |
} | |
usleep(0.05*1000*1000); | |
} | |
} | |
void eventTriggered() { | |
GenScEvent.notify(); | |
} | |
void stopTriggered(){ | |
sc_stop(); | |
} | |
public: | |
ThreadSafeEvent threadSafeEvent; | |
ThreadSafeEvent threadStopEvent; | |
}; | |
void* PollingThread(void* arg) { | |
int cnt = 0; | |
Foo *foo = (Foo*)(arg); | |
while (cnt<3) { | |
cnt++; | |
printf("[POLL]: %d: Before generating event from PollingThread \n", cnt); | |
usleep(3*1000*1000); | |
foo->threadSafeEvent.notify(); | |
printf("[POLL]: %d: Event notified from PollingThread \n", cnt); | |
} | |
usleep(5*1000*1000); | |
foo->threadStopEvent.notify(); | |
}; | |
class sc_top : public sc_module { | |
private: | |
SC_HAS_PROCESS(sc_top); | |
public: | |
sc_top(sc_module_name name="SCTOP"): sc_module(name) { | |
SC_THREAD(processing_thread); | |
} | |
void processing_thread(){ | |
int cnt =0; | |
while (true) { | |
printf("[PROC]: processing_thread called \n"); | |
cout << "[PROC]: Wait GenScEvent time: " << sc_time_stamp(); | |
wait(GenScEvent); | |
workingFlag = 1; | |
cnt++; | |
wait(10, SC_SEC); // advance simulation time | |
cout << "[PROC]: Process and Finish "<<cnt << " GenScEvent time: " << sc_time_stamp(); | |
workingFinishEvent.notify(); | |
workingFlag = 0; | |
} | |
} | |
}; | |
int sc_main(int argc, char *argv[]) { | |
Foo foo("foo"); | |
sc_top u_sc_top("u_sc_top"); | |
pthread_t thread; | |
pthread_create(&thread, NULL, PollingThread, &foo); | |
sc_start(); | |
return 0; | |
} |
对应的 CMakeLists.txt
cmake_minimum_required (VERSION 3.5) | |
project (demo) | |
include_directories (${PROJECT_SOURCE_DIR}/include) | |
find_library(SystemC_LIB systemc HINTS ${PROJECT_SOURCE_DIR}/lib) | |
set (syc_LIST ${PROJECT_SOURCE_DIR}/src/syc.cpp) | |
add_executable (syc ${syc_LIST}) | |
find_package(Threads REQUIRED) | |
target_link_libraries (syc ${SystemC_LIB} Threads::Threads) |
以上代码实现了 :
- 1. 主线程中运行 SystemC 仿真模型,子线程中运行异步触发程序 (也可以根据自己的需要反过来,子线程中运行 SystemC 仿真模型,主线程运行触发程序。)
- 2. 子线程每隔 3 秒触发一次 SystemC 仿真模型,主线程中的 SystemC 进行响应。
- 3. 子线程主动触发三次之后,睡眠 5 秒,告知 SystemC 仿真结束。
# 结果
SystemC 2.3.3-Accellera --- Mar 12 2024 15:33:04
Copyright (c) 1996-2018 by all Contributors,
ALL RIGHTS RESERVED
[POLL]: 1: Before generating event from PollingThread
[PROC]: processing_thread called
[PROC]: Wait GenScEvent time: 0 s[POLL]: 1: Event notified from PollingThread
[POLL]: 2: Before generating event from PollingThread
[PROC]: Process and Finish 1 GenScEvent time: 10 s[PROC]: processing_thread called
[PROC]: Wait GenScEvent time: 10 s[POLL]: 2: Event notified from PollingThread
[POLL]: 3: Before generating event from PollingThread
[PROC]: Process and Finish 2 GenScEvent time: 20 s[PROC]: processing_thread called
[PROC]: Wait GenScEvent time: 20 s[POLL]: 3: Event notified from PollingThread
[PROC]: Process and Finish 3 GenScEvent time: 30 s[PROC]: processing_thread called
[PROC]: Wait GenScEvent time: 30 s
Info: /OSCI/SystemC: Simulation stopped by user.
# 后记
本博客目前以及可预期的将来都不会支持评论功能。各位大侠如若有指教和问题,可以在我的 github 项目 或随便一个项目下提出 issue,或者知乎 私信,并指明哪一篇博客,我看到一定及时回复,感激不尽!