美文网首页
TLM-事务级建模

TLM-事务级建模

作者: 陈成_Adam | 来源:发表于2020-02-12 16:12 被阅读0次

通过阅读本文,你将知道:

  • 什么是TLM?

  • 为什么使用TLM?

  • 怎样使用TLM?

介绍

TLM的英文全称是Transaction Level Modeling,也就是事务级建模

我们知道,对一个系统建模可以分为很多个层次,比如算法抽象级别寄存器传输级别等。事务级建模是介于算法抽象级别和寄存器传输级别之间的一个层次。

事务级建模中的事务指的是模块之间的数据事件的交互。数据可以是一个或多个字,或者是一种数据结构,而同步或者中断等则属于事件的交互。

事务级建模的核心思想是在一个系统建模的过程中将运算功能通信功能分开。模块之间的通信使用函数调用的方法来实现。这样模块不需要关注端口定义以及端口时序,从而建模速度更快,最终的仿真程序运行速度也要更快。

image

事务级模型可以分为三种:没有时序信息的模型、周期近似的模型和精确到每个周期的模型。根据一些公司的经验,没有时序信息的事务级模型的仿真速度要比RTL模型快1000到10000倍,而有时序信息的模型比RTL模型快100到1000倍,而精确时钟的模型比RTL模型快10到100倍。

image

使用TLM的好处很多(这也是为什么使用TLM的原因):

  • 使用TLM可以快速搭建架构模型。这里的快速是相对于RTL模型而言的。

  • 这个架构模型可以:1. 验证架构的可行性 2. 做性能分析 3. 硬件功能验证阶段的Golden Model 4. 让软件开发提前在架构模型上进行

  • 运行速度快。同样的,这里的速度快也是相对于RTL模型而言的。

TLM实践

下面以一个最简单的例子来说明怎样使用TLM。

这个例子完成的功能是一个模块向另一个模块发送一个数据,发送模块命名为:Initiator,接收模块命名为:Target。

整个过程分为三个步骤:

  1. 连接Initiator和Target
  2. Initiator发送数据
  3. Target接收数据

连接Initiator和Target

两个模块通过Socket连接,下面是连接代码:

    Initiator i("Initiator"); // 创建发起者对象
    Target t("Target"); // 创建接收者对象

    i.initiator_socket(t.target_socket); // 使用Socket连接发起者和接收者

所以我们需要分别在Initiator和Target类中声明Socket,代码分别为:

    tlm_utils::simple_initiator_socket<Initiator> initiator_socket;
    tlm_utils::simple_target_socket<Target>  target_socket;

至此,两个模块的连接已经完成。

Initiator发送数据

下面我们开始发送事务。

我们需要在Initiator模块创建一个线程方法用来构建并发送事务:

    Initiator(sc_module_name name) : sc_module(name) {
        SC_THREAD(initiator_thread); // 注册线程方法
    }

    void
    initiator_thread() {
        while (true) {
            tlm::tlm_generic_payload *transaction_ptr = new tlm::tlm_generic_payload(); // 创建数据对象
            sc_time delay = SC_ZERO_TIME;

            initiator_socket->b_transport(*transaction_ptr, delay); // 开始传输

            gp_status = transaction_ptr->get_response_status(); // 获取接收者返回的状态

            if (gp_status == tlm::TLM_OK_RESPONSE) {
                std::cout << "TLM_OK_RESPONSE" << std::endl;
                wait(SC_ZERO_TIME);
            } else {
                std::cout << "TLM_OK_RESPONSE_NOT" << std::endl;
            }
        }
    }

至此,发送者的数据发送逻辑已经OK。

Target接收数据

下面添加Target接收数据的逻辑。

在上一小节的代码中,我们看到Initiator是通过下面的代码发送的数据:

            initiator_socket->b_transport(*transaction_ptr, delay); // 开始传输

上面代码中调用了b_transport方法,其实,这个方法的定义是在Target中,这样数据的传输通过方法调用就完成了。要传输的数据在transaction_ptr对象中。

所以,我们需要在Target中需要:

  1. 声明b_transport方法
  2. 注册b_transport方法
  3. 实现b_transport方法

声明b_transport方法

这里的方法名字可以根据业务逻辑换成其他名字。

    void
    b_transport(tlm::tlm_generic_payload  &payload, sc_core::sc_time &delay_time);

注册b_transport方法

    Target(sc_module_name name) : sc_module(name) {
        target_socket.register_b_transport(this, &Target::b_transport); // 注册我们自己定义的b_transport到target_socket中
    }

实现b_transport方法

    void
    b_transport(tlm::tlm_generic_payload  &payload, sc_core::sc_time &delay_time) {
        std::cout << "b_transport" << std::endl;

        payload.set_response_status(tlm::TLM_OK_RESPONSE); // 设置返回值

        return;
    }

至此,接收者就完成了数据的接收。

完整代码

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

class Initiator : public sc_module {
public:
    SC_HAS_PROCESS(Initiator);

    Initiator(sc_module_name name) : sc_module(name) {
        SC_THREAD(initiator_thread);
    }

    void
    initiator_thread() {
        while (true) {
            tlm::tlm_generic_payload *transaction_ptr = new tlm::tlm_generic_payload();
            sc_time delay = SC_ZERO_TIME;

            initiator_socket->b_transport(*transaction_ptr, delay);

            gp_status = transaction_ptr->get_response_status();

            if (gp_status == tlm::TLM_OK_RESPONSE) {
                std::cout << "TLM_OK_RESPONSE" << std::endl;
                wait(SC_ZERO_TIME);
            } else {
                std::cout << "TLM_OK_RESPONSE_NOT" << std::endl;
            }
        }
    }

    tlm_utils::simple_initiator_socket<Initiator> initiator_socket;

private:
    tlm::tlm_response_status gp_status;
};

class Target : public sc_module {
public:
    SC_HAS_PROCESS(Target);

    Target(sc_module_name name) : sc_module(name) {
        target_socket.register_b_transport(this, &Target::b_transport);
    }

    tlm_utils::simple_target_socket<Target>  target_socket;

private:
    void
    b_transport(tlm::tlm_generic_payload  &payload, sc_core::sc_time &delay_time) {
        std::cout << "b_transport" << std::endl;

        payload.set_response_status(tlm::TLM_OK_RESPONSE);

        return;
    }
};

int sc_main(int argc, char *argv[]) {
    Initiator i("Initiator");
    Target t("Target");

    i.initiator_socket(t.target_socket);

    sc_start();

    return 0;
}

参考

  • 《SoC设计方法与实现》第三版 郭炜、魏继增、郭筝等

  • 《TLM_2_0_presentation.pptx》

相关文章

  • TLM-事务级建模

    通过阅读本文,你将知道: 什么是TLM? 为什么使用TLM? 怎样使用TLM? 介绍 TLM的英文全称是Trans...

  • SystemC事务级建模03之DMI

    现在我们对以下情形进行事务级建模:GPU往显存(DDR)写一个32位的数据。 按照前面文章介绍的做法,我们可以在C...

  • SystemC事务级建模02之数据透传给子模块

    上一篇文章,介绍了SystemC事务级建模01之最简单的模块间数据传输[https://www.jianshu.c...

  • SystemC事务级建模01之最简单的模块间数据传输

    现在来看一个非常简单的情形:CPU传输数据给GPU。我们使用SystemC来对该情形进行事务级的建模。 CPU是事...

  • Verilog描述组合逻辑电路

    2018年7月18日:行为级建模以及分模块、分层次的结构化建模: 行为级建模:always,过程赋值语句,条件语句...

  • Verilog语法小结

    建模方式 数据流建模 行为级建模 结构化建模通过调用底层逻辑模块来进行电路描述,值得注意的是:底层模块中有参数时,...

  • hibernate和mybatis缓存

    相同: 1.都分为两级缓存,一级缓存和二级缓存,一级缓存都是session事务级别的,在一个事务中有效,事务执行完...

  • 数据仓库工具箱—处理维度变换

    首先,确定采购是建模的业务过程,采购事务包括采购请求、采购订单,托运通知、发票和付款等 多个采购事务来自不同的源系...

  • InnoDb与MyISAM引擎的区别

    事务处理 MyISAM不支持事务,而InnoDB是支持事务的。 MyISAM只支持表级锁,而InnoDB支持行级锁...

  • 数据仓库系列2-数据仓库建模介绍

    一.建模理论 1.1 ER实体模型 在信息系统中,将事务抽象为“实体”(Entity)、“属性”(Property...

网友评论

      本文标题:TLM-事务级建模

      本文链接:https://www.haomeiwen.com/subject/lilcfhtx.html