SV 时钟移位示例代码解析

一、完整模块代码

复制代码
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 的可调延迟。

三、补充注意事项

  1. 你原始代码里的 src_clk 没有在端口声明,这是个明显的遗漏,我在完整代码里补上了,实际使用时需要把它作为模块的输入端口。
  2. 这种延迟方式的精度由 pll_clk 的频率决定,如果需要更高精度的移相,通常会配合专用的延迟线(如 FPGA 的 IODELAY)或 PLL 的相位控制功能。
  3. always @(*) 里的 case 语句一定要加 default 分支,否则会生成不必要的锁存器,影响电路稳定性。
相关推荐
XINVRY-FPGA9 小时前
XC7A100T-2CSG324I AMD Xilinx Artix-7 FPGA
arm开发·人工智能·嵌入式硬件·神经网络·fpga开发·硬件工程·fpga
Szime9 小时前
四通道高速ADC国产替代:14位500MSPS深智微科技选型参考
科技·单片机·嵌入式硬件·fpga开发
X_xcccc9 小时前
2026高端FPGA开发平台深度解析与选型指南
fpga开发·ultrascale+·kintex 7·派普蓝电子·fpga定制板卡·amd fpga
Szime20 小时前
高速 ADC 国产替代选型:通信、雷达、仪器仪表项目要看哪些参数?
单片机·嵌入式硬件·fpga开发
Szime20 小时前
国产高速ADC推荐与选型观察:从进口依赖到国产替代评估,深智微科技提供项目导入支持
科技·fpga开发
森旺电子1 天前
Vivado使用心得
fpga开发
FPGA小徐1 天前
AI 浪潮下,FPGA 如何实现自我重塑与行业变革
人工智能·fpga开发
FPGA小徐1 天前
[FPGA IP系列] FPGA常用存储资源大全(RAM、ROM、CAM、SRAM、DRAM、FLASH
fpga开发
Szime1 天前
AD9218 国产替代方向:双通道 10 位 105MSPS ADC 选型支持
单片机·嵌入式硬件·fpga开发·汽车
ALINX技术博客1 天前
ALINX VD100+Simulink 快速实现 FPGA 图像处理 Sobel 边缘检测
图像处理·人工智能·fpga开发