前言
在写一个寄存器实现信号延迟一拍的时候,出现了信号不延迟的问题,这里分析一下错误原因
代码编写
编写代码如下:
module reg_1(
input sys_rst_n,
input sys_clk ,
input a ,
output reg a_delay
);
//a_delay
always @(posedge sys_clk or negedge sys_rst_n) begin //当时钟上升沿到来的时候,把输入a的值赋给a_delay
if(!sys_rst_n)
a_delay <= 1'b0;
else
a_delay <= a;
end
endmodule
编写测试文件如下:
`timescale 1ns/1ns
module tb_reg_1();
parameter CLK_PERIOD = 5'd20;
reg sys_rst_n;
reg sys_clk ;
reg a ;
wire a_delay ;
initial begin
sys_clk <= 1'b0;
sys_rst_n <= 1'b0;
a <= 1'b0;
#(CLK_PERIOD/2)
sys_rst_n <= 1'b1;
a <= 1'b0;
#(CLK_PERIOD)
a <= 1'b1;
#(CLK_PERIOD*2)
a <= 1'b0;
end
always #(CLK_PERIOD/2)
sys_clk <= !sys_clk;
reg_1 u_reg_1(
.sys_rst_n(sys_rst_n),
.sys_clk (sys_clk ),
.a (a ),
.a_delay (a_delay )
);
endmodule
测试波形图如下:
delay 信号并没有延迟一周期
原因分析如下,虽然写了always语句,用来延迟时钟,但是当敏感信号触发的时候,所有输入信号都是最新的值,也就是说,当a和sys_clk同步变化的时候,由于sys_clk上升而进入该always语句块的时候,a已经是变化后的值了。
具体可以参考《ZYNQ学习:Verilog语言心得(二)》
这里对其进行补充
正确代码
后面是正确的rtl代码:
module reg_1(
input sys_rst_n,
input sys_clk ,
input a ,
output reg a_delay
);
reg a_1;
//a_1
always @(posedge sys_clk or negedge sys_rst_n) begin //当时钟上升沿到来的时候,把输入a的值赋给a_1
if(!sys_rst_n) begin
a_1 <= 1'b0;
a_delay <= 1'b0;
end
else begin
a_1 <= a;
a_delay <= a_1;
end
end
endmodule
成功延时一周期
总结
1.当敏感事件被触发的时候,可能有很多信号处于跳变状态,这时候,判断他们的值需要分析
2.当敏感信号上升或下降沿被触发的时候,在语句块内,该跳变信号的值是跳变后的值
3.当敏感信号上升或下降沿被触发的时候,在语句块内,其他所有跳变中输入信号的值是跳变后的值
4.当敏感信号上升或下降沿被触发的时候,在语句块内,其他被always赋值的输出信号,是跳变前的值,这是因为always语句并行执行,先把所有always的右值算出来然后再放到左边,不同always之间没有优先级。
补充5:当敏感信号上升或下降沿被触发的时候,在语句块内,所有跳变中被always赋值内部信号,是跳变前的值
补充6:在实现寄存器延迟功能的时候,需要在模块内部新定义reg来实现寄存,直接对输入信号进行always赋值是没有用的,如果信号变化和时钟同步,信号会同步变化。
1.对于模块中被always赋值的信号a_module,想要对其进行延迟非常简单,只需要加入always块
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
a_delay <= 1'b0;
else
a_delay <= a_module;
end
这样a_delay就是延迟后的信号了,因为a_inmodule信号是一个时序信号,肯定是和clk上升沿对齐的,所以当上升沿来临的时候,本always块取值还是a_inmodule之前的值,自然能实现延迟
2.对于输入信号a_in,就有一点复杂了,如果输入信号和时钟上升沿是对齐的,那么就需要先用一个reg,转为内部信号,然后再进行延时:
reg a_1;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
a_1 <= 1'b0;
a_delay <= 1'b0;
end
else begin
a_1 <= a_in
a_delay <= a_1;
end
end
3.如果输入信号没有和时钟对齐,上面的方法可能会导致信号延迟两拍,即信号先延后到下一个时钟上升沿,然后再延后一个周期。需要根据需要判断使用代码。
用思维导图表示如下: