一、完整模块代码
module phase_dly (
input pll_clk,
input rst_n,
input tm,
input [3:0] phase_sel,
output reg phase_dly_clk
);
// 1. 复位同步(防止亚稳态)
wire sync_rst_n;
reset_sync #(0, 2) u_micro_src_rst_sync (
.q (sync_rst_n),
.d (rst_n),
.clk (pll_clk),
.sm (1'b0),
.srstn (1'b1)
);
// 2. 测试模式控制:tm=1时强制相位选择为0
wire [3:0] phase_sel_tm = tm ? 4'b0 : phase_sel;
// 3. 移位寄存器链:生成src_clk的多拍延迟版本
reg [14:0] phase_clk;
wire src_clk; // 这里是你代码中遗漏的源时钟输入,我补上了
always @(posedge pll_clk or negedge sync_rst_n) begin
if (~sync_rst_n) begin
phase_clk <= 15'b0;
end else begin
// 第21行核心代码:src_clk作为最低位,整体左移1位
phase_clk <= {phase_clk[13:0], src_clk};
end
end
// 4. 组合逻辑:根据phase_sel选择对应延迟拍数的信号
always @(*) begin
case (phase_sel_tm)
4'd0 : phase_dly_clk = phase_clk[0];
4'd1 : phase_dly_clk = phase_clk[1];
4'd2 : phase_dly_clk = phase_clk[2];
4'd3 : phase_dly_clk = phase_clk[3];
4'd4 : phase_dly_clk = phase_clk[4];
4'd5 : phase_dly_clk = phase_clk[5];
4'd6 : phase_dly_clk = phase_clk[6];
4'd7 : phase_dly_clk = phase_clk[7];
4'd8 : phase_dly_clk = phase_clk[8];
4'd9 : phase_dly_clk = phase_clk[9];
4'd10: phase_dly_clk = phase_clk[10];
4'd11: phase_dly_clk = phase_clk[11];
4'd12: phase_dly_clk = phase_clk[12];
4'd13: phase_dly_clk = phase_clk[13];
4'd14: phase_dly_clk = phase_clk[14];
default: phase_dly_clk = phase_clk[0]; // 防止锁存器生成
endcase
end
endmodule
二、逐段解析,重点讲清第 21 行和整体逻辑
1. phase_clk <= {phase_clk[13:0], src_clk};
-
语法拆解 :
-
{A, B}是 Verilog 的位拼接运算符,会把信号 A 和信号 B 按顺序拼接成一个新的宽信号。 -
phase_clk[13:0]取phase_clk的低 14 位,src_clk是 1 位信号,拼接后得到一个 15 位的信号。 -
这个 15 位信号再赋值给
phase_clk,等价于:verilog
phase_clk[14] <= phase_clk[13]; phase_clk[13] <= phase_clk[12]; ... phase_clk[1] <= phase_clk[0]; phase_clk[0] <= src_clk;
-
-
核心作用 :构建一个15 级的移位寄存器链 ,
src_clk信号会被每一拍(pll_clk周期)移位一次,从而在phase_clk寄存器中保存src_clk过去 15 拍的所有状态。phase_clk[0]:当前拍的src_clk(延迟 0 拍)phase_clk[1]:上一拍的src_clk(延迟 1 拍)- ...
phase_clk[14]:14 拍前的src_clk(延迟 14 拍)
2. 后续的 always @(*) 组合逻辑
- 这部分的作用是根据相位选择信号
phase_sel,从移位寄存器链中挑选出对应延迟拍数的信号 ,作为最终输出phase_dly_clk。 - 比如
phase_sel = 4'd5,就会选择phase_clk[5],实现src_clk延迟 5 个pll_clk周期的输出。 tm信号是测试模式控制:当tm=1时,phase_sel_tm会被强制设为4'b0,输出固定为phase_clk[0],通常用于固定相位或测试功能。
3. 模块整体功能
这是一个基于高速时钟采样的数字时钟延迟 / 移相电路:
- 利用高频的
pll_clk采样低速的src_clk,通过移位寄存器链生成多拍延迟版本。 - 通过配置
phase_sel,可以灵活调整输出时钟phase_dly_clk相对于src_clk的相位(延迟拍数)。 - 延迟的最小步长就是
pll_clk的周期,比如pll_clk是 100MHz(周期 10ns),那么每拍延迟就是 10ns,最大可实现 140ns 的可调延迟。
三、补充注意事项
- 你原始代码里的
src_clk没有在端口声明,这是个明显的遗漏,我在完整代码里补上了,实际使用时需要把它作为模块的输入端口。 - 这种延迟方式的精度由
pll_clk的频率决定,如果需要更高精度的移相,通常会配合专用的延迟线(如 FPGA 的 IODELAY)或 PLL 的相位控制功能。 always @(*)里的case语句一定要加default分支,否则会生成不必要的锁存器,影响电路稳定性。