专栏首页文武兼修ing——机器学习与IC设计高级综合工具StratusHLS学习笔记(2)

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

学习目标为:

  • 如何使用高级综合生成流水线
  • 如何使用Stratus进行层次化设计

1.生成流水线

Stratus允许指定一个主循环(while(1))中的内容为流水线方式实现,即每个时钟周期均可以进入数据执行,需要在主循环开始时添加如下语句指定使用流水线实现:

HLS_PIPELINE_LOOP(<STALL_TYPE>, <cycle>, <name>);

上述指定该loop为流水线实现,具有三个参数,分别如下所示:

  • STALL_TYPE:实现类型,包括HARD_STALLSOFT_STALL两种
  • cycle:数据进入间隔,即“每隔多少个时钟周期可进入一个数据”,当cycle=1时表示每个周期均可进入数据
  • name:流水线配置名称,每个循环流水线名称不同即可

对于STALL_TYPE中的两种,具有以下的区别:

  • HARD_STALL:当流水线的某一级阻塞时,整条流水线停止运行
  • SOFT_STALL:当流水线的某一级阻塞时,仅阻塞级之前的流水线停止运行,阻塞级之后的流水线继续运行

对于要生成流水线的代码片(循环体),Stratus有以下的要求:

  • 循环展开(Nested Loops):循环体中仅可以嵌套次数指定的循环,且被指定生成流水线的循环要么为无限循环,要么为指定次数循环
  • 数据依赖(Data Dependencies):需要保证每一级需要的数据在运行这一级之前已经生成,即数据流向固定向前,不存在反向数据流(产生数据冲突),若发生这种情况Stratus会报错:Unable to satisfy HLS_HLS_PIPELINE_LOOP directive "main_pipeline",possibly because of a statement in this line.
  • 端口访问(Port Access Conflicts):对于端口的访问需要谨慎,需要避免连续两个周期访问一个端口的写法,因为会产生对端口的访问冲突(前一次进入loop和后一次loop在同一周期需要访问同一个接口),这种情况会报出Warning:Pipelining forces multiple assignments to output data_out
  • 非平衡流水线(Unbalanced Protocol Blocks):避免在展开为流水线的循环中使用消耗时钟周期不同的条件判断。即若在循环中使用if-else语句,两个代码块消耗的时钟周期必须一致。
  • 循环跳出(Conditional Exits in Pipelined Loops):允许使用break语句跳出循环,但用于判断是否跳出循环的逻辑消耗的时间必须少于数据进入间隔时钟周期

学习过程使用上一次使用的+1功能电路,将其执行线程改为以下按流水线展开:

void dut_template::t() {
    {
        HLS_DEFINE_PROTOCOL("reset");
        x_in.reset();
        y_out.reset();
        wait();
    }
    while(1) {
        // HLS_PIPELINE_LOOP(HARD_STALL, 1, "main_loop");
        HLS_PIPELINE_LOOP(SOFT_STALL, 1, "main_loop");
        DT x_val = x_in.get();
        DT out_val = x_val + 1;
        y_out.put(out_val);
    }
}

这里使用了输入间隔为1个周期(每个周期均可输入)的SOFT_STALL形式的流水线。

2.层次化设计

为了观察流水线功能,这次将两个+1功能模块dut_template连在一起进行仿真,顶层为pipeline_test,代码如下所所示:

#ifndef _DUT_PIPE
#define _DUT_PIPE

#include "cynw_p2p.h"
#include "cynw_fifo.h"
#include "defines.h"
#include "dut_template_wrap.h"

SC_MODULE(pipeline_test) {
public:
    cynw_p2p<DT, ioConfig>::base_in x_in;
    cynw_p2p<DT, ioConfig>::base_out y_out;
    cynw_p2p<DT, ioConfig> tmp;
    sc_in_clk clk;
    sc_in<bool> rst;

    dut_template_wrapper *ut0;
    dut_template_wrapper *ut1;

    SC_CTOR(pipeline_test):
        x_in("x_in"),y_out("y_out"),tmp("tmp"),
        clk("clk"),rst("rst") {

        ut0 = new dut_template_wrapper("ut0");
        ut0->clk(clk);
        ut0->rst(rst);
        ut0->x_in(x_in);
        ut0->y_out(tmp);

        ut1 = new dut_template_wrapper("ut1");
        ut1->clk(clk);
        ut1->rst(rst);
        ut1->x_in(tmp);
        ut1->y_out(y_out);
    }   

    // void t();  不可调用函数进行连线!!!

};

#endif

首先关注使用的p2p接口如下所示:

    cynw_p2p<DT, ioConfig>::base_in x_in;
    cynw_p2p<DT, ioConfig>::base_out y_out;

