微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

systemC/TLM:peq_with_cb_and_phase的简单用法

在systemC/TLM编程中,peq (payload event queue)是一个非常重要的工具,尤其是在模拟RTL中的pipeline等场景下,是必不可少的。

peq有peq_with_get 和peq_with_cb_and_phase (cb是callback的简称) 两种形式。以下主要分析peq_with_cb_and_phase,并简称peq。

peq_with_get 的用法可参考 systemC/TLM:peq_with_get的简单用法_123axj的博客-CSDN博客

peq_with_cb_and_phase是一个模板类,两个模板参数,其中第二个认为 tlm phase;第一个参数一般为 此peq变量 所在的class name。

peq没有认构造函数,必须使用列表初始化方式进行初始化。构造函数中的OWNER*一般设置为this,参数cb是一个callback function的指针,这个callback函数的形式为void (OWNER::*cb)(tlm_payload_type&, const tlm_phase_type&); 参数有两个,认为tlm_generic_payload&和tlm_phase&,无返回值。callback函数中不允许存在显式或隐式的wait逻辑。

Peq被notify一次后,always会调用一次这个callback函数调用的时间根据notify 的delay时间而定。

template<typename OWNER, typename TYPES=tlm::tlm_base_protocol_types>

class peq_with_cb_and_phase : public sc_core::sc_object

typedef typename TYPES::tlm_payload_type tlm_payload_type;

typedef typename TYPES::tlm_phase_type tlm_phase_type;

typedef void (OWNER::*cb)(tlm_payload_type&, const tlm_phase_type&);

peq_with_cb_and_phase(OWNER* , cb );

peq_with_cb_and_phase(const char* , OWNER* , cb);

struct tlm_base_protocol_types

{

  typedef tlm_generic_payload tlm_payload_type;

  typedef tlm_phase tlm_phase_type;

};

一个简单的使用示例和打印结果分别如下:

#include <iostream>

#include "systemc.h"
#include "tlm_utils/peq_with_cb_and_phase.h"

using namespace std;
using namespace sc_core;

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", this, &TestPlatform::Peq_callback_func) {
    SC_THREAD(PushPeq_1);
    SC_THREAD(PushPeq_2);
  };

private:
  void Peq_callback_func(tlm::tlm_generic_payload &trans,
                         const tlm::tlm_phase &phase);
  void PushPeq_1();
  void PushPeq_2();

  ~TestPlatform() = default;

public:
  sc_time m_period;
  tlm_utils::peq_with_cb_and_phase<TestPlatform> m_test_peq;
};

void TestPlatform::PushPeq_1() {
  tlm::tlm_generic_payload *t_trans = new tlm::tlm_generic_payload();
  t_trans->set_address(0x100);
  tlm::tlm_phase t_phase = tlm::BEGIN_REQ;

  // the transaction that peq will notify can't be a temporary memory space
  m_test_peq.notify(*t_trans, t_phase, 10 * m_period);
  cout << "[" << sc_time_stamp() << "] notify trans 1 to peq, notify cycle = 10"
       << endl;
}

void TestPlatform::PushPeq_2() {
  wait(2 * m_period);
  tlm::tlm_generic_payload *t_trans = new tlm::tlm_generic_payload();
  t_trans->set_address(0x200);
  tlm::tlm_phase t_phase = tlm::END_REQ;

  m_test_peq.notify(*t_trans, t_phase, 8 * m_period);
  cout << "[" << sc_time_stamp() << "] notify trans 2 to peq, notify cycle = 8"
       << endl;
}

// this is an error using example
void TestPlatform::Peq_callback_func(tlm::tlm_generic_payload &trans,
                                     const tlm::tlm_phase &phase) {
  if (phase == tlm::BEGIN_REQ) {
    cout << "[" << sc_time_stamp() << "] BEGIN REQ , addr=0x" << std::hex
         << trans.get_address() << endl;
  } else if (phase == tlm::END_REQ) {
    cout << "[" << sc_time_stamp() << "] END REQ , addr=0x" << std::hex
         << trans.get_address() << endl;
  } else {
    assert(false);
  }
}

int sc_main(int argc, char **argv) {
  TestPlatform *m_platform;
  m_platform = new TestPlatform("TestPlatform");
  sc_start(1, SC_US);
  return 0;
}


[0 s] notify trans 1 to peq, notify cycle = 10

[2 ns] notify trans 2 to peq, notify cycle = 8

[10 ns] BEGIN REQ , addr=0x100

[10 ns] END REQ , addr=0x200

原文地址:https://www.jb51.cc/wenti/3280715.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