Verilog N 位双向移位寄存器:设计与实现
在数字电子学中,移位寄存器 是触发器的级联,一个触发器的输出 q 连接到下一个触发器的数据输入 (d)。因为所有触发器在同一时钟工作,移位寄存器中存储的位阵列将移动一位。例如,若一个 5 位右移寄存器初始值为 10110 且输入固定为 0,则下一个模式为 01011,再下一个为 00101。
设计
此移位寄存器设计有五个输入和一个 n 位输出,通过 parameter MSB 参数化表示移位寄存器宽度。若 n=4 则为 4 位,n=8 则为 8 位。
主要特性:
- 可通过 en 引脚启用或禁用
- 可通过 dir 控制左移或右移
- 若 rstn 拉低,复位寄存器输出变为 0
- 输入数据值可通过 d 引脚控制
module shift_reg #(parameter MSB=8) (
input d, // 第一个触发器的数据输入
input clk, // 所有触发器的时钟输入
input en, // 启用/禁用移位寄存器
input dir, // 移位方向:左或右
input rstn, // 复位寄存器为默认值
output reg [MSB-1:0] out // 读取所有触发器当前值
);
// 此 always 块在时钟上升沿触发
// 进入后先检查复位是否为 0,是则复位寄存器
// 否则检查移位寄存器是否启用
// 不启用 => 保持前值。启用则按请求方向移位
always @ (posedge clk)
if (!rstn) out <= 0;
else begin
if (en)
case (dir)
0 : out <= {out[MSB-2:0], d}; // 右移
1 : out <= {d, out[MSB-1:1]}; // 左移
endcase
else out <= out;
end
endmodule
硬件原理图
测试平台
测试平台用于验证移位寄存器功能。设计实例化到顶层 module,输入驱动不同值,可在输出 out 观察行为。
module tb_sr;
parameter MSB = 16; // 可选参数表示移位寄存器位数
reg data; // 驱动设计 d 输入
reg clk; // 驱动时钟
reg en; // 驱动使能
reg dir; // 驱动移位方向
reg rstn; // 驱动复位
wire [MSB-1:0] out; // 捕获设计输出
// 实例化设计(16位移位寄存器)并连接 TB 信号
shift_reg #(MSB) sr0 (
.d (data), .clk (clk), .en (en), .dir (dir), .rstn (rstn), .out (out)
);
// 生成时钟:周期 20ns,频率 50MHz
always #10 clk = ~clk;
// 时间 0 初始化变量为默认值
initial begin
clk <= 0; en <= 0; dir <= 0; rstn <= 0; data <= 'h1;
end
// 驱动主激励验证功能
initial begin
// 1. 施加复位,一段时间后释放
rstn <= 0; #20 rstn <= 1; en <= 1;
// 2. 连续 7 个时钟向数据引脚驱动交替值
repeat (7) @ (posedge clk) data <= ~data;
// 4. 改变移位方向并再驱动 7 个时钟交替值
#10 dir <= 1;
repeat (7) @ (posedge clk) data <= ~data;
// 5. 接下来 7 个时钟不驱动数据,允许按方向单纯移位
repeat (7) @ (posedge clk);
// 6. 结束仿真
$finish;
end
// 监控变量值并打印到日志供调试
initial $monitor ("rstn=%0b data=%b, en=%0b, dir=%0b, out=%b", rstn, data, en, dir, out);
endmodule
下面日志中高亮绿色为移位寄存器启用时段,黄色为方向改变时段,蓝色为数据输入保持不变时段。
仿真日志
ncsim> run rstn=0 data=1, en=0, dir=0, out=xxxxxxxxxxxxxxxx rstn=0 data=1, en=0, dir=0, out=0000000000000000 rstn=1 data=1, en=1, dir=0, out=0000000000000000 rstn=1 data=0, en=1, dir=0, out=0000000000000001 rstn=1 data=1, en=1, dir=0, out=0000000000000010 rstn=1 data=0, en=1, dir=0, out=0000000000000101 rstn=1 data=1, en=1, dir=0, out=0000000000001010 rstn=1 data=0, en=1, dir=0, out=0000000000010101 rstn=1 data=1, en=1, dir=0, out=0000000000101010 rstn=1 data=0, en=1, dir=0, out=0000000001010101 rstn=1 data=0, en=1, dir=1, out=0000000001010101 rstn=1 data=1, en=1, dir=1, out=0000000000101010 rstn=1 data=0, en=1, dir=1, out=1000000000010101 rstn=1 data=1, en=1, dir=1, out=0100000000001010 rstn=1 data=0, en=1, dir=1, out=1010000000000101 rstn=1 data=1, en=1, dir=1, out=0101000000000010 rstn=1 data=0, en=1, dir=1, out=1010100000000001 rstn=1 data=1, en=1, dir=1, out=0101010000000000 rstn=1 data=1, en=1, dir=1, out=1010101000000000 rstn=1 data=1, en=1, dir=1, out=1101010100000000 rstn=1 data=1, en=1, dir=1, out=1110101010000000 rstn=1 data=1, en=1, dir=1, out=1111010101000000 rstn=1 data=1, en=1, dir=1, out=1111101010100000 rstn=1 data=1, en=1, dir=1, out=1111110101010000 Simulation complete via $finish(1) at time 430 NS + 0
Verilog
- Verilog 入门:数字电路设计完整教程
- 掌握 Verilog 拼接操作:实用指南
- 深入理解 Verilog 赋值语句:类型、语法与最佳实践
- Verilog阻塞与非阻塞赋值:关键区别详解
- 掌握Verilog函数:高效RTL设计的复用利器
- 理解Verilog任务:函数vs任务、语法与用法全解析
- Verilog 时钟发生器设计与实现指南
- 掌握 Verilog 数学函数:高效硬件设计的利器
- 掌握 Verilog $timeformat:精度控制与显示格式化
- 理解与打印 Verilog 任意作用域下的 Timescale
- 掌握 Verilog 文件 I/O:打开、读取、写入和关闭
- Verilog 入门指南:Hello World 示例