今日头条
学习FPGA,笔者推崇的学习方法是先整体再局部。先对FPGA 有一个整体的认识,包括知道有哪些知识点,这些知识点所处的位置和作用。然后在此基础上再逐个突破。
FPGA知识大串讲是一个系列文章,先概括性地将FPGA的知识点串联起来,使读者对FPGA有一个整体的认识,为后续的各项学习打下坚实基础。
本系列文章由6篇文章组成。第一篇文章阐述大部分同学的学习误区。第二篇文章,介绍了FPGA所有的知识点,并将其串联起来。剩下的4篇文章,是对所有知识的分别概述,其内容包括:组合逻辑、D触发器、时序逻辑和FPGA 时序。
首先我们看一下学习误区。
第1节 误区1:学习语法过多
大部分初学者最大的学习误区就是花费大量的时间用于VERILOG语法的语法,并作为学习的重点。
入门就看VERILOG,相信这是很多读者入门FPGA的普遍做法,甚至,甚至部分同学花了几个月时间用来学习语法。
但其实VERILOG 里面的语法百分之九十的是用来测试用的,设计仅仅用到其中10%的语法,而且设计语法非常之简单,大部分代码是由一个一个always、assign和例化等组成的
上图是实现FPGA例化功能的代码,将模块test_edge放到本模块中来,其作用类似于C语言的函数调用,其语法亦相似,将接口信号一个一个关联起来即可。还未掌握例化语法的读者,可以自行查找相关知识。
FPGA的设计,通过使用ALWAYS的格式来实现。ALWAYS格式有两种,时序逻辑的ALWAYS和组合逻辑的ALWAYS,其结构如下。
当要实现不同功能时,在ALWAYS格式里,添加if else,以及加减乘除、逻辑运算等即可,如下面的代码
上面实现串口接收功能、一个典型的FPGA代码。第1至38行是接口、信号的定义,其他则是主体的设计部分。由上面代码可以看出FPGA的代码有以下几个特点。
Ø FPGA代码由多个结构简单、相似的ALWAYS和ASSIGN组成的。本例中一共用到了8个ALWAYS语句和7个ASSIGN语句,除此之外没有其他结构。复杂点的FPGA代码,亦仅是多了一个例化功能。
Ø 每个ALWAYS块只用到简单的语法,均是由if else,以及加减乘除、逻辑判断等基本操作。没有复杂的东西,相信具有C语言基础的读者,一般能读懂,或者能猜到大概功能。
Ø 除了第一个简单的ALWAYS之外,其他每个ALWAYS只设计一个信号。例如,第53至62行只设计cnt0,第92至98行只设计dout信号。这是至简设计法的一大特色,这样的设计才符合硬件设计的特点。这不是没有根据的,规范的企业如华为海思、中兴等,均是如此风格的代码。
由此可见,VERILOG语法是非常简单的。虽然语法简单,但如何通过简单的if else以及加减乘除,就实现强大的FPGA功能,这又很不简单,所以不同于学习C、C++等软件语言,学习FPGA没有必要花太多的精力于语法上,关键在于应用。
第2节 误区2:追求代码精简
钻研VERILOG语法,追求使用最少的代码实现功能,这又是一个大误区。
放在C、C++、JAVA等语言上,追求精简的代码实现,是一个正常的需求。但放在FPGA,则完全不是这回事。
衡量FPGA设计优秀的标准,不是看代码量的多少,而是比较综合出来的电路,它使用了多少资源,能够支持的时钟频率高低等。
例如一个加法器,在200M的时钟频率下,可以直接使用“+”来实现。但假如要跑到300M或者更高频率,业界会把该加法器拆分成多个逻辑门,并且在逻辑门之间增加寄存器(即流水线设计)。这样设计,代码会由原来的1行,变成上百行,并且难以读懂。虽然代码量增加了,但电路却更优秀了。
总而言之,不要追求VERILOG代码的精简,而是追求电路的优秀设计,多学习流水线、资源换速度、速度换资源等设计方式,这才是好的FPGA学习方向。
第3节 误区3:肤浅的实验
通过开发板学习FPGA是一个较好的入门方法,例如MDY的ALTERA学习板MP801、XILINX学习板MP802,既有LED灯、数码管、VGA等简单接口,还有SDRAM、DDR、千兆网等高级接口,其拥有大量免费的学习资源,包括工程、视频、文档等,是学习FPGA非常好的方法。
但部分读者拿到学习工程后,每个工程都是新建工程、编译工程、上板、看现象,仅此而已。实验做了很多,设计能力却提高得很慢。因为这里缺少关键的一步:自己去写代码。
读懂功能要求后,要亲自去写一写代码,边写边仿真,边仿真边修改。写不出来的时候,对着仿真波形多思考思考。通过这种方法,训练代码设计能力、仿真调试能力,掌握MODELSIM等工具的使用。
代码完成设计后,上板验证,这个时候现象大概率是不正确的,使用在线调试工具去定位问题找到问题。通过这种方法,训练定位问题能力、解决问题能力,掌握在线调试工具的使用。
最后,将自己设计的代码,与开发板的官方代码对比,吸收好的方面,改进自己的设计能力。
按照上面步骤,当您亲自完成一个功能设计,获得极大成就感和满足感的同时,设计能力也切实得到了提高,这样几个设计循环上来,基本上就掌握FPGA设计了。
第4节 误区5:软件思维
VERILOG是硬件描述语言,它是对硬件的描述,而非软件的设计。FPGA开发本质上是硬件的开发,与设计电路原理图是相似的,因此要用硬件思维。而C、C++、JAVA等语言是软件开发,使用的是软件思维。
有C语言基础的同学,很容易按照软件思维来进行FPGA设计,这是不正确的一种思想。那么,硬件思维和软件思维本质上有什么不同呢?
我们先看下软件是如何设计的。
上面4行是软件代码,先让a为1;然后让b=a+1,即让b为2;再让a为2;最后c=a+2,即让c为4。这有什么特色?
Ø 软件代码是一行一行顺序执行的;
Ø 软件是一种过程设计,是让信号怎么做、怎么变的设计。
Ø 软件考虑的是此时此刻,该信号要怎么做。
而硬件设计思维,我们可以通过MP801开发板的电路设计为例进行阐述。
假设我们要设计一款MP801开发板,这个开发板使用了多个元器件,例如有FPGA主芯片、AD、DA、数码管、按键等。每个元器件都有它自己独特的功能。
首先,每个元器件不一定有输入,但一定会有输出。例如,晶振输出50M时钟;当按下按键时,电平输出为0,未按下时输出为1;数码管的输出,则是颜色的发光状态等。
其次,每个元器件通常都有一个数据手册,该手册描述的是该元器件的输出功能,即在什么样情况下,会有怎么样的输出。以晶振为例,文档一般会说明电源电压为多少,然后输出50M的时钟信号。再以AD9280为例,文档会说明输入二进制值为多少时,输出什么样的电平,例如值为8’h00时,输出电压为0V;值为8’hff时,输出电压为5V等。
再次,您可以发现,每个数据手册一定会说明清楚,在所有的情况下,输出会有什么样的变化。
最后,当选中了元器件后,硬件工程师的工作,就是把它们正确地连起来。
当电路板开发并生产完成后,一通电,全部元器件都同时在工作。不存在说某个元器件工作,另一个元器件不工作的情况(这里不工作是指不通电的情况,而不是不变化。事实上,不变化也是该元器件的一个输出功能)。当然,更不存在,此时元器件A工作,元器件B消失的情况,事实上,这些元器件是一直保持存在的。
上面就是硬件的设计过程,我们可以总结出硬件思维的特色。
Ø 硬件首先是描述一个“元器件”,它是什么,它有什么功能,即在什么情况下,有什么样的输出。软件是让它怎么做,过多久为1,过多久又为2等。这就是VERILOG这个硬件描述语言的特性,一个ALWAYS语句,就相当于一个“元器件”,每个ALWAYS都是描述“元器件”(设计信号)的变化情况。
Ø 描述一个“元器件”是什么时,就要概括所有的情况,就如数据手册般的清晰。对应的是FPGA的ALWAYS语句,其设计的信号,一定是所有条件if else下的变化。特别注意的是,不同于软件只考虑此时此刻值为多少,硬件和FPGA考虑的是“整个电路生命周期”下的各种情况处理方式。
Ø 当您选完了“元器件”后,就是把元器件连接起来。对应FPGA,则是通过相同“信号名”来接各个部分连接起来。
Ø 最后,一通电,全部“元器件”都同时工作了。对应FPGA,就是VERILOG代码会综合成电路网表,最终会下载到FPGA,像电路般全部同时运行。ALWAYS设计的各种信号是一直物理存在的。
认真体会软件思维和硬件思维的异同,有助于我们更好更规范地进行FPGA开发。同时,正确地理解硬件思维,对于一些错误观念和设计法,就有自己的判断了。
例1:有部分读者阅读VERILOG代码时,会想当然地认为begin 里面代码都是串行执行的,例如下面的代码,会认为按顺序从第2至11行顺序地串行执行。
从严格的意义上,笔者认为“顺序串行执行”这个概念是不正确的,FPGA本身就没有“执行”的概念。由前面讲述可知,ALWAYS仅是像数据手册那样,描述“元器件”cnt的功能,即描述cnt在所有情况下的变化情况。所以,正确的理解,应当是像读“数据手册”那般,“阅读”cnt的功能。
例2:大家可以看出下面代码,是按软件思维,还是按硬件思维设计的呢?
不用理解上面代码实现了什么功能,从风格上就可以看出其是用软件思维来设计的。可以猜想其写代码的过程,如先写第13行代码,让byte_satee加1;然后写第14至18行代码,让Pre_CMOS_iData变化,这怎么看起来,都像是软件的一种过程思维。其次,将多个信号放在一个ALWAYS中描述,就像将多个不同元器件都写在一个数据手册上,必定是杂乱无章,讲不清楚的。
比较规范的设计方法,推荐一个ALWAYS设计一个信号,如下面代码,就是实现了相似的功能。一个信号一个信号地描述设计,长期坚持,必定能写出越来越优秀的代码。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !