RTL例子

module led
(
input wire in1,
input wire in2,
input wire sel,
output reg out //输出控制LED灯
);
//输入只能是wire型变量 输出可以是wire型变量也可以是reg型变量
//如果输出是在always块中被赋值(即在“<=”的左边)就要用reg变量
//如果输出在assign语句中被赋值(即在“=”的左边)就要用wire型变量

always@(*)
//always@(sel,in1,in2)

//"*"为通配符,表示只要if括号中的条件或赋值号右边的变量发生变化,则立即执行下面的代码
//"*"在此always@中等价于“(sel,in1,in2)”写法,使用always记得加@
/*
if(sel == 1'b1)
out = in1;
else
out = in2;
*/
//verilogs 中case写法

case(sel)
1'b1 : out = in1;
1'b0 : out = in2;
default : out = in1; //default与C语言用法一样,如果能穷举所有情况就可不使用default
endcase

endmodule

Testbench例子

`timescale 1ns/1ns
module tb_led();

//要在initial块和always块中被赋值的变量一定是reg型
//在testbench 中待测试RTL模块的输入永远是reg型变量
reg in1;
reg in2;
reg sel;

//在testbench中待测试RTL模块的输出永远是wire型变量
wire out;

//initial语句是不可以被综合的,一般只在testbench中表达而不在RTL代码中表达
//initial块中的语句上电后只执行一次,主要用于初始化仿真中要输入的信号
//初始化值在没有特殊要求的情况下给0和1都可以,如果不赋初值,仿真是信号会显示不定态(ModelSim中的波形显示红色)

initial
begin
//在仿真中 begin...end 块中的内容都是顺序执行的,在没有延时的情况下几乎没有差别,看上去是同时执行的,如果有延时才能表达的比较明了;
//而在 rtl 代码中 begin...end 相当于括号的作用,在同一个 always 块中给多个变量赋值的时候要加上
in1 <= 1'b0;
in2 <= 1'b0;
sel <= 1'b0;
end

always #10 in1 <= {$random} % 2;

always #10 in2 <= {$random} % 2;

always #10 sel <= {$random} % 2;

initial begin
$timeformat(-9,0,"ns",6);;//设置显示的时间格式,此处表示的是(打印时间单位为纳秒,小数点后打印的小数位为0位,时间值后打印的字符串为“ns”
//打印的最小数量字符为6个
//只要监测的变量(时间、in1, in2, sel, out)发生变化,就会打印出相应的信息
$monitor("@time %t:in1=%b in2=%b sel=%b out=%b",$time,in1,in2,sel,out);
end

led led_inst //第一个是被实例化模块的名子,第二个是我们自己定义的在另一个
//模块中实例化后的名字。同一个模块可以在另一个模块中或不同的
//另外模块中被多次实例化,第一个名字相同,第二个名字不同
(
//前面的“in1”表示被实例化模块中的信号,后面的“in1”表示实例化该模块并要和这个
//模块的该信号相连接的信号(可以取名不同,一般取名相同,方便连接和观察)
//“.”可以理解为将这两个信号连接在一起
.in1(in1),
.in2(in2),
.sel(sel),
.out(out)
);

endmodule

发表回复