abner_ma

  • 97 主题
  • 173 帖子
  • 1201 积分
  • 身份:版主
  • 论坛新秀
  • E币:840

FPGA Verilog设计中的规则技巧要点

2020-11-27 21:34:59 显示全部楼层

    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代码。

最新评论

楼层直达:
我要评论
0
4
广告
关闭 热点推荐上一条 /7 下一条
快速回复 返回列表