高级综合工具StratusHLS学习笔记(3)

学习目标:

  • 学习如何使用Stratus IDE生成存储器模型
  • 学习如何在代码中使用存储器模型

1.存储器生成

存储器生成使用Stratus IDE内置的存储器模型生成器,首先使用Stratus IDE打开工程,在左侧边栏中打开project选项卡,打开libraries,右键Memories,选择New Memory Library新建存储器库,新建后可以在工程下发现同名文件夹

随后,右击新建的库memlib选择新建存储器,可以打开如下的界面进行配置:

  • Memory name:存储器名称,使用存储器时使用该名称进行调用
  • Word size:数据位宽,即每个地址存储多少个bit
  • Number of words:地址数量,即有多少个word,存储容量为Word size \times Number of wordsbit
  • Latency:从地址输入到数据输出消耗的时钟周期数量
  • Setup time:通常意义的建立时间加保持时间,即控制信号需要在时钟沿附近保持的长度,不要写0。
  • Output delay:输出延迟,即从时钟沿或数据输入到数据输出的延迟时间,不要写0。
  • Area:面积,HLS将在综合报告中使用该面积(如果填写)

中间的Option部分可以选择时序的方式,时序有以下几种:

  • Allow chaining:使用左侧的Setup time和Output delay计入延迟估算,在必要时插入寄存器
  • Disallow chaining:不计入延迟估算,等效于Setup time和Output delay都填写0
  • Registers at memories:强制插入寄存器

在这个页面填写常规信息后,点击上方的Port端口添加或编辑端口信息,该界面如下所示。可以通过编辑端口数量、选择端口类型和编辑端口名称,这些端口名称将在波形中体现。

随后点击OK即可生成存储器模型,生成的存储器模型文件结构如下所示:

在调用存储器模型的文件中,需要引用头文件memlib.h

2.存储器使用

在高级综合中使用存储器通过wrapper和port构成:

  • wrapper:存储器模块,通过调用该模块生成存储器
  • port:访问接口,在一个模块中声明一个存储器的port并将该port和wrapper指针连接即可进行存储器访问

对于wrapper,其声明方式为<memory name>::wrapper<ioConfig> * point,例如声明一个名称为RAM的wrapper,命名为m_mem如下所示:

RAM::wrapper<ioConfig> * m_mem;

定义后需要在构造函数(SC_CTOR)中对其进行实例化和绑定clk和rst端口,如下所示:

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

对于port,声明方式为<memory name>::port<ioConfig> port,例如声明一个名称为RAM的port,命名为ram_port如下所示:

RAM::port<ioConfig> ram_port;

同样的,需要在构造函数中绑定clk和rst端口:

ram_port.clk_rst(clk, rst);

并且需要在顶层将wrapper绑定到端口上,如下所示(m_dut为ram_port所属的模块):

m_dut->ram_port(*m_mem);

随后可以使用类似数组的方式对存储进行访问,访问方式如下所示:

read_data = ram_port[i] // 从i地址读取数据
ram_port[i] = write_data // 将数据写入i地址

最后,需要在project.tcl中添加存储器库,使用use_hls_lib指令,写法如下所示:

use_hls_lib "./memlib"

另外,对于一个存储器模型,具有以下的参数可以方便代码的编写:

名称 说明
<memory name>::SIZE 存储器word数量(Number of words)
<memory name>::address_width 存储器地址位宽
<memory name>::data_width 存储器数据位宽

3.实际工程

这里实现了一个将memory集成的加法器功能,功能为输入一个数据i,从存储器的地址i获取数据并与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;  // 存储器访问接口
    
    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) // 存储器初始化过程
    {
        ram_port[i] = i; // 写入存储器
    }
    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];  // 从存储器中读取数据
        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"); // 实例化
        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

对于以上工程,project.tcl中的库部分如下所示:

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"

除此之外,基本与之前的工程相同,进行仿真,不带流水线的结果如下所示:

带流水线的结果如下所示:

可以发现流水线有三级,分别是输入地址、获取输出和计算和。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容