需要注意的是本次使用了base_inbase_out而不是inout(参考笔记1),因为这两个端口的目的仅仅为连接使用,相当于连线,因此不需要使用inout,也不需要指定时钟与复位信号。随后关注调用部分:

    dut_template_wrapper *ut0;
    dut_template_wrapper *ut1;

这里的调用方式为调用dut_template_wrapper而不是dut_template,这是Stratus的区别,若要在高级综合中保留层次结构,则需要在这里调用wrapper而不是本身,对应的,也需要在tcl中指定子模块dut_template为待综合模块。最后一点需要注意的是,SC_CTOR中连线部分需要在本函数中编写,不可像system中一样调用函数进行连线,否则会在仿真过程中产生问题。该设计对应的project.tcl如下所示:

...
use_tech_lib    "$LIB_PATH/$LIB_LEAF"


set_attr clock_period           10.0
set_attr message_detail         3
set_attr default_input_delay    0.1

set_attr cc_options             "  -g --std=c++0x"
enable_waveform_logging -vcd
set_attr end_of_sim_command "make saySimPassed"

define_system_module basic_ut/main.cpp
define_system_module basic_ut/system.cpp
define_system_module basic_ut/tb.cpp

define_hls_module pipeline_test dut_module/pipeline_test.cpp 
define_hls_module dut_template dut_module/dut_template.cpp # 子模块也需要指定为待综合模块

define_io_config * TLM
define_io_config * PIN

define_hls_config pipeline_test BASIC
define_hls_config dut_template BASIC # 子模块也需要指定综合等级

define_sim_config T -io_config TLM
define_sim_config B -io_config PIN

define_sim_config H {pipeline_test RTL_V BASIC}

3.仿真结果

仿真结束后使用verdi查看波形,未添加流水线的波形如下所示:

可以发现这种情况下每两个周期才能输入一个数据,添加了流水线的波形如下所示:

添加了流水线展开后,可以发现每个时钟周期均可输入新的数据。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 抽象数据结构与表抽象数据结构表

    抽象数据结构 抽象数据结构(ADT)是一些操作的集合,集合了一些必要且重用性高的操作,这些操作在一个项目中只被编写一次。抽象数据结构只定义操作的存在,并不定义操...

    月见樽
  • 关于空难数据集的探索分析导入数据集伤亡分析机型处理时间分析

    写在前面: 这是我见过的最严肃的数据集,几乎每一行数据背后都是生命和鲜血的代价。这次探索分析并不妄图说明什么,仅仅是对数据处理能力的锻炼。因此本次的探索分析...

    月见樽
  • 栈与栈的实现栈栈的基本操作栈的实现

    栈 栈是一种基础的数据结构,只从一端读写数据。基本特点就”后进先出“,例如顺序入栈1,2,3,4,5,再顺序出栈是5,4,3,2,1 栈的基本操作 栈的基本操作...

    月见樽
  • 一篇文章教你如何捕获前端错误

    JavaScript代码在用户浏览器中执行时,由于一些边界情况、本地环境的不可控等因素,可能会存在js运行时错误。

    2020labs小助手
  • 一篇文章教你如何捕获前端错误

    随着前端页面承载功能越来越多,用户本地浏览器环境也错综复杂,因此即使有完善的测试,我们也无法保证上线的代码不会出错。在这种场景下,前端页面的监控就成了各个web...

    杨振涛
  • MySQL 快速删除大量数据(千万级别)的几种实践方案——附源码

     笔者最近工作中遇见一个性能瓶颈问题,MySQL表,每天大概新增776万条记录,存储周期为7天,超过7天的数据需要在新增记录前老化。连续运行9天以后,删除一天的...

    NaughtyCat
  • Shadow Brokers决定退隐江湖,并放出方程式免费入侵工具

    去年8月Shadow Brokers入侵了NSA的方程式小组,获取了部分软件和黑客工具——这件事大概足以让Shadow Brokers名垂青史了,虽然有关Sha...

    FB客服
  • 在 Java 的反射中,Class.forName 和 ClassLoader 的区别

    最近在面试过程中有被问到,在Java反射中Class.forName()加载类和使用ClassLoader加载类的区别。当时没有想出来后来自己研究了一下就写下来...

    芋道源码
  • 2017前端技术大盘点!

    腾讯NEXT学位
  • 商业价值:苹果iTV,再一次改变世界?

      苹果(Apple)公司打算进军智能电视领域,这在行业里已经不是秘密,有关苹果智能电视的消息也是不绝于耳,结合苹果产品线的命名规则,苹果智能 电视基本上就是i...

    阳光岛主

扫码关注云+社区

领取腾讯云代金券