接口的返回值,入口参数,都是需要用pragma约束的。

首先来回顾一下接口。
a clock and reset have been added to the design:
ap_clk and ap_rst.
A block-level I/O protocol has been added to control the RTL design: ports
ap_start, ap_idle and ap_done, ap_ready.

The default block-level I/O protocol is called
ap_ctrl_hs.
另一个常用的选项是ap_ctrl_none。
When the interface protocol ap_ctrl_none is used, no block-level I/O protocols areadded to the design. The only ports are those for the clock, reset and the data ports.

+++++++++++++++++++++++++++++++++++
来看第一个例子。

int adders(int in1, int in2, int in3) {
#pragma HLS INTERFACE ap_ctrl_none port=return#pragma HLS INTERFACE ap_none port=in3
#pragma HLS INTERFACE ap_none port=in2
#pragma HLS INTERFACE ap_none port=in1int sum;sum = in1 + in2 + in3;return sum;}

ap_ctrl接口的作用是和其他模块握手,告诉其他模块当前模块的FSM的状态。

#pragma HLS INTERFACE ap_ctrl_none port=return

ap_ctrl接口,是约束到return上的。

再来看看port-level。
对于纯输入信号,常用的是ap_none。
ap_none is the default I/O protocol for these C arguments.

#pragma HLS INTERFACE ap_none port=in1

表示当FSM运行在start for input状态时,会从port拍入数据。
这里,参数是以形参实体变量形式给出的,在实现时,被实现为一个single direction的input port。
模块内部可以配置一个reg。

这个例子中,模块内例化了两个加法处理器,最后将结果传输到return。

++++++++++++++++++++++++++++++++++++++++
第二个例子

void adders_io(int in1, int in2, int *in_out1) {*in_out1 = in1 + in2 + *in_out1;
}

第三个参数是形参指针,也就是说,它具备双向inout的能力,
返回值return是void的,也就是说,return可以不提供data port。

对于in1和in2,它们仍然是纯形参实体变量,input port。
可以选择ap_none,则只有input data port,没有任何input handshake port。这是默认选项,所以可以不加约束也是一样的效果。
也可以选择ap_stable,它类似于ap_none,区别在于,被认为是一个正常操作期间是恒定的值,它不是在FSM的start for input 状态读取,而是在模块复位后,在input after rst状态读取的。
所以,如果要使ap_stable的值生效,需要reset模块。通常用于配置常数参数。

也可以选择ap_vld,由前级模块发出有效信号。

#pragma HLS INTERFACE ap_vld port=in1

如果想向前级传递确认信号,可以选择ap_ack,

#pragma HLS INTERFACE ap_ack port=in2

对于inout的形参指针,可以选择ap_hs,那么这个接口具有最完备的握手信号集,支持双向传输。
既有input lane 还有output lane,两套data port。
in_out_i, in_out_i_ap_vld, in_out_i_ack,
in_out_o, in_out_o_ap_vld, in_out_o_ack,

在本例中,可以看出,它作为inout在使用,所以它的ap_hs握手,会有一个ovld来指示输出有效数据。

#pragma HLS INTERFACE ap_hs port=in_out1

本例中,虽然return端口是void,但是ap_ctrl_hs是默认模式,所以仍然会有
ap_start, ap_idle and ap_done, ap_ready.

++++++++++++++++++++++++++++++++++++++
第三个例子。

void array_io (dout_t d_o[N], din_t d_i[N]) {int i, rem;// Store accumulated datastatic dacc_t acc[CHANNELS];dacc_t temp;// Accumulate each channelFor_Loop: for (i=0;i<N;i++) {rem=i%CHANNELS;temp = acc[rem] + d_i[i];acc[rem] = temp;d_o[i] = acc[rem];}
}

两个形参数组,也即形参指针。
模块内部定义了一个static array,这将被实现为BRAM。
数组是一个一维的向量,所以,需要在一个for循环里,对一维向量的每个元素进行逐个处理。

数组在HLS中,默认被实现为SPRAM。
所以,形参数组,被默认实现为RAM port,因为假设的是RAM存在于模块外部。
这时,默认使用的接口约束是ap_memory。
RAM port理论上是有 read channel和write channel的。
在本例中,d_o这个RAM port,只被用来write,所以,它的read channel被省去了。
只有d_o_d0,d_o_addr0,d_o_we0,d_o_ce0。
在本例中,d_i这个RAM_port,只被用来read,所以,它的write channel被省去了。
只有d_i_q0,d_i_addr0,d_i_ce0.

the rolled for-loop ensure only one data sample can be read (or written) at a time.
for循环默认被理解为一个顺序执行的FSM,如果要提高并行度,就需要UNROLL FOR LOOP。

#pragma HLS UNROLL

被UNROLL后,同时访问RAM的需求就来了,需要给RAM多增加访问端口。

给d_i端口添加资源约束,

#pragma HLS RESOURCE variable=d_i core=RAM_2P_BRAM

注意,这里给端口添加资源约束,并不是模块内将端口用此资源来实现,而是说,假定模块外部,连接到此端口上的资源类型。
有,
d_i_q0,d_i_addr0,d_i_ce0,
d_i_q1,d_i_addr1,d_i_ce1,

给d_o端口添加接口约束,

#pragma HLS INTERFACE ap_fifo port=d_o

这里,将d_o端口约束为ap_fifo,并不是模块内将端口用一个FIFO来实现,而是说,假定模块外部,连接到此端口上的,是一个FIFO,所以d_o需要呈现为一个ap_fifo接口。
d_o_din, d_o_write, d_o_full_n,

这里,说明一点,形参数组,本质上是形参指针,可以被实现为RAM接口,也可以实现为FIFO接口。

之前使用SPRAM时,II是66,使用了DPRAM时,II是33,II降了一半,
要想更大程度的降低II,还需要继续增大RAM的访问接口,

给d_o端口,继续添加约束,添加数组分割约束,

#pragma HLS ARRAY_PARTITION variable=d_o block factor=4 dim=1

这个约束,使得d_o端口,将被分割成多个子端口,每个子端口,都被实现为FIFO接口。
d_o_din0, d_o_write0, d_o_full_n0,
d_o_din1, d_o_write1, d_o_full_n1,
d_o_din2, d_o_write2, d_o_full_n2,
d_o_din3, d_o_write3, d_o_full_n3,

继续添加约束,
给d_i端口,添加数组分割约束,

#pragma HLS ARRAY_PARTITION variable=d_i block factor=2 dim=1

这个约束,使得d_o端口,将被分割成多个子端口,每个子端口,都被实现为DPRAM接口。
d_i_0_q0,d_i_0_addr0,d_i_0_ce0,
d_i_0_q1,d_i_0_addr1,d_i_0_ce1,
d_i_1_q0,d_i_1_addr0,d_i_1_ce0,
d_i_1_q1,d_i_1_addr1,d_i_1_ce1,

现在,II被降到了17,
如果还想最大程度的降低II,可以考虑complete模式的数组分割约束。

#pragma HLS ARRAY_PARTITION variable=d_o complete dim=1
#pragma HLS ARRAY_PARTITION variable=d_i complete dim=1
#pragma HLS ARRAY_PARTITION variable=acc complete dim=1

d_i被完全分割时,就需要去掉之前的资源约束了,删除RAM_2p_BRAM的资源约束。
通常也是不推荐使用资源约束的。

此时,II降低到了1。
注意,谨慎使用资源约束。

可以看到,综合后,d_o数组每个元素都有一套自己的FIFO接口。

注意,HLS在约束时,有两个概念,一个是variable,一个是port,在模块内部,大多数情况下,去识别variable,只有在top层的模块,会有从形参variable衍生出的同名的port,这些portname,最终会以端口prefix前缀的形式存在。

+++++++++++++++++++++++++++++++++++++++++
第四个例子。

void axi_interfaces (dout_t d_o[N], din_t d_i[N]) {int i, rem;// Store accumulated datastatic dacc_t acc[CHANNELS];// Accumulate each channelFor_Loop: for (i=0;i<N;i++) {rem=i%CHANNELS;acc[rem] = acc[rem] + d_i[i];d_o[i] = acc[rem];}
}

首先,这里面有for循环,为了提高效率,首先要将for循环UNROLL。

#pragma HLS UNROLL factor=8

展平成8倍面积。
Select a factor of 8 to partially unroll the for-loop. This is equivalent to re-writing the C code to execute eight copies of the loop-body in each iteration of the loop (where the new loop only executes for 4 iterations in total, not 32,now i+=8).

然后,为了增加访问接口,进行数组分割,

#pragma HLS ARRAY_PARTITION variable=d_o cyclic factor=8 dim=1

这个约束,将d_o形参数组,分割成8个子数组,这次是以cyclic交替形式分割的。这也是实现为stream的推荐分割方式。

然后,为d_o形参数组,约束接口形式。将d_o形参数组,对外的接口形式,约束为axis形式。

#pragma HLS INTERFACE axis register both port=d_o

同样的,为d_i增加数组分割约束和接口约束。

#pragma HLS ARRAY_PARTITION variable=d_i cyclic factor=8 dim=1
#pragma HLS INTERFACE axis register both port=d_i

When the report opens in the information pane, confirm both d_i and d_o are implemented as eight separate AXI4-Stream ports.
d_o_0_AXIS,d_o_1_AXIS,d_o_2_AXIS,d_o_3_AXIS,
d_o_4_AXIS,d_o_5_AXIS,d_o_6_AXIS,d_o_7_AXIS,
d_i_0_AXIS,d_i_1_AXIS,d_i_2_AXIS,d_i_3_AXIS,
d_i_4_AXIS,d_i_5_AXIS,d_i_6_AXIS,d_i_7_AXIS,

此时的II,降低为9,
为了进一步降低II,还要继续对for循环优化,
虽然UNROLL了循环体,使其平铺了8路处理机,但是处理机内部的,仍然是顺序执行的,
在第一个操作步处理完后,只能等待其他后续操作步处理完,并再一次调度到首个操作步时,才能再次接收输入。
这种情况下,可以使用pipeline优化for循环。
使用了流水线约束后,循环体处理机在被综合时,不再是被综合成一个顺序FSM,分别调度每个操作步,而是将每个操作步综合成独立的处理机,每个操作步拥有自己的FSM。操作步之间,通过握手及FIFO实现同步。

#pragma HLS PIPELINE  rewind

指定II的目标是1,也可以不指定,因为默认II就是1.
rewind使得流水线连续向前运转。无间隔执行。
When the top-level of the design is a loop, you can use the pipeline rewind option.
when implemented in RTL, this loop runs continuously (with no end of function and function re-start cycles).
一般场合中,rewind并不常用。因为通常模块都需要re-start。

此时的II,降为4,

一次完整的数组输入,是32个数据,分为8个端口,共需要4次才能完整输入全部数据。

+++++++++++++++++++++++++++++++++++++++++
第五个例子。

void axi_interfaces (dout_t d_o[N], din_t d_i[N]) {int i, rem;// Store accumulated datastatic dacc_t acc[CHANNELS];// Accumulate each channelFor_Loop: for (i=0;i<N;i++) {rem=i%CHANNELS;acc[rem] = acc[rem] + d_i[i];d_o[i] = acc[rem];}
}

首先,这里面有for循环,为了提高效率,首先要将for循环UNROLL。

#pragma HLS UNROLL factor=8

展平成8倍面积。
Select a factor of 8 to partially unroll the for-loop. This is equivalent to re-writing the C code to execute eight copies of the loop-body in each iteration of the loop (where the new loop only executes for 4 iterations in total, not 32,now i+=8).

再使用pipeline优化for循环。

#pragma HLS PIPELINE  rewind

然后,为了增加访问接口,进行数组分割,

#pragma HLS ARRAY_PARTITION variable=d_i cyclic factor=8 dim=1
#pragma HLS ARRAY_PARTITION variable=d_o cyclic factor=8 dim=1

将return的访问,以及ap_ctrl的访问,收纳到s_axi_lite总线中去,ap_ctrl和return,不再以IO端口的形式存在,而是位于s_axilite总线中的register。

#pragma HLS INTERFACE s_axilite port=return

HLS第二十八课(UG871,接口综合)相关推荐

  1. JAVA 基础 / 第二十八课:接口与继承 / 如何设计JAVA的接口?

    2018-03-19 在设计LOL的时候,进攻类英雄有两种,一种是进行物理系攻击,一种是进行魔法系攻击.这时候,就可以使用接口来实现这个效果.  接口就像是一种约定,我们约定某些英雄是物理系英雄,那么 ...

  2. NeHe OpenGL第二十八课:贝塞尔曲面

    NeHe OpenGL第二十八课:贝塞尔曲面 贝塞尔曲面: 这是一课关于数学运算的,没有别的内容了.来,有信心就看看它吧. 贝塞尔曲面 作者: David Nikdel ( ogapo@ithink. ...

  3. Java调用大数据接口,学习Hadoop第二十八课(java通过调用接口来操作HBase)

    上节课我们一起简单学习了HBase的一些理论,这节课我们一起学习用java调HBase的接口来操作HBase. 我们首先建一个工程,这里我们还用原始的新建一个lib包.然后我们把下载的hbase-0. ...

  4. JAVA 基础 / 第二十九课:接口与继承 / JAVA中的对象转型

    2018-03-19 一.明确引用类型与对象类型的概念 引用类型与对象类型的概念 在这个例子里,有一个对象 new ADHero(), 同时也有一个引用ad 对象是有类型的, 是ADHero 引用也是 ...

  5. 【问链财经-区块链基础知识系列】 第二十八课 区块链如何助力万亿规模的供应链金融蛋糕

    编者按:我国经济已由高速增长阶段转向高质量发展阶段.赊销项下的账期占压给实体经济的发展带了很大的束缚,国家近两年来多次发文鼓励和推动应收账款融资的发展.但传统应收类供应链金融模式,如保理.应收账款质押 ...

  6. java 实现类转接口_JAVA 基础 / 第二十九课:接口与继承 / JAVA中的对象转型

    2018-03-19 一.明确引用类型与对象类型的概念 引用类型与对象类型的概念 在这个例子里,有一个对象 new ADHero(), 同时也有一个引用ad 对象是有类型的, 是ADHero 引用也是 ...

  7. 第二十八课:focusin与focusout,submit,oninput事件的修复

    focusin与focusout 这两个事件是IE的私有实现,能冒泡,它代表获得焦点或失去焦点的事件.现在只有Firefox不支持focusin,focusout事件.其实另外两个事件focus和bl ...

  8. 新版标准日本语中级_第二十八课

    语法   1. いや,~:いや是否定的表达方式,与いいえ类似,但いや的语气轻微.也用于否定自己刚刚说出的话.   いえ也一样,但いえ比较有礼貌,男女都可以使用,而いや多为男性使用.此外,除了否定还可以 ...

  9. JAVA 基础 / 第二十九课:接口与继承 / JAVA 重写方法和多态

    2018-03-19 子类可以继承父类的对象方法.在继承后,重复提供该方法,就叫做方法的重写:又叫覆盖 override 1.父类Item 父类Item有一个方法,叫做effect package p ...

最新文章

  1. systemverilog硬件设计及建模_3D建模和渲染都吃什么硬件?设计师该如何选购电脑...
  2. python 修改文件名_Python 批量修改文件名
  3. 当你收到面试通知后,如下的准备可以大大提升面试成功率
  4. 华为服务器维护岗位,服务器日常维护工作
  5. 身份证被盗用申请信用卡,造成逾期被催收怎么办?
  6. 设计灵感|总有一款对话界面符合你的应用风格!
  7. [ES6系列-01]Class:面向对象的“新仇旧恨”
  8. 6自由度机械臂的建立
  9. 【02】Java进阶:17-单例设计模式、多例设计模式、枚举、工厂设计模式、Lombok
  10. 网站CDN加速是什么? 看完这篇你就明白了!
  11. 服务器网卡支持热插拔吗,HDMI接口能“热插拔”吗?这篇告诉你
  12. shader篇-渲染纹理
  13. 驱动器控制模式功能简介(CSP,CSV,CST等)
  14. python显示日历_Python 程序显示日历
  15. Java实现微信小程序校验图片是否含有违法违规内容
  16. BT结束,高宽带有何用?
  17. HTML+CSS期末大作业:电影网站设计——猫眼电影(9页)
  18. OpenStack Dashboard
  19. steam 平台 饥荒 联机版 Linux云服务器 搭建教程
  20. 浏览器加载解析渲染机制的全面解析

热门文章

  1. bzoj 1821 部落划分
  2. Thymeleaf从入门到出家
  3. 高精度定位技术有哪些
  4. 接触JAV第一步HelloWorld
  5. 14个Java技术网站,程序员必备!
  6. ssh load pubkey invalid format错误
  7. 海思mv100(android 4.4)WiFi调试
  8. 软件测试整理一:测试基础知识以及开发、测试模型、按照开发阶段进行测试
  9. 将来不会倒闭的8种行业,你上车了吗?
  10. 学会这10款AI绘画工具,你也可以成为插画师