在systemC/TLM编程中,peq是一个非常重要的工具,尤其是在模拟RTL中的pipeline等场景下,是必不可少的。
我们可以认为peq是一个可以设置路径延时的管道,一个transaction在入口处设置好延时,延时一到就从出口处可以看到这个transaction了。
同一拍可以在Peq的出口处get到多个transaction。
peq的好处是,不管在在入口处push了多少transaction,相应transaction的时间一到,在出口处肯定可以看到,保证过程的延时正确,且不会漏掉transaction。
peq的源码路径在:~systemc-2.3.1/src/tlm_utils/peq_with_get.h,如果想了解其使用的,可以直接看源码,或者参考systemC的官方说明文档。
以下给出了一个简单的peq实例。实现的基本功能是:A在0T时push一个transaction到pipeline,路径延时10T;B在2T时push transaction 2到pipeline,路径延时3T。得到的仿真结果为:
peq在使用过程中需要主要以下几点:
-
由于peq_with_get的唯一一个构造函数中,有不带默认值的参数;说明peq_with_get没有默认构造函数,所以定义的peq_with_get成员变量必须在初始化列表中进行初始化。如果没有初始化,而会编译错误
-
peq中类型不用保证必须是tlm::tlm_generic_payload,可以为任意类型,实例中用的是unsigned int。但需要注意的是notify的必须不能是一个临时内存空间的内容,一般情况,会让其指向new 动态分配的内存空间。比如实例中,不能在没有new的情况下,直接notify一个局部变量* t_num_1。
-
如果同一个transaction 被notify两次,不会覆盖前一次,两次都会被get到。
-
在get peq的thread中,while get_next_transaction中,不能有其他的wait event,否则就会出现,预定的时间本可以get到,但因为此thread还在等待另外的event,所以get到trans的时间会比正常要延后。也不能有wait cycle之类的延时。
当然,在错误地使用wait 其他event或cycle的情况下,transaction本身是没有丢掉的。例如在本实例中在处理第1个trans的过程中 wait 了 10T ,那第number1还能被get next transaction到么,答案是可以的。仿真结果为: -
在GetPeq thread中,wait()等待的是thread对应的敏感事件,也就是peq.get_event(),此wait()绝对不能省略,否则由于thread中没有其他的wait,会导致程序陷入死循环。总结第4点和第5点就是,在GetPeq thread中,有且只能有一个wait,就是wait peq.get_event()。
-
在get next transaction的时候必须一次性一直get,直至等于NULL。因为同一拍可能会get到多个transaction,如果不是get直到NULL,则很可能会丢失transaction。比如我们采用这种形式,而又恰巧错误地使用了wait了10T,则会导致number 1丢失。仿真结果为:
t_get = m_test_peq.get_next_transaction();
if(t_get != NULL)
实例 源代码main.cpp
/*
Original 2020-03-15
README:
This is a example to teach you how to use a peq in systemC/TLM
Assume that you want to implement such a scenario:
A delay 10T to a pipeline at 0T; B delay 3T to the same pipeline at 2T
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
you need particular attention that
1. the only constructor of peq_with_get have a paramater, \
it have no default constructor,\
so you must initialize it use initialization list
you can check the constructor at ~systemc-2.3.1/src/tlm_utils/peq_with_get.h
peq_with_get(const char* name) : sc_core::sc_object(name)
2. for other points, can check my csdn blog
*/
#include <iostream>
#include "systemc.h"
#include "tlm_utils/peq_with_get.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_test_peq("test_peq")
{
SC_THREAD(PushPeq_1);
SC_THREAD(PushPeq_2);
SC_THREAD(GetPeq);
sensitive<<m_test_peq.get_event();//sensitive event list
};
public:
void PushPeq_1();
void PushPeq_2();
void GetPeq();
~TestPlatform()
{;}
public:
sc_time m_period;
tlm_utils::peq_with_get<unsigned int >
m_test_peq;
};
void TestPlatform::PushPeq_1()
{
unsigned int * t_num_1 = new unsigned int ;
* t_num_1 = 100;
// the transaction that peq will notify can't be a temporary memory space
m_test_peq.notify(*t_num_1 , 10 * m_period );
cout<<"["<<sc_time_stamp()
<<"] notify number 1 to peq, notify cycle = 10"
<<endl;
}
void TestPlatform::PushPeq_2()
{
wait(2* m_period);
unsigned int * t_num_2 = new unsigned int ;
* t_num_2 = 200;
m_test_peq.notify(*t_num_2 , 3 * m_period );
cout<<"["<<sc_time_stamp()
<<"] notify number 2 to peq, notify cycle = 3"
<<endl;
}
void TestPlatform::GetPeq()
{
unsigned int * t_get = NULL;
while(1)
{
wait(); //wait sensitive event list
//here must get next transaction entil t_get is NULL
while((t_get = m_test_peq.get_next_transaction()) != NULL)
{
cout<<"["<<sc_time_stamp()
<<"] get number "
<< * t_get
<<endl;
delete t_get; //dynamic memory space, delete when no use
t_get = NULL;
//in this block, must can't wait any event or cycle delay
// if not, the time of transaction obtained will not accurate
// wait(10 * m_period);
}
}
}
/*
//this is an error using example
void TestPlatform::GetPeq()
{
unsigned int * t_get = NULL;
while(1)
{
wait();
//this is an error using example
// get_next_transaction not until NULL & wait other cycle
// will lead to number 1 missing
t_get = m_test_peq.get_next_transaction();
if(t_get != NULL)
{
cout<<"["<<sc_time_stamp()
<<"] get number "
<< * t_get
<<endl;
delete t_get;
t_get = NULL;
wait(10 * m_period);
}
}
}
*/
int sc_main(int argc, char** argv)
{
TestPlatform * m_platform;
m_platform = new TestPlatform("TestPlatform");
sc_start(1,SC_US);
return 0;
}
原文地址:https://www.jb51.cc/wenti/3280722.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。