FPGA速度优化

速度优化



前言

本篇主要学习十年老鸟的文章,在此自己做一个总结。
逻辑设计漫谈——逻辑级数

速度优化,主要就是设计时序进行优化

  • 吞吐量:每个时钟周期能处理的数据量,多少bit,b/s。为了提高吞吐量,大量的并行的设计被使用,再对数据处理完成之后对外传输,一般使用告诉串行I/O口,使得提高速率的前提又增加了稳定性
  • 设计延时:输入数据和数据被处理后输出的时间间隔。对于吞吐量来说,只关心流水线末端下线产品的数量,很少关系数据被处理的传输延迟。即尽量采用并行操作,减少流水操作。
  • 设计时序:指设计时钟速度,两个时序单元之间的最大延迟,决定了时钟频率(速度),可以得到一个最大时钟频率

绪论:什么是逻辑级数

在这里插入图片描述

在这里插入图片描述
先理解数据传递:a和b分别经过寄存器,然后经过组合逻辑(&a_reg) | (|b_reg)进入到寄存器sum的过程。那么寄存器与寄存器之间的LUT就是组合逻辑级数。这个LUT的作用就是查找表,存储了(&a_reg) | (|b_reg)结果所有的值,根据查找表输出给寄存器SUM。

其中一个reg[0],代表存一个bit的值,a和b分别有4个,那么就是用4个reg来寄存。

要对(&a_reg) | (|b_reg)进行数据结果存储,需要4输入的查找表,因此使用LUT4即可存储所有结果。

一、时序优化:概念篇

tip:从核心上理解就是关键路径的延迟太大,可以从插入流出、减小扇出(扇出过大会影响布局布线)、组合逻辑重组、操作符平衡(组合逻辑存在流水,如何是这个流水变成并行的,也就是组合逻辑重组)、消除代码优先级(使用case语句,使用 if else语句不超过7级)。

本质就是消除两个时序逻辑reg之间的逻辑级数或者减少布线的长度,使得两个reg之间更近

有两种,一种是解决布线问题,一种是解决组合逻辑级数问题(也可以说是设计让基本逻辑器件怎么去计算的问题,涉及的核心就是查找表lut,进位链,选择器等等)

1.1 减少关键路径上的时序

关键路径:时序路径上的组合逻辑都会增加路径延迟,两个寄存器之间的最大延迟就是关键路径,减少了,就优化了时序,增加了时钟频率。也就是说木桶理论。

1.1.1 关键路径重组:解决逻辑级数问题

多用于多个路径组合的场合,将重组先后的顺序,使得寄存器之间的关键路径被拉的更近

1.1.2 解决扇出问题:解决布线长度问题

**tip:**Fanout即扇出,模块直接调用的下级模块的个数,如果这个数值过大的话,在FPGA直接表现为路径延时(net delay)较大,不利于时序收敛。因此,在写代码时应尽量避免高扇出的情况。

  • 适当的逻辑赋值:信号扇出过大,会造成布局布线困难,从而导致延迟过大。通过对信号的复制(面积换速度),可以分担扇出过大的问题。又分为逻辑复制寄存器复制
    **解决扇出:
    方法一:**组合逻辑复制如下:

在这里插入图片描述
方法二:在代码中可以设置信号属性,将对应信号的max_fanout属性设置成一个合理的值,当实际的设计中该信号的fanout超过了这个值,综合器就会自动对该信号采用优化手段,常用的手段其实就是寄存器复制。属性设置如下代码所示:

(* max_fanout = “3” *)reg signed [15:0] din_d;

方法三:通常BUFG是用于全局时钟的资源,可以解决信号因为高扇出产生的问题。但是其一般用于时钟或者复位之类扇出超级大的信号,此类信号涉及的逻辑遍布整个芯片,而BUFG可以从全局的角度优化布线。而且一块FPGA芯片中BUFG资源也有限,在7k325tffg900上也仅有32个,如果用于普通信号的高扇出优化也不大现实。因此,在时钟上使用BUFG是必须的,但是如果设计中遇到某些复位信号因高扇出产生的时序问题时,可以在此信号上使用BUFG来优化。

1.1.3 路径上插入寄存器:解决逻辑级数问题

中间插入寄存器,面积换速度(插入流水线);

1.1.4 寄存器平衡:解决逻辑级数问题

操作符平衡(组合逻辑存在流水,如何是这个流水变成并行的),使用括号来重组组合逻辑 如,z<=abcd变成z<=(ab)(cd)

1.1.5 并行结构::解决逻辑级数问题

如out1 <= a + b +c + d变成out1 <=( a + b) +(c + d)

1.1.6 消除代码优先级::解决逻辑级数问题

消除代码优先级(使用case语句,使用 if else语句不超过7级),if语句需要顺序去判断,所以耗时;
如果非要使用 if else 那么当if中的控制线是互斥的,就可以改写为多个if并行的方式

二、组合逻辑的存在形式

对于组合逻辑的优化,就是在写代码时要知道,软件会用什么资源来实现加法、比较和条件语句。多bit的实现方式就是先从单bit入手,一级一级的处理,然后输出一个最终结果,中间处理的并行过程就是级数。

2.1 加法器

逻辑设计漫谈——常用代码的逻辑级数预估(加法器)
详细可参见上面连接。

本文的结论是基于K7系列FPGA。

推理过程看上述链接即可。
在这里插入图片描述
assign sum_o = a_i + b_i;// 8bit相加,这里为什么用LUT2而不用多个LUT4或者其他的,就不纠结了,这里仅仅对写代码时做到大致的心中有数即可。

在这里插入图片描述

  • 这里使用的资源是LUT2,即8bit数据,分别每个bit分别进行查找表,然后得到的两个4bit的输出结果,因为是4bit输入,所有需要carry4这个进位链进行继续计算,最后将两个carry4再相加,得到最终的值。其实做基本的计算逻辑就是先单bit计算作为基本元素,然后有基本元素组建更大的计算单元,这时候就需要例如carry4这样的计算单元了。

从这张表进行分析:

  • 两个变量的加法的lut使用lut情况下,每个bit使用对应的一个lut2,8个就使用8个。
  • 因为使用的是lut2,所有8个bit的加法后,会得到8组单bit相加的结果,这个时候,就需要进位了,这里直接使用可以进行4bit进位链处理的caary4,也就是使用2个carry4完成进位工作。

得到的规律:加入计算时,先使用lut来进行查找表计算,当计算完成后,交个进位器进行进位处理,然后输出结果。在写代码时,就应该开了使用几个查找表可以用于计算,当计算完成后,会用几个进位器进行进位。
对于3个数相加,或者4个数相加,vivado软件会自动优化资源,但是逻辑级数会增加。这里大致知道即可

小结:对于加法,就是从单bit各自相加(这里是两个32bit喔!也就是说总共多少位宽,就要有多少个底层资源的输入口,lut2是两个口,需要计算的总位宽是64,所有总共用32个lut2),然后使用进位链。因为进位链是4bit的,所有8bit要输入到两个进位链中。总的来说,加法的逻辑级数,取决于使用多少个进位链,比如32bit A+B,需要32个lut2,和32/4个进位链,lut2当然是并行的,但是carry4坑定是串行的,因此级数为5。对于A+B+C,软件会进行资源优化,但是逻辑级数是增加的。

2.2 比较器

逻辑设计漫谈——常用代码的逻辑级数预估(比较器)

判断条件如:大于、小于、等于、不等于等等

8bit 比较器:assign p_o = a_i == b_i;
在这里插入图片描述
这里回想,加法器是如何相加的。这里比较器两个8bit比较,总需要16bit的输入口,则需要3个lut6,一个slice中刚好有4个lut6,刚好就可以使用,那么处理方式就是先进行6:6的比较,因为是比较器,所以输出是1bit。然后剩下两个再放到下一个lut,并且和未比较的4个bit一起放到后级的LUT6,这样生成一个查找表,即完成组合逻辑计算。

对于9bit,如果按照之前的推测,使用3个3比3的LUT6,在加上一个LUT6即可完成比较,实际上是使用一个CARRY4,
在这里插入图片描述
继续推测12bit,如果使用LUT6可以将比较分为4组LUT6和一组最后的比较,即5组,但是实际上4LUT+CARRY4。原因是4个LUT和1个CARRY4只需要1个SLICE就可以实现,而5个LUT需要两个SLICE。SLICE之间的内部走线相对于跨SLICE的走线无疑是更短的,下面两个图是就是两种方式的布局布线图。同时如果1个SLICE的4个LUT都已经被使用但CARRY4没有使用的话,这个CARRY4基本也就没法被其他逻辑使用了

从slice的角度来看,如果一个12位宽的数据进行比较,资源利用率是最佳的

在Xilinx Vivado中,一个SLICE是FPGA内部的可配置逻辑单元,通常被认为是FPGA的最小逻辑单元。一个SLICE主要包含以下几个部分:
查找表(LUT):每个SLICE包含4个6输入的查找表。LUT用于实现逻辑功能,可以配置成各种布尔函数。每个LUT有6个输入(A1到A6)和两个输出(O5和O6)。一个LUT可以配置为一个6输入的查找表,或者两个5输入的查找表。
触发器(FF):每个SLICE包含8个触发器。这些触发器可以配置成D触发器或锁存器。其中4个触发器可以配置为边沿触发的D型触发器或电平敏感的锁存器,另外4个只能作为D触发器。
多路复用器(MUX):SLICE中包含多个多路复用器,用于实现数据选择和路由功能。
进位链(Carry Chain):SLICE中包含进位链逻辑,用于实现加法器、计数器等算术运算

在这里插入图片描述

  • 对于等于,一般就看是否在一个slice中是否完成计算,但是对于大于等于这些,9-16会使用两个SLICE来完成。因为想要逻辑级数小,就在8bit以内搞定比较。
  • 对于常数的比较,逻辑级数少的可怜

小结:对于比较器,可以使用LUT6资源和进位资源。一个slice中的lut6为4个,进位链为1个。因此,逻辑级数,主要还是引开进位链或者是否剩余bit需要参加下一次计算来定。比如12bit 的A==B,总共输入需要24bit,则需要4个LUT6,4个LUT6计算结果为4个1bit数据,需要参加接下来的比较,然后再用一个进位链,则刚好使用2个逻辑级数。

2.3 条件语句

逻辑设计漫谈——常用代码的逻辑级数预估(条件语句)

直接看结果:

也有的说:ifelse当中如果不存在多个条件同时满足的时候,vivado都会按照case语句去综合电路,一但ifelse里面存在优先级的问题就不是这样子

在这里插入图片描述
上面的结论是在所有的条件不相关的且没有组合逻辑的情况下得到的,但很多情况下各个条件也存在相关性,且有组合逻辑代码

在这里插入图片描述
在这里插入图片描述
链接中说:“笔者认为在FPGA中将if条件语句综合成LUT实现之后,if条件语句的实现已经转换成了输入是16bit(12个数据bit和4个用于条件的bit),输出是1bit情况下如何构造查找表的问题了,所谓的输出优先顺序只是在查找表中体现,而不会体现在电路上。”。

分析:如果加上条件语句中的4bit和数据的12bit,那么16bit的输入,就可以用3个LUT6,生成查找表,然后将3个LUT6的数据整合计算(再使用一个查找表),那么使用4个超招标,即逻辑级数为2.

小结:对于条件语句,最终也是体现在查找表上,同样是看总过输入有多少bit(包括条件中的bit),如上图所示,总过输入有16bit,输出一bit。那么如何在查找表上体现呢?和加法器和比较器一样,有16个输入,那么可以用3个LUT6就可以满足,然后三个LUT6会有3个1bit输出,再使用一个lut对3个lut6的输出进行处理,就可以得到结果。

总结

两个ff之间的组合逻辑延迟过大,解决核心就是思考如何让两个ff之间距离更近。导致ff之间延迟的原因有扇出,组合逻辑综合后的电路结构是串形的(尽量用操作符去优化让其综合合成并行的电路),优先级问题。或者去使用插入寄存器去解决(加一级流水)

此外,对于底层资源如何被利用,主要看你这块的计算,总共输入有多少bit,使用多少个LUT,使用LUT后,后续又怎么处理,是使用1个进位链,还是使用两个等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值