高級(jí)綜合工具StratusHLS學(xué)習(xí)筆記(3)

學(xué)習(xí)目標(biāo):

  • 學(xué)習(xí)如何使用Stratus IDE生成存儲(chǔ)器模型
  • 學(xué)習(xí)如何在代碼中使用存儲(chǔ)器模型

1.存儲(chǔ)器生成

存儲(chǔ)器生成使用Stratus IDE內(nèi)置的存儲(chǔ)器模型生成器,首先使用Stratus IDE打開(kāi)工程,在左側(cè)邊欄中打開(kāi)project選項(xiàng)卡,打開(kāi)libraries,右鍵Memories,選擇New Memory Library新建存儲(chǔ)器庫(kù),新建后可以在工程下發(fā)現(xiàn)同名文件夾

隨后,右擊新建的庫(kù)memlib選擇新建存儲(chǔ)器,可以打開(kāi)如下的界面進(jìn)行配置:

  • Memory name:存儲(chǔ)器名稱,使用存儲(chǔ)器時(shí)使用該名稱進(jìn)行調(diào)用
  • Word size:數(shù)據(jù)位寬,即每個(gè)地址存儲(chǔ)多少個(gè)bit
  • Number of words:地址數(shù)量,即有多少個(gè)word,存儲(chǔ)容量為Word size \times Number of wordsbit
  • Latency:從地址輸入到數(shù)據(jù)輸出消耗的時(shí)鐘周期數(shù)量
  • Setup time:通常意義的建立時(shí)間加保持時(shí)間,即控制信號(hào)需要在時(shí)鐘沿附近保持的長(zhǎng)度,不要寫(xiě)0。
  • Output delay:輸出延遲,即從時(shí)鐘沿或數(shù)據(jù)輸入到數(shù)據(jù)輸出的延遲時(shí)間,不要寫(xiě)0。
  • Area:面積,HLS將在綜合報(bào)告中使用該面積(如果填寫(xiě))

中間的Option部分可以選擇時(shí)序的方式,時(shí)序有以下幾種:

  • Allow chaining:使用左側(cè)的Setup time和Output delay計(jì)入延遲估算,在必要時(shí)插入寄存器
  • Disallow chaining:不計(jì)入延遲估算,等效于Setup time和Output delay都填寫(xiě)0
  • Registers at memories:強(qiáng)制插入寄存器

在這個(gè)頁(yè)面填寫(xiě)常規(guī)信息后,點(diǎn)擊上方的Port端口添加或編輯端口信息,該界面如下所示??梢酝ㄟ^(guò)編輯端口數(shù)量、選擇端口類型和編輯端口名稱,這些端口名稱將在波形中體現(xiàn)。

隨后點(diǎn)擊OK即可生成存儲(chǔ)器模型,生成的存儲(chǔ)器模型文件結(jié)構(gòu)如下所示:

在調(diào)用存儲(chǔ)器模型的文件中,需要引用頭文件memlib.h

2.存儲(chǔ)器使用

在高級(jí)綜合中使用存儲(chǔ)器通過(guò)wrapper和port構(gòu)成:

  • wrapper:存儲(chǔ)器模塊,通過(guò)調(diào)用該模塊生成存儲(chǔ)器
  • port:訪問(wèn)接口,在一個(gè)模塊中聲明一個(gè)存儲(chǔ)器的port并將該port和wrapper指針連接即可進(jìn)行存儲(chǔ)器訪問(wèn)

對(duì)于wrapper,其聲明方式為<memory name>::wrapper<ioConfig> * point,例如聲明一個(gè)名稱為RAM的wrapper,命名為m_mem如下所示:

RAM::wrapper<ioConfig> * m_mem;

定義后需要在構(gòu)造函數(shù)(SC_CTOR)中對(duì)其進(jìn)行實(shí)例化和綁定clk和rst端口,如下所示:

m_mem = new RAM::wrapper<ioConfig>("ram_wrapper");
m_mem->clk_rst(clk,rst);

對(duì)于port,聲明方式為<memory name>::port<ioConfig> port,例如聲明一個(gè)名稱為RAM的port,命名為ram_port如下所示:

RAM::port<ioConfig> ram_port;

同樣的,需要在構(gòu)造函數(shù)中綁定clk和rst端口:

ram_port.clk_rst(clk, rst);

并且需要在頂層將wrapper綁定到端口上,如下所示(m_dut為ram_port所屬的模塊):

m_dut->ram_port(*m_mem);

隨后可以使用類似數(shù)組的方式對(duì)存儲(chǔ)進(jìn)行訪問(wèn),訪問(wèn)方式如下所示:

read_data = ram_port[i] // 從i地址讀取數(shù)據(jù)
ram_port[i] = write_data // 將數(shù)據(jù)寫(xiě)入i地址

