systemC/TLM: simple use of peq

In system C / TLM programming, peq is a very important tool, especially in simulation of pipeline and other scenes in RTL.
We can think that peq is a pipeline that can set path delay. A transaction has a delay set at the entrance. Once the delay arrives, the transaction can be seen from the exit.
The same shot can get multiple transaction s at the exit of Peq.
The advantage of peq is that no matter how many transactions are push ed at the entrance, when the time of the corresponding transaction arrives, you can definitely see it at the exit to ensure that the process delay is correct and the transaction will not be missed.
The source path of PEQ is ~ systemc-2.3.1/src/tlm_utils/peq_with_get.h. If you want to know what it uses, you can directly read the source code, or refer to the official documentation of systemC.
A simple example of peq is given below. The basic functions are: a push a transaction to pipeline at 0T, with a path delay of 10T; B push transaction 2 to pipeline at 2T, with a path delay of 3T. The simulation results are as follows:

During the use of peq, the following points are needed:

  1. Since PEQ with get's only constructor has parameters without default values, it means PEQ with get has no default constructor, so the PEQ with get member variables defined must be initialized in the initialization list. If it is not initialized, it will compile an error

  2. The type in peq does not need to be TLM:: TLM ﹣ generic ﹣ payload. It can be any type. The instance uses unsigned int. However, it should be noted that the content of notify cannot be a temporary memory space. Generally, it will point to the memory space allocated dynamically by new. For example, in an instance, you cannot directly notify a local variable * t ﹣ num ﹣ 1 without new.

  3. If the same transaction is notified twice, the previous transaction will not be overwritten, and both transactions will be got.

  4. In the thread of get peq, while get next transaction, there cannot be other wait event s, otherwise it will appear. The scheduled time can be got, but because this thread is waiting for another event, the time to get to the transaction will be later than normal. There should be no delay such as wait cycle.
    Of course, in the case of using wait other event s or cycle s by mistake, the transaction itself is not lost. For example, in this example, in the process of processing the first transaction, if 10T has been wait, can the number1 be obtained by get next transaction? The answer is yes. The simulation results are as follows:

  5. In get PEQ thread, wait() is waiting for the sensitive event corresponding to the thread, that is, peq.get_event(), which must not be omitted. Otherwise, because there is no other wait in the thread, the program will fall into a dead cycle. To sum up the fourth and fifth points, in get PEQ thread, there can only be one wait, that is, wait peq.get_event().

  6. When getting next transaction, you must get it all at once until it is equal to NULL. Because the same shot may get multiple transactions, if it is not get until NULL, the transaction is likely to be lost. For example, if we take this form and use wait by mistake for 10T, we will lose number 1. The simulation results are as follows:
    t_get = m_test_peq.get_next_transaction();
    if(t_get != NULL)

    Instance source code 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 = 5"
		<<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;
}

Published 5 original articles, praised 0, visited 85
Private letter follow

Tags: Programming

Posted on Sat, 14 Mar 2020 23:57:56 -0700 by SamShade