目录
3.2.1.4 DFF with reset value(Dff8p)
3.2.1.5 DFF with asynchronous reset(Dff8ar)
3.2.1.6 DFF with byte enable(Dff16e)
3.2.1.7 D Latch(Exams/m2014 q4a)
3.2.1.9 DFF+gate(Exams/m2014 q4d)
3.2.1.10 Mux and DFF(Mt2015 muxdff)
3.2.1.11 Mux and DFF(Exams/2014 q4a)
3.2.1.12 DFFs and gates(Exams/ece241 2014 q4)
3.2.1.13 Creat circuit from truth table(Exams/ece241 2013 q7)
3.2.1.14 Detect an edge(Edgedetect)
3.2.1.15 Detect both edges(Edgedetect2)
3.2.1.16 Edge capture register(Edgecapture)
3.2.1.17 Dual-edge triggered flip-flop(Dualedge)
前言
HDLbits网站如下
Problem sets - HDLBits (01xz.net)
从本期开始我们继续HDLbits第三章Circuits的学习,本期的内容是3.2.1 Latches and Flip-Flops
3.2.1.1 D flip-flop(Dff)
D触发器是一种存储1位并在时钟信号上升沿定期更新的电路。
D触发器由逻辑综合器在使用时序always块时创建。D触发器是“组合逻辑块后跟触发器”的最简单形式,其中组合逻辑部分只是一个wire信号。
创建单个D触发器。

Solution:
module top_module(
input clk,
input d,
output reg q);
// Use non-blocking assignment for edge-triggered always blocks
always @(posedge clk)
q <= d;
// Undefined simulation behaviour can occur if there is more than one edge-triggered
// always block and blocking assignment is used. Which always block is simulated first?
endmodule
边沿触发时序akways块采用非阻塞赋值。如果有多个使用阻塞赋值的边沿触发always块,则可能会出现未定义的仿真行为。且哪个always块先仿真呢?
3.2.1.2 D flip-flops(Dff8)
创建 8 位 D 触发器。所有 D触发器 都应由 clk 的上升沿触发。
Solution:
module top_module (
input clk,
input [7:0] d,
output [7:0] q
);
always@(posedge clk)
q[7:0]<=d[7:0];
endmodule
3.2.1.3 DFF with reset(Dff8r)
创建具有高电平有效的同步复位的8位D触发器。所有D触发器都应由 clk 的上升沿触发。
Solution:
module top_module (
input clk,
input reset, // Synchronous reset
input [7:0] d,
output [7:0] q
);
always@(posedge clk)
if(reset)
q <= 8'b0;
else
q[7:0] <= d[7:0];
endmodule
3.2.1.4 DFF with reset value(Dff8p)
创建具有高电平有效的同步复位的8位D触发器。触发器必须复位为 0x34 而不是零。所有的触发器应该由clk的下降沿触发。
Hint:将寄存器复位为“1”有时称为“预设”
Solution:
module top_module (
input clk,
input reset, // Synchronous reset
input [7:0] d,
output [7:0] q
);
always@(negedge clk)
if(reset)
q <= 8'h34;
else
q[7:0] <= d[7:0];
endmodule
3.2.1.5 DFF with asynchronous reset(Dff8ar)
创建具有高电平有效的异步复位的8位D触发器。所有D触发器都应由 clk 的上升沿触发。
Hint:同步和异步复位触发器之间代码的唯一区别在于敏感列表
Solution:
module top_module (
input clk,
input areset, // active high asynchronous reset
input [7:0] d,
output [7:0] q
);
always@(posedge clk,posedge areset)
if(areset)
q<=8'b0;
else
q<=d;
endmodule
3.2.1.6 DFF with byte enable(Dff16e)
创建16位D触发器。所有D触发器都应由 clk 的上升沿触发。字节使能输入控制是否应在该周期写入16位寄存器的每个字节。byteena[1]控制高字节d[15:8],而bytenna[0]控制低字节d[7:0]。
restn 低电平有效同步复位。
所有的D触发器由clk的上升沿触发。
Solution:
module top_module (
input clk,
input resetn,
input [1:0] byteena,
input [15:0] d,
output [15:0] q
);
always@(posedge clk)
if(~resetn)
q<=0;
else
begin
case(byteena)
2'b11:q<=d;
2'b10:q[15:8]<=d[15:8];
2'b01:q[7:0]<=d[7:0];
endcase
end
endmodule
3.2.1.7 D Latch(Exams/m2014 q4a)
实现以下电路:

