1. 组合逻辑的测试模块
- 最简单的测试模块编写方式: 步进式信号。所谓步进式信号,即按时间顺序列出所有可能的输入信号组合,用于观察输出的情况是否满足要求。这种写法的好处是不需要太多的思考,非常适合输入端口较少的逻辑组合电路,。例如参考如下的设计模块,这是一个带有使能端的 3-8 译码器,在,en 为高电平时停止工作,输出全唯 1, 在 en 为 0 时正常工作,若无输入也输出全唯 1。ex 信号是为了区分输入全为 1 时的电路的工作状态而特意保留的扩展输出位。
3-8译码器
- 设计模块
module decoder3x8(din, en, dout, ex);
input [2:0] din;
input en;
output [7:0] dout;
output ex;
reg [7:0] dout;
reg ex;
always @(din or en)
if(en)
begin
dout=8'b1111_1111;
ex=1'b1;
end
else
begin
case(din)
3'b000: begin
dout=8'b1111_1110;
ex=1'b0;
end
3'b001: begin
dout=8'b1111_1101;
ex=1'b0;
end
3'b010: begin
dout=8'b1111_1011;
ex=1'b0;
end
3'b011: begin
dout=8'b1111_0111;
ex=1'b0;
end
3'b100: begin
dout=8'b1110_1111;
ex=1'b0;
end
3'b101: begin
dout=8'b1101_1111;
ex=1'b0;
end
3'b110: begin
dout=8'b1011_1111;
ex=1'b0;
end
3'b111: begin
dout=8'b0111_1111;
ex=1'b0;
end
default:begin
dout=8'b1111_1111;
ex=1'b0;
end
endcase
end
endmodule
该设计模块一共有四位的信号输入(一个 3 位输入加一个 1 位输入), 非常适合用步进试的信号方式。
- 由此编写的测试模块
module tbdecoder;
reg [2:0] din;
reg en;
wire [7:0] dout;
wire ex;
initial
begin
#10 en=0;din=3'b000;
#10 en=0;din=3'b001;
#10 en=0;din=3'b010;
#10 en=0;din=3'b011;
#10 en=0;din=3'b100;
#10 en=0;din=3'b101;
#10 en=0;din=3'b110;
#10 en=0;din=3'b111;
#10 en=0;din=3'b1x1;
#10 en=0;din=3'b000;
#10 en=0;din=3'b001;
#10 en=0;din=3'b010;
#10 en=0;din=3'b011;
#10 en=0;din=3'b100;
#10 en=0;din=3'b101;
#10 en=0;din=3'b110;
#10 en=0;din=3'b111;
#10 $stop;
end
decoder3x8 idecoder(din, en, dout, ex);
endmodule
- 功能仿真波形图
使用这种信号生成方式完成一些小的测试模块是很方便的,它与随机信号的最大不同在于信号的可控性,本例中信号的产生都是设计者已知的,不会出现未知情况,而随机信号则均为未知,每次都需要临时分析。但是当设计的输入信号位数较多时,采用这种方法来指定测试信号就显得比较麻烦,用随机数就简单许多。
2. 时序逻辑的测试模块
如果待测试的设计文件是一个时序电路,由于需要时钟信号和复位信号,以及一些模块间交互信号,测试模块的编写就变得复杂一些,这是可以使用@来进行信号定位,同时使用一些任务来帮助设计者判断结果。
4位的并串转换模块
- 设计模块
module p2s(data_in, clock, reset, load, data_out, done);
input [3:0] data_in;
input clock, reset, load;
output data_out;
output done;
reg done;
reg [3:0] temp;
reg [3:0] cnt;
always@(posedge clock or posedge reset)
begin
if(reset)
begin
temp<=0;
cnt<=0;
done<=1;
end
else if(load)
begin
temp<=data_in;
cnt<=0;
done<=0;
end
else if(cnt==3)
begin
temp<={temp[2:0],1'b0};
cnt<=0;
done<=1;
end
else
begin
temp <= {temp[2:0],1'b0};
cnt<=cnt+1;
done<=0;
end
end
assign data_out=(done==1)?1'bz:temp[3];
endmodule
该设计模块的基本功能就是在 load 为 1 时接收一个 4 位的数据,在接下来的 4 个周期里依次输出这4位信息,输出结束后 done 信号变为 1, 表示一次转换完毕, 可以继续接收下一个数据。 如果 done 信号位 0 则表示转换还在进行,不能输入数据。
- 为此设计模块编写测试模块
module tbp2s;
reg [3:0] data_in;
reg clock,reset,load;
wire data_out;
wire done;
initial
begin
reset=1;
#15 reset=0;
end
initial clock=1;
always #5 clock=~clock;
always @(done)
begin
if(done==1)
begin
data_in=$random%16;
load=1;
end
else
begin
load=0;
end
end
always @(posedge clock)
if(load==1)
begin:dis
integer i;
i=3;
repeat(4)
begin
@(posedge clock)
if(data_out==data_in[i])
$display("Output Right!");
else
$display("Bad Output!data_out= %b ,but data_in[%d]= %b",data_out,i,data_in[i]);
i=i-1;
end
end
p2s ip2s(data_in,clock,reset,load,data_out,done);
endmodule
运行仿真后可得到波形图,从图中可以看到,data_out 产生的 4 位数出就是 data_in 中的数据。同事还会有文字提示信息如下
前三个错误信息的原因是 i 的定位问题, 由于 reset 产生复位信号之后对 i 产生了影响,在该工作周期结束后即可恢复正常。