锁存器
首先是关于锁存器,如果一段组合电路,if-else语句中如果缺少else分支,很容易就会生成锁存器。或者是即便有else分支,但是else分支的赋值仍然等于它本身,这也会导致锁存器的生成。
for example
module lat(wr_n, data_in, data_out, rst_n
);
input wr_n;
input [3:0]data_in;
input rst_n;
output [3:0]data_out;
reg [3:0]data_out;
always @(wr_n, rst_n)begin
if(rst_n == 1'b0)
data_out = 4'b0000;
else
if(wr_n == 1'b0)
data_out = data_in;
end
endmodule
使用vivado生成的RTL结构如下
行为级仿真(综合前)
首先我们进行功能仿真(综合前)
tb如下
module tb(
);
reg rst_n, wr_n;
reg [3:0]data_in;
wire [3:0]data_out;
lat u0(.rst_n(rst_n), .data_in(data_in), .wr_n(wr_n), .data_out(data_out));
initial begin
rst_n = 1'b0;
wr_n = 1'b1;
data_in = 4'b1111;
#1000;
rst_n = 1'b1;
#5;
wr_n = 1'b0;
data_in = 4'b1010;
#5;
wr_n = 1'b1;
data_in = 4'b0011;
end
endmodule
可以看到在wr_n拉高的同时,data_in也进行了变化,按理来说wr_n拉高以后,锁存器应该与输入 无关,而仅保持锁存器的值,行为级仿真的结果也是符合要求的
综合后功能仿真
可是在进行综合后的功能仿真时就出现了问题
首先是可以看到综合后仿真是带了一点点的延迟,然后当wr_n拉高和data_in同时变化时,锁存器仍然改变了采样了此时的变化,这明显不是我们想要的。
然后我们对tb进行修改,让data_in的变化稍微滞后(1ns)于wr_n的拉高
module tb(
);
reg rst_n, wr_n;
reg [3:0]data_in;
wire [3:0]data_out;
lat u0(.rst_n(rst_n), .data_in(data_in), .wr_n(wr_n), .data_out(data_out));
initial begin
rst_n = 1'b0;
wr_n = 1'b1;
data_in = 4'b1111;
#1000;
rst_n = 1'b1;
#5;
wr_n = 1'b0;
data_in = 4'b1010;
#5;
wr_n = 1'b1;
#1;
data_in = 4'b0011;
end
endmodule
而后继续进行综合后仿真
这样综合后仿真的波形就符合我们的要求。也就是说锁存器要想保持,wr_n必须提前拉高一段时间。
综合后时序仿真
然后我们进行综合后时序仿真
这是我们发现综合的时序仿真又不符合我么的要求,因为最后锁存器保存的值仍然是wr_n 拉高以后变化的值,尽管我们已经让data_in的信号变化滞后于wr_n拉高后的1ns
仔细观察,发现锁存器从开始的0变成a,整整滞后于wr_n拉低以后的6ns之多!也就是说锁存器在wr_n低电平采样到输入信号而后到输出整整延迟了6ns,(输入到输出延迟),但是通过vivado报告最大路径延时不过1.5ns,这应该是vivado加了pad以后的延时
然后继续修改testbench,将data_in变化滞后于wr_n的拉高信号5ns
module tb(
);
reg rst_n, wr_n;
reg [3:0]data_in;
wire [3:0]data_out;
lat u0(.rst_n(rst_n), .data_in(data_in), .wr_n(wr_n), .data_out(data_out));
initial begin
rst_n = 1'b0;
wr_n = 1'b1;
data_in = 4'b1111;
#1000;
rst_n = 1'b1;
#5;
wr_n = 1'b0;
data_in = 4'b1010;
#5;
wr_n = 1'b1;
#5;
data_in = 4'b0011;
end
endmodule
然后继续进行综合后的时序仿真, 可以看到波形是符合我们的要求的。
多说一点
之前在进行ram的仿真时,同样是综合前行为级仿真与参考模型完全正确,但是,综合后仿真却出了问题,费了很大功夫去找电路的问题,然后发现输出data_out一直为0,然后查到可能是复位的问题,说是如果复位时间很短,ram可能尚未完成初始化,所以将rst_n复位信号延迟到1000ns之后,然后在进行正常的写读操作。最终解决问题。
心得
因为之前没怎么进行过综合后仿真(包括功能仿真和时序仿真),所以当仿真出现问题是,很容易会怀疑到自己的电路出了,但其实有时候也可能是我们的testbench出了问题,包括复位信号,以及激励的变化等,都和功能仿真是有一些区别的。