(实习准备)学习 FPGA 中跨时钟域通信问题的处理。
跨时钟域通信出现的问题:
亚稳态问题:
如下图所示,触发器的存储需要有一个建立时间
解决办法
电平同步器: 针对单bit
脉冲同步器: 针对单bit
FIFO, RAM : 针对多bit
同步器
- 复位处理模块
- 快到慢的同步器
- 慢到快的同步器
- 双边缘检测器
“打两拍“ 同步的原理:异步赋值会产生亚稳态。概率数学上的处理的方式。每个触发器发生亚稳态的概率是独立的,多个触发器串联可以使 发生亚稳态的概率大大减小。“打三拍” 降低的概率和“打两拍”的差别不大。
同步复位代码:
verilog
// 代码规范:
// 模块名为 功能+_module ,如果是驱动则以 _driver结尾
// 信号的名称 i_,o_ 分别表示 输入和输出的前缀
// 寄存器变量的声明 以 reg_ 进行开头
module sync_rst_module(
input i_sysclk ,
input i_rst ,
output o_sync_rst
);
// 告诉综合器,将这两个寄存器放在同一个 CLB 中
(* ANYNC_REG = "TRUE"*)
reg r_rst1, r_rst2;
// 一般的规范要求一个always块中只能处理一个信号,但是这里的设计比较简单,这里就直接写在一起了
always @(posedge i_sysclk) begin
if (i_rst) begin
r_rst1 <= 1'b1;
r_rst2 <= 1'b1;
end else begin
r_rst1 <= i_rst;
r_rst2 <= r_rst1;
end
end
assign o_sync_rst = r_rst2;
endmodule
慢时钟域到快时钟域同步:设计上和同步复位的代码是差不多的
verilog
module s2f_sync_module(
input i_clk_slow ,
input i_signal ,
input i_clk_fast ,
output o_sync_signal
);
(* ANYNC_REG = "TRUE"*)
reg r_s1, r_s2;
always @(posedge i_clk_fast) begin
r_s1 <= i_signal;
r_s2 <= r_s1;
end
assign o_sync_signal = r_s2;
endmodule
快时钟域到慢时钟域同步:也叫脉冲同步器。
与慢到快不同的是需要进行脉冲周期延拓
verilog
module f2s_sync_module(
input i_clk_slow ,
input i_signal ,
input i_clk_fast ,
output o_sync_signal
);
reg r_d1, r_d2;
// 延拓用的寄存器
wire r_pos;
(* ANYNC_REG = "TRUE"*)
reg r_s1, r_s2;
always @(posedge i_clk_slow) begin
r_d1 <= i_signal;
r_d2 <= r_d1;
end
// 信号延拓 2个周期
assign r_pos = i_signal | r_d1 | r_d2;
// 打两拍用的寄存器
(* ANYNC_REG = "TRUE"*)
reg r_p1, r_p2;
always @(posedge i_clk_slow) begin
r_p1 <= r_pos;
r_p2 <= r_p1;
end
// 同步输出
assign o_sync_signal = r_p2;
endmodule
异步FIFO
待补充, 参考 《Simulation and Synthesis Techniques for Asynchronous FIFO Design》