blocking & non-blocking transport之间的相互转换

在之前博客SystemC/TLM: blocking & non-blocking transport_123axj的博客-CSDN博客中讲到了SystemC中的blocking 和 non-blocking transport,需要 initiator 和 target 两边的transport类型一致,也就是都为 blocking transport 或者都为 non-blocking transport。

而假如 initiator 和 target 两边的transport类型不一致时,是否可以正常执行呢?如果 我们使用的协议只有request和response两个channel,只使用BEGIN_REQ, END_REQ, BEGIN_RESP, END_RESP 这几个tlm phase,则答案是可以 ;如果使用的是诸如AXI之类的其他接口协议,则不能。以下主要讨论前者,我们可以借用之前的代码将 MyInitiator 和 MyTarget_Nb 绑定一起(以下称之为 top_module_b2nb),将MyInitiator_Nb 和 MyTarget 绑定一起(以下称之为 top_module_nb2b)。

对于top_module_b2nb,由于 MyTarget_Nb中m_target_port只注册了nb_transport_fw 函数,而没有注册b_transport 函数,所以 MyInitiator 在执行m_initiator_port->b_transport(*t_payload, t_delay); (实际执行的是 tlm_utils/simple_target_socket.h中的 b_transport函数 )的时候,我们发现 b_transport函数中有如下的逻辑,可以得知,m_b_transport_ptr 是空指针,m_nb_transport_ptr是有指向的,此时进行 b2nb 的转换,simple_target_socket.h中的b2nb_thread() 是用于 b2nb转换的sc_thread。

    void b_transport(transaction_type& trans, sc_core::sc_time& t)
    {
      if (m_b_transport_ptr) {
        // forward call
        sc_assert(m_mod);
        (m_mod->*m_b_transport_ptr)(trans, t);
        return;
      }

      // b->nb conversion
      if (m_nb_transport_ptr) {
        m_peq.notify(trans, t);
         ….
      }
    }

对于top_module_nb2b,MyInitiator_Nb 注册了nb_transport_bw,而MyTarget中注册了b_transport. MyInitiator_Nb在执行m_initiator_port->nb_transport_fw(*t_payload, BEGIN_REQ, t_delay); (实际执行的是 tlm_utils/simple_target_socket.h中的 nb_transport_fw函数 )的时候,会发现 m_nb_transport_ptr指针为空,m_b_transport_ptr非空,此时会 spawn一个 nb2b_thread,在nb2b_thread 中,我们发现其直接向initiator 发起 BEGIN_RESP phase,也就是说其 省略了END_REQ phase。

如果我们直接使用 SystemC/TLM: blocking & non-blocking transport_123axj的博客-CSDN博客 中的MyInitiator_Nb 和 My_Target 相连,会导致 MyInitiator_Nb::SendReqThread() 一直在等待 收到END_REQ phase,进而MyInitiator_Nb 不能再发出第2个request。

为此,可以增加一个m_slv_begin_resp_evt,MyInitiator_Nb::SendReqThread()中 wait m_slv_end_req_evt | m_slv_begin_resp_evt,这样MyInitiator_Nb 就可以发出后续多个request 了。

 

    sync_enum_type nb_transport_fw(transaction_type& trans,
                                   phase_type& phase,
                                   sc_core::sc_time& t)
    {
      if (m_nb_transport_ptr) {
          …..
      }

      // nb->b conversion
      if (m_b_transport_ptr) {
        if (phase == tlm::BEGIN_REQ) {
              …..
            sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread, this, ph),
                            sc_core::sc_gen_unique_name("nb2b_thread"), &opts);
        }
        if (phase == tlm::END_RESP) {
            ….
          }
}

  void nb2b_thread(process_handle_class* h)
    {

      while(1) {
         ….
        phase_type phase    = tlm::BEGIN_RESP;
        sync_enum_type sync = m_owner->bw_nb_transport(*trans, phase, t);
}
    }

 

b2nb 代码实现

// 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

#include <systemc>

#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"

