Verilog HDL基础概念:
整数:
在Verilog HDL中, 整数有四种进制表示形式:
-
二进制整数(b或B)
-
十进制整数(d或D)
-
十六进制整数(h或H)
-
八进制整数(o或O)
数字表达方式有以下三种:
-
size\] 'base value:这是一种全面的描述方式。
如:一个4位二进制数的位宽为4; 一个4位十六进制数的位宽为16
base:为o或O,b或B,d或D,h或H之一;
value:base进制下的常量的数值。
-
'base value:数的位宽采用缺省位宽(由具体的机器系统决定,但至少32位)。
-
Value:在这种描述方式中,采用缺省进制十进制。
eg:
4'b1111 // This is a 4-bit binary number
12'habc // This is a 12-bit hexadecimal number
16'd255 // This is a 16-bit decimal number
'hc3 // This is a 32-bit hexadecimal number
'o21 // This is a 32-bit octal number
276 // This is a 32-bit decimal number by defaul
(2+3)'b10 //非法:位长不能够为表达式
x和z值:
x代表不定值,z代表高阻值。
x(或z)在十六进制值中代表4位x(或z),在八进制中代表3位x(或z),在二进制中代表1位x(或z)。
z还可以写作?。在使用case表达式时建议使用这种写法,以提高程序的可读性。
eg:
4'b10x0 //位宽为4的二进制数,从低位数起第二位为不定值
4'b101z //位宽为4的二进制数从低位数起第一位为高阻值
12'dz //位宽为12的十进制数其值为高阻值(第一种表达方式)
12'd? //位宽为12的十进制数其值为高阻值(第二种表达方式)
8'h4x //位宽为8的十六进制数其低四位值为不定值
下划线(underscore_):
可以用下划线将数分隔开,以提高程序可读性。
下划线不可以用在位宽和进制处,只能用在具体的数字之间。
eg:
16'b1010_1011_1111_1010 //合法格式
8'b_0011_1010 //非法格式
字符串:
Verilog 语言中,字符串常常用于表示命令内需要显示的信息。
用" "括起来的一行字符串,换新一行用 "\n" 字符,与 C 语言一致。
在字符串中可以用 C 语言中的各种格式控制符,
eg: \n 换行符,\t 制表符 ,\\ 字符\本身 ,\" 字符"
在字符串中可以用 C 语言中的各种数值型式控制符,
eg: %b(二进制), %o(八进制), %d(十进制), %h(十六进制), %t( 时间类型),%s (字符串类型)
标识符:
'$' 符号表示 Verilog 的系统任务和函数
常用的系统任务和函数有下面几种:
$time //找到当前的仿真时间
$display, $monitor //显示和监视信号值的变化
$stop //暂停仿真
$finish //结束仿真
eg:
initial monitor(time,,"a=%b, b=%d", a, b); //每当a 或b值变化时该系统任务都显示当前的仿真时刻并分别用二进制和十六进制显示信号a和b的值
数据类型:
Wire :表示器件之间的物理连接, 称为网络连接类型
Reg :表示抽象的储存单元,称为寄存器类型
wire**(**网络连线): 由模块或门驱动的连线。驱动端信号的改变会立刻传递到输出的连线上。
wire型数据常用来表示以assign关键字指定的组合逻辑信号。
Verilog程序模块中输入输出信号类型缺省时自动定义为wire型。
wire型信号可以用作任何方程式的输入,也可以用作"assign"语句或实例元件的输出。
wire [位宽] 数据名1, 数据名2,... 数据名i;
wire a; //定义了一个一位的wire型数据
wire [7:0] b; //定义了一个八位的wire型数据
wire [4:1] c, d; //定义了二个四位的wire型数据
Reg :寄存器是数据储存单元的抽象。寄存器数据类型的关键字是reg。可以通过赋值语句改变寄存器储存的值。
在"always"块内被赋值的每一个信号都必须定义成reg型。
reg [位宽] 数据名1,数据名2,... 数据名i;
reg rega; //定义了一个1位reg型数据
reg [3:0] regb; //定义了一个4位的reg型数据
reg [4:0] regc, regd; //定义了两个5位的reg型数据
位选择和部分选择:
wire或者reg向量名[bit_select_expr]
reg [5:0] State;
wire [3:0] Prt;
wire Bbq;
State [1] && State [4] //寄存器位选择。
Prt [0] | Bbq //线网位选择。
部分选择中,向量的连续序列被选择。形式如下:
wire或者reg向量名[常数表达式1:常数表达式2]
reg [5:0] State;
wire [0:3] Prt;
State [4:1] //寄存器部分选择。
Prt [3:2] //线网部分选择。
存储器:
通过对reg型变量建立数组来对存储器建模。
reg [n-1:0] 存储器名[m-1:0];
reg[n-1:0]定义了存储器中每一个存储单元的大小,即该存储单元是一个n位的寄存器。
存储器名后的[m-1:0] 则定义了该存储器中有多少个这样的寄存器。最后用分号结束定义语句。
一个由n个1位寄存器构成的存储器组不同于一个n位的寄存器。
reg [n-1:0] rega; //一个n位的寄存器
reg mema [n-1:0]; //一个由n个1位寄存器构成的存储器组
一个n位的寄存器可以在一条赋值语句里进行赋值,而一个完整的存储器则不行。
rega =0; //合法赋值语句
mema =0; //非法赋值语句
mema[3]=0; //正确.给memory中的第3个存储单元赋值0
Verilog HDL模块概念:
1.Verilog HDL程序是由模块构成的。每个模块的内容都是嵌在module和endmodule两个语句之间。每个模块实现特定的功能;
2.模块是可以进行层次嵌套的。可以将大型的计分割成不同的小模块来实现特定的功能,最后通过顶层模块调用子模块来实现整体功能;
3.每个模块要进行端口定义,并说明输入输出口,然后对模块的功能进行行为逻辑描述;
4.Verilog HDL区分大小写;
5.Verilog HDL是自由格式的,即结构可以跨越多行编写,也可以在一行内编写。白空(新行、制表符和空格)没有特殊意义。除了endmodule语句外,每个语句和数据定义的最后必须有分号;
6.可以用/ *.....* /和//对Verilog HDL程序的任何部分作注释。
模块结构:
"模块"(block)是Verilog的基本设计单元。
一个模块是由两部分组成的,一部分描述接口,另一部分描述逻辑功能, 即定义输入是如何影响输出的。
Verilog模块结构完全嵌在module和endmodule声明语句之间;
每个Verilog程序包括四个主要部分:端口定义、I/O说明、内部信号声明、功能定义。
eg:

