使用SystemC做RTL和C/C++ 的联合仿真

作者:Jackie Gao,AMD工程师;来源:AMD开发者社区

前言

当FPGA开发者需要做RTL和C/C++联合仿真的时候,一些常用的方法包括使用MicroBlaze软核,或者使用QEMU仿真ZYNQ的PS部分。

此教程介绍一种通过SystemC做RTL/C/C++联合仿真的方法,所有的BFMs(Bus Function Module)都是通过SystemC完成。

文中所涉及的所有代码均在Vivado和Modelsim/Questasim上做了验证。

简介

SystemC基础
SystemC是标准C/C++语言的延伸,即可以描述硬件,也具有C/C++的特性。这个特点让SystemC特别适合做系统级别的设计、建模以及验证。

SystemC是周期精确的,其主要的组包括

  • 信号,用来连接两个或者多个模块,提供了传输系统间传输与交流数据的通道。
  • 端口,模块的输入、输出接口。
  • 模块,类似VHDL里面的Entity和敏感列表。
  • 主函数(sc_main),与C/C++一致,函数的入口。
  •  
    在SystemC中实例化一个RTL的实体

    在SystemC中实例化一个RTL的实体很直观,你只需要为其RTL实体手写一个对应的SystemC的外部模块,之后这个模块就可以在SystemC的环境被被其它类调用。

    下面将举例说明如果在SystemC中构建一个VHDL的实体

    示例 VHDL的设计
    entity counter is
    port(
    clk : in std_logic;
    reset: in std_logic;
    count: std_logic_vector(7 downto 0)
    );
    end;

    architecture rtl of counter is

    end rtl;

    对应的SystemC模块
    class counter : public sc_foreign_module {
    public:
    sc_in clk;
    sc_in reset;
    sc_out > count;
    counter(sc_module_name nm) : sc_foreign_module(nm, "work.counter"),
    clk("clk"),
    reset("reset"),
    count("count") {
    }
    };

    需要注意的是,你还可以通过ModelSim/QuestaSim提供的scgenmod工具自动生成VHDL、Verilog对应的SystemC的模块。

    用SystemC设计BFMs

    因为SytemC是通过时钟驱动的, 在SystemC里面写BFMs就变得很直接
    在SystemC中实现AXI4-Lite的读操作可以如下,
    u32 Xil_In32(UINTPTR Addr) {
    u32 data;

    if (aresetn_i.read() == SC_LOGIC_0) {
    awaddr.write(0);
    awvalid.write(SC_LOGIC_0);
    wdata.write(0);
    wvalid.write(SC_LOGIC_0);
    bready.write(SC_LOGIC_1);
    araddr.write(0);
    arvalid.write(SC_LOGIC_0);
    rready.write(SC_LOGIC_1);
    }
    else {

    sc_core::wait(aclk_i.posedge_event());

    araddr.write(addr);
    arvalid.write(SC_LOGIC_1);

    uint32_t num_clocks = 0;
    while (arready.read() != SC_LOGIC_1) {
    sc_core::wait(aclk_i.posedge_event());
    num_clocks++;

    if (num_clocks == m_timeout_clks) {
    arvalid.write(SC_LOGIC_0);
    return -1;
    }
    }

    arvalid.write(SC_LOGIC_0);

    num_clocks = 0;
    while (rvalid.read() != SC_LOGIC_1) {
    sc_core::wait(aclk_i.posedge_event());
    num_clocks++;

    if (num_clocks == m_timeout_clks) {
    return -1;
    }
    }

    data = rdata.read().to_uint();
    }

    return data;
    }

    在SystemC中实现AXI4-Lite的写操作可以如下
    void Xil_Out32(UINTPTR Addr, u32 Value) {

    if (aresetn_i.read() == SC_LOGIC_0) {
    awaddr.write(0);
    awvalid.write(SC_LOGIC_0);
    wdata.write(0);
    wvalid.write(SC_LOGIC_0);
    bready.write(SC_LOGIC_1);
    araddr.write(0);
    arvalid.write(SC_LOGIC_0);
    rready.write(SC_LOGIC_1);
    }
    else {
    sc_core::wait(aclk_i.posedge_event());

    awaddr.write(Addr);
    awvalid.write(SC_LOGIC_1);
    wdata.write(Value);
    wvalid.write(SC_LOGIC_1);

    uint32_t num_clocks = 0;
    bool m_awready = false;
    bool m_wready = false;
    while ((!m_awready) || (!m_wready)) {
    sc_core::wait(aclk_i.posedge_event());

    if (awready.read() == SC_LOGIC_1) {
    m_awready.write(true);
    awvalid.write(SC_LOGIC_0);
    }

    if (wready.read() == SC_LOGIC_1) {
    m_wready.write(true);
    wvalid.write(SC_LOGIC_0);
    }

    num_clocks++;
    if (num_clocks == m_timeout_clks) {
    awvalid.write(SC_LOGIC_0);
    wvalid.write(SC_LOGIC_0);
    return;
    }
    }

    num_clocks = 0;
    while (bvalid.read() != SC_LOGIC_1) {
    sc_core::wait(aclk_i.posedge_event());
    num_clocks++;
    if (num_clocks == m_timeout_clks) {
    return;
    }
    }
    }
    }

    系统设计框图

    完整的系统框图如下所示。清楚的展示是SystemC /DUT之间的调用关系。

    软件需求

    在教程中,需要以下设计工具

  • Vivado Design Suite
  • Modelsim/Questasim
  • 预先编译的Vivado IP的仿真库
  •  
    示例工程

  • 打开Vivado,创建一个空的工程。
  • 在Vivado里面,打开Create and Package New IP wizard,选择Create a new AXI4 peripheral,之后create an AXI4 peripheral using the default template。
  • 使用scgenmod指令创建SystemC的外部模块。
  • 重写xil_io.c文件,其实现是通过上面介绍的SystemC完成BFMs的方法。
  • 编译,连接。最后运行vsim。
  •  
    测试结果

    以下是Questasim的仿真结果,通过打印的信息可以看到 RTL和C/C++的联合仿真功能的运行。
    # vsim -t 1ps xil_defaultlib.Env xil_defaultlib.glbl -onfinish stop -L xpm -L unisims_ver -L secureip -L unimacro_ver -L xil_defaultlib -l simlog.txt -assertdebug
    # ******************************
    # * User Peripheral Self Test
    # ******************************
    # User logic slave module test...
    #
    # - slave register write/read passed
    #
    # ** Note: (vsim-6574) SystemC simulation stopped by user.

    最新文章

    最新文章