4. 单比特电平同步器设计
单比特电平同步器是跨时钟域设计中最基础、使用最频繁的电路结构。它的任务非常明确:把一个在源时钟域中持续保持稳定的单比特电平信号,安全地传递到目的时钟域,并输出一个在目的时钟域中干净的、无亚稳态传播风险的电平信号。理解它的结构、参数选择与约束方法,是后续掌握脉冲同步、握手同步和异步FIFO的前提。
一、为什么两级触发器能消除亚稳态
当源时钟域的信号在目的时钟的建立/保持窗口内发生跳变时,目的触发器的输出可能进入既非高也非低的亚稳态。亚稳态不会永久保持,它会在一定时间内随机地衰减到稳定值,这个衰减时间服从指数分布。如果只用一级触发器,亚稳态可能直接传播到下游组合逻辑,造成不可预测的行为。
两级触发器同步器的核心思想是:让第一级触发器专门"承受"亚稳态,给它一个完整的时钟周期去衰减;第二级触发器在第一级输出已经稳定的前提下采样,从而输出干净的电平。这里有一个关键前提——源信号在目的时钟域看来必须是"慢变"的,即它在被采样期间保持稳定足够长的时间,否则同步器无法保证正确捕获。
二、结构细节与参数选择
标准的两级同步器由两个同沿触发的D触发器串联组成,共用目的时钟clk_b。第一级触发器的D端接异步输入,Q端接第二级触发器的D端,第二级触发器的Q端作为同步后的输出。两级之间不插入任何组合逻辑,这是硬性要求——任何组合逻辑都会破坏亚稳态衰减的时间预算。
参数选择主要围绕三个量:目的时钟频率、源信号的最小保持宽度、以及目标MTBF(平均无故障时间)。MTBF的经典估算公式为:
MTBF = e^(t_r / τ) / (T_0 × f_clk × f_data)
其中:
t_r = 留给亚稳态衰减的时间(通常取一个clk_b周期)
τ = 触发器亚稳态时间常数(PolarFire器件典型值约几十ps量级)
T_0 = 亚稳态窗口宽度常数(约几十ps量级)
f_clk = 目的时钟频率
f_data= 异步数据跳变频率
在PolarFire器件中,τ和T_0由工艺决定,设计者能控制的是t_r和f_clk。提高MTBF最直接的方法是增加同步级数或降低目的时钟频率。对于绝大多数消费级和工业级应用,两级同步器在100MHz以下的clk_b下已经能提供足够的MTBF;如果源信号跳变极其频繁或可靠性要求极高,可以扩展到三级。
另一个关键参数是源信号的最小保持宽度。电平同步器要求源信号在被同步期间保持稳定至少两个clk_b周期(考虑最坏相位情况),否则可能完全丢失该电平。例如clk_b为50MHz(周期20ns),源信号至少要保持40ns以上。如果源信号是窄脉冲,必须改用脉冲同步器或握手协议。
三、PolarFire Libero中的实现
在Libero SoC中实现电平同步器有两种方式。第一种是直接写RTL,用两个always块或一个always块内的两级寄存器描述。第二种是调用Libero提供的同步器宏(如CORESYNC),但手写RTL更透明、更便于约束。
下面是一个可直接综合的Verilog示例,采用异步复位、同步释放的复位策略:
module level_sync (
input wire clk_b, // 目的时钟
input wire rst_n, // 异步复位,低有效
input wire data_a, // 源时钟域电平信号
output wire data_b_sync // 同步后输出
);
reg sync_meta;
reg sync_out;
always @(posedge clk_b or negedge rst_n) begin
if (!rst_n) begin
sync_meta <= 1'b0;
sync_out <= 1'b0;
end else begin
sync_meta <= data_a; // 第一级:承受亚稳态
sync_out <= sync_meta; // 第二级:输出稳定值
end
end
assign data_b_sync = sync_out;
endmodule
综合后需要在Libero的时序约束文件(SDC)中做两件事。第一,对data_a到第一级触发器的路径设置伪路径(false path),因为这是跨时钟域路径,静态时序分析无法也不应该分析它:
set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b]
第二,确保两级触发器被布局在相邻位置,减少布线延迟差异。在Libero的Floorplanner中,可以把这两个寄存器手动约束到同一个Logic Element或相邻的LE中。PolarFire的SmartFusion2/MPF器件中,每个LE包含多个寄存器和LUT,把同步器两级放在同一LE内可以最小化t_r的损耗。
syn_keep或preserve属性防止优化。
四、验证方法与结果判读
验证电平同步器需要覆盖三个场景:源信号在clk_b采样窗口外跳变、在采样窗口内跳变、以及源信号保持时间不足。在Libero中可以用Testbench加ModelSim仿真,也可以上板用SmartDebug观察。
仿真时,让clk_a和clk_b为不同频率的非整数倍关系(例如clk_a=37MHz,clk_b=50MHz),源信号data_a每隔一段随机时间翻转。观察data_b_sync:它应该在data_a变化后的2~3个clk_b周期内跟随变化,且不出现毛刺或振荡。如果看到输出在中间电平停留超过一个周期,说明亚稳态衰减时间不够,需要检查t_r是否被组合逻辑或布线延迟吃掉。
上板验证时,可以用一个LED或逻辑分析仪观察data_b_sync。更严格的方法是把data_b_sync再打一拍,用两级输出做边沿检测,统计在固定时间窗口内捕获到的跳变次数是否与源端一致。如果丢失跳变,说明源信号保持宽度不足或同步器级数不够。
| 检查项 | 预期结果 | 异常处理 |
|---|---|---|
| 同步延迟 | 2~3个clk_b周期 | 检查是否插入了组合逻辑 |
| 输出毛刺 | 无 | 确认两级FF同沿触发 |
| 跳变丢失 | 无 | 增大源信号保持宽度或加第三级 |
| 时序报告 | 跨时钟路径被设为false path | 补充SDC约束 |
最后需要强调:电平同步器只适用于单比特、慢变信号。如果源信号是总线或多比特,必须使用异步FIFO或握手同步,否则各比特到达目的域的时间不一致会造成数据错误。这是CDC验证中最常见的误区之一。