FPGA学习笔记(4)——时序逻辑电路入门
一、写一个触发器
重要:课程中提到:如果边沿触发的时钟信号和输入信号变化沿对其了,则认为该次触发采集的是输入信号在触发沿时刻前一段时间的值。(原理或许是触发器只是将储存的逻辑值传给输出Q,输入信号改写逻辑值需要延迟时间,这是否是一种竞争?)
举个例子,要实现一个具有置零端的触发器:

同步触发对应代码:
module flip_flop //D触发器
(
input wire sys_clk,
input wire sys_rst_n,
input wire key_in,
output reg led_out
);
//同步置零
always@(posedge sys_clk)
if(sys_rst_n == 1'b0)
led_out <= 1'b0;
else
led_out <= key_in;
//异步置零
// always@(posedge sys_clk || negedge sys_rst_n)
// if(sys_rst_n == 1'b0)
// led_out <= 1'b0;
// else
// led_out <= key_in;
endmodule
对应的test bench
`timescale 1ns/1ns
module tb_flip_flop();
reg sys_clk;
reg sys_rst_n;
reg key_in;
wire led_out;
initial
begin
sys_clk = 1'b1;
key_in <= 1'b0;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
#50
sys_rst_n <= 1'b0;
#80
sys_rst_n <= 1'b1;
#130
sys_rst_n <= 1'b0;
#200
sys_rst_n <= 1'b1;
end
always #10 sys_clk = ~sys_clk;
always #20 key_in <= {$random} % 2;
initial
begin
$timeformat(-9, 0, "ns", 6);
$monitor("@time = %t: sys_clk=%b sys_rst_n=%b key_in=%b led_out=%b", $time, sys_clk, sys_rst_n, key_in, led_out);
end
flip_flop tb_flip_flop_inst_0
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.key_in (key_in),
.led_out (led_out)
);
endmodule
得到的modelism仿真:

可以发现,确实如上面所说,若输入信号端变化沿对其,该次触发采集的是输入信号在触发沿时刻前一段时间的值。但是,我还想关注一点的是tb文件中的monitor是如何输出那一时刻每个端口的信号值呢?截取一个片段来看:

可以看到,仿真时刻为20ns时,对应时序图的黄色参考线,打印的信息是该时刻后一段时间的逻辑值。
二、触发器改写为异步置零,只需要改写条件
对照预设功能时序图,秩序将条件改写即可:
//同步置零
always@(posedge sys_clk)
if(sys_rst_n == 1'b0)
led_out <= 1'b0;
else
led_out <= key_in;
//异步置零
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
led_out <= 1'b0;
else
led_out <= key_in;
对应时序图:

三、其他
同步清零对用的RTL图:

异步清零对应的RTL图:

对比可以发现,对于同步置零端,仅仅通过改变输入端的逻辑组合就可以实现。更推荐使用异步复位。
4583

被折叠的 条评论
为什么被折叠?



