Skip to content

Commit

Permalink
fix typo
Browse files Browse the repository at this point in the history
  • Loading branch information
sonnyhcl committed Jun 10, 2018
1 parent 999dc0c commit da1527a
Showing 1 changed file with 22 additions and 16 deletions.
38 changes: 22 additions & 16 deletions 01-Introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,19 @@ HLS工具没有强大到可以处理任何代码。很多我们平时在软件

FPGA由一个可编程逻辑模块的矩阵和与之相连的内存组成,通常这些模块是以查找表(LUT)的形式存在,也就是说把地址信号输入进去,对应内存位置的内容会直接被输出出来。一个N位查找表可以以一个N位输入真值表的方式来表示。

<<<<<<< HEAD
![这里是图片的描述文字](/images/lut.jpg)

上图中的a部分是一个2位输入查找表,共有 $2^2$ 个配置比特。使用者通过编写程序来控制这些比特以实现某种功能。b部分是一个2位输入AND门的真值表,通过对应4个可能的结果产出(out一列),我们可以把a中的2位查找表编写成b中的AND门,即四个查找表输入依次对应b中的00,01,10,11。按照这个模式编写查找表,我们可以轻松的改变它的功能,让它充当我们需要的部件。对于小的布尔逻辑(Boolean),这样的编写方式更加的灵活高效。实际中的FPGA大多使用4-6位输入的查找表作为运算基础,一些大型FPGA内甚至有几百万个这一级别的查找表。
=======
![图片1.1:a部分是一个两位输入查找表,写作2-LUT。每一个configuration bit,即备置比特,可以根据查找表的功能变化而变化,这样的特性让它具有了可编写的特性。b部分是AND门的编写方式,out一列的数值从上到下依次对应了配置比特0-3的数值。c部分是一个由查找表和触发器组成的简单的slice。这个查找表拥有九个配置比特,其中八个决定查找表的功能,剩下一个决定直接使用查找表的输出或使用触发器中储存的输出。slice的性质见下文。](/images/lut.jpg)

上图中的a部分是一个2位输入查找表,共有${2}^{2}$个配置比特。使用者通过编写程序来控制这些比特以实现某种功能。b部分是一个2位输入AND门的真值表,通过对应4个可能的结果产出(out一列),我们可以把a中的2位查找表编写成b中的AND门,即四个查找表输入依次对应b中的00,01,10,11。按照这个模式编写查找表,我们可以轻松的改变它的功能,让它充当我们需要的部件。对于小的布尔逻辑(Boolean),这样的编写方式更加的灵活高效。实际中的FPGA大多使用4-6位输入的查找表作为运算基础,一些大型FPGA内甚至有几百万个这一级别的查找表。


{% hint style ='info' %}怎样将图片1.1中的查找表编写成一个XOR门呢?一个OR门?我们需要一个几位输入的查找表?{% endhint %}
{% hint style ='info' %}
怎样将图片1.1中的查找表编写成一个XOR门呢?一个OR门?我们需要一个几位输入的查找表?
{% endhint %}


{% hint style ='info' %}一个2位输入的查找表最多可以被编写出多少种形态?一个n位输入的查找表呢?{% endhint %}
{% hint style ='info' %}
一个2位输入的查找表最多可以被编写出多少种形态?一个n位输入的查找表呢?
{% endhint %}


触发器(FF)是FPGA最基本的内存单位,通常触发器是配有查找表的,这样是为方便查找表之间的复制与组合。在这基础上再加入一个规定它们的函数(例如全加器),就可以创建一个更为复杂的逻辑单位,称为可配置逻辑块(CLB)或逻辑矩阵块(LAB)。有些设计工具中还会把它称作片(Slice)。为避免歧义,我们将在下文中用slice作描述,这样读者可以对在Vivado设计工具中出现的Slice更加熟悉。一个slice是几个查找表,触发器,和多路复用器(MUX)组合到一起而形成的更强大的可编程逻辑单位。每个slice需要的小部件数视FPGA的架构而变,但总体来说每个slice真的只包含不多的几个部件。图片1.1中的c部分就是由1个三位输入查找表和1个触发器组成的slice。slice可以变得更加复杂一点,比如常见的全加器。FPGA内部通常有一些定义好的全加器slice,这看起来有点违背FPGA的“可编写性”。但实际上使用全加器在硬件设计中太过于常见,把所有的全加器每次重新编写成一个slice会降低效率。灵活性和高效综合考虑,一些被配置好的slice是一个对整个系统有益的设计。
Expand All @@ -84,7 +83,9 @@ FPGA由一个可编程逻辑模块的矩阵和与之相连的内存组成,通



{% hint style ='info' %}比较自搭乘积和DSP48基础上乘积的性能,两种情况下可获得的最高频率分别是多少?FPGA资源利用上有什么变化吗?{% endhint %}
{% hint style ='info' %}
比较自搭乘积和DSP48基础上乘积的性能,两种情况下可获得的最高频率分别是多少?FPGA资源利用上有什么变化吗?
{% endhint %}


块RAM(BRAM)是另一个预配好的模块。BRAM是一个支持多种内存形式和接口的可配置随机储存器,可以储存字节,对字,全字,双字等等等。BRAM还可以把这些数据传给本地片上总线(与可编程逻辑交流)或处理器总线(与片上处理器交流)等等接口。总体来说它有两个功能,一是芯片上各部分的数据转移,二是储存大一些的数据集。slice经过编写也可以储存数据(通过触发器),但这样做会增加额外消耗。
Expand Down Expand Up @@ -123,15 +124,17 @@ FPGA由一个可编程逻辑模块的矩阵和与之相连的内存组成,通

图片1.6中的系统通过两种方法可以实现。第一种方法是把HLS产生的加速器核当作一个普通的核。用HLS创造出这种核之后把他们与IO接口核和标准核组合到一起(可以通过Vivado IP Inegrator这样的软件),这样我们就得到了完整的设计。这个方法叫做**以核为基础的设计方法**,与使用HLS之前的FPGA设计方法十分相似。第二种方法则着重于设计样板或平台,称为**平台为基础的设计方法**,这种方法下设计师先用IO接口核和标准核组合出一个样板,然后再用HLS通过****(shell)的接口将各式算法或**对象**组合进去。只要壳支持双边的接口,加速器核在平台与平台之间的移动也非常容易。

## 1.4设计优化
## 1.4 设计优化

### 1.4.1 性能特点

在开始讨论怎么去优化之前,我们先要讨论一下判断一个设计特点的标准。计算时间就是一个衡量设计好坏的重要标准。很多人把时钟周期数作为一个同步电路性能的指标,但实际上对于两个使用不同时针的电路这是不得当的,而时针不同又是HLS下的绝大多数情况。比如说,我们现在已经规定好了Vivado HLS的输入时钟限制,那么工具根据时钟的不同会从同一段代码中产生不同的结构,所以这不是一个很恰当的比较方式。秒数是一个更好的对应比较指标。Vivado HLS工具会提供一个周期数和周期频率的报告,用户可以用此得出某段代码的操作时间。



{% hint style ='tip' %}改变时钟频率有时候可以优化设计。Vivado HLS工具把时钟频率作为一个输入,所以改变一个输入可以导致产出的结构完全不同。我们会在后文继续讨论。书中章节2.4描述了根据时钟周期决定限制。书中章节2.5讨论了改变时钟周期如何通过操作链提升产力。{% endhint %}
{% hint style ='tip' %}
改变时钟频率有时候可以优化设计。Vivado HLS工具把时钟频率作为一个输入,所以改变一个输入可以导致产出的结构完全不同。我们会在后文继续讨论。书中章节2.4描述了根据时钟周期决定限制。书中章节2.5讨论了改变时钟周期如何通过操作链提升产力。
{% endhint %}


我们用任务(task)这个术语来表示一个行为的基本单位,用户可以在Vivado HLS中发现与之对应的是调用函数。任务延迟就是任务开始到任务完成中间的这段时间。任务间隔则是任务开始到下一个任务开始之间的这段时间。所有的任务输入,输出和计算的时间都被算在任务延迟里,但是任务的开始并不等同于读取输入,同样任务的结束也不等同于写出输出。在很多设计中,数据率是一个很重要的东西,它同时取决于任务间隔和函数参数的多少。
Expand All @@ -143,15 +146,16 @@ FPGA由一个可编程逻辑模块的矩阵和与之相连的内存组成,通
Vivado HLS工具通过计算一个任务输出到输入之间这个过程需要的寄存器数来决定周期。因此,0周期的任务延迟是可以实现的,也就是组合逻辑下路径上没有任何寄存器。另一个常用的工作是计算输入输出并把结果存到寄存器里,通过这些数据找到路径上的寄存器数。这样的计算有花费很多的周期。


{% hint style ='tip' %}很多工具把任务间隔称为生产力(throughput)。这个词语听起来和间隔没什么关系。一个任务间隔的变长不可避免的会减少一段固定时间内能完成的任务数,也就是“生产的力度”。还有一些工具用延迟来描述读输入和写输出的关系。非常不幸的是,在一些复杂的设计中,任务的特点很难仅仅用输入输出来分析,比如有时候一个任务需要读很多次数据。{% endhint %}
{% hint style ='tip' %}
很多工具把任务间隔称为生产力(throughput)。这个词语听起来和间隔没什么关系。一个任务间隔的变长不可避免的会减少一段固定时间内能完成的任务数,也就是“生产的力度”。还有一些工具用延迟来描述读输入和写输出的关系。非常不幸的是,在一些复杂的设计中,任务的特点很难仅仅用输入输出来分析,比如有时候一个任务需要读很多次数据。
{% endhint %}


### 1.4.2 面积和产力的取舍

为了更深入的讨论使用HLS工具过程中的问题,我们需要分析一个简单但很常见的硬件函数——有限脉冲响应(FIR)滤波器。FIR会对输入做固定系数下的卷积,它可以被用作充当各式滤波器(高通,低通,带通),最简单的FIR可能就是一个移动平均滤波器。有关FIR的具体内容会在第二章展开,在这里我们从高层简要的谈一下。

```c

#include "stdio.h"

#define NUM_TAPS 4
Expand Down Expand Up @@ -222,11 +226,13 @@ Vivado HLS可以产出更加流水,平行,性能上也更好的结构。其
用户可以通过在代码中添加**#pagma HLS pipeline**来指导Vivado HLS工具产生函数流水结构。这段指令需要一个参数来规划流水的起始间隔,也就是一个函数流水的任务间隔。图片1.10展示了一个可行的设计——每周期一抽头的架构。任务用到了一个乘法器和一个加法器完成滤波器。这种设计的任务间隔和任务延迟都是4个周期。图片1.11展示的是一个每周期一样本的结构,它使用了4个乘法器和3个加法器。这种设计的任务延迟和任务间隔都是1个周期,所以它每个周期都接受一个新的输入。当然这两种之外还有很多可行的设计,比如每周期两抽头设计,或每周期两样本设计,在一些特定应用中各自有各自的优势,我们将在第二章中讨论更多优化。

![](images/filter_one_sample.jpg)

![图片1.10:每周期一抽头设计。可以由图片1.8中的代码产出](images/filter_one_sample_behavior.jpg)



![](images/filter_one_tap.jpg)

![图片1.11:每周期一样本设计。可以由图片1.8中的代码加入函数流水指令产出](images/filter_one_tap_behavior.jpg)


Expand All @@ -243,8 +249,7 @@ Vivado HLS可以产出更加流水,平行,性能上也更好的结构。其

另一个影响速率的关键因素就是**资源限制**,其中一种形式是设计边缘的跳线,因为一个同步电路中的每根跳线在每周期只能传送抓取1个比特的数据。因此,如果 int32_t f(int32_t x)这样形式的函数作为一个单独模块在100MHZ的频率和1的任务间隔下运行,它最大的数据处理量就是3.2G比特。另一种资源限制来自于内存,因为大多数内存每周期只支持一定次数的访问。还有一种资源限制来自于用户所给的限制,如果用户规定了在综合中可用的操作数,这其实是给处理率添加了限制条件。

```
```c
#define NUM_TAPS 4

void block_fir(int input[256], int output[256], int taps[NUM_TAPS],
Expand Down Expand Up @@ -276,7 +281,9 @@ void block_fir(int input[256], int output[256], int taps[NUM_TAPS],
举例而言,在不同的工具中输入图片1.8的代码,图片1.10和图片1.11都是可能的产出结果。但是加入了图片1.12中的那些指令之后就会一定产出特定的一种结果。这个情况下延迟线被展开,乘积的for循环都被用流水的方式实施,产出的结构会于图片1.11中的结构相似。
{% hint style ='info' %}本章介绍了很多不同处理率的方法,其中最快的甚至到了每周期一样本的结构。但是,还有很多的应用需要更高的处理率,比如每周期多个样本。这样的设计需要怎样的代码呢?以设计一个每周期四样本的FIR滤波器为例,这样的设计需要多少资源(加法器和乘法器的数量)?与每周期一样本相比哪个资源使用更多?{% endhint %}
{% hint style ='info' %}
本章介绍了很多不同处理率的方法,其中最快的甚至到了每周期一样本的结构。但是,还有很多的应用需要更高的处理率,比如每周期多个样本。这样的设计需要怎样的代码呢?以设计一个每周期四样本的FIR滤波器为例,这样的设计需要多少资源(加法器和乘法器的数量)?与每周期一样本相比哪个资源使用更多?
{% endhint %}
我们将会在第二章具体讨论每种优化怎样影响性能和资源使用。
Expand Down Expand Up @@ -337,4 +344,3 @@ void block_fir(int input[256], int output[256], int taps[NUM_TAPS],
第五章描述了快速傅立叶变换的优化,它其实本身就是DFT的一个重构代码。FFT本身就是一个阶段化很明显的算法,所以非常适合任务流水。最终版优化代码需要一些其他优化包括循环流水,展开,数组优化等。每一章其实都在附录中的项目有所关联,他们最终的集成到一起可以组成一个无线交流系统。
第六章到第十一章对更多的应用做出了讲解。第六章讲述了如何使用测试平台和RTL同仿真,还讨论了一下数组和循环的优化。这些基本的优化策略很常见,在大多数程序中都有使用。第七章介绍了数据流的实时计算这个策略。第八章展示了两种应用(前缀和,直方图),这两个应用本身相对简单,但重建他们的代码需要很小心的实行优化。第九章会用很大篇幅讲述不同接口与交互的使用,比如视频直播需要某种特定的总线与内存接口。除此之外还需要一些数组和循环的优化。第十章介绍了几种排序算法,所以自然需要很大量的优化。最后一章则是建立了一个复杂的数据压缩结构,会包含大量复杂的模块。
>>>>>>> 25e4cab826d8a62a4fa67a203c99706f12639379

0 comments on commit da1527a

Please sign in to comment.