通信算法之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本身其实不太适合复杂的算法,但是却特别适合数据量大、流程简单的算法,这是它很大的一个优势。

相关推荐
Li_RuiQi17 小时前
DAgger方法演进_独立学习笔记
笔记·学习·计算机视觉
Li_RuiQi1 天前
DAgger与交互式模仿学习_ACT学习笔记
笔记·学习
He BianGu1 天前
【笔记】C# 中BindingFlags的详细作用
笔记·c#
AI视觉网奇1 天前
turtle 入门教程笔记
笔记
跨知易知识产权1 天前
美国专利确权是什么,和专利诉讼有什么不一样?
笔记
杨逢昌工厂6S管理1 天前
126-杨逢昌6S三环体系:越做越乱的现场熵增机理与基准化治理——一线现场诊断笔记
经验分享·笔记·职场和发展·学习方法
悟道书生1 天前
若依 RBAC 权限控制学习笔记
java·网络·笔记·sql·学习·vue
陈哈哈11111 天前
折腾了半天,总算把 Vim 9.2 装明白了
笔记
陈哈哈11111 天前
折腾了半天,总算把 OpenGL 的开发环境给装明白了
笔记
深圳老胡1 天前
STM32F103 硬件 SPI 与软件 IO 模拟 SPI 最高速度差异详解
笔记·stm32·单片机·代码规范·1024程序员节