SC_THREAD和SC_METHOD是在systemC/TLM编程中实现 模拟RTL并行执行的关键所在。
SC_METHOD的实现主体中不能有wait,所以它必须配合sensitive敏感列表一起使用,当敏感列表中的event被notify时,SC_METHOD的函数主体 被执行一次。并且,Method同一拍只能被执行一次。
在SC_METHOD的使用过程中,经常会犯一个错误,就是敏感事件被多次触发时,很有可能会把某些次的触发给隐藏掉。以下给出一个实例。
假设我们要建模这样一个场景:一个pipeline为10T,A 以每隔3T的频率往pipeline入口push,经pipeline的10T后,预期让SC_METHOD执行一次。假设A是从0T开始push,那么我们预期的结果是:在10T,13T,16T…的时候分别执行一次SC_METHOD的内容。
但假设我们在写代码时这样来实现:
/*
Original 2020-03-16
README:
This is a example of the interrelation between SC_METHOD and sc_event in systemC/TLM
execute:
g++ -g -Wall -lsystemc -m64 -pthread main.cpp -L/$(your systemc path)/lib-linux64 -I/$(your systemc path)/include -I/$(your systemc path)/src/tlm_utils -o sim
*/
#include <iostream>
#include <fstream>
#include "systemc.h"
using namespace std;
class TestPlatform
: public sc_module
{
public:
SC_HAS_PROCESS(TestPlatform);
TestPlatform(const sc_module_name& name)
: sc_module(name)
,m_period (sc_time(1000,SC_PS))
,m_pipeline_delay(m_period * 20)
{
SC_METHOD(TestMethod);
sensitive << m_event <<m_event_2 ;
dont_initialize();
SC_THREAD(NotifyEvtThread);
// SC_THREAD(NotifyEvtThread_2);// this line can enable m_event_2 notify
};
public:
void TestMethod();
void NotifyEvtThread();
void NotifyEvtThread_2();
~TestPlatform()
{;}
public:
sc_time m_period;
sc_time m_pipeline_delay;
sc_event m_event;
sc_event m_event_2;
};
void TestPlatform::TestMethod()
{
cout<<" ["<<sc_time_stamp()<<" ]"
<< "ethod execute one time, notify time is "
<< sc_time_stamp() - m_pipeline_delay
<<endl;
}
void TestPlatform::NotifyEvtThread()
{
while(1)
{
m_event.notify( m_pipeline_delay);
cout<<" ["<<sc_time_stamp()<<" ]"<< "notify event "<<endl;
wait(3 *m_period);
}
}
void TestPlatform::NotifyEvtThread_2()
{
while(1)
{
m_event_2.notify( m_pipeline_delay);
cout<<" ["<<sc_time_stamp()<<" ]"<< "notify event 2222 "<<endl;
wait(5 *m_period);
// wait(3 *m_period);
}
}
int main(int argc, char** argv)
{
TestPlatform * m_platform;
m_platform = new TestPlatform("TestPlatform");
sc_start(50,SC_NS);
return 0;
}
那么最终的仿真结果如下,奇怪了,怎么跟预想的不一致呢。
接着让我们来分析一下原因。实际上,method中只能记录最早的一笔event,之后再有event notify没有用,不会覆盖掉之前的。0T 第1次notify,第一次执行method是20ns,执行method的时候 同时将记录的event删除掉,21ns的时候被notify,然后这个event被记录下来,然后41ns的时候 执行method。
所以说,由于我们将pipeline的10T直接用m_event.notify( m_pipeline_delay);来实现,导致了多次的m_event 触发 被隐藏掉了。
注意:程序中的dont_initialize是为了让0T的时候,SC_METHOD不要强制初始化执行一次。
进一步分析。
如果是sensitive << m_event <<m_event_2 ;则相当于是这个method对应两个坑位,两个event分别进行计时。两个event之间互不影响,应该 也可以查看本次是哪个event导致的method执行,但此功能暂时还不太会用。
假设NotifyEvtThread_2()中每隔5拍m_event_2.notify( m_pipeline_delay),那么仿真结果如下。可以发现SC_METHOD在40ns和41ns的时候分别被执行了一次;分别对应event2和event的notify结果。
同时,需要注意一点:Method同一拍只能执行一次。如果两个event的notify时间点完全相同,但method依然是只能在同一拍执行一次。可以修改NotifyEvtThread_2()中也是每隔3拍m_event_2.notify( m_pipeline_delay).仿真结果如下。
综上,我们在使用SC_METHOD的时候一定要特别注意,为了避免不必要的debug,尽量在功能简单的时候使用SC_METHOD,尽量不要出现敏感列表为两个event,尽量不要在多个thread函数中notify event。复杂场景请使用SC_THREAD,以后我们再重点分析。
那怎么才能正确地实现 最初的那个建模场景呢?且看下次分析。