sc_module
systemc 的手册看完了,感觉还是从第五章开始讲比较好,先学会用,然后在研究底层原理。
sc_moduel code
class sc_module
: public sc_object
{
public:
virtual ~sc_module();
virtual const char* kind() const;
void operator() (
const sc_bind_proxy†& p001,
const sc_bind_proxy†& p002 = SC_BIND_PROXY_NIL,
const sc_bind_proxy†& p003 = SC_BIND_PROXY_NIL,
...
const sc_bind_proxy†& p063 = SC_BIND_PROXY_NIL,
const sc_bind_proxy†& p064 = SC_BIND_PROXY_NIL );
virtual const std::vector<sc_object*>& get_child_objects() const;
virtual const std::vector<sc_event*>& get_child_events() const;
protected:
sc_module( const sc_module_name& );
sc_module();
void reset_signal_is( const sc_in<bool>& , bool );
void reset_signal_is( const sc_inout<bool>& , bool );
void reset_signal_is( const sc_out<bool>& , bool );
void reset_signal_is( const sc_signal_in_if<bool>& , bool );
void async_reset_signal_is( const sc_in<bool>& , bool );
void async_reset_signal_is( const sc_inout<bool>& , bool );
void async_reset_signal_is( const sc_out<bool>& , bool );
void async_reset_signal_is( const sc_signal_in_if<bool>& , bool );
sc_sensitive† sensitive;
void dont_initialize();
void set_stack_size( size_t );
void next_trigger();
void next_trigger( const sc_event& );
void next_trigger( const sc_event_or_list & );
void next_trigger( const sc_event_and_list & );
void next_trigger( const sc_time& );
void next_trigger( double , sc_time_unit );
void next_trigger( const sc_time& , const sc_event& );
void next_trigger( double , sc_time_unit , const sc_event& );
void next_trigger( const sc_time& , const sc_event_or_list &);
void next_trigger( double , sc_time_unit , const sc_event_or_list & );
void next_trigger( const sc_time& , const sc_event_and_list & );
void next_trigger( double , sc_time_unit , const sc_event_and_list & );
void wait();
void wait( int );
void wait( const sc_event& );
void wait( const sc_event_or_list &);
void wait( const sc_event_and_list & );
void wait( const sc_time& );
void wait( double , sc_time_unit );
void wait( const sc_time& , const sc_event& );
void wait( double , sc_time_unit , const sc_event& );
void wait( const sc_time& , const sc_event_or_list & );
void wait( double , sc_time_unit , const sc_event_or_list & );
void wait( const sc_time& , const sc_event_and_list & );
void wait( double , sc_time_unit , const sc_event_and_list & );
virtual void before_end_of_elaboration();
virtual void end_of_elaboration();
virtual void start_of_simulation();
virtual void end_of_simulation();
private:
// Disabled
sc_module( const sc_module& );
sc_module& operator= ( const sc_module& );
};
void next_trigger();
void next_trigger( const sc_event& );
void next_trigger( const sc_event_or_list & );
void next_trigger( const sc_event_and_list & );
void next_trigger( const sc_time& );
void next_trigger( double , sc_time_unit );
void next_trigger( const sc_time& , const sc_event& );
void next_trigger( double , sc_time_unit , const sc_event& );
void next_trigger( const sc_time& , const sc_event_or_list & );
void next_trigger( double , sc_time_unit , const sc_event_or_list & );
void next_trigger( const sc_time& , const sc_event_and_list & );
void next_trigger( double , sc_time_unit , const sc_event_and_list & );
void wait();
void wait( int );
void wait( const sc_event& );
void wait( const sc_event_or_list & );
void wait( const sc_event_and_list & );
void wait( const sc_time& );
void wait( double , sc_time_unit );
void wait( const sc_time& , const sc_event& );
void wait( double , sc_time_unit , const sc_event& );
void wait( const sc_time& , const sc_event_or_list & );
void wait( double , sc_time_unit , const sc_event_or_list & );
void wait( const sc_time& , const sc_event_and_list & );
void wait( double , sc_time_unit , const sc_event_and_list & );
#define SC_MODULE(name) struct name : sc_module
#define SC_CTOR(name) implementation-defined; name(sc_module_name)
#define SC_HAS_PROCESS(name) implementation-defined
#define SC_METHOD(name) implementation-defined
#define SC_THREAD(name) implementation-defined
#define SC_CTHREAD(name,clk) implementation-defined
const char* sc_gen_unique_name( const char* );
typedef sc_module sc_behavior;
typedef sc_module sc_channel;
} // namespace sc_core
sc_module 用法
继承
sc_module 构造函数是private 属性,并且提供的很函数都属于protected,所以要使用第一步先继承,sc_module 不能单独使用。
class user_module:public sc_module {};
具体的function,逻辑算法,完全可以按照纯c++的行为实现,这一点自由度还是很高的,这也是SC最大的优势,但是同时这也是劣势。因为既不偏向软件工程师,也不偏向硬件工程师,导致很难被推广,现在已经跟SV不是一个级别,看看各家工具对SV,SC的支持度,也能感觉出来,具体SC的优缺点上一篇博文有提到。
使用c++ 继承方式的写法,具体例子可以参考计算机体系结构研究仿真之SystemC基础(五) - 知乎 (zhihu.com)
process
process主要包括下面这三个
#define SC_METHOD(name) implementation-defined
#define SC_THREAD(name) implementation-defined
#define SC_CTHREAD(name,clk) implementation-defined
在user_module中例实现 process ,很多初学sc 的小伙伴背景都是纯软的,可以先理解为c++ 带锁的thread。有硬件背景的可以理解为D触发器,这两者的共同点都是在行为上是并行的,但是在实际运行时候是串行的。
reset
SC 中的reset 与rtl 中的reset 作用是一样的,可以设置边沿/电平触发,只不过根据实际场景,区分了async和非async,简单理解为同步复位,异步复位,具体使用的时候 需要结合SC的语法进行。
reset_signal_is() 方法在指定的信号通道变为活动状态(高或低,取决于参数)时停止任何当前正在执行的进程。然后,它重置线程样式进程的上下文,以便从头开始调用它们,而不会继续延用原有的context继续执行,SC只是帮你清理了context,thread中需要清理其他动作需要自己使用if(reset_signal){xxx},去完成,这是个很大的误区,以为设置了reset 信号,那么所有端口都会自动清零,reset 只管当前的通道。
它实际上不会重置或更改任何其他通道的值。对于方法样式的进程,它不需要这样做,因为它们不像线程那样持有任何状态。所以他只对当前的通道有效。
async有无的区别,主要是用于SC_CHREAD上,可参考。但是三种SC process都可以用任一种方式设置reset信号。
wait
wait的概念不好理解,与c++ pthread 的wait 很像,但是实例上更像是是在模拟一个逻辑电路的行为,只有wait的时间或者信号变化时候,才会执行指定的动作。
wait函数根据参数不同,具体调用需要重载函数,这些重载函数的主要集中在event和time不一样,event 指某个事件,这些事件自由度很高,包括信号变化,运行过程,计算结果等行为。time则指的是仿真时间,指定等待 n unit 的时间后,触发具体的行为。
wait 只能放在SC_THREAD中使用。
next_trigger
next_trigger也是根据参数不同,具体调用需要重载函数。参数类型和wait 的参数很像,所以功能上跟wait的行为也很像,可以指定当前process 执行时候,具体触发的行为,包括event和time。
这个功能是有悖于实际物理电路的,一个电路接好,无法改变具体的行为,但是这也是SC的优势,高自由度,高扩展性,高易用性。
具体用法后面做专门介绍 ,next_trigger 可以用于优化CA 模型的性能。
sensitive
关于senstitive,可以参考,下面例子。HDL4SE:软件工程师学习Verilog语言(十二)_ieee 1666-2020 system c标准-CSDN博客
Systemc语法知识总结_systemc学习-CSDN博客
宏定义 SC_xxxx
这些都是sc_module 下面,或者必选存在于sc_module(包括派生类)使用的的宏定义,主要功能还是为了简化大量冗余的代码,使代码更加简洁,最受用的群体还是硬件工程师。
比如SC_MODULE ,SC_CTOR 就可以让你像类似于rtl的 编写一个module。
#define SC_MODULE(name) struct name : sc_module
#define SC_CTOR(name) implementation-defined; name(sc_module_name)
SC_MODULE(M1)
{
SC_CTOR(M1) //构造器定义
: i(0)
{}
int i;
...
};
下面这四宏定义则是配套使用的,如果 module 中需要开辟sc porcess 则应该使用以下宏定义。
#define SC_HAS_PROCESS(name) implementation-defined
#define SC_METHOD(name) implementation-defined
#define SC_THREAD(name) implementation-defined
#define SC_CTHREAD(name,clk) implementation-defined
NOTE
NOTE 1—Because the constructors are protected, class sc_module cannot be instantiated directly but may be used as a base class.
NOTE 2—A module should be publicly derived from class sc_module.
NOTE 3—It is permissible to use class sc_module as an indirect base class. In other words, a module can be derived from another module. This can be a useful coding idiom.
example
int sc_main (int argc, char* argv[])
{
Top_level_module top("top");
std::vector<sc_object*> children = top.get_child_objects();
// Print out names and kinds of top-level objects
for (unsigned i = 0; i < children.size(); i++)
std::cout << children[i]->name() << " " << children[i]->kind() << std::endl;
sc_start();
return 0;
}