背景
关于边沿检测,写过的博文也很多,不下于4篇了,当然都是学习过程中边学边记的,过了那么久设计的沉淀,又过了一个疫情的荒诞时光,安静下来,还谈一下这个问题,并给出一种新的写法(其实都是一个原理)。也许你觉得不值一提,但总会有点意义。
新检测方法
这种写法在Vivado中进行行为仿真时,tb文件中,即使在上升沿给0变1数据,也能检测到边沿。如下:
initial begin
//sys_rst = 1;
vio_txen = 0;
#7
//sys_rst = 0;
@(posedge sys_clk) vio_txen = 1;
# 64 vio_txen = 0;
// #26
// @(posedge sys_clk) vio_txen = 1;
// # 20 vio_txen = 0;
end // initial
真正实现了边沿的检测。
对于tb文件中不在0到1时给输入数据,更不在话下:
initial begin
//sys_rst = 1;
vio_txen = 0;
#7
//sys_rst = 0;
@(negedge sys_clk) vio_txen = 1;
# 64 vio_txen = 0;
#26
@(posedge sys_clk) vio_txen = 1;
# 20 vio_txen = 0;
end // initial
总之,检测能力一流!
旧检测方法
我们最常用的边沿检测方式,以上升沿检测为例,大概就是对输入数据寄存一拍,然后用寄存后的数据取反,逻辑与上输入数据:
//____________________code start___________________
module rise_detect_traditionnal(
input sys_clk,
input sys_rst,
input vio_txen,
output vio_txen_rise
);
reg vio_txen_r ;
//------------------Code Start Here-----------------//
always @ (posedge sys_clk or posedge sys_rst)
begin
if(sys_rst)
vio_txen_r <= 1'b0 ;
else
vio_txen_r <= vio_txen ;
end
assign vio_txen_rise = ~ vio_txen_r & vio_txen;
endmodule
这种方法诚然没有问题,但存在让人迷惑的地方,在vivado仿真时候,如果输入数据是在时钟上升沿从0到1的一个数据,那么就看不到检测的上升沿:
测试文件同上!
仿真图如下:
可见,后一个上升沿没有检测到。
当然这种问题的解释也在上一篇博客的最后讲到了。
改进旧检测方法
当然对于上一种旧检测方案的改进是,首先将待检测数据同步到时钟域内,之后再寄存一拍,最后用同步数据和寄存数据取上升沿检测逻辑。也就是打两拍,保证没有问题。这也是最最标准且常见的。
如下:
module rise_detect_improved(
input sys_clk,
input sys_rst,
input vio_txen,
output vio_txen_rise
);
reg vio_txen_r1;
reg vio_txen_r2;
always @(posedge sys_clk) begin
if (sys_rst) begin
vio_txen_r1 <= 0;
vio_txen_r2 <= 0;
end
else begin
vio_txen_r1 <= vio_txen;
vio_txen_r2 <= vio_txen_r1;
end
end //always
assign vio_txen_rise = (~vio_txen_r2)& vio_txen_r1;
endmodule
仿真图如下:
可见,没有任何问题,这种也是我最喜欢用的方式。
设计介绍
背景已经把所有的基本上都讲了,这里主要提的还是今天博客的主题,就是一种新写法。可能在你眼里不是新写法,但请考虑下萌新哈。
设计代码
module rising_detect(
input sys_clk,
input sys_rst,
input vio_txen,
output reg vio_txen_rise
);
wire vio_txen ;
reg vio_txen_r ;
//------------------Code Start Here-----------------//
always @ (posedge sys_clk or posedge sys_rst)
begin
if(sys_rst)
vio_txen_r <= 1'b0 ;
else
vio_txen_r <= vio_txen ;
end
always @ (posedge sys_clk or posedge sys_rst)
begin
if(sys_rst)
vio_txen_rise <= 1'b0 ;
else if((~vio_txen_r) & vio_txen)
vio_txen_rise <= 1'b1 ;
else
vio_txen_rise <= 1'b0 ;
end
endmodule
仿真情况
module rise_detect_tb();
//______________ wire and reg definition ___________________________________
reg sys_clk;
reg sys_rst;
reg vio_txen;
wire vio_txen_rise;
//____________________ simulation code start _______________________________
//____________________generate system clock ________________________________
initial begin
sys_clk = 0;
forever begin
# 5 sys_clk = ~sys_clk;
end // forever
end // initial
//______________________ generate input data ________________________________
initial begin
sys_rst = 1;
vio_txen = 0;
#7 sys_rst = 0;
@(negedge sys_clk) vio_txen = 1;
# 64 vio_txen = 0;
#26
@(posedge sys_clk) vio_txen = 1;
# 20 vio_txen = 0;
end // initial
//_____________________ instantiation the design under test ___________________
rising_detect inst_rising_detect
(
.sys_clk (sys_clk),
.sys_rst (sys_rst),
.vio_txen (vio_txen),
.vio_txen_rise (vio_txen_rise)
);
endmodule
仿真图
最后想提出的问题
各位有没有注意到这个仿真图:
延迟一拍的数据和原数据一致,但是为什么还可以产生正常的上升沿检测结果?
放大看看:
评论区留言,提出你的见解呗?
同行邀请
工程分享
链接
提取码:48ka