通信算法之306:精通FPGA-笔记核心

1、hls代替不了verilog

hls虽然可以翻译成verilog,但是如果不了解verilog,只是认为写写c就可以实现算法加速,这几乎是不可能的。软件工程里面有一个没有银弹的道理,说的就是这个意思。

2、先有时序图,后有verilog代码

fpga虽然是底层设计,但是本身也是有规律可循的。不管什么开发,最好把时序图、接口图、状态机画好,然后再写verilog代码。和c编译不同,quartus和vivado编译综合的时间都不短,所以最好想清楚了再编代码、调试,这样会比较稳妥一些。

不管是什么样的需求或者是硬件协议标准,最终都是要转化成时序图、状态机的。所以开发过程中最好多画时序图,多画状态机。正向去开发软件,这样就会理解的更加深刻。虽然学习的过程中可能会慢一点。

很多人都以为写fpga,就是编写verilog,学习一门编程语言而已。这种观点,其实只对了一半。verilog作为一门语言,其本身是为了简化数字电路设计而存在的。但是,这种语言,和软件的编程语言不一样。这是因为,软件的编程语言是变成一条一条的汇编指令,最终这些汇编指令都是由cpu来执行完成的。数字电路则不同,verilog里面的语句是需要变成门电路、触发器、rom、ram、消耗fpga资源的。因此,在编写的时候需要格外慎重。

学过数字电路的同学,一般都会知道组合逻辑和时序逻辑。组合逻辑就是输出和输入是强相关的。只要输入发生变化,输出也会及时发生变化。时序逻辑则不同,它的输出只会发生在时钟上升沿或者下降沿的时候对输入进行响应。除此之外,时序逻辑还有记忆功能。这说明,输出结果除了和输入有关,还和历史状态有关,这本身就很有意义了。

所以,真正学好fpga,并不是说谁的verilog语法了解的多谁就学的好。关键是还在于理清组合逻辑和时序逻辑,设计好时序。在根据功能需求设计好时序图之后,就可以尝试一下设计状态机。有了上面两个部分的加持,就可以把时序图转化为verilog语句了。

有些同学说,为什么在fpga计算的过程中要拆分成组合逻辑和时序逻辑呢。这中间主要还是基于性能的考虑。假设时序逻辑之间的组合逻辑时间太长,这势必就会影响算法的运行频率。别人可以跑200M,你只能10M。如果把较长的运算过程拆分成若干个子状态,这样就可以实现流水线操作。数据a在做a状态运算时,数据b就可以做b状态运算。这样相比而言,运行效率就会比普通的组合逻辑高很多。

说到绘画时序图,现在有很多很好的工具,比如说wavedrom,就是很好的选择。首先尝试编写组合逻辑,比如在浏览器url输入https://wavedrom.com/editor.html,

再谈fpga开发(怎么写verilog)

如果你学fpga,很多人都会告诉你,verilog和c差不多。也就是说,如果有c的基础,学习verilog很容易。确实,verilog的语法不是很难。难的是后面思维模式,即并发处理和状态机的处理模式。fpga里面写的其实不是verilog代码,而是后面的数字电路,即时序电路和组合逻辑电路。今天正好分析下,该怎么写verilog。

1、先画流程和波形图

fpga的基础其实是信号。这些信号可以是真实的信号,比如来自于各个pin引脚的信号,也可以是抽象的信号,比如说来自于sdram的数据。为什么说是抽象的信号,因为很多fpga的ide支持ip配置,基本上不需要自己写ip,即可以很灵活地访问sdram里面的数据,这种情况下使用sdram就非常轻松了,相关的信号就好比是抽象的一个数据信号。

有了这些基础信号,或者是基础数据之后,下面就是作业流程。比如说会经过哪些状态,信号和信号之间有什么依赖,按时间轴运行下去的话,不同信号应该怎么变化等等。在这一阶段可以不用写代码,而是先确认业务流程和业务逻辑。

2、确认输入、输出

如果是简单的模块,那么就是clk、rst和外部pin脚。编写子模块的画,那就是clk、rst,输入就是data、data_valid,输出就是result、result_en。

3、拆分状态,构建状态机

对于复杂的逻辑,最好把业务或者是算法,拆分成若干个状态。这个状态可以是模块的状态,也可以是模块内的子状态。拆分状态有一个好处,就是后续信号编写的时候,只需要判断当前状态下自己是如何变化的即可,相当于所有的信号都围绕这个状态机去进行判断。

4、添加中间变量寄存器,依据状态机编写代码

和c语言编写一样,对于输入和输出之间,需要很多的中间变量。fpga也差不多,为了达到我们的设计目的,在fpga运行的过程当中,为了实现基本功能,除了状态机之外,还需要添加很多的中间变量。变量和变量之间存在依赖,这个时候状态机就派上用场了。按照之前波形图的设计,分成输入、中间寄存器、输出三个部分。中间寄存器是可以随时来增删处理的,编写中间寄存器的代码,基本也是根据波形图和状态机来进行处理的。

比如说某一个中间结果寄存器,确认下它有哪几个状态,不同状态下是怎么进行变化的。实际编写的时候,可以一个状态、一个状态去编写代码,也可以先把一个中间寄存器的所有状态都编写好,再去编写下一个中间寄存器,这都是可以的。个人其实是比较推荐第一种处理方式。

需要注意的是,同一状态下的register都是并发运行的,这个是和c编程不太一致的地方。假设计算0到100,第一个clock,就是0+99、1+98是并发运算的,这一点需要稍微注意下。

