DFF前面部分都比较简单,这里不赘述,直接从值得注意的开始做笔记。
Create circuit from turth table
这一题一开始我是用if-else做的,很符合常规思路,后面了解到原来还可以用case来描述,只要把两个要判断的条件括起来就行。
module top_module (
input clk,
input j,
input k,
output Q);
always@(posedge clk)
begin
case({j,k})
2'b00 : Q <= Q;
2'b01 : Q <= 0;
2'b10 : Q <= 1;
2'b11 : Q <= ~Q;
endcase
end
endmodule
边沿检测
时钟边沿检测是一个比较重要的内容,所以也花了不少的时间进行梳理。
Detect an edge
上升沿检测:
module top_module(
input clk,
input [7:0] in,
output reg [7:0] pedge);
reg [7:0] d_last;
always @(posedge clk) begin
d_last <= in; // Remember the state of the previous cycle
pedge <= in & ~d_last; // A positive edge occurred if input was 0 and is now 1.
end
endmodule
粗略地汇总一下,方便记忆和理解,可能有误,请多指教。(下图不是很严谨,只是为了理解,如果把clk也画出来会更好)
- 当检测到上升沿或者下降沿的时候,产生一个周期宽度的脉冲,就适合通过将信号打一拍后与原信号进行运算。
- 上升沿:将原信号in打一拍并求反得到~in1,再和原信号in进行与运算,即可检测上升沿。(由于 in & ~in1是非阻塞赋值给pedge,所以会在下一个clk才会赋值,因此波形会慢一拍)
- 下降沿:将原信号in打一拍得到in1,再将in求反后和in1进行与运算,即可检测下降沿。
- 双边沿:这更简单,直接将in打一拍得到in1后跟in进行异或即可。
- 从这个练习我才稍微懂了一点所谓的打一拍具体指什么。其实在非阻塞赋值<=时,综合器就会产生一个DFF,那么<=右边计算完的数(右值组合电路计算可以当做瞬间完成)会在下一拍才能给到左值。
进一步解释:
根据电路图很好理解,为了让原来的信号保持一下也可以说是延迟一个时钟,就能做出上升沿的判断,后面加入一个寄存器的目的就是为了让检测延迟一个时钟显示,也保证检测只持续一个时钟。(如果想让检测信号不止持续一个时钟,那参考下面的Edge capture register)
参考网址:https://blog.csdn.net/weixin_42664351/article/details/112131448
Detect both edges
module top_module (
input clk,
input [7:0] in,
output [7:0] anyedge
);
reg [7:0] last;
always@(posedge clk)
begin
last <= in;
anyedge <= last ^ in;
end
endmodule
Edge capture register
这道题和之前不一样的地方在于,一旦检测到下降沿,就让检测信号一直保持1,直到被重置。因此需要每个位矢量都进行下降沿检测,如果有下降沿就置1,否则就保持。
参考代码:
module top_module (
input clk,
input reset,
input [31:0] in,
output [31:0] out
);
reg [31:0] last;
always@(posedge clk)
begin
last <= in;
if(reset)
out <= 0;
else
begin
//last <= in;
for(int i=0; i < 32; i = i+1)
out[i] <= (~in[i] & last[i]) ? 1 : out[i];
//单纯写out[i] <= ~in[i] & last[i],则只有一个脉冲而已
end
end
endmodule
注:一开始将last <= in 写在了重置信号后,感觉没什么问题,但是报错了。后来把电路图画出来才知道,打拍需要在组合逻辑之前进行的。不过这个图只是单指一位的情况。
Dual-edge triggered flip-flop
思路分析:
- 双沿触发触发器在时钟的两个边沿触发。但是,FPGA没有双沿触发触发器,因此始终不接受@(posedge clk或negedge clk)作为合法敏感性列表。
- 分别写出正沿触发和负沿触发的D触发器,赋值给q1,q2,再利用clk作为地址进行选择,上升沿就将q1给q,下降沿将q2给q.
参考代码:
module top_module (
input clk,
input d,
output q
);
reg q1,q2;
always@(posedge clk)
begin
q1 <= d;
end
always@(negedge clk)
begin
q2 <= d;
end
assign q = clk ? q1 : q2;
endmodule
附上综合图