请注意这是一个锁存器,所以Quartus产生会推断latch出现的warning。
Hint:
- 锁存器是电平敏感电路(不是边缘敏感),所以在always块中,使用电平敏感列表。
- 然而,这仍然是时序电路,所以使用非阻塞赋值!
- D 锁存器在启用时就像一个wire(或非反相buffer),并在禁用时保留当前值。
Solution:
module top_module (
input d,
input ena,
output q);
always@(*)
begin
if(ena)
q<=d;
end
endmodule
always@(*)表示缺省,会根据always块内部的内容自动识别敏感变量。
3.2.1.8 DFF(Exams/m2014 q4b)
实现以下电路:

Solution:
module top_module (
input clk,
input d,
input ar, // asynchronous reset
output q);
always@(posedge clk,posedge ar)
begin
if(ar)
q<=0;
else
q<=d;
end
endmodule
由电路图知,clk和AR都是上升沿触发。
3.2.1.9 DFF+gate(Exams/m2014 q4d)
实现以下电路:

Solution:
module top_module (
input clk,
input in,
output out);
always@(posedge clk)
out<=in^out;
endmodule
3.2.1.10 Mux and DFF(Mt2015 muxdff)
考虑下面的时序电路:

假设您要为该电路实现分级 Verilog 代码,使用其中包含触发器和数据选择器的子模块的三个副本。为此子模块编写一个名为 top_module 的 Verilog 模块(包含一个触发器和数据选择器)。
Solution:
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
本题就是写一个触发器和数据选择器的模块,当L=0,选择q_in为D触发器的输入;当L=1,选择r_in为D触发器的输入。
实现的就是并行输入的3位移位寄存器
3.2.1.11 Mux and DFF(Exams/2014 q4a)
考虑如下所示的 n 位移位寄存器电路:

为该电路的一级编写一个名为 top_module 的 Verilog 模块,包括触发器和多路复用器。
Solution:
module top_module (
input clk,
input w, R, E, L,
output Q
);
wire temp1,temp2;
assign temp1=(E?w:Q);
assign temp2=(L?R:temp1);
always@(posedge clk)
begin
Q<=temp2;
end
endmodule
3.2.1.12 DFFs and gates(Exams/ece241 2014 q4)
给定如图所示的有限状态机电路,假设D触发器在状态机启动之前初始复位为零。
创建这个电路。

Solution:
module top_module (
input clk,
input x,
output z
);
reg q0,q1,q2;
always@(posedge clk)
begin
q0<=q0^x;
q1<=~q1&x;
q2<=~q2|x;
end
assign z=~(q0 | q1 | q2);
endmodule
always块中非阻塞赋值 左边必须是reg型,故声明q0、q1、q2为reg型
3.2.1.13 Creat circuit from truth table(Exams/ece241 2013 q7)
JK 触发器具有以下真值表。仅使用 D 型触发器和门实现 JK 触发器。注:Qold 是时钟上升沿前 D 触发器的输出。

Solution:
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
/*
always@(posedge clk)
Q <= (j & ~Q) | (~k & Q);
*/
endmodule
根据D触发器和JK触发器的特性方程推出方法二,见代码中注释部分。
3.2.1.14 Detect an edge(Edgedetect)
对于 8 位向量中的每一位,检测输入信号何时从一个时钟周期内的 0 变为下一个时钟周期内的 1(类似于上升沿检测)。输出位应在发生 0 到 1 转换后的周期内置位。
这里有些例子。为了清楚起见,分别显示了 in[1] 和 pedge[1]。

Solution:
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
上升沿检测,采用一个D触发器即d_last来存储上一个时钟周期的输入,d_last、in对应位分别为0、1时,则检测到上升沿。
3.2.1.15 Detect both edges(Edgedetect2)
对于 8 位向量中的每一位,检测输入信号何时从一个时钟周期内变为下一个时钟周期内(检测上升沿和下降沿)。输出位应在发生 0 到 1 转换后的周期内置位。
这里有些例子。为了清楚起见,分别显示了 in[1] 和 pedge[1]。

Solution:
module top_module (
input clk,
input [7:0] in,
output [7:0] anyedge
);
reg [7:0]d_last;
always@(posedge clk) begin
d_last<=in;
anyedge<=in^d_last;
end
endmodule
边沿检测即输入发生变化,故使用异或来检测。
3.2.1.16 Edge capture register(Edgecapture)
对于16位向量中的每一位,当输入信号在一个时钟周期内从1变为下一个周期的0时进行捕获。“捕获”意味着直到寄存器复位(同步复位)输出将保持为1。
每bit输出的行为就像一个SR触发器:输出位应该在1到0转换发生后的周期置位(为1)。当reset为高电平时,输出应在时钟上升沿复位(为0)。如果上述两个事件同时发生,则reset具有高优先级。在下面4个实例波形的最后4个周期中,”reset“比”set“早一个周期发生,因此这里没有发生冲突。
在下面的示例波形中,为清楚起见,再次分别展示了reset、in[1]、out[1]。

Solution:
module top_module (
input clk,
input reset,
input [31:0] in,
output [31:0] out
);
reg [31:0]d_last;
always@(posedge clk) begin
d_last<=in;
if(reset)
out <=0;
else
out <=(d_last&~in)|out;
end
endmodule
边沿捕获和边沿检测最大的区别在于,捕获是只要出现了一次下降沿,不管再过多少周期输出还是1,只有当reset的时候,out才会复位到0;而检测就是就是检测这一次下降沿,如果下个周期不是下降沿则输出就变为0。
所以本题中,使用if-else语句体现了reset的高优先级,out <=(d_last&~in)|out; 中(d_last&~in)表示下降沿,|out 表示没有下降沿信号的话则继续保持高电平。
3.2.1.17 Dual-edge triggered flip-flop(Dualedge)
您熟悉在clk的上升沿或时钟的下降沿触发的触发器。双边沿触发触发器在时钟的两个边沿触发。但是,FPGA 没有双边沿触发器,并且始终不接受@(posedge clk 或 negedge clk) 作为合法的敏感列表。
构建一个功能类似于双边沿触发器的电路:

(注意:它不一定完全等效:触发器的输出没有毛刺,但仿真这种行为的更大的组合电路可能会。但我们将在这里忽略这个细节。)
Hint:
- 您无法在 FPGA 上创建双边沿触发触发器。但是您可以创建上升沿触发和下降沿触发触发器。
- 这个问题是一个中等难度的电路设计问题,但只需要基本的 Verilog 语言特性。 (这是一个电路设计问题,而不是一个编码问题。)在尝试编码之前先手工绘制一个电路可能会有所帮助。
Solution:
//mux方法
module top_module (
input clk,
input d,
output q
);
reg q1,q2;
assign q=(clk?q1:q2);
always@(posedge clk) begin
q1<=d;
end
always@(negedge clk) begin
q2<=d;
end
endmodule
这种方法由于Tcq延迟的存在,输出波形会产生glitch毛刺,即q1、q2的值还没更新,就已经执行了assign q=(clk?q1:q2)
module top_module(
input clk,
input d,
output q);
reg p, n;
// A positive-edge triggered flip-flop
always @(posedge clk)
p <= d ^ n;
// A negative-edge triggered flip-flop
always @(negedge clk)
n <= d ^ p;
// Why does this work?
// After posedge clk, p changes to d^n. Thus q = (p^n) = (d^n^n) = d.
// After negedge clk, n changes to p^n. Thus q = (p^n) = (p^p^n) = d.
// At each (positive or negative) clock edge, p and n FFs alternately
// load a value that will cancel out the other and cause the new value of d to remain.
assign q = p ^ n;
// Can't synthesize this.
/*always @(posedge clk, negedge clk) begin
q <= d;
end*/
endmodule
第二种方法是通过异或,非常巧妙,且消除了glitch
本节开始,写得非常磕磕绊绊,还是基本功不扎实,不过这也正是我学HDLbits的原因。
本文详细介绍了Verilog中D触发器的各种变体,如标准DFF、带复位的DFF、异步复位DFF等,并展示了如何创建8位和16位触发器,以及结合多路复用器和锁存器的电路设计。通过实例解析了上升沿、下降沿检测和边缘触发器的设计技巧。

4531

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



