本章目录:
1. 关键字
关键字 | 含义 |
---|---|
module | 模块开始定义 |
input | 输入端口定义 |
output | 输出端口定义 |
inout | 双向端口定义 |
parameter | 参数定义 |
wire | wire信号定义 |
reg | reg信号定义 |
always | 产生reg信号语句的关键字 |
assign | 产生wire信号语句的关键字 |
begin | 语句的开始标志 |
end | 语句的结束标志 |
posedge/negedge | 时序电路的标志 |
case | case语句开始标志 |
default | case语句默认分支标志 |
endcase | case语句结束标志 |
if | 判断语句开始标志 |
else | 判断语句标志 |
for | 循环语句标志 |
endmodule | 模块结束标志 |
2. 运算符
2.1 分类
2.1.1 按其功能分类
- 算术运算符(+,-,×,/,%)
- 赋值运算符(=,<=)
- 关系运算符(>,<,>=,<=)
- 逻辑运算符(&&,||,!)
- 条件运算符( ? :)
- 位运算符(,|,,&,)
- 移位运算符(<<,>>)
- 拼接运算符({ })
- 其它
2.1.2 按其所带操作数的个数分类
- 单目运算符(unary operator):可以带一个操作数,操作数放在运算符的右边。
- 二目运算符(binary operator):可以带二个操作数,操作数放在运算符的两边。
- 三目运算符(ternary operator):可以带三个操作,这三个操作数用三目运算符分隔开。
2.1.2.1 举例
clock = ~clock; // ~是一个单目取反运算符, clock 是操作数。
c = a | b; // 是一个二目按位或运算符, a 和 b 是操作数。
r = s ? t : u; // ?: 是一个三目条件运算符, s,t,u 是操作数。
2.2 优先级
3. 数据类型
Verilog 中共有 19 种数据类型。
基本的四种类型: reg 型、wire 型、integer 型、parameter 型。
其他类型:large 型、medium 型、small 型、scalared 型、time 型、tri 型、trio 型、tril 型、triand 型、trior 型、trireg 型、vectored 型、wand 型和 wor 型。
1) wire 型
wire 型数据常用来表示以 assign 关键字指定的组合逻辑信号。Verilog 程序模块中输入、输出信号类型默认为 wire 型。wire 型信号可以用做方程式的输入,也可以用做“assign”语句或者实例元件的输出。wire 型信号的定义格式如下:
wire [n-1:0] 数据名 1,数据名 2,……数据名 N;
这里,总共定义了 N 条线,每条线的位宽为 n。下面给出几个例子:
wire [9:0] a, b, c; // a, b, c 都是位宽为 10 的 wire 型信号
wire d;
2) reg 型
reg 是寄存器数据类型的关键字。寄存器是数据存储单元的抽象,通过赋值语句可以改变寄存器存储的值,其作用相当于改变触发器存储器的值。reg 型数据常用来表示 always 模块内的指定信号,代表触发器。通常在设计中要由 always 模块通过使用行为描述语句来表达逻辑关系。在 always 块内被赋值的每一个信号都必须定义为 reg 型,即赋值操作符的右端变量必须是 reg 型。reg 型信号的定义格式如下:
reg [n-1:0] 数据名 1,数据名 2,……数据名 N;
这里,总共定义了 N 个寄存器变量,每条线的位宽为 n。下面给出几个例子:
reg [9:0] a, b, c; // a, b, c 都是位宽为 10 的寄存器
reg d;
reg 型数据的缺省值是未知的。reg 型数据可以为正值或负值。但当一个 reg 型数据是一个表达式中的操作数时,它的值被当作无符号值,即正值。如果一个 4 位的 reg 型数据被写入-1,在表达式中运算时,其值被认为是+15。
reg 型和 wire 型的区别在于:reg 型保持最后一次的赋值,而 wire 型则需要持续的驱动。
3) integer 型
也是一种寄存器数据类型,integer 类型的变量为有符号数,而 reg 类型的变量则为无符号数,除非特别声明为有符号数。
还有就是 integer 的位宽为宿主机的字的位数,但最小为 32 位,用 integer 的变量都可以用reg 定义,只是用于计数更方便而已。reg, integer, real,time 都是寄存器数据类型,定义在 Verilog 中用来保存数值的变量,和实
际的硬件电路中的寄存器有区别。
4) parameter 型
在 Verilog HDL 中用 parameter 来定义常量,即用 parameter 来定义一个标志符表示一个常数。采用该类型可以提高程序的可读性和可维护性。
parameter 型信号的定义格式如下:
parameter 参数名 1 = 数据名 1;
下面给出几个例子:
parameter s1 = 1;
parameter [3:0] S0=4’h0
4. 缩位运算
缩减运算符是单目运算符,也有与或非运算。其与或非运算规则类似于位运算符的与或非运算规则,但其运算过程不同。位运算是对操作数的相应位进行与或非运算,操作数是几位数则运算结果也是几位数。而缩减运算则不同,缩减运算是对单个操作数进行或与非递推运算,最后的运算结果是一位的二进制数。
4.1 缩减运算的具体运算过程
- 第一步先将操作数的第一位与第二位进行或与非运算,
- 第二步将运算结果与第三位进行或与非运算,
- 依次类推,直至最后一位。
4.1.1 例如
reg [3:0] B;
reg C;
C = &B;
相当于:
C =( (B[0]&B[1]) & B[2] ) & B[3];
5. 三态门设计
5.1 概述
三态指其输出既可以是一般二值逻辑电路(使能EN=1),即正常的高电平(逻辑 1)或低电平(逻辑 0),又可以保持特有的高阻抗状态(使能EN=0),高阻态相当于隔断状态(电阻很大,相当于开路)。
5.2 三态门的 Verilog 代码实现
module Tri(
input din,
input en,
output reg dout
);
always @(din or en)
if (en)
dout <= din;
else
dout <= 1'bz;
// 数据流描述
// assign dout = en ? din : 1'bz;
endmodule
6. 可综合
6.1 verilog 可综合和不可综合语句
(1)所有综合工具都支持的结构:always,assign,begin,end,case,wire,tri,generate,aupply0,supply1,reg,integer,default,for,function,and,nand,or,nor,xor,xnor,buf,not,bufif0,bufif1,notif0,notif1,if,inout,input,instantitation,module,negedge,posedge,operators,output,parameter。
(2)所有综合工具都不支持的结构:time,defparam,$finish,fork,join,initial,delays,UDP,wait,force。
(3)有些工具支持有些工具不支持的结构:casex,casez,wand,triand,wor,trior,real,disable,forever,arrays,memories,repeat,task,while。
6.2 建立可综合模型的原则
要保证 Verilog HDL 赋值语句的可综合性,在建模时应注意以下要点:
(1)不使用 initial。
(2)不使用#10。
(3)不使用循环次数不确定的循环语句,如 forever、while 等。
(4)不使用用户自定义原语(UDP 元件)。
(5)尽量使用同步方式设计电路。
(6)除非是关键路径的设计,一般不采用调用门级元件来描述设计的方法,建议采用行为语句来完成设计。
(7)用 always 过程块描述组合逻辑,应在敏感信号列表中列出所有的输入信号。
(8)所有的内部寄存器都应该能够被复位,在使用 FPGA 实现设计时,应尽量使用器件的全局复位端作为系统总的复位。
(9)对时序逻辑描述和建模,应尽量使用非阻塞赋值方式。对组合逻辑描述和建模,既可以用阻塞赋值,也可以用非阻塞赋值。但在同一个过程块中,最好不要同时用阻塞赋值和非阻塞赋值。
(10)不能在一个以上的 always 过程块中对同一个变量赋值。而对同一个赋值对象不能既使用阻塞式赋值,又使用非阻塞式赋值。
(11)如果不打算把变量推导成锁存器,那么必须在 if 语句或 case 语句的所有条件分支中都对变量明确地赋值。
(12)避免混合使用上升沿和下降沿触发的触发器。
(13)同一个变量的赋值不能受多个时钟控制,也不能受两种不同的时钟条件(或者不同的时钟沿)控制。
(14)避免在 case 语句的分支项中使用 x 值或 z 值。
6.3 不可综合 verilog 语句
1、initial
只能在 test bench 中使用,不能综合。(写了 initial 虽然可以通过综合,但那个不叫“能综合”)
2、events
event 在同步 test bench 时更有用,不能综合。
3、real
不支持 real 数据类型的综合。
4、time
不支持 time 数据类型的综合。
5、force 和 release
不支持 force 和 release 的综合。
6、assign 和 deassign
不支持对 reg 数据类型的 assign 或 deassign 进行综合,支持对 wire 数据类型的 assign或 deassign 进行综合。
7、fork join
不可综合,可以使用非块语句达到同样的效果。
8、primitives
支持门级原语的综合,不支持非门级原语的综合。
9、table
不支持 UDP 和 table 的综合。
10、敏感列表里同时带有 posedge 和 negedge
如:always @(posedge clk or negedge clk) begin…end
这个 always 块不可综合。
11、同一个 reg 变量被多个 always 块驱动
12、延时
以#开头的延时不可综合成硬件电路延时,综合工具会忽略所有延时代码,但不会报错。
如:a=#10 b;
这里的#10 是用于仿真时的延时,在综合的时候综合工具会忽略它。也就是说,在综合的时候上式等同于 a=b;
13、与 X、Z 的比较
可能会有人喜欢在条件表达式中把数据和 X(或 Z)进行比较,殊不知这是不可综合的,综合工具同样会忽略。所以要确保信号只有两个状态:0 或 1。
7. VHDL 的结构
- 实体(Entity):描述所设计的系统的外部接口信号,定义电路设计中所有的输入和输出端口;
- 结构体 (Architecture) :描述系统内部的结构和行为;
- 包集合 (Package):存放各设模块能共享的数据类型 、常数和子程序等 ;
- 配置 (Configuration):指定实体所对应的结构体;
- 库 (Library):存放已经编译的实体 、结构体 、包集合和配置。
VHDL 基本设计单元结构:程序包说明、实体说明和结构体说明三部分:
8. VHDL:WAIT 语句格式
WAIT FOR
WAIT UNTIL
WAIT ON
9. 原语
原语,即 primitive。不同的厂商,原语不同;同一家的 FPGA,不同型号的芯片,可以也不一样;原语类似最底层的描述方法。使用原语的好处,可以直接例化使用,不用定制 IP;即可通过复制原语的语句,然后例化 IP,就可使用。
9.1 常见原语
9.1.1 IBUF 和 IBUFDS(IO)
IBUF 是输入缓存,一般 vivado 会自动给输入信号加上,IBUFDS 是 IBUF 的差分形式,支持低压差分信号(如 LVCMOS、LVDS 等)。在 IBUFDS 中,一个电平接口用两个独特的电平接口(I 和 IB)表示。一个可以认为是主信号,另一个可以认为是从信号。主信号和从信号是同一个逻辑信号,但是相位相反。
9.1.2 IDDR(Input/Output FuncTIons)
被设计用来接收 DDR 数据,避免额外的时序复杂性。
9.1.3 IBUFG 和 IBUFGDS(IO)
IBUFG 即输入全局缓冲,是与专用全局时钟输入管脚相连接的首级全局缓冲。所有从全局时钟管脚输入的信号必须经过 IBUF 元,否则在布局布线时会报错。
10. False-path
总得来说,FALSE PATH 就是我们在进行时序分析时,不希望工具进行分析的那些路径。一般不需要工具时序分析的路径指的是异步的路径,异步路径就是指的不同时钟域的路径。
11. 编译预处理
编译预处理是 VerilogHDL 编译系统的一个组成部分,指编译系统会对一些特殊命令进行预处理,然后将预处理结果和源程序一起在进行通常的编译处理。以" ’ " (反引号) 开始的某些标识符是编译预处理语句。在 Verilog HDL 语言编译时,特定的编译指令在整个编译过程中有效(编译过程可跨越多个文件),直到遇到其他不同的编译程序指令。常用的编译预处理语句如下:
(1) 'define,'undef
(2) 'include
(3)'timescale
(4)'ifdef,'else.'endif
(5)'default_nettype;
(6)'resetall
(7)'unconnect_drive,'nounconnected-drive;
(8)'celldefine,`endcelldefine