SystemC事务级建模03之DMI

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SystemC事务级建模03之DMI相关的知识,希望对你有一定的参考价值。

参考技术A 现在我们对以下情形进行事务级建模:GPU往显存(DDR)写一个32位的数据。

按照前面文章介绍的做法,我们可以在CPU发起一个事务,然后DDR接收并处理。但是,写显存的操作通常具有频繁和数据量大的特点,频繁的发起事务会降低仿真的执行效率。这里介绍一个比较高效的方法,

DMI,Direct Memory Interface,直接存储访问接口,即一个模块可以拥有另一个模块的存储的指针。

下面开始建模,

GPU是事务发起者,所有他有一个initiator socket;DDR是事务接收者,所以他有一个target socket,

给target socket注册一个获取存储指针的方法,

该方法返回存储指针,

注册一个访问DDR的进程方法,

在该方法中访问DDR,

在上面的方法中,往显存的0xf开始的地址写入了一个32位的数据:0x12345678

Hello TLM

前言

目标

了解TLM程序的基本过程。TLM的英文全称是Transaction Level Modeling,中文翻译为事务级建模。它是在SystemC基础上的一个扩展库。

功能描述

模块A向模块B发送一个“Hello”字符串

任务拆解

  1. 创建模块A和B
  2. 连接模块A和B
  3. 模块A发送“Hello”到B

创建模块A和B

包含头文件systemc.h

#include "systemc.h"

模块A

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

    A(sc_module_name name) : sc_module(name) {

    }
}

模块B

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

    B(sc_module_name name) : sc_module(name) {

    }
}

连接模块A和B 

任务拆解

  1. 添加TLM相关的头文件
  2. 模块A添加Initiator Socket
  3. 模块B添加Target Socket
  4. 连接模块A和B

添加TLM相关的头文件

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

模块A添加Initiator Socket

public:
    tlm_utils::simple_initiator_socket<A> socket;

模块B添加Target Socket

public:
    tlm_utils::simple_target_socket<B> socket;

连接模块A和B

int 
sc_main(int argc, char* argv[]) {
    A a("A"); // 实例化模块A
    B b("B"); // 实例化模块B

    a.socket(b.socket); // 连接模块A和B

    sc_start(10, SC_NS); // 仿真运行10纳秒

    return 0;
}

模块A发送“Hello”到B

任务拆解

  1. 模块A发送“Hello”
  2. 模块B接收“Hello”

模块A发送“Hello”

在类A的构造方法中注册一个用来发送数据的方法hello

A(sc_module_name name) : sc_module(name) {
    SC_THREAD(hello);
}

在类A中创建发送数据的方法hello

void hello() {
    tlm::tlm_generic_payload *payload = new tlm::tlm_generic_payload();
    assert(payload != nullptr);

    const char *data{"Hello"};
    payload->set_data_ptr((unsigned char *) data);

    sc_time delay = SC_ZERO_TIME;

    socket->b_transport(*payload, delay);

    delete payload;
}

模块B接收“Hello”

在类B的构造方法中注册一个用来接收数据的方法hello

B(sc_module_name name) : sc_module(name) {
    socket.register_b_transport(this, &B::hello);
}

在类B中创建接收数据的方法hello

void hello(tlm::tlm_generic_payload  &payload, sc_core::sc_time &delay_time) {
    const char *data = reinterpret_cast<const char *>(payload.get_data_ptr());
    std::cout << data << std::endl;
}

附录 

运行结果

        SystemC 2.3.3-Accellera --- Sep 20 2019 16:02:02
        Copyright (c) 1996-2018 by all Contributors,
        ALL RIGHTS RESERVED
Hello

Process finished with exit code 0

完整代码

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

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

    A(sc_module_name name) : sc_module(name) {
        SC_THREAD(hello);
    }

public:
    tlm_utils::simple_initiator_socket<A> socket;

private:
    void
    hello() {
        auto *payload = new tlm::tlm_generic_payload();
        assert(payload != nullptr);

        const char *data{"Hello"};
        payload->set_data_ptr((unsigned char *) data);

        sc_time delay = SC_ZERO_TIME;

        socket->b_transport(*payload, delay);

        delete payload;
    }
};

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

    B(sc_module_name name) : sc_module(name) {
        socket.register_b_transport(this, &B::hello);
    }

public:
    tlm_utils::simple_target_socket<B> socket;

private:
    void
    hello(tlm::tlm_generic_payload  &payload, sc_core::sc_time &delay_time) {
        const char *data = reinterpret_cast<const char *>(payload.get_data_ptr());
        std::cout << data << std::endl;
    }
};

int
sc_main(int argc, char* argv[]) {
    A a("A");
    B b("B");

    a.socket(b.socket);

    sc_start(10, SC_NS);

    return EXIT_SUCCESS;
}

参考资料

https://www.doulos.com/knowhow/systemc/tlm2/tutorial__1/

以上是关于SystemC事务级建模03之DMI的主要内容,如果未能解决你的问题,请参考以下文章

从验证的角度,systemverilog和systemc谁更合适

systemC全加器建模

systemC的同步时序建模

systemC三态建模

systemC的组合逻辑建模

jchdl进展 - 20180918