一, 该如何学习面向FPGA的逻辑设计?
学习面向FPGA的逻辑设计是一个因人而异的过程,因为基础,目标的不一样,学习的方法和过程都会有很大的差异,但是我们仍然可以总结出其中的规律。从而总结出一个大致相同的过程:
1,学习语法。
a,语法是相对简单的,找一本语法的书,认真的学习一下Design和Verify的语法,任何一个基础再差的人,学习一个星期也绰绰有余。
b,怎么样才能叫语法学好了呢?如果你看见红芯电子的例程,不会有语法上的问题,就可以了,不需要钻牛角尖,设计当中,主要的语法如always块,assign,case明白就可以了,当然,验证要求的语法要多一些。这些可以通过后面设计当中慢慢强化。
2,学习简单电路设计
a,在学习语法的同时,你肯定会尝试着去写一些简单的电路,这个时候肯定是模仿居多,比如说控制LED灯的闪烁,数码管的控制等简单电路。
b,这个阶段,我建议大家写一些基本的Code并明白他会综合成怎么样一个电路。比如说case语句生成怎样一个电路,和 if else 生成的电路会有怎么样的区别。
3,学习简单的TestBench。
a,Testbench是测试的激励文件,毕竟你写的Code肯定需要Debug,最好的办法就是仿真,用Modelsim,Active-HDL,NCverilog等工具。
b,这个阶段你只要能写一些简单Testbench就可以了,让你能看见波形,通过波形来debug
4,学习各种接口设计。
a,在语法,简单电路,Testbench都没有问题之后,就可以开始学习一些常见接口的设计了,比如UART,SPI,I2C,1-wire等,对应的器件和接口有串口,SPIFlash,串行AD/DA,EEPROM,DS18B20,IR,PS2,DS1302Z等
b,我相信,这个时候,作为初学者,其实还是模仿居多,我并不反对。但是一定要注意,一个一个来,每学习一个,需要仔细的去分析相应器件的Datasheet,然后参考别人设计的实现方式,特别是细节。然后自己尝试着写,看能否实现功能,最后要自己换一个同类型的接口,在不参考其他人的情况下,能否实现。不能实现就需要继续分析原因,能实现就可以学习下一个类型的接口。
c,常见的接口很多,特殊的接口更多,是没有办法一个一个学完的,作为初学者,需要做到就是学习一个掌握一类,如果你能仅参考Datasheet(在工程中,很多时候我们确实只Datasheet)完成相应的接口设计的时候,你就已经成长了。
5,学习模块划分技巧。
a,在各种基本的借口设计都已经完成以后,这个时候你就可以尝试着写一些更为复杂的电路来实现一些功能呢?比如说做一个“数码管+RTC”来实现时钟的功能,能否配合按键使之可以配置时钟,能否加上闹钟的功能,能否加上计时器的功能?能否将数码管换成LCD?如果这些都实现了,你会发现这就是一个电子表。
b,这个时候你就要学习模块划分了,毕竟一个再简单的系统,也是分许许多多的模块的,为了有更清晰的思路,为了更好的维护,我们需要将整个设计划分开,分成更加小的模块,然后一个一个实现并测试,总后再来一个综合测试。
c,这个部分以后我们还会有专门章节来详细阐述。
6,学习构建自动化测试环境。
a,在做一些小东西的时候,特别是分层设计以后,你肯定会觉得简单的testbench不够用了,每一个module都要单独写Testbench,为了测试不同情况下就需要写很多的Testbench,这个时候肯定是很麻烦的,这个时候就需要构建一个自动化的测试环境。
b,在Linux下用Makefile可以很简单的构建,但是就目前大家的开发环境全部是在Windows下,也可以构建,用Modelsim的do文件也可以构建。
c,因为篇幅的关系,这个部分以后我们还会有专门章节来详细阐述。
7,学习常见Device Control 设计和验证。
a,这个时候,一些小系统可以轻松完成的时候,就会发现,小的东西可以轻易的做出来,但是复杂的东西就比较困难。这时你就需要学习一些较大的控制电路
的设计,比如SDRAM control,LCD control(裸屏)。
b,这些Controller都有一个共同的特点,就是要求高速。要知道,高速电路是比较考验技术的。特别是IO速度超过100M以后,就会需要综合考虑器件选型和电路优化了。
c,这类controller里面,基本上都是用寄存器来控制,就是与外部用总线相连。外部总线配置controller里面的寄存器,从而修改controller里面的配置,并且接收外部总线的数据来实现功能,要学习并习惯这种控制方式。
d,这个时候我建议不要轻易的模仿别人的电路,原因很简单,简单的电路和基本的技巧都已经没有问题了。剩下的就是模块的划分和模块内部的组合以及电路的优化。这个东西就靠自己的理解,每个人的情况和出发点都不一样,模仿已经没有意义了,而且,独立跨过这道坎,在非专业的设计里面,你已经是一个小高手了。
8,学习划分系统模块,分配任务。
a,在FPGA常见的嵌入式系统里面,一般都是ARM+FPGA的结构,这个时候需要你根据对FPGA与ARM的理解来分配任务,有些任务适合FPGA来做,有些任务适合ARM来做,这个阶段应该是能够从需求里面分析出ARM FPGA各自擅长和承担的任务。
b,一般来说FPGA都是做为一个协处理模块,负责高速IO,高精度时序控制,并行多路计算,或者是复杂算法的实现,比如FFT。
c,从系统的层面分析问题的能力,很难通过学习来得到,必须要经过一个又一个得项目来实现。
二, 学习面向FPGA的逻辑设计注意事项。
我看过很多初学者发给我的代码,也帮助他们debug。我发现这些代码问题都比较严重,先总结比较突出的几点,做理论上的描述,然后下一章我会仔细跟大家分析这些代码的错误之处。
1,Coding Style。
a,Coding Style的重要性怎么强调都不为过,好的Coding Style可以极大的避免一些低级错误的出现。从而极大的减轻Debug的压力和测试的难度。
b,好的Coding style可以避免常见的错误如:多驱动源,Latch,仿真结果与电路结果不一致。
c,好的Coding style可以优化电路的性能如:电路最高速度,占用资源数量。
d,当然,上面只是简单的描述,好的Coding style是可以极大的节省开发时间,减少Bug的数量的。
e,那怎么样的Coding style才是好的Coding style,可以说,不同的公司因为文化的不一样会有不一样的要求,但是有些基本的是相同的,如:
i. 同步设计。
ii. 组合时序分开。
iii. 不允许出现不能综合的符号。
iv. 寄存器输出。
v. 不允许Latch,不允许组合循环。
vi. Case嵌套不超过2层,if else嵌套不超过3层。
vii. 命名规则。
viii. 空行规则。
ix. Clock使用规则。
x. 复位信号使用规则。
f,当然,上面只是简单的描述,以后我们会详细的阐述Coding Style规则,现在说的再多,也是枉然,没有实践,很快就会忘记的。
2, 同步设计。
这个问题在初学者中尤为严重,原因也很简单,在网络上Down的代码里面,基本上就是这样写的,很多人有样学样,这个是绝对不可取的。
a,同步设计我们设计电路的基本规则之一,理由很简单,现在的EDA工具基本上无法支持异步电路的分析,也就是说,综合工具帮你分析的电路能跑多快,异步的话就是错误的,在低速的时候表现不出来,但是如果高速的话,这种Bug是极难找到的。
b,什么叫同步设计,就是所有的寄存器都在同一个clock的控制下变化,从表现来说,就是有寄存器的敏感列表都是(posedge SYSCLK or negedge RST_B),如果在其他的信号的上升沿作为敏感列表,就是非通不了。
c,很多人要问,按照always @ (posedge SYSCLK or negedge RST_B)这个写法,那么RST_B信号不就是异步的一个信号了,确实是的,但是为什么还要这样写呢?原因也很简单,异步Reset的DFF的资源消耗比同步的小很多,而且Reset信号会在top module里面进行一次同步。
d,那么有些时候,我们一个设计当中,需要不同的clock,比如有些专用电路的clock频率是固定的,这个时候就会有2个,3个甚至更多时钟。这个就是跨时钟域的设计了,跨时钟域设计的时候,不同时钟域之间的信号,如果是单根控制信号,可以用单稳态触发器,如果是数据,建议用FIFO。但是单个时钟域里面还是同步的。 |