文章来源:FPGA入门到精通
核心设计建议详解(4-7)
建议4:多位宽跨时钟域使用FIFO
解释:多位宽信号跨时钟域时,简单的同步器无法保证所有位同时稳定,可能产生亚稳态或数据错乱。FIFO通过握手或格雷码指针确保数据完整传输。
示例(异步FIFO接口):
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
// 实例化一个异步FIFO进行跨时钟域数据传输
async_fifo #(
.DATA_WIDTH(16),
.FIFO_DEPTH(32)
) u_cdc_fifo (
.wr_clk (clk_a),
.wr_en (data_valid_a),
.din (data_a),
.rd_clk (clk_b),
.rd_en (ready_b),
.dout (data_b),
.full (fifo_full),
.empty (fifo_empty)
);
建议5:控制集管理——不超过15%
解释:控制集定义为(时钟信号 + 时钟使能 + 复位信号)的组合。Xilinx FPGA中,每个Slice的触发器共享控制集。过多控制集会大幅降低资源利用率,甚至导致布线失败。
控制集估算参考:
. 理想:控制集数量 < 总触发器数的7.5%
. 警戒线:7.5% ~ 15%
. 必须优化:> 15%
优化方法对比:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
// 优化前:每个模块有不同的复位和使能,产生多个控制集
module bad_control_set (
input clk, rst1, rst2, ce1, ce2,
input [3:0] d1, d2,
output reg [3:0] q1, q2
);
always @(posedge clk) begin
if (rst1) q1 <= 0; // 控制集 {clk, 无ce, rst1}
else if (ce1) q1 <= d1;
end
always @(posedge clk) begin
if (rst2) q2 <= 0; // 控制集 {clk, 无ce, rst2} — 不同
else if (ce2) q2 <= d2;
end
endmodule
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
// 优化后:统一复位和使能
module good_control_set (
input clk, rst, ce,
input [3:0] d1, d2,
output reg [3:0] q1, q2
);
always @(posedge clk) begin
if (rst) begin // 共享控制集
q1 <= 0;
q2 <= 0;
end else if (ce) begin
q1 <= d1;
q2 <= d2;
end
end
endmodule
建议6:优先选择同步复位
解释:同步复位能被时钟滤除毛刺,时序分析更简单,且能充分利用Xilinx FPGA中触发器SR端口的特性。异步复位虽然响应快,但容易因复位释放的时序问题导致亚稳态。
同步复位示例:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
module sync_reset_dff (
input clk,
input rst, // 同步复位
input d,
output reg q
);
always @(posedge clk) begin
if (rst)
q <= 1'b0;
else
q <= d;
end
endmodule
建议7:异步复位必须同步释放
解释:如果必须使用异步复位,需要将复位信号通过两级同步器同步到目标时钟域,并展宽到足够长度,确保所有触发器在同一时钟边沿退出复位状态。
异步复位同步释放电路:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
module async_reset_sync_release (
input clk,
input async_rst_n, // 异步复位输入
output reg sync_rst_n // 同步后的复位输出
);
reg rst_meta;
always @(posedge clk or negedge async_rst_n) begin
if (!async_rst_n) begin
rst_meta <= 1'b0;
sync_rst_n <= 1'b0;
end else begin
rst_meta <= 1'b1;
sync_rst_n <= rst_meta;
end
end
endmodule
使用同步后复位的逻辑模块:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
module user_logic (
input clk,
input async_rst_n,
input d,
output reg q
);
wire sync_rst_n;
async_reset_sync_release u_sync (
.clk(clk),
.async_rst_n(async_rst_n),
.sync_rst_n(sync_rst_n)
);
always @(posedge clk or negedge sync_rst_n) begin
if (!sync_rst_n)
q <= 1'b0;
else
q <= d;
end
endmodule