最后,需要在project.tcl中添加存儲(chǔ)器庫(kù),使用use_hls_lib指令,寫(xiě)法如下所示:

use_hls_lib "./memlib"

另外,對(duì)于一個(gè)存儲(chǔ)器模型,具有以下的參數(shù)可以方便代碼的編寫(xiě):

名稱 說(shuō)明
<memory name>::SIZE 存儲(chǔ)器word數(shù)量(Number of words)
<memory name>::address_width 存儲(chǔ)器地址位寬
<memory name>::data_width 存儲(chǔ)器數(shù)據(jù)位寬

3.實(shí)際工程

這里實(shí)現(xiàn)了一個(gè)將memory集成的加法器功能,功能為輸入一個(gè)數(shù)據(jù)i,從存儲(chǔ)器的地址i獲取數(shù)據(jù)并與i相加,加法部分模塊如下所示:

#ifndef __DUT_TEMPLATE__H
#define __DUT_TEMPLATE__H
#include "cynw_p2p.h"
#include "cynw_fifo.h"
#include "defines.h"
#include "memlib.h"
SC_MODULE(dut_template) {
public:

    cynw_p2p<DT, ioConfig>::in x_in;
    cynw_p2p<DT, ioConfig>::out y_out;
    RAM::port<ioConfig> ram_port;  // 存儲(chǔ)器訪問(wèn)接口
    
    sc_in_clk clk;
    sc_in<bool> rst;

    SC_CTOR(dut_template):
        x_in("x_in"),
        y_out("y_out"), 
        clk("clk"), rst("rst")
    {
        SC_CTHREAD(t, clk.pos());
        reset_signal_is(rst, 0);
        x_in.clk_rst(clk, rst);
        y_out.clk_rst(clk, rst);
        ram_port.clk_rst(clk, rst);
    }
    void t();
};

#endif
#include "dut_template.h"

void dut_template::t() {
    {
        HLS_DEFINE_PROTOCOL("reset");
        x_in.reset();
        y_out.reset();
        ram_port.reset();
        wait();
    }
    for (int i = 0; i < RAM::SIZE; ++i) // 存儲(chǔ)器初始化過(guò)程
    {
        ram_port[i] = i; // 寫(xiě)入存儲(chǔ)器
    }
    while(1) {
        HLS_PIPELINE_LOOP(SOFT_STALL, 1, "main_loop"); // 使用流水線
        DT x_val = x_in.get();
        sc_uint<RAM::address_width> addr = x_val;  
        sc_uint<RAM::data_width> ram_data = ram_port[addr];  // 從存儲(chǔ)器中讀取數(shù)據(jù)
        DT out_val = x_val + ram_data;
        y_out.put(out_val);
    }
}

頂層模塊如下所示:

#ifndef _DUI_MEM
#define _DUI_MEM
#include "cynw_p2p.h"
#include "cynw_fifo.h"
#include "defines.h"
#include "memlib.h"
#include "dut_template_wrap.h"

SC_MODULE(memory_acc_test) {
public:

    cynw_p2p<DT, ioConfig>::base_in x_in;
    cynw_p2p<DT, ioConfig>::base_out y_out;
    
    RAM::wrapper<ioConfig> * m_mem;  // 定義RAM的wrapper
    dut_template_wrapper *m_dut;
    
    sc_in_clk clk;
    sc_in<bool> rst;

    SC_CTOR(memory_acc_test):
        x_in("x_in"),
        y_out("y_out"), 
        clk("clk"), rst("rst")
    {
        m_mem = new RAM::wrapper<ioConfig>("ram_wrapper"); // 實(shí)例化
        m_mem->clk_rst(clk,rst); // 綁定端口

        m_dut = new dut_template_wrapper("m_dut");
        m_dut->clk(clk);
        m_dut->rst(rst);
        m_dut->x_in(x_in);
        m_dut->y_out(y_out);
        m_dut->ram_port(*m_mem); // 將wrapper綁定到port上
    }
};

#endif

對(duì)于以上工程,project.tcl中的庫(kù)部分如下所示:

set LIB_PATH "[get_install_path]/share/stratus/techlibs/GPDK045/gsclib045_svt_v4.4/gsclib045/timing"
set LIB_LEAF "slow_vdd1v2_basicCells.lib"

use_tech_lib    "$LIB_PATH/$LIB_LEAF"
use_hls_lib "./memlib"

除此之外,基本與之前的工程相同,進(jìn)行仿真,不帶流水線的結(jié)果如下所示:

帶流水線的結(jié)果如下所示:

可以發(fā)現(xiàn)流水線有三級(jí),分別是輸入地址、獲取輸出和計(jì)算和。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容