class MyInitiator : public sc_core::sc_module
{
public:
  SC_HAS_PROCESS(MyInitiator); // must have this line
  explicit MyInitiator(sc_core::sc_module_name name)
      : sc_core::sc_module(name),
        m_initiator_port("initiator_port")
  {
    SC_THREAD(MainThread);
  }

  void MainThread()
  {
    int t_cycle_cnt = 0;
    sc_core::sc_time t_delay = sc_core::SC_ZERO_TIME;
    while (1)
    {
      t_cycle_cnt++;
      t_delay = sc_core::sc_time(t_cycle_cnt, sc_core::SC_NS);
      tlm::tlm_generic_payload *t_payload = new tlm::tlm_generic_payload();
      t_payload->set_address(0x10000 + t_cycle_cnt);
      std::cout << "\033[34m [" << sc_core::sc_time_stamp() << "]"
                << " begin call b_transport, addr=0x" << std::hex << t_payload->get_address()
                << " delay cycle " << t_cycle_cnt
                << " \033[0m" << std::endl;
      m_initiator_port->b_transport(*t_payload, t_delay);
      std::cout << "\033[34m [" << sc_core::sc_time_stamp() << "]"
                << " end call b_transport, addr=0x" << std::hex << t_payload->get_address()
                << " delay cycle " << t_cycle_cnt
                << " \033[0m\n" << std::endl;
      wait(1, sc_core::SC_NS);
    }
  }

  tlm_utils::simple_initiator_socket<MyInitiator> m_initiator_port;
};

class MyTarget_Nb : public sc_core::sc_module
{
public:
  SC_HAS_PROCESS(MyTarget_Nb); // must have this line
  explicit MyTarget_Nb(sc_core::sc_module_name name)
      : sc_core::sc_module(name), m_target_port("target_port_nb")
  {
    m_target_port.register_nb_transport_fw(this, &MyTarget_Nb::nb_transport_fw_func);

    SC_THREAD(MainThread);
    SC_THREAD(BeginRespThread);
  }

  // don't recommend add wait logic in nb_transport_fw / nb_transport_bw
  tlm::tlm_sync_enum nb_transport_fw_func(tlm::tlm_generic_payload &payload,
                                          tlm::tlm_phase &phase, sc_core::sc_time &delay)
  {
    switch (phase)
    {
    case tlm::BEGIN_REQ:
      m_req_fifo.write(&payload);
      std::cout << this->name()
                << "\033[35m [" << sc_core::sc_time_stamp() << "]"
                << " nb_transport_fw_func recv BEGIN_REQ phase, addr=0x" << std::hex << payload.get_address()
                << " \033[0m" << std::endl;
      break;
    case tlm::END_RESP:
      std::cout << this->name() << "\033[35m [" << sc_core::sc_time_stamp() << "]"
                << " nb_transport_fw_func recv END_RESP phase, addr=0x" << std::hex << payload.get_address()
                << " \033[0m\n"
                << std::endl;
      break;
    default:
      assert(false);
    }
    return tlm::TLM_ACCEPTED;
  }

  void MainThread()
  {
    tlm::tlm_phase t_phase = tlm::END_REQ;
    sc_core::sc_time t_delay = sc_core::SC_ZERO_TIME;
    while (1)
    {
      tlm::tlm_generic_payload *t_payload = m_req_fifo.read();

      /***********************************/
      // here can add your block logic, for back pressure use
      wait(1, sc_core::SC_NS);
      /***********************************/

      std::cout << this->name() << "\033[38m [" << sc_core::sc_time_stamp() << "]"
                << " call nb_transport_bw, END_REQ phase, addr=0x" << std::hex << t_payload->get_address()
                << " \033[0m" << std::endl;
      m_target_port->nb_transport_bw(*t_payload, t_phase, t_delay);

      /***********************************/
      // after END_REQ phase, indicate slave recv req successfully,
      // then handle req, return BEGIN_RESP
      /***********************************/
      m_resp_fifo.write(t_payload);

      wait(1, sc_core::SC_NS);
    }
  }

