Verilog 基本语法
一、 Verilog 只有一个部分,即module,称之为模块,模块的接口部分主要分为三个部分,即模块命名部分、参数声明部分和端口列表部分。
(1)模块声明部分很简单,语法关键字是module,在空格后面跟随一个名字即可。
(2) 参数声明部分关键字是parameter,parameter的作用主要有两个,一个是增加代码的可重用性,另一个是定义代码中的常量,增加代码可读性和方便代码修改。
(3)端口列表部分,Verilog中的端口有三种分别是输入端口、输出端口、以及双向端口,inout 是双向端口,既可以接收数据也可以发送数据,主要是在处理总线数据时使用,一般不用于FPGA的内部逻辑。
3.模块实现部分
从端口定义结束到endmodule关键字之间为模块实现部分,模块实现按照功能特性分为----声明部分和语句部分。
(1)声明部分
声明参数,这种写法是错误的

module portDefine( input [WIDTH-1:0] a,
 output b
 );
 parameter WIDTH=8;
 wire [WIDTH-1:0] t;
 endmodule


需要调整顺序
(2) 语句部分
模块中的语句部分是整个模块功能的核心,其中的语句都是并行执行的,并行语句主要包括三类:实例化语句、程序块、和连续赋值语句。
这里主要介绍程序块与连续赋值语句。
**程序块:**程序块中最常用的一种就是always 程序块,always程序块会反复不断地执行,always类型分为三种
类型一:纯组合逻辑,always里面只描述组合逻辑,敏感信号列表里应该包括所有的而输入信号,输入信号的判断有三种,满足下述三个条件之一的就是输入信号:
条件一:出现在赋值等号右边的信号
条件二:出现在条件判断中的信号
条件三:没有出现在赋值等号左边的信号
类型二:纯同步的时序逻辑always,这个always只描述通部时序逻辑,敏感列表中只包括同步逻辑的时钟信号。
类型三:具有异步复位信号的时序逻辑always
连续赋值语句:连续赋值语句是针对线网变量的一种赋值语句,线网变量对应FPGA中的一段连线,连线的值随着驱动源的变化不断变化的,因此称为连续赋值语句,是一种描述组合逻辑的语句,以下是一个例子:
wire a,b;
assign a=b;
同样的功能使用always 语句也可以描述
reg a;
wire b;
always @(b)
a=b;
二、 Verilog 数据类型
Verilog有三大类数据类型,分别是寄存器数据类型、线网数据类型、参数数据类型,真正起作用的数据类型是寄存器数据类型与线网数据类型,它们俩共同遵守Verilog的四值逻辑系统。
在Verilog中逻辑系统中有四种值,即四种状态:
逻辑0: 逻辑低电平
逻辑1: 逻辑高电平
不确定逻辑X:表示不可推断电平,一般是由于赋值冲突引起的。
高阻逻辑Z:相当于电路中的断路。
1、寄存器数据类型
Verilog 中规定,凡是在程序块中被赋值的变量,都必须是寄存器类型的,在数字电路中,如果该程序块描述的是时序逻辑,则寄存器变量被综合为寄存器,如果该程序块描述的是组合逻辑,则寄存器变量会综合为硬件连线,如果描述的是不完全组合逻辑,该寄存器变量对应为锁存器。
(1) reg是寄存器数据类型中最主要最常用的类型
(2)integer是整数类型,例如循环语句中的循环变量参数,integer i
2、线网数据类型
Verilog中规定,模块中的input和inout端口必须是线网类型,连续赋值语句的被赋值对象是线网类型,线网类型实际上对应着硬件的连线,包括以下几个类型:
(1) wire
wire a; 如果不写,默认是定义1 bit的wire 类型。
(2) tri
tri和wire在用法上是一模一样的,不过如果我们需要定义一些会被三态门驱动的硬件连线,用tri来命名会让代码更有可读性。
(3) supply1和supply0
这两个线网类型表示强行上拉到逻辑1和强行下拉到逻辑0,可以理解为电源线和地线,在Verilog被用做常数使用。
3、参数数据类型
(1) parameter
可以声明两个地方,一个是模块的接口部分,另一个是模块实现的声明部分。
(2) localparam
这个关键字与parameter类似,唯一的不同的就是在上层模块中的例化不能对其取值进行重新定义。
(3)specparam
Verilog中有一种特殊的语法块,叫做specify,主要用于定义模块中的时序模块,在specify语法块中也可以拥有自己的参数,为了区别与module内的参数,所以使用了specparam的关键字。
4、数组的定义
Verilog中只支持一维数组,例如要定义一个32bit宽,可存储512个数据的存储器,声明为:
reg [31:0] myRam[511:0]
以下操作是没问题的:
wire [31:0] dout;
assign dout=myRam[256];
以下操作是不允许的
wire signbit;
assgin signBit=myRam[128][31];
若要查看myRam中存储的某一个数据中的一个bit
assign dout=myRam[256];
assign signBit=dout[31];
5、Verilog 初始化
初始化针对的是FPGA中有内部记忆的单元,例如寄存器、BLOCK、RAM等,对于无法记忆的单元,例如硬件连线,没有必要也无法对其进行赋初值,在Verilog语言中,有两种初始化的方法,分别是分布式和集中式
分布式赋初值是在声明变量的时候顺便赋初值,例如:
reg [7:0] data=8’hff;
集中式赋值则是采用了initial,initial与always 最大的区别是在于always是永不停止的执行,initial只在程序最开始的时候执行一次,initial内部的寄存器类型变量使用阻塞与非阻塞赋值都行,没有区别。