HDLbits day7
Sequential Logic
1、Latches and Flip-Flops
1.1D flip-flop
AD 触发器是一种在时钟信号的(通常)上升沿存储位并定期更新的电路。当使用时钟控制的always块时,逻辑合成器会创建 D 触发器。AD触发器是“组合逻辑块后接触发器”的最简单形式,其中组合逻辑部分只是一条线。
创建一个 D 触发器。
module top_module ( input clk, // Clocks are used in sequential circuits input d, output reg q );// // Use a clocked always block // copy d to q at every positive edge of clk // Clocked always blocks should use non-blocking assignments always@(posedge clk) q<=d; endmodule
1.2、D flip-flops
创建 8 个 D 触发器。所有 DFF 都应由clk的上升沿触发。
module top_module ( input clk, input [7:0] d, output [7:0] q ); always@(posedge clk) q<=d; endmodule
1.3、DFF with reset
创建 8 个具有高电平有效同步复位的 D 触发器。所有 DFF 都应由clk的上升沿触发。
module top_module ( input clk, input reset, // Synchronous reset input [7:0] d, output [7:0] q ); always@(posedge clk) begin if(reset) q<=0; else q<=d; end endmodule
1.4、DFF with reset value
创建 8 个具有高电平有效同步复位的 D 触发器。触发器必须重置为 0x34 而不是零。所有 DFF 都应由clk的下降沿触发。
module top_module ( input clk, input reset, input [7:0] d, output [7:0] q ); always@(negedge clk) begin if(reset) q<=8'h0x34; else q<=d; end endmodule
1.5、DFF with asynchronous reset
创建 8 个具有高电平有效异步复位的 D 触发器。所有 DFF 都应由clk的上升沿触发。
module top_module ( input clk, input areset, // active high asynchronous reset input [7:0] d, output [7:0] q ); always@(posedge clk or posedge areset) if(areset) q<=0; else q<=d; endmodule
1.6、DFF with byte enable
创建 16 个 D 触发器。有时只修改一组触发器的一部分很有用。字节使能输入控制 16 个寄存器中的每个字节是否应在该周期写入。byteena[1]控制高字节d[15:8],而byteena[0]控制低字节d[7:0]。
resetn是一个同步的低电平有效复位。
所有 DFF 都应由clk的上升沿触发。
module top_module ( input clk, input resetn, input [1:0] byteena, input [15:0] d, output [15:0] q ); always@(posedge clk) begin if(!resetn) q<=0; else begin q[15:8]<=byteena[1]?d[15:8]:q[15:8]; q[7:0]<=byteena[0]?d[7:0]:q[7:0]; end end endmodule
1.7、D Latch
实现以下电路:
1)请注意,这是一个锁存器,因此预计会出现关于已推断锁存器的 Quartus 警告。
2)锁存器是电平敏感(非边沿敏感)电路,因此在一个始终块中,它们使用电平敏感灵敏度列表。
3)但是,它们仍然是顺序元素,因此应该使用非阻塞赋值。
4)D 锁存器在启用时就像一条线(或非反相缓冲器),在禁用时保留当前值。
module top_module ( input d, input ena, output q); //always@(ena) always@(*) if(ena) q<=d; endmodule
1.8、DFF
实现以下电路:
module top_module ( input clk, input d, input ar, // asynchronous reset异步复位 output q); always@(posedge clk or posedge ar) if(ar) q<=0; else q<=d; endmodule
1.9、DFF
实现以下电路:
module top_module ( input clk, input d, input r, // synchronous reset同步复位 output q); always@(posedge clk) if(r) q<=0; else q<=d; endmodule
1.10、DFF+gate
实现以下电路:
module top_module ( input clk, input in, output out); always@(posedge clk) begin out<=in^out; end endmodule
1.11、Mux and DFF
考虑下面的时序电路:
假设您要为此电路实现分层 Verilog 代码,使用其中具有触发器和多路复用器的子模块的三个实例化。为此子模块编写一个名为top_module的 Verilog 模块(包含一个触发器和多路复用器)。
module top_module ( input clk, input L, input r_in, input q_in, output reg Q); always@(posedge clk) Q<=L?r_in:q_in; endmodule
1.12、Mux and DFF
考虑如下所示 的n位移位寄存器电路:
为该电路的一个阶段编写一个名为 top_module 的 Verilog 模块,包括触发器和多路复用器。
module top_module ( input clk, input w, R, E, L, output Q ); always@(posedge clk) begin Q<=L?R:E?w:Q; end endmodule
1.13、DFFs and gates
给定如图所示的有限状态机电路,假设 D 触发器在机器开始之前初始复位为零。
建立这个电路。
小心复位状态。确保每个 D 触发器的Q输出确实是其 Q 输出的倒数,即使在模拟的第一个时钟沿之前也是如此。
module top_module ( input clk, input x, output z ); reg q1,q2,q3; always@(posedge clk) begin q1<=x^q1; q2<=x&(~q2); q3<=x|(~q3); end assign z=~(q1|q2|q3); endmodule
1.14、create circuit from truth table
JK 触发器具有以下真值表。实现一个只有 D 型触发器和门的 JK 触发器。注意:Qold 是正时钟沿之前 D 触发器的输出。
J | K | Q |
0 | 0 | Qold |
0 | 1 | 0 |
1 | 0 | 1 |
1 | 1~ | Qold |
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
1.15、Detect an edge
对于 8 位向量中的每一位,检测输入信号何时从一个时钟周期的 0 变为下一个时钟周期的 1(类似于上升沿检测)。输出位应在发生 0 到 1 转换后的周期设置。
这里有些例子。为清楚起见,in[1] 和 pedge[1] 分别显示。
module top_module ( input clk, input [7:0] in, output [7:0] pedge ); reg [7:0] state_in; always@(posedge clk) begin state_in<=in; pedge<=~state_in∈ //pedge<=state_in~∈错误写法 //pedge<=state_in^in;检测输入信号从0跳变到1的位置,用xor门会同时检测到从1变到0的位置 end endmodule
1.16、Detect both edges
对于 8 位向量中的每一位,检测输入信号何时从一个时钟周期变为下一个时钟周期(检测任何边沿)。输出位应在发生 0 到 1 转换后的周期设置。
这里有些例子。为清楚起见,in[1] 和 anyedge[1] 分别显示
1)上升沿加下降沿检测。上升沿核心检测逻辑: ~in_last & in。下降沿类似上升沿核心逻辑为: in_last & ~in。最后运用或逻辑组合起来即可。核心代码:anyedge = (~in_last & in) | (in_last & ~in)。
2)异或逻辑检测。边沿检测,从整体来看,即信号发生变化就进行检测输出。因此使用异或逻辑 。核心代码:in ^ in_last 。
module top_module ( input clk, input [7:0] in, output [7:0] anyedge ); reg [7:0] state_in; always@(posedge clk) begin state_in<=in; anyedge<=state_in^in; end endmodule
1.17、Edge capture register
对于 32 位向量中的每一位,在输入信号从一个时钟周期的 1 变为下一个时钟周期的 0 时进行捕捉。“捕获”表示输出将保持为 1,直到寄存器复位(同步复位)。
每个输出位的行为类似于 SR 触发器:输出位应在 1 到 0 转换发生后的周期设置(为 1)。当复位为高电平时,输出位应在正时钟沿复位(为 0)。如果上述两个事件同时发生,则重置优先。在下面示例波形的最后 4 个周期中,“reset”事件比“set”事件早一个周期发生,因此这里不存在冲突。
在下面的示例波形中,为清楚起见,reset、in[1] 和 out[1] 再次分别显示。
1)题意:检测下降沿,检测到后out一直为高,直到reset == 1时,out才为0。
2)方法:先通过边沿检测,得到一个脉冲信号,然后如果这个脉冲信号为高,将其输出给out,输出为低就不管(保持前面状态)。
但是这样做,边沿检测时会延迟一个clk,在将其输出给out时又会延迟一个clk,这样就与题目中给的时序图不符,3)改正:直接将边沿检测信号与输出信号本身相或赋值给输出信号,就能在一个clk下完成,得到与题目符合的时序图。
4)设初始 in:0000,out:0000
然后假设in:0001 -> 0000,这时out:0001
假设in:0001 -> 0101,这时out:0101
module top_module ( input clk, input reset, input [31:0] in, output [31:0] out ); reg [31:0] state_in; always@(posedge clk) state_in<=in; always@(posedge clk)//同步复位 begin if(reset) out<=32'h0000; else out<=(state_in&~in)|out; end endmodule
1.18、Dual-edge triggered flip-flop
您熟悉在时钟上升沿或时钟下降沿触发的触发器。在时钟的两个边沿触发双边触发触发器。但是,FPGA 没有双边触发触发器,并且始终不接受 @(posedge clk 或 negedge clk)作为合法的敏感度列表。
构建一个功能类似于双边触发触发器的电路:
(注意:它不一定完全等效:触发器的输出没有毛刺,但模拟这种行为的更大组合电路可能会。但我们将在这里忽略这个细节。)
您无法在 FPGA 上创建双边触发触发器。但是您可以同时创建正沿触发和负沿触发触发器。
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