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 分支,否则会生成不必要的锁存器,影响电路稳定性。
相关推荐
物质波波波10 小时前
WS-RPE:面向边缘物理AI实时特征值计算的硬件工作窃取调度器与冗余PE激活架构
人工智能·fpga开发·架构·系统架构·硬件架构
我爱C编程13 小时前
基于FPGA的DSB调制解调系统verilog开发
fpga开发·verilog·fpga·dsb
zlinear数据采集卡14 小时前
USB HS 480M高速传输与SRAM记录仪:DABM-D223数据存储系统全解析
arm开发·嵌入式硬件·fpga开发·开源
逻辑诗篇16 小时前
基于 XCVU13P 的 4 路 100G 光纤 PCIe 处理板 PCIE727 硬件规格全解析
fpga开发
玩嵌入式谁会脱发呀19 小时前
【FPGA】 verilog设计spi读写flash实现数据DMA搬运
fpga开发
LabVIEW开发2 天前
LabVIEW 如何把地下震源定位误差做到5米内
fpga开发·labview·labview知识·labview功能·labview程序
Dr.kangder2 天前
嵌入式处理器架构解析(十)——DSP+FPGA
fpga开发·架构·嵌入式
szxinmai主板定制专家2 天前
Zynq MPSoC实现半导体真空腔体状态监测|FPGA多传感器时序同步采集方案
fpga开发·zynq·控制器·mpsoc·半导体设备·fpga同步
学习FPGA的电气小兴兴2 天前
基于FPGA的DDS信号发生器设计,生成频率可调的正弦波、三角波、锯齿波和方波
fpga开发·数字信号处理·fpga·vivado·dsp·dds·diy
szxinmai主板定制专家3 天前
Zynq MPSoC半导体高精度运动控制方案|FPGA硬件插补实现亚微米级伺服实时控制
人工智能·嵌入式硬件·fpga开发·zynq·运动控制·ethercat