  void BeginRespThread()
  {
    tlm::tlm_phase t_phase = tlm::BEGIN_RESP;
    // sc_core::sc_time t_delay = sc_core::SC_ZERO_TIME;
    sc_core::sc_time t_delay = sc_core::sc_time(1, sc_core::SC_NS);
    while (1)
    {
      tlm::tlm_generic_payload *t_payload = m_resp_fifo.read();
      std::cout << this->name() << "\033[38m [" << sc_core::sc_time_stamp() << "]"
                << " call nb_transport_bw, BEGIN_RESP phase, addr=0x" << std::hex << t_payload->get_address()
                << " \033[0m" << std::endl;
      m_target_port->nb_transport_bw(*t_payload, t_phase, t_delay);

      wait(1, sc_core::SC_NS);
    }
  }

  tlm_utils::simple_target_socket<MyTarget_Nb> m_target_port;
  sc_core::sc_fifo<tlm::tlm_generic_payload *> m_req_fifo;
  sc_core::sc_fifo<tlm::tlm_generic_payload *> m_resp_fifo;
};

class MyTop : public sc_core::sc_module
{
public:
  SC_HAS_PROCESS(MyTop);
  explicit MyTop(sc_core::sc_module_name name)
      : sc_core::sc_module(name),
        m_init("init"),
        m_target("target")
  {
    m_init.m_initiator_port.bind(m_target.m_target_port);
  }

  MyInitiator m_init;
  MyTarget_Nb m_target;
};

int sc_main(int argc, char **argv)
{
  MyTop m_top_module("my_top_module_b2nb");
  sc_core::sc_start(20, sc_core::SC_NS);
  return 0;
}

nb2b 代码实现

// 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

#include <systemc>

#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"

class MyInitiator_Nb_1 : public sc_core::sc_module
{
public:
  SC_HAS_PROCESS(MyInitiator_Nb_1); // must have this line
  explicit MyInitiator_Nb_1(sc_core::sc_module_name name)
      : sc_core::sc_module(name),
        m_initiator_port("initiator_port"), m_test_peq("peq")
  {
    m_initiator_port.register_nb_transport_bw(this, &MyInitiator_Nb_1::nb_transport_bw_func);
    SC_THREAD(SendReqThread);
    SC_THREAD(SendEndRespThread);
    sensitive << m_test_peq.get_event(); // sensitive event list
  }

  void SendReqThread()
  {
    int t_cycle_cnt = 0;
    tlm::tlm_phase t_phase = tlm::BEGIN_REQ;
    sc_core::sc_time t_delay = sc_core::SC_ZERO_TIME;
    while (1)
    {
      t_cycle_cnt++;
      t_delay = sc_core::sc_time(t_cycle_cnt, sc_core::SC_NS);
      tlm::tlm_generic_payload *t_payload = new tlm::tlm_generic_payload();
      t_payload->set_address(0x10000 + t_cycle_cnt);
      std::cout << this->name() << "\033[34m [" << sc_core::sc_time_stamp() << "]"
                << " call nb_transport_fw, BEGIN_REQ phase, addr=0x" << std::hex << t_payload->get_address()
                << " delay cycle " << t_cycle_cnt
                << " \033[0m" << std::endl;
      m_initiator_port->nb_transport_fw(*t_payload, t_phase, t_delay);
      std::cout << this->name() << "\033[34m [" << sc_core::sc_time_stamp() << "]"
                << " call nb_transport_fw, BEGIN_REQ phase finish, addr=0x" << std::hex << t_payload->get_address()
                << " delay cycle " << t_cycle_cnt
                << " \033[0m" << std::endl;
      /***********************************/
      // here can add your block logic,
      // basic block logic: need wait recv END_REQ phase
      wait(m_slv_end_req_evt | m_slv_begin_resp_evt);
      /***********************************/

      wait(1, sc_core::SC_NS);
    }
  }

