3. 时钟域与复位域建模

多时钟SoC仿真的第一道门槛,不是写激励,而是把“时间”本身建模正确。RTL里每个时钟、每个复位都有明确的物理来源和约束;验证环境如果只用一个clk和rst_n去驱动整个DUT,那么CDC路径上的亚稳态、复位释放顺序、门控时钟的使能窗口都会被仿真器“抹平”,后续所有CDC检查都建立在错误的时间模型上。本节要解决的就是:在RTL和验证环境中,如何把多时钟、异步复位、同步复位、时钟门控这四类对象定义清楚,并用一份时钟关系描述文件把它们之间的频率、相位、同源/异步关系固化下来。

一、先分清四类时钟/复位对象的语义

多时钟SoC中,时钟不是“一个信号”,而是一组带属性的对象。建模前必须先区分:

  • 主时钟(primary clock):由PLL、晶振或外部引脚直接产生,是频率和相位的源头,例如clk_cpu_1g、clk_ddr_800m。
  • 生成时钟(generated clock):由主时钟经分频、倍频、门控或时钟选择器产生,例如clk_apb = clk_axi / 4,它与源时钟同源,相位关系可推导。
  • 异步复位(async reset):复位有效沿与时钟无关,典型写法always @(posedge clk or negedge rst_n),复位释放必须做同步化处理。
  • 同步复位(sync reset):复位在时钟沿采样,always @(posedge clk)内判断if(!rst_n),释放天然与时钟对齐。

时钟门控(clock gating)是另一类特殊对象:它不改变时钟频率,但会改变时钟的“存在性”。集成时钟门控单元(ICG)用使能信号en控制时钟是否翻转,使能信号本身必须来自被门控时钟域或经过同步,否则会产生毛刺或截断脉冲。在验证环境中,门控时钟不能简单用force关掉,否则会丢失使能窗口内的行为。

二、RTL侧的建模要点

RTL中时钟和复位通常由顶层端口或时钟生成模块提供。一个可综合的时钟分频示例:

// 主时钟 1GHz 分频出 250MHz APB 时钟
reg [1:0] div_cnt;
always @(posedge clk_cpu_1g or negedge rst_sys_n)
  if (!rst_sys_n) div_cnt <= 2'b00;
  else            div_cnt <= div_cnt + 1'b1;

assign clk_apb = div_cnt[1];   // 4分频,同源生成时钟

异步复位同步释放的标准结构,是CDC验证中必须识别的模式:

// 异步复位、同步释放
reg rst_sync_meta, rst_sync_out;
always @(posedge clk_apb or negedge rst_sys_n)
  if (!rst_sys_n) {rst_sync_out, rst_sync_meta} <= 2'b00;
  else            {rst_sync_out, rst_sync_meta} <= {rst_sync_meta, 1'b1};

这里rst_sys_n是异步复位源,rst_sync_out是同步化后的复位,供APB域使用。验证环境必须能分别观测这两个信号,否则无法判断复位释放是否真的对齐到clk_apb。

三、验证环境中的时钟/复位生成

在Xcelium + SystemVerilog环境中,推荐用interface封装时钟和复位,再由clock generator统一驱动。关键参数包括周期、占空比、初始相位、抖动(jitter)和启动延迟。示例:

interface clk_rst_if(input bit ref_clk);
  logic clk_cpu_1g, clk_apb, rst_sys_n, rst_apb_sync_n;
  // 1GHz: 周期1ns, 占空比50%
  initial begin clk_cpu_1g = 0; forever #0.5 clk_cpu_1g = ~clk_cpu_1g; end
  // 250MHz APB: 周期4ns, 与CPU同源但相位偏移0.2ns
  initial begin clk_apb = 0; #0.2; forever #2 clk_apb = ~clk_apb; end
  // 异步复位:上电后保持低电平20ns再释放
  initial begin rst_sys_n = 0; #20 rst_sys_n = 1; end
endinterface

注意:验证环境中的时钟相位偏移必须与时钟关系描述文件一致,否则CDC检查工具(如Xcelium的CDC app)会按错误关系推断同步/异步,导致漏报或误报。

四、时钟关系描述文件

时钟关系描述文件是连接RTL、验证环境和CDC检查工具的“契约”。它通常以SDC约束或专用配置文件形式存在,至少应包含:时钟名、源、周期、相位、同源组、异步组、门控关系。下面是一份可直接参考的示例(字段为教学示例,非实测数据):

时钟名源周期(ns)相位(ns)同源组异步组门控
clk_cpu_1gPLL01.00.0G0—否
clk_apbclk_cpu_1g/44.00.2G0—否
clk_ddr_800mPLL11.250.0G1G0否
clk_gated_coreclk_cpu_1g1.00.0G0—en_core
rst_sys_n外部引脚———异步—
rst_apb_sync_nrst_sys_n同步———同步于clk_apb—

这份文件的作用有三:一是让验证环境按相同参数生成时钟;二是让CDC工具知道哪些跨域路径是“同源可推导”、哪些是“真异步需同步器”;三是让复位域检查能区分异步复位源和同步化后的复位。

五、四类对象的关系与检查路径

把上述内容串起来,可以用一张关系图看清时钟域、复位域、门控和描述文件之间的连接。下图以本节真实对象绘制:左侧是RTL/验证环境中的时钟与复位源,中间是时钟关系描述文件,右侧是CDC检查工具关注的跨域路径与复位域边界。

RTL / 验证环境时钟源 clk_cpu_1g PLL0 · 1.0ns · 相位0 clk_apb clk_cpu_1g/4 · 4.0ns · 相位0.2 clk_ddr_800m PLL1 · 1.25ns · 异步于G0 clk_gated_core ICG · en_core · 同源G0 rst_sys_n 异步复位源 · 外部引脚 rst_apb_sync_n 同步释放 · 对齐clk_apb 时钟关系描述文件 • 时钟名 / 源 / 周期 / 相位 • 同源组 G0 / G1 • 异步组:G0 ↔ G1 • 门控关系:en_core • 复位域:异步源 / 同步化 • 生成时钟推导路径 SDC / 专用配置 create_clock create_generated_clock set_clock_groups -asynchronous CDC检查关注点 G0 ↔ G1 跨域 真异步 · 需同步器 两级触发器 / 握手 G0 内部跨域 同源 · 相位可推导 检查建立/保持余量 门控时钟域 en_core 同步检查 门控窗口内数据保持 复位域边界 异步释放同步化 复位交叉域检查 时钟关系一致性 RTL / TB / 描述文件三方对齐 同源组内相位可推导,异步组间必须插入同步器;门控时钟的使能信号需同步到被门控域

图中左侧的clk_cpu_1g与clk_apb同属G0,相位差0.2ns可推导,CDC工具按同源关系检查;clk_ddr_800m属于G1,与G0真异步,任何跨域路径都必须有同步器。门控时钟clk_gated_core虽然同源G0,但使能en_core必须同步到clk_cpu_1g,否则门控沿可能截断时钟脉冲。复位域方面,rst_sys_n是异步源,rst_apb_sync_n是同步化后的复位,两者在CDC检查中属于不同复位域,跨复位域的数据路径需要单独检查。

建立时钟关系描述文件时,建议先列出所有时钟源和生成路径,再标注同源组和异步组,最后补充门控和复位域。描述文件一旦确定,RTL、验证环境、CDC约束三处必须使用同一份参数,任何一处不一致都会导致CDC检查结果不可信。
常见错误:在验证环境中用force clk_gated_core = 0关闭门控时钟,这会绕过ICG的使能逻辑,使门控窗口内的数据保持行为无法被验证。正确做法是驱动en_core,让ICG自然关断时钟。

完成本节建模后,应能回答三个问题:每个时钟的频率、相位、同源/异步关系是否明确?每个复位的异步源和同步化路径是否可观测?每个门控时钟的使能信号是否已同步到正确时钟域?这三个问题答清楚,后续的CDC路径检查和复位域检查才有可靠的时间基准。