Verilog语言来设计FPGA。不同于用C语言实现功能,C语言你可以用很笨很乱的代码,基本都能解决问题,但是Verilog设计硬件电路不一样,如果设计思路不规范,设计代码逻辑混乱,功能无法实现不说,问题更是不能定位。整理此文目的,希望对大家FPGA设计规范,基本语法的掌握能有一点启示。在Verilog设计代码中注意这些规范,以免设计出混乱的电路。
通过读一些Verilog的书,可以发现,里面设计很多规则,一时难以完全吸收,会产生一种混乱的设计思路,虽然实现
一些简单的流水灯电路,可能不会受太多影响,但是项目稍微庞大将会出现一些问题。
零、入门基础
(1)D触发器
上面硬件语言描述的就是D触发器的特性
复位时Q=0;当有时钟上升沿的时候,把D的值给了Q
先有时钟上升沿再有Q的变化.
没有时钟上升沿到来,那么Q的值就保持不变
时钟之后1点点Q的值变化。先有上升沿再有Q变化
D触发器就想成是一个硬件器件。
(2)设计思维
想象成芯片。
硬件电路芯片。
有一个物的概念。
把名字相同的东西链接起来,是某个功能的硬件东西。
下载到板子,就按特定功能去运行了。
不能出现上面这个设计
要注意设计思路,不能是软件思路。而应该按并行思路设计。
加一条件
结束条件
一、语法规范中的用与不用
1、语法精简,去除不常用语法。
Verilog语法结构很多,还是很复杂的,现在规范语法,只是用很少的语法,实现所有功能。
设计中不用的语法:
(1) initial(设计不用、仿真使用)
(2) task/function(设计不用、仿真很少用)
(3) for/while/repeat/forever(设计不用、仿真很少用)
(4) integer(设计不用)
(5) 模块内部不能有X态、Z态、内部不能有三态接口
(6) Casex/casez(设计仿真都不用)
(7) Force/wait/fork(设计不用,仿真很少用)
(8) #5 (设计不用,仿真时使用)
2、常用的设计语法
(1) reg/wire、parameter
(2) assign(建议改名时使用,不是很常用)、always(最常用)
(3) 只允许使用ifelse和case两种条件语句
(4) 算数运算符(+-*/%)
(5) 赋值运算符(=,<=)(时序逻辑用<=,组合逻辑用=;其他情况不存在)
(6) 关系运算符(<,>,<=,>=)
(7) 逻辑运算符(&&,||,!)(为了避免歧义,逻辑运算符两边为1bit信号)
(8) 位运算符(<<,>>)
(9) 拼接运算符({})
只用标黄的三个语法,几乎可以设计出所有项目需求。
二、电路设计的三种结构
(1) 组合逻辑电路
固定结构:
always@(*)begin
语句;
end
(2) 时序逻辑电路
a)同步复位的时序电路
always@(posedge clk)begin
if(rst_n==1’b0)begin
语句;
else begin
语句;
end
end
b)异步复位的时序电路(复位时钟信号来就复位)
always@(posedge clkor negedge rst_n)begin
if(rst_n==1’b0)begin
语句;
else begin
语句;
end
end
同步异步相对于时钟而言,同步就是与时钟同步
三、电路设计要点
(1)一个always只产生一个信号(是设计思想和设计方法、给代码调试分析带来优点)
不能是下面这样:
应该是:
(2)一个信号只能在一个always中产生
(3)always是产生信号的方法,在什么情况下,这个信号的值为多少。一个always需考虑全部情况
(4)条件判断语句只使用if else 和 case ,其他都不用。
(5)含有posedge或 negedge的,一定是D触发器,是时序电路。
(6)设计时,如果想立刻有结果,就用组合逻辑;如果想延时一拍有结果,就用时序逻辑。
四、运算符语法
1’b0:1根线,二进制表示值为0。
3’b110:3根线,二进制表示值为110。
5’d10:5根线,十进制表示值为10。
8’ha2:8根线,十六进制表示值为a2。
(1)模块的例化+参数例化
不是顶层模块,被其他模块调用。例化两个后,模块名一样,占用两个电路例化—》搭建复杂电路,从小到大
例化方法及书写:
模块定义左+实例化右(模块名 例化名(区分模块123。。。))
参数例化,例化的目标可能和原模块的位宽不一致,所以进行参数的例化
(2)设计中只用两种类型,一个reg(寄存器)、一个wire(导线)。
1. wire和reg都是定义信号,没有其他意思(寄存器或者线)
2. 本模块内,用always里设计的信号都用reg;其他如assign、例化模块输出的信号用wire。
assign可以认为是对信号定义或者命名
例:Row是本模块产生吗是,是always产生吗 不是是例化产生的 用wire类型
(3)参数化 parameter,参数名称大写。
(4)算数运算符:
+-*(用的多)/%(用得少、占用资源很大)
+(加), -(减), *(乘), /(除)
1. 直接使用
2. 除法和求余少用
(5)关系运算符
>=(大于等于),>(大于), <(小于) ,<=(小于等于),==(等于)
1. 直接使用,结果为逻辑真或假
2. 只使用:==,>=和<
(6)赋值运算符
时序用<= 逻辑用=
(7)逻辑运算符
||(或者),&&(并且)
1. 按字面去理解
(8)位运算符
(9)移位运算符
1. <<(右移),>>(左移)
2. 左移,低位补零
3. 右移,高位补零
4. 左移,其实就是乘法. a = b<<2 等价于 a = b*4。
5. 右移,其实就是除法。a=b>>2,等价于a = b/4
(10)拼接运算符
(11)
(12)
data[cnt] <= 0;
将0赋给data中第cnt跟线。
data <= din[cnt];
将din第cnt根线的值,赋给data
reg [3:0] data;
data <= {data[2:0],data[3]}
等价于:
data[3:0] <= {data[2:0],data[3]}
等价于(以下同时赋值):
data[0] <= data[3];
data[1] <= data[0];
data[2] <= data[1];
data[3] <= data[2];
例如:现在值为4’b1011,赋值后为4’b0111,再之后是4’b1110
五、设计总结
三种电路:组合逻辑1+时序逻辑2
两种条件:if else+case
一一法则:一个always只产生一个信号+一个信号只能在一个always中产生;
目的:最简单的代码+最简洁的方式,实现易读、健壮、高效的Verilog代码。