一、引言在 FPGA 设计中几乎每个项目都离不开时钟管理。无论是驱动高速接口还是为低速外设提供节拍我们经常需要从一颗主时钟派生出多个不同频率的时钟。Xilinx 提供的Clocking WizardIP 核便是完成这一任务的利器它能生成低抖动、相位对齐的多路时钟且配置灵活。本文将以一个具体设计为例带你从顶层模块到仿真验证完整实现 “输入 100MHz 主时钟输出 32 分频、64 分频、150 分频三路时钟” 的全过程。同时本文代码严格遵循了一套高可读性、高可维护性的编码规范非常适合团队协作与项目迭代。二、功能描述模块tops是对 Clocking Wizard 生成 IPclk_wiz_0的顶层封装功能如下输入时钟i_clk100MHz周期 10ns输入复位i_rst高有效复位直接控制 IP 核的复位输出时钟o_clk32div32 分频3.125MHzo_clk64div64 分频1.5625MHzo_clk150div150 分频0.6667MHz内部结构极为简洁外部信号通过 wire 线网连接到 IP 核输出时钟直接引出。这种“顶层只做连线”的设计思路使得模块清晰易懂维护成本极低。三、设计思路与创新点1. 极简顶层复杂功能交给 IP顶层模块tops不包含任何分频逻辑只负责把端口信号与clk_wiz_0的端口对接。所有时钟生成、去抖动、相位对齐工作均由已经验证的 IP 完成。这种“高内聚、低耦合”的策略让顶层代码像一份 “接线说明书”一目了然。2. 严格且统一的编码规范优秀的代码不仅要机器能跑更要让人好读。本设计应用了一整套命名与分组规则端口对齐方向、类型、名称整齐排列视觉舒适。分组注释代码按param → reg → wire → assign → FSM → inst → combine_Logic → always固定顺序分区并用醒目的分隔行标注。即使某组暂时为空如状态机、组合逻辑仍保留注释行为未来扩展预留位置。统一前缀所有内部线网以w_开头寄存器以r_开头输出打拍寄存器以ro_开头。仅凭前缀就能判断信号类型。状态机预留虽然没有用到 FSM但分组行已占位将来引入状态控制时只需在对应区域添加代码整体框架不受影响。这种风格在多人协作、长期维护的项目中价值巨大新人能快速定位功能区块减少沟通与误读。3. 复位极性明确接口直观Clock Wizard IP 的reset端口为高有效。本设计中外部复位信号i_rst也是高有效因此可以直接连接无需极性转换。这样处理的好处是接口语义直观i_rst 1代表复位i_rst 0代表正常工作。省去顶层中的反相器逻辑连线干净。如果板级复位信号是低有效只需在实例化时改为~i_rst即可修改点极单一且显眼后续调试不会产生歧义。4. 简洁高效的仿真激励测试模块test_tops没有使用复杂的 task 或 UVM只用几十行代码就完成了激励产生。其设计亮点用always #5 i_clk ~i_clk直接生成 100MHz 时钟。仿真开始时i_rst为高复位状态100ns 后拉低模拟上电后短暂复位再释放的过程便于观察 IP 锁定信号。输出信号以 wire 形式引出可在波形窗口中直接观察分频波形。四、完整代码顶层模块 tops.vtimescale 1ns / 1ps module tops( input i_clk, input i_rst, output o_clk32div, output o_clk64div, output o_clk150div ); // param // reg // wire wire w_clk32div; wire w_clk64div; wire w_clk150div; wire w_locked; // assign assign o_clk32div w_clk32div; assign o_clk64div w_clk64div; assign o_clk150div w_clk150div; // FSM // inst clk_wiz_0 clk_wiz_0u ( .clk_out1 (w_clk32div), .clk_out2 (w_clk64div), .clk_out3 (w_clk150div), .reset (i_rst), // 复位极性高有效与IP核一致 .locked (w_locked), .clk_in1 (i_clk) ); // combine_Logic // always endmodule仿真测试模块 test_tops.vtimescale 1ns / 1ps module test_tops; reg i_clk; reg i_rst; wire o_clk32div; wire o_clk64div; wire o_clk150div; // 实例化待测模块 tops tops_u( .i_clk (i_clk), .i_rst (i_rst), .o_clk32div (o_clk32div), .o_clk64div (o_clk64div), .o_clk150div(o_clk150div) ); initial begin i_clk 1b1; i_rst 1b1; // 初始处于复位状态 #100; i_rst 1b0; // 释放复位 end always #5 i_clk ~i_clk; // 生成 100MHz 时钟 endmodule复位时序说明仿真中i_rst从高变低模拟上电后复位释放的过程。由于 IP 核复位高有效因此初始i_rst1时芯片处于复位100ns 后拉低PLL 开始锁定。实际板级调试时请根据复位按键的电路特性调整初始电平及持续时间。五、仿真波形分析预期结果在 Vivado 仿真器中运行上述代码可观察到输入时钟i_clk稳定的 100MHz 方波。复位释放后IP 的locked信号内部w_locked从 0 跳变为 1表示 PLL 锁定成功。输出时钟o_clk32div周期约 320ns3.125MHzo_clk64div周期约 640ns1.5625MHzo_clk150div周期约 1500ns0.6667MHz三路时钟相位对齐无毛刺可直接供后续模块使用。六、总结本文通过一个多路时钟分频的案例展示了如何将 Xilinx Clocking Wizard IP 无缝集成到规范化 Verilog 项目中。核心创新不仅在于使用 IP 快速实现灵活分频更在于系统性编码规范的应用和极简顶层设计思想。这种风格能极大提升团队开发效率减少低级错误。希望本文能帮助读者掌握时钟管理的基本设计方法并在自己的工程中写出易读、易维护、易扩展的 Verilog 代码。如果你觉得有收获欢迎点赞收藏一起交流 FPGA 设计心得
FPGA实战(09):手把手教你用 Xilinx Clocking Wizard 实现多路时钟分频 —— 附规范化 Verilog 设计与完整仿真代码
一、引言在 FPGA 设计中几乎每个项目都离不开时钟管理。无论是驱动高速接口还是为低速外设提供节拍我们经常需要从一颗主时钟派生出多个不同频率的时钟。Xilinx 提供的Clocking WizardIP 核便是完成这一任务的利器它能生成低抖动、相位对齐的多路时钟且配置灵活。本文将以一个具体设计为例带你从顶层模块到仿真验证完整实现 “输入 100MHz 主时钟输出 32 分频、64 分频、150 分频三路时钟” 的全过程。同时本文代码严格遵循了一套高可读性、高可维护性的编码规范非常适合团队协作与项目迭代。二、功能描述模块tops是对 Clocking Wizard 生成 IPclk_wiz_0的顶层封装功能如下输入时钟i_clk100MHz周期 10ns输入复位i_rst高有效复位直接控制 IP 核的复位输出时钟o_clk32div32 分频3.125MHzo_clk64div64 分频1.5625MHzo_clk150div150 分频0.6667MHz内部结构极为简洁外部信号通过 wire 线网连接到 IP 核输出时钟直接引出。这种“顶层只做连线”的设计思路使得模块清晰易懂维护成本极低。三、设计思路与创新点1. 极简顶层复杂功能交给 IP顶层模块tops不包含任何分频逻辑只负责把端口信号与clk_wiz_0的端口对接。所有时钟生成、去抖动、相位对齐工作均由已经验证的 IP 完成。这种“高内聚、低耦合”的策略让顶层代码像一份 “接线说明书”一目了然。2. 严格且统一的编码规范优秀的代码不仅要机器能跑更要让人好读。本设计应用了一整套命名与分组规则端口对齐方向、类型、名称整齐排列视觉舒适。分组注释代码按param → reg → wire → assign → FSM → inst → combine_Logic → always固定顺序分区并用醒目的分隔行标注。即使某组暂时为空如状态机、组合逻辑仍保留注释行为未来扩展预留位置。统一前缀所有内部线网以w_开头寄存器以r_开头输出打拍寄存器以ro_开头。仅凭前缀就能判断信号类型。状态机预留虽然没有用到 FSM但分组行已占位将来引入状态控制时只需在对应区域添加代码整体框架不受影响。这种风格在多人协作、长期维护的项目中价值巨大新人能快速定位功能区块减少沟通与误读。3. 复位极性明确接口直观Clock Wizard IP 的reset端口为高有效。本设计中外部复位信号i_rst也是高有效因此可以直接连接无需极性转换。这样处理的好处是接口语义直观i_rst 1代表复位i_rst 0代表正常工作。省去顶层中的反相器逻辑连线干净。如果板级复位信号是低有效只需在实例化时改为~i_rst即可修改点极单一且显眼后续调试不会产生歧义。4. 简洁高效的仿真激励测试模块test_tops没有使用复杂的 task 或 UVM只用几十行代码就完成了激励产生。其设计亮点用always #5 i_clk ~i_clk直接生成 100MHz 时钟。仿真开始时i_rst为高复位状态100ns 后拉低模拟上电后短暂复位再释放的过程便于观察 IP 锁定信号。输出信号以 wire 形式引出可在波形窗口中直接观察分频波形。四、完整代码顶层模块 tops.vtimescale 1ns / 1ps module tops( input i_clk, input i_rst, output o_clk32div, output o_clk64div, output o_clk150div ); // param // reg // wire wire w_clk32div; wire w_clk64div; wire w_clk150div; wire w_locked; // assign assign o_clk32div w_clk32div; assign o_clk64div w_clk64div; assign o_clk150div w_clk150div; // FSM // inst clk_wiz_0 clk_wiz_0u ( .clk_out1 (w_clk32div), .clk_out2 (w_clk64div), .clk_out3 (w_clk150div), .reset (i_rst), // 复位极性高有效与IP核一致 .locked (w_locked), .clk_in1 (i_clk) ); // combine_Logic // always endmodule仿真测试模块 test_tops.vtimescale 1ns / 1ps module test_tops; reg i_clk; reg i_rst; wire o_clk32div; wire o_clk64div; wire o_clk150div; // 实例化待测模块 tops tops_u( .i_clk (i_clk), .i_rst (i_rst), .o_clk32div (o_clk32div), .o_clk64div (o_clk64div), .o_clk150div(o_clk150div) ); initial begin i_clk 1b1; i_rst 1b1; // 初始处于复位状态 #100; i_rst 1b0; // 释放复位 end always #5 i_clk ~i_clk; // 生成 100MHz 时钟 endmodule复位时序说明仿真中i_rst从高变低模拟上电后复位释放的过程。由于 IP 核复位高有效因此初始i_rst1时芯片处于复位100ns 后拉低PLL 开始锁定。实际板级调试时请根据复位按键的电路特性调整初始电平及持续时间。五、仿真波形分析预期结果在 Vivado 仿真器中运行上述代码可观察到输入时钟i_clk稳定的 100MHz 方波。复位释放后IP 的locked信号内部w_locked从 0 跳变为 1表示 PLL 锁定成功。输出时钟o_clk32div周期约 320ns3.125MHzo_clk64div周期约 640ns1.5625MHzo_clk150div周期约 1500ns0.6667MHz三路时钟相位对齐无毛刺可直接供后续模块使用。六、总结本文通过一个多路时钟分频的案例展示了如何将 Xilinx Clocking Wizard IP 无缝集成到规范化 Verilog 项目中。核心创新不仅在于使用 IP 快速实现灵活分频更在于系统性编码规范的应用和极简顶层设计思想。这种风格能极大提升团队开发效率减少低级错误。希望本文能帮助读者掌握时钟管理的基本设计方法并在自己的工程中写出易读、易维护、易扩展的 Verilog 代码。如果你觉得有收获欢迎点赞收藏一起交流 FPGA 设计心得