目录
导读
一、模块结构
1、模块的端口定义
2、模块内容
二、数据类型
1、常量
2、参量
3、变量
1、寄存器数据类型
2、线网型数据类型
参考声明
本篇博文主要介绍Verilog HDL 语法的基本框架和数据类型、常量变量等。
推荐PC端或者pad端食用~~
以一个简单的组合逻辑的例子进行示例说明,给出模块的模板:
//********************************** 文 件 说 明 **********************************\
// 版本:0.0
//设计日期:2021 09 15
// 作者:在路上,正出发
//功能说明:作语法示例
//相关参考:
//*********************************************************************************\
//********************************** 代 码 部 分 **********************************\
`timescale 1ns/1ps
module module_example #(
//*************---------------------- 参数列表 --------------------------**********\
parameter ADDER_WIDTH = 2'd3,
parameter SUM_WIDTH = 3'd4
//各 parameter 之间以逗号隔开 且 最后一个 parameter 后面无 逗号
)(
//*************-------------------- 输入端口列表 -----------------------***********\
input [ADDER_WIDTH-1:0] I_ADD1,
input [ADDER_WIDTH-1:0] I_ADD2,
//*************-------------------- 输出端口列表 -----------------------***********\
output [SUM_WIDTH-1:0] O_SUM_RES
//各 output 之间以逗号隔开 且 最后一个 output 后面无 逗号
);
//*************-------------------- 内部参数定义 ----------------------************\
//*************-------------------- 内部信号定义 ----------------------************\
//*************------------------- 模块的程序设计 ---------------------************\
assign O_SUM_RES = I_ADD1+I_ADD2;
endmodule
//*********************************************************************************\
Verilog HDL 的程序结构位于 module 和 endmodule 之间,每个Verilog 程序主要包括四个部分:IO端口定义、声明、内部参数和信号定义、功能定义。
建议在进行端口声明时直接定义其类型(输入、输出、双端口),如上例所示。这样简单明了。
模块端口不加特殊声明 默认 wire 类型,模块端口的输出端可以定义为 reg 类型。如果直接将 always 块内的输出直接送到输出端口 那么输出必须定义为 reg 类型 ,这是语法要求,否则会报错。
端口的 位宽默认是 1位,当需要多位时就需要指定位宽,如:output reg [11 : 0] O_RES 。一般都是左边是高位,右边是低位,当然也可以反过来写成:output reg [0 : 11] O_RES 为了方便设计,一般都是选择前者。
顶层模块调用底层模块,对应端口连接时有两种方式:
1、引用端口的顺序和所声明端口的顺序严格对应。这种方法使用较少。
2、引用端口时用 英文 "." 来引用原模块的端口名,这种方法最为常用,尤其在端口数目多的时候:
module_example #( .ADDER_WIDTH(ADDER_WIDTH), .SUM_WIDTH(SUM_WIDTH) ) inst_module_example ( .I_ADD1 (I_ADD1), .I_ADD2 (I_ADD2), .O_SUM_RES (O_SUM_RES) );
此部分也即模块的实现部分,主要包括中间变量或模块内部信号的声明和逻辑设计。
1、内部信号或者参数的声明:
内部信号的声明主要就是 wire 、reg 型的声明。内部参数(非模块传输参数)可以用 localparam 进行声明。
2、逻辑设计:
逻辑设计包括模块调用和程序块。模块调用的方式上面有例子说明。程序块中主要是 组合逻辑和时序逻辑。最常用到的语句块就是 always 语句块。
always 语句块的总体结构:
always @ (<敏感向量表>) begin <逻辑描述>; end
对于 always 块实现纯组合逻辑,敏感向量表应该是 该逻辑块所有的输入信号 ,以英文 逗号 隔开。
对于 always 块实现纯同步时序逻辑,敏感向量表应该是 时钟信号的边沿。
对于 always 块实现纯异步时序逻辑,敏感向量表应该是 时钟信号的边沿 和 复位信号的边沿。
注意:某些语句只能在 always 语句块内 使用 比如 if-else
除了always语句块,还有常用的连续赋值语句 assign ,该语句只对线网型变量赋值。线网型变量一般对应到 FPGA 内部是一段连线 ,连线的值会随着驱动源变化而不断变化。
首先介绍Verilog HDL 语法的四值系统:
逻辑1:高电平;
逻辑0:低电平;
不确定逻辑X:未知电平,一般由于赋值冲突造成;
高阻逻辑Z:高阻态,相当于电路开路;
二进制表示法:< 二进制位宽 > ' b < 二进制数 > (B 、b 均可) 例:8‘b0011_1001
注意:可以赋值 高阻态 Z(z 或 ?) ,但不可以赋值 不定态 X (x)。当二进制位宽过大时,可以用下划线分割开,便于查看,下划线处于数字之间。
八进制表示法:< 二进制位宽 > ' o < 八进制数 > (O 、o 均可) 例:6‘o71
注意:八进制赋值,经常出现位宽不匹配的情况,编译器会将高位截断。同样支持下划线表示法。支持高阻态。
十六进制表示法:< 二进制位宽 > ' h < 十六进制数 > (H 、h 均可) 例:8‘h39
注意:支持下划线表示法。支持高阻态。
十进制表示法:< 二进制位宽 > ' d < 十进制数 > (D 、d 均可) 例:8‘d39
注意:十进制数不要超过位宽的表示范围。支持高阻态,但是只有一个Z(z),如8'dz。负数的 常量表达式注意:-8'd100 而不是 8'd-100。
parameter :Verilog HDL 语法中,常用 parameter 来定义常量。从而提高程序的可读性和代码可维护性。可以声明在模块接口部分(如文章开头的示例代码);也可以声明在模块内部。在模块接口处使用 parameter 可以实现模块的复用,在模块的例化时可以重新给定 parameter 的数值(如 模块端口的定义小节 的例子),这给模块的设计带来很大的灵活性。
语法:parameter <参量名> = <常量表达式> ;
localparam:使用方法与 parameter 基本一致,不同的是,localparam 只能用在模块内部,不能实现参量复用。
语法:localparam <参量名> = <常量表达式> ;
specparam:specify 语法块中,定义模块的时序模型,为了区别于module内的参数,使用关键字:specify。(使用极少,模块设计基本用不到)
语法:specparam <参量名> = <常量表达式> ;
Verilog HDL 语法中,凡是在 程序块 中被赋值的信号(变量)必须为寄存器类型。但是未必在实际电路中就是寄存器。如果程序块中描述的是组合逻辑则,实际电路中寄存类型变量对应硬件连线;如果描述的是时序逻辑,实际电路中寄存器类型的变量对应寄存器;对于组合时序逻辑混合的程序块,实际电路中寄存器类型的变量可能对应锁存器。
1、reg
reg型变量是寄存器类型中用的最多的,具体语法:reg <位宽范围> <变量名> <变量数目范围>;
示例:reg [15:0] R_COUNTER [512:1]; //512个16位的reg型数据空间
reg [3:0] R_1,R_2,R_3;
reg R_VALID;
2、integer
整数类型,位宽等于32;实际设计时除了仿真,一般不用 integer 进行设计。具体语法:integer <变量名>;
示例:integer K;
3、real
实数类型,抽象级别高,一般都不建议使用该类型。
模块的输入接口(input)、双端口(inout)必须为线网类型,连续赋值的对象为线网类型。实际电路中,线网类型对应硬件连线。
1、wire
wire 是线网类型中最最常用的一种类型。语法:wire <位宽范围> <变量名> <变量数目范围>;
示例:wire [15:0] W_COUNTER [1024:1];//1024个16位宽的 wire 型数据
wire [3:0] W_1,W_2,W_3;
wire W_VALID;
2、tri
tri 用法和 wire 在语法上完全一致。三态门驱动的硬件连线用此定义。
3、supply1/supply0
表示上拉到逻辑1/逻辑0。用的很少,亦可作常数1/0来用。
4、wand/triand
线与(wand、triand)一般用于集电极开路电路中。但是FPGA内部一般无OC门,基本不用此类型。
5、wor/trior
FPGA内部一般此结构,线或一般不用。
6、tri1/tri0/trireg
分别表示高阻态时,可以进行上拉、下拉、保持之前逻辑。一般不用。
【1】夏宇闻. Verilog 数字系统设计教程 第二版.
【2】狄超. FPGA之道.
【3】IEEE Standard for Verilog Hardware Description Language 1364-2005.
博文声明:整理时间有限,如有发现任何纰漏,及时私信我更正~
掌握了基本的Verilog语法,不去实战练习的话很难有大的突破。牛客网可以为大家提供一个免费的刷题练习的平台。非常推荐大家使用。
链接如下:牛客网-Verilog专项https://www.nowcoder.com/link/pc_csdncpt_zls_verilog这个里面有很多代码题目练习,对于新手来说可以快速掌握Verilog编程的基本语法,对于老手来说也可以巩固自己的编程能力。不用付费免费试用哦。基本是每个即将找工作的人必备的刷题网站。快行动起来吧!