module block (a,b,c,d);
input a,b;
output c,d;
assign c= a | b ;
assign d= a & b;
endmodule
模块的端口定义:
模块的端口声明了模块的输入输出口。其格式如下:
module 模块名(端口1,端口2,端口3,.........);
如:module sample ( q, a, b, sel, clk, resetn ) ;
I/O说明:对输入输出端口的属性进行定义,包括端口的方向、 信号位宽等。
定义端子方向有如下语句:
input(输入端口)
output(输出端口)
inout(双向端口)
定义信号位宽:
信号类型 [MSB:LSB] 信号名
如:input [11:0] address;
inout [ 7:0] data;
内部信号说明:在模块内用到的和与端口有关的wire 和 reg 变
量的声明。
如: reg [width-1 : 0] R变量1,R变量2 ......;
wire [width-1 : 0] W变量1,W变量2......;
模块的功能定义可以用采用下面的4种方式描述:
- 数据流方式;
2.行为方式;
3.结构方式;
4.混合描述方式。
数据流描述方式:用连续赋值语句"assign" ,只能描述组合逻辑。
连续赋值语句的语法为:
assign [delay] LHS_net = RHS_ expression
无论右边的操作数何时发生变化, 右边表达式都重新计算, 并且在指定的时延后赋给左边线网变量。如果没有定义时延值, 缺省时延为0。
eg:

`timescale 1ns/ 1ns
module Decoder2x4 (A, B, EN, Z);
input A, B, EN;
output [ 0 :3] Z;
wire Abar, Bbar;
assign #1 Abar = ~ A;
assign #1 Bbar = ~ B; 。 assign #2 Z[0] = ~ (Abar & Bbar & EN) ;
assign #2 Z[1] = ~ (Abar & B & EN) ;
assign #2 Z[2] = ~ (A & Bbar & EN) ;
assign #2 Z[3] = ~ (A & B & EN) ;
endmodule
连续赋值语句是隐式而非显式的建模方式。
连续赋值语句是并发执行的,也就是说各语句的执行顺序与其在描述中出现的顺序无关。
行为描述方式:
用类似软件程序中的各种算符,直接表示输入输出信号之间的关 系
的描述方法称为行为描述。
设计的行为功能使用下述过程语句结构描述:
-
initial语句:此语句只执行一次。
-
always语句:此语句总是循环执行, 或者说重复执行。
只有寄存器类型数据能够在这两种语句中被赋值。
所有的initial语句和always语句在0时刻并发执行。
always:
always 语句中有一个与事件控制 相关联的顺序过程(begin-end对)。
这意味着只要A、B或Cin 上发生事件,即A、B或Cin之一的值发变化,顺序过程就执行。
在顺序过程中(begin-end对)的语句顺序执行,并且在顺序过程执行结束后被挂起。
顺序过程执行完成后,always 语句再次等待A、B或Cin上发生的事件。

module FA_Seq (A, B, Cin, Sum, Cout);
input A, B, Cin;
output Sum, Cout;
reg Sum, Cout;
reg T1, T2, T3;
always @ ( A or B or Cin )
begin
Sum = (A ^ B) ^ Cin;
T1 = A & Cin;
T2 = B & Cin;
T3 = A & B;
Cout = (T1| T2) | T3;
end
endmodule
initial:
initial语句包含一个顺序过程。 这一顺序过程在0 ns时开始执行, 并 且在顺序过程中所有语句全部执行完毕后, initial语句永远挂起。此语句只执行一次。
`timescale 1ns / 1ns
module Test;
reg Pop, Pid;
initial
begin
Pop = 0;
Pid = 0;
#5 Pop = 1;
#3 Pid = 1;
#6 Pop = 0;
#2 Pid = 0;
end ...
endmodule
门语句:

module FA_Str (A, B, Cin, Sum, Cout);
input A, B, Cin;
output Sum, Cout;
wire S1, T1, T2, T3;
xor X1 (S1, A, B);
xor X2 (Sum, S1, Cin);
and A1 (T3, A, B);
and A2 (T2, B, Cin);
and A3 (T1, A, Cin);
or O1 (Cout, T1, T2, T3);
Endmodule
混合描述方式:结构的和行为的描述自由混合。模块描述中可以包含实例化的门、 模块实例化语句、连续赋值语句以及always语句。

module FA_Mix (A, B, Cin, Sum, Cout);
input A,B, Cin;
output Sum, Cout;
reg Cout;
reg T1, T2, T3;
wire S1;
xor X1(S1, A, B); // 门实例语句。
always @ ( A or B or Cin ) //always语句
begin
T1 = A & Cin;
T2 = B & Cin;
T3 = A & B;
Cout = (T1| T2) | T3;
end
assign Sum = S1 ^ Cin; // 连续赋值语句
endmodule