|
2.1.简单的Verilog HDL模块
2.1.1. Verilog 语法简介
下面先介绍一个个简单的Verilog HDL程序,从中了解Verilog模块的特性。
module test_project_top( //模块名
input clk, // 时钟输入
input resetn, // 复位
input[7:0] a, //信号输入,信号a 位宽为8 bit
input[7:0] b, //信号输入,信号b 位宽为8 bit
input en, // 信号是能输入 信号en 位宽为1 bit
output reg [8:0] c, // 寄存器类型定义,信号输出 c为9bit
output reg [15:0] d // 寄存器类型定义,信号输出 d 为16bit
);
/*........*/ //.........表示注释部分,注释只是为了方便程序员理解程序,对编译是不起作用的。
/*一个 .v文件中主要由 一个或多个 module ... endmodule块组成
每个module块内包括:模块名,输入端口,输出端口,以及多个时序电路,组合电路等组成
*/
// 简单的时序电路组成
always@(posedge clk or negedge resetn)
begin
if(~resetn) // 或者 if(!resetn) 取 resetn 反
begin
d<=16'h0;
end
else
begin
if(en) // if en ==1 那么 d等于a*b+a/b;否则d<=0
d<=a*b+a/b; // + , - ,* ,/ 加减乘除
else
d<=0;
end
end
// 简单的组合电路
always@(a or b) // 只要其中a或b一个变化就执行always块内语句
begin
if(en) // verilog 语法 if ... else ...,在组合电路中一个if对应一个else,不能缺else,防止产生锁存器
c<=a*b+a/b;
else
c<=0;
end
wire[8:0] sum; // 常见变量定义类型:wire-线网型,reg-寄存器
assign sum =a+b; // 组合电路赋值,关键字 assign
wire[15:0] multy;
assign multy = (en ) ? a*b :0;// 如果 en ==1,那么 multy =a*b,否则multy =0;
wire e;
assign e =&a; // & 按位与
wire f;
assign f =|b;// | 按位或
wire [8:0] c_sum;
// 实例化模块
my_add u_add_top( // my_add 模块名 ,u_add_top 实例化名
.clk(clk), //端口连接输入
.resetn(resetn),//端口连接输入
.a(a),//端口连接输入
.b(b),//端口连接输入
.c(c_sum)//端口连接输出
);
endmodule
这个小程序表述了一个.v文件包含了常用的verilog语法,变量的定义类型包括:wire,reg等,常见的运算符号跟C语言中相同,理解较容易。在这个例子中存在着两个模块。模块test_project_top引用由模块my_add定义的实例部件u_add_top。模块test_project_top是顶层模块。模块my_add则被称为子模块。在实例部件u_add_top中,带 “.”的表示被引用模块的端口,名称必须与被引用模块my_add的端口定义一致,小括号中表示在本模块中与之连接的线路。
2.1.2、Verilog用于模块的测试
Verilog 还可以用来描述变化的测试信号。描述测试信号的变化和测试过程的模块也叫做测试平台(Testbench 或Testfixture),它可以对上面介绍的电路模块(无论是行为的或结构的)进行动态的全面测试。通过观测被测试模块的输出信号是否符合要求,可以调试和验证逻辑系统的设计和结构正确与否,发现问题及时修改。
下面我们来看一个Verilog的测试模块,
// 测试激励产生
`timescale 1ns / 1ps
module test_project_top_tb; // 测试文件模块名
// 信号测试激励,输入变量声明
reg clk ;
reg reset;
reg [7:0] a;
reg [7:0] b;
reg en;
// 输出变量声明
wire[8:0] c;
wire [15:0] d;
// 信号变量初始化 ,关键字 initial
initial
begin
clk =0;
reset =0;
a =0;
b =0;
en =0;
#1000; // 在1000 ns后 reset拉高
reset =1;
end
// 时钟生成
always #5 clk =~clk; //时钟周期 10ns ,每隔5ns 取反一次
always @(posedge clk)
begin // {$random} 为系统任务,它会产生一个随机数
#1 a= {$random}%256; // 产生随机的位信号流a和b ,%256为做模256运算
#3 b = {$random}%256; // 分别延迟1和3个时间单位后产生随机的位信号流a 和b
end
always #10000 en = !en; //产生周期为10000个单位时间的选通信号变化
// 实例化 被测试模块
test_project_top u_top(
.clk(clk), // 时钟输入
.resetn(reset), // 复位
.a(a), //信号输入,信号a 位宽为8 bit
.b(b), //信号输入,信号b 位宽为8 bit
.en(en), // 信号是能输入 信号en 位宽为1 bit
.c(c), // 寄存器类型定义,信号输出 c为9bit
.d(d) // 寄存器类型定义,信号输出 d 为16bit
);
endmodule
本测试例程是对2.1.1中的小程序的测试,属于RTL级功能仿真,主要调试语法及时序信号是否跟设计时一致。对于初学者来说,这是最基本的技能,必须熟练掌握。 |
|