systemC/TLM:peq的简单用法

在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在使用过程中需要主要以下几点:

  1. 由于peq_with_get的唯一一个构造函数中,有不带默认值的参数;说明peq_with_get没有默认构造函数,所以定义的peq_with_get成员变量必须在初始化列表中进行初始化。如果没有初始化,而会编译错误
    在这里插入图片描述

  2. peq中类型不用保证必须是tlm::tlm_generic_payload,可以为任意类型,实例中用的是unsigned int。但需要注意的是notify的必须不能是一个临时内存空间的内容,一般情况,会让其指向new 动态分配的内存空间。比如实例中,不能在没有new的情况下,直接notify一个局部变量* t_num_1。

  3. 如果同一个transaction 被notify两次,不会覆盖前一次,两次都会被get到。

  4. 在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到么,答案是可以的。仿真结果为:
    在这里插入图片描述

  5. 在GetPeq thread中,wait()等待的是thread对应的敏感事件,也就是peq.get_event(),此wait()绝对不能省略,否则由于thread中没有其他的wait,会导致程序陷入死循环。总结第4点和第5点就是,在GetPeq thread中,有且只能有一个wait,就是wait peq.get_event()。

  6. 在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;
}

发布了8 篇原创文章 · 获赞 0 · 访问量 192

猜你喜欢

转载自blog.csdn.net/zgcjaxj/article/details/104877270