  // don't recommend add wait logic in nb_transport_fw / nb_transport_bw
  tlm::tlm_sync_enum nb_transport_bw_func(tlm::tlm_generic_payload &payload,
                                          tlm::tlm_phase &phase, sc_core::sc_time &delay)
  {
    switch (phase)
    {
    case tlm::END_REQ:
      std::cout << this->name()
                << "\033[35m [" << sc_core::sc_time_stamp() << "]"
                << " nb_transport_bw_func recv END_REQ phase, addr=0x" << std::hex << payload.get_address()
                << " \033[0m" << std::endl;
      m_slv_end_req_evt.notify();
      break;
    case tlm::BEGIN_RESP:
      std::cout << this->name() << "\033[35m [" << sc_core::sc_time_stamp() << "]"
                << " nb_transport_bw_func recv BEGIN_RESP phase, addr=0x" << std::hex << payload.get_address()
                << " \033[0m" << std::endl;
      m_test_peq.notify(payload);
      m_slv_begin_resp_evt.notify();
      break;
    default:
      assert(false);
    }
    return tlm::TLM_ACCEPTED;
  }

  void SendEndRespThread()
  {
    tlm::tlm_generic_payload *t_get = NULL;
    tlm::tlm_phase t_phase = tlm::END_RESP;
    sc_core::sc_time t_delay = sc_core::SC_ZERO_TIME;
    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)
      {
        std::cout << this->name() << "\033[34m [" << sc_core::sc_time_stamp() << "]"
                  << " call nb_transport_fw, END_RESP phase, addr=0x" << std::hex << t_get->get_address()
                  << " \033[0m\n" << std::endl;
        m_initiator_port->nb_transport_fw(*t_get, t_phase, t_delay);
        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
      }
    }
  }

  sc_core::sc_event m_slv_end_req_evt;
  sc_core::sc_event m_slv_begin_resp_evt;
  tlm_utils::simple_initiator_socket<MyInitiator_Nb_1> m_initiator_port;
  tlm_utils::peq_with_get<tlm::tlm_generic_payload> m_test_peq;
};

class MyTarget : public sc_core::sc_module
{
public:
  SC_HAS_PROCESS(MyTarget); // must have this line
  explicit MyTarget(sc_core::sc_module_name name)
      : sc_core::sc_module(name), m_target_port("target_port")
  {
    m_target_port.register_b_transport(this, &MyTarget::RecvReqFunc);
  }

  //void at_target_2_phase::b_transport(tlm::tlm_generic_payload &payload, sc_core::sc_time &delay_time)
  void RecvReqFunc(tlm::tlm_generic_payload &payload, sc_core::sc_time &delay)
  {
    wait(delay);
    std::cout << "\033[35m [" << sc_core::sc_time_stamp() << "]"
              << " RecvReqFunc " << std::hex << payload.get_address() << " \033[0m" << std::endl;
  }

  tlm_utils::simple_target_socket<MyTarget> m_target_port;
};

class MyTarget_Nb : public sc_core::sc_module
{
public:
  SC_HAS_PROCESS(MyTarget_Nb); // must have this line
  explicit MyTarget_Nb(sc_core::sc_module_name name)
      : sc_core::sc_module(name), m_target_port("target_port_nb")
  {
    m_target_port.register_nb_transport_fw(this, &MyTarget_Nb::RecvReqFunc);
  }

  tlm::tlm_sync_enum RecvReqFunc(tlm::tlm_generic_payload &payload, 
    tlm::tlm_base_protocol_types::tlm_phase_type& phase, sc_core::sc_time &delay)
  {
    wait(delay);
    std::cout << "\033[35m [" << sc_core::sc_time_stamp() << "]"
              << " RecvReqFunc " << std::hex << payload.get_address() << " \033[0m" << std::endl;
  }

  tlm_utils::simple_target_socket<MyTarget_Nb> m_target_port;
};

class MyTop : public sc_core::sc_module
{
public:
  SC_HAS_PROCESS(MyTop);
  explicit MyTop(sc_core::sc_module_name name)
      : sc_core::sc_module(name),
        m_init("init"),
        m_target("target")
  {
    m_init.m_initiator_port.bind(m_target.m_target_port);
  }

  MyInitiator_Nb_1 m_init;
  MyTarget m_target;
};

int sc_main(int argc, char **argv)
{
  MyTop m_top_module("my_top_module_nb2b");
  sc_core::sc_start(20, sc_core::SC_NS);
  return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

123axj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值