HDLBits 练习题:8 位移位寄存器
原题
This exercise is an extension of module_shift. Instead of module ports being only single pins, we now have modules with vectors as ports, to which you will attach wire vectors instead of plain wires. Like everywhere else in Verilog, the vector length of the port does not have to match the wire connecting to it, but this will cause zero-padding or trucation of the vector. This exercise does not use connections with mismatched vector lengths.
You are given a module my_dff8
with two inputs and one output (that implements a set of 8 D flip-flops). Instantiate three of them, then chain them together to make a 8-bit wide shift register of length 3. In addition, create a 4-to-1 multiplexer (not provided) that chooses what to output depending on sel[1:0]
: The value at the input d, after the first, after the second, or after the third D flip-flop. (Essentially, sel
selects how many cycles to delay the input, from zero to three clock cycles.)
The module provided to you is: module my_dff8 ( input clk, input [7:0] d, output [7:0] q );
The multiplexer is not provided. One possible way to write one is inside an always
block with a case
statement inside.
题目描述
这道练习题是对 module_shift
模块的扩展。在这次练习中,模块的端口不再只是单个引脚,而是包含向量的端口,因此需要将线网向量连接到这些模块的端口,而不是普通的线网。在 Verilog 中,端口的向量长度可以与连接的线网不匹配,但这会导致零填充或截断向量。不过,这道题不涉及长度不匹配的连接。
你将实现一个 my_dff8
模块,它有两个输入和一个输出(实现一组 8 个 D 触发器)。你的任务是实例化三个这样的 my_dff8
模块,并将它们串联在一起,以构建一个宽度为 8 位、长度为 3 的移位寄存器。此外,创建一个 4 到 1 的多路复用器(未提供),根据 sel[1:0]
选择输出:输入 d
的值、经过第一个、第二个或第三个 D 触发器后的值(即,sel
选择输入延迟的时钟周期数,从零到三个时钟周期)。
代码实现
下面是一个可能的实现结构:
module shift_register (
input clk,
input [7:0] d,
input [1:0] sel,
output [7:0] y
);
wire [7:0] q1, q2, q3;
// 实例化三个 D 触发器
my_dff8 dff1 (.clk(clk), .d(d), .q(q1));
my_dff8 dff2 (.clk(clk), .d(q1), .q(q2));
my_dff8 dff3 (.clk(clk), .d(q2), .q(q3));
// 多路复用器
always @(*) begin
case (sel)
2'b00: q = d; // 不延迟
2'b01: q = q1; // 延迟 1 个时钟周期
2'b10: q = q2; // 延迟 2 个时钟周期
2'b11: q = q3; // 延迟 3 个时钟周期
default: q = 8'b0; // 默认情况
endcase
end
endmodule
原理解析
串联多个 D 触发器可以实现不同的时钟周期延迟,主要是因为 D 触发器在每个时钟边沿(上升或下降沿)对输入信号进行采样,并在输出端保持这个值直到下一个时钟边沿。
串联多个 D 触发器可以实现不同的时钟周期延迟,主要是因为 D 触发器在每个时钟边沿(上升或下降沿)对输入信号进行采样,并在输出端保持这个值直到下一个时钟边沿。具体原因如下:
-
D 触发器的工作原理:
- D 触发器会在时钟信号的上升沿(或下降沿)将输入数据
d
的当前值锁存到输出q
中。在时钟信号的下一个上升沿,D 触发器会更新其输出,显示新的输入值。 - 也就是说,D 触发器在每个时钟周期的边沿时刻对输入进行采样,而在下一个时钟周期之前,输出保持不变。
- D 触发器会在时钟信号的上升沿(或下降沿)将输入数据
-
串联连接的延迟:
- 当将多个 D 触发器串联连接时,第一个触发器的输出
q1
成为第二个触发器的输入d
,第二个触发器的输出q2
成为第三个触发器的输入,依此类推。 - 这样,输入信号
d
经过第一个 D 触发器后,在下一个时钟周期内将更新q1
的值。在再下一个时钟周期,q1
的值将被传递给第二个 D 触发器,并在接下来的时钟周期内更新q2
。 - 因此,输入信号
d
在经过三个触发器时,分别会在时钟周期 1、2 和 3 后出现在q1
、q2
和q3
的输出上。
- 当将多个 D 触发器串联连接时,第一个触发器的输出
举例说明
假设在时钟信号的第 1 个周期时输入 d
为 8'b00000001
,那么:
-
第一个周期(时钟上升沿):
q1
=d
=8'b00000001
(延迟 0 周期)
-
第二个周期(时钟上升沿):
q2
=q1
=8'b00000001
(延迟 1 周期)
-
第三个周期(时钟上升沿):
q3
=q2
=8'b00000001
(延迟 2 周期)
-
第四个周期(时钟上升沿):
- 如果此时
d
变为8'b00000010
,那么:q1
=8'b00000010
(延迟 1 周期)q2
=q1
=8'b00000001
(延迟 2 周期)q3
=q2
=8'b00000001
(延迟 3 周期)
- 如果此时
通过这种方式,我们可以利用串联的 D 触发器来控制信号的延迟,选择在 sel
控制下的输出值(即 d
、q1
、q2
或 q3
),从而实现灵活的信号延迟控制。