5、继续编写仿真代码、确认波形

实际编写verilog代码的时候,难免有失误,这种情况就需要通过编写仿真代码,来进行验证和处理了。不要一下子就去编译、综合、直接上板子调试,浪费时间,效率也比较低。等到仿真差不多了,没有明显的错误之后,再去进行fpga实际验证,这是比较务实的处理办法。仿真的意义,就是在于提前从逻辑层面,验证信号逻辑和自己设计的业务流程,是否一致。

6、多看、多练习

纸上得来终觉浅,绝知此事要躬行。很多时候,我们看资料、看文档,觉得自己学会了某个协议、某个算法,但是没有动手去实践一下,其实未必是真的掌握了。所以,最好的处理办法就是自己动手去实践、去分析。在实践的过程当中,我们遇到了错误、分析错误,这样才是真正掌握了对应的开发知识,而不仅仅是纸上谈兵。

学习的过程中,主要是看别人的设计套路、编写习惯,比如跨域使用fifo、多用fpga提供的ip、多使用厂家的sample code等等

7、学习别人的verilog代码

对于同一个问题,可以自己先去尝试。用各种办法尝试,实在没有办法了,再去看答案,而不是一上来就抄别人的答案,这样效果会差很多。别人写得再好,也不是自己的。只有自己反复思考,通过比较两者之间的差别,才能把别人的东西变成自己的东西。

再谈fpga开发(算法变成verilog代码)

在计算机专业课里面,一般不太专门谈算法。一部分算法其实是放在数据结构里面,还有一部分是放在数理逻辑里面的。不管是哪一种情况,算法本身其实还是非常重要的。哪怕是没有听过算法的同学,对排序查找肯定是比较熟悉的,比如说冒泡排序的复杂度o(n*),而快速排序的复杂度只有o(nlogn),这也是一种算法。从复杂度也看得出来,如果数据量不大的情况下,两个排序其实差不太多,但是一旦数据量变大之后,效果就很明显了。

但我们写算法的时候,一般都是用c写,或者是matlab,那么如何转成rtl呢,这中间怎么处理呢?

1、先准备算法

fpga本身只是负责算法的加速。但是算法本身是否合理,这一点不是fpga说了算的。所以在使用fpga之前,首先要保证算法本身是合理的。我们可以通过matlab做预研,或者是通过c语言来做仿真,这都是可以的。只有保证了算法自己是ok的,才存在fpga加速的可能性。

2、构建数据通路

一个算法,可以看成是一个黑盒,输入就是外部的数据,输出就是我们想要的结果。经过一番操作之后,就可以实现从输入到输出的一个过程。对于纯软件而言,这个过程就是串行的。c语言编译之后,变成汇编指令,由cpu去一条、一条执行来完成的。对fpga,则是另外一种处理方法。

简单的数据处理,那么可以直接组合电路来完成,比如a=b+c,或者是a=b<<c,再或者是a=b^c等等。但是如果算法中存在循环,而且是很多的循环,鉴于频率和延时的原因,组合逻辑电路不可能太长,这个时候就会出现中间结果需要保存的情况,这些中间结果就放在寄存器里面。因此,整个处理过程,就变成了输入->寄存器->输出三个部分。

3、再设计状态机

一般的算法,都是可以转换成顺序、判断、循环三个部分。整个算法至上而下梳理的时候,我们习惯于把它切分成若干个状态,一般就是init、process、done三个状态。如果复杂一点,还可以进一步细分成init、process1、process2、...、done等几个状态。过程当中,如果某一个子状态内容较多,还可以进一步分解,比如说process1_1、process1_2、....等等。实际算法中有哪些状态,完全根据具体情况、具体分析。

4、算法的深入优化

有了寄存器、有了状态机,c语言代码其实都可以转成verilog代码的。但是做到这一步还是不够的。前面我们说过,fpga相比较cpu而言,它的高效率更多地是来自于它的并行处理。因此,我们有必要对算法做进一步的优化,比如说单个状态内,相关的信号尽可能做到并发处理;不同的模块之间也尽可能做到并发处理;数据尽可能做到边接收、边处理。fpga本身其实不太适合复杂的算法,但是却特别适合数据量大、流程简单的算法,这是它很大的一个优势。

相关推荐
茴香豆的茴12 小时前
转码刷 LeetCode 笔记[2]:203. 移除链表元素(python)
笔记·leetcode·链表
wdfk_prog2 小时前
[Linux]学习笔记系列 -- [arm][lds]
linux·运维·arm开发·笔记·学习
范纹杉想快点毕业3 小时前
C 语言主控开发与显控开发能力体系及技术栈详解,STM32、QT、嵌入式、边缘系统显示
stm32·单片机·tcp/ip·microsoft·fpga开发·51单片机·wpf
无名咸鱼4 小时前
CICD部署流程详解文档笔记
笔记·ci/cd
一颗正在价投韭菜4 小时前
《范仲淹传》读书笔记与摘要
笔记·学习·范仲淹
微小冷5 小时前
OV5640 相机开发流程
fpga开发·verilog·ov5640·双目相机·相机开发
teeeeeeemo6 小时前
js 实现 ajax 并发请求
开发语言·前端·javascript·笔记·ajax
老虎06276 小时前
JavaWeb(苍穹外卖)--学习笔记17(Apache Echarts)
笔记·学习·apache
szxinmai主板定制专家8 小时前
基于FPGA的热电偶测温数据采集系统,替代NI的产品(二)总体设计方案
arm开发·人工智能·嵌入式硬件·fpga开发