时钟相关¶
时钟是时序逻辑中最重要的组成部分,驱动电路的状态发生变化。在 FPGA 逻辑设计中,正确使用时钟非常重要。
时钟产生¶
FPGA 中,时钟可以由以下两种方式产生:
- 外部输入:由 FPGA 芯片外部的晶振的周期震荡产生并输入到 FPGA 中;
- 内部生成:FPGA 内部具有 PLL (Phase-Locked Loops) 或 MMCM (Mixed-Mode Clock Manager) 等时钟管理组件可以根据已有的时钟产生新的时钟,并更改频率、相位等属性。
通常,如果需要的时钟频率与输入的不一致(更高或者更低),就需要使用 PLL/MMCM 来生成新的时钟。Vivado 提供了相应的 IP Core,称为 Clocking Wizard。
在初始化 IP 时,提供输入时钟的频率、抖动(可取默认值)等信息,而后指定需要的时钟信息,即可生成新的时钟供使用。
一般来说,此类 IP 会提供一个名称类似 locked
的信号,表明输出是否稳定,可以用作其生成的时钟对应的(异步)复位信号(注意极性)。
禁止分频
在非 testbench 代码中,禁止使用分频的方法生成时钟,否则可能会导致不可预料的时序问题。
对于少数需要输出分频后的时钟信号到外设的协议,需要十分谨慎地实现(例如从寄存器直接输出,减少延迟),并辅以相应的时序约束(保证输出信号到芯片输入端时满足 setup/hold 等条件),实现前请查阅资料并咨询助教。
频率不准确
由于内部器件的限制,可能无法得到需要的精确频率(配置 IP 时会告知实际频率),并且同一个 PLL 产生的不同时钟频率也很可能会相互制约。在这种情况下,可以使用多个 PLL 尝试缓解问题,但同时也要注意 FPGA 的 PLL 数量是有限的。
每个(输入或者生成的)时钟与它驱动的所有寄存器,构成了一个独立的 时钟域(clock domain) 。注意,这是时钟域的 唯一判断方式 。即使两个时钟的频率和相位相同,甚至由同一个 PLL 生成,也不能轻易认为属于一个时钟域。
注意事项¶
在使用时钟信号时,需要注意以下事项,否则可能导致时序问题:
- 禁止 使用时钟信号的下降沿。
- 禁止 将时钟信号进行手动分频或者与其他信号进行逻辑运算后,再作为时钟信号使用(称为门控时钟,gate-controlled clock)。
- 不建议 用 PLL 生成频率太高(如数百 MHz)或者过低(如低于 1000Hz)的时钟,这通常并不能成功。在设计中,通常也不需要这么做。
- 不推荐 在设计中使用过多的时钟,核心逻辑尽量使用单一时钟域。
- 建议 在时钟信号名称中标注频率或用途,以防混淆。
跨时钟域¶
由于两个时钟域的信号变化周期不同,因此通常不能直接使用跨过时钟域采样的信号;否则,可能由于数据建立时间不足产生的亚稳态获得错误的结果。当需要在两个时钟域间(包括 FPGA 与外部器件间)传递数据时,一般采取以下方法:
谨慎思考
有很多常见的操作不需要跨时钟域完成,尤其是每隔一段固定时间间隔进行某项操作。为达成这一目的,使用状态机计数即可。通常来说,VGA、SFP 等对于时序要求比较严格的信号,才需要自己的时钟域。在查看下面的说明之前,请务必仔细思考跨时钟域的必要性。
寄存器同步¶
对于少量控制信号,使用(至少)两个寄存器进行采样即可(clk
为需要使用此信号的时钟域):
wire other_domain;
reg [1:0] sync;
wire this_domain;
assign this_domain = sync[1];
always @(posedge clk) begin
if (rst) begin
sync <= 2'b0;
end else begin
sync <= {sync[0], other_domain};
end
end
可以将此逻辑封装成模块,以便使用。对于 Vivado 用户,也可使用 XPM (Xilinx Parameterized Macros, UG974) 中的 XPM_CDC_SINGLE
和 XPM_CDC_ARRAY_SINGLE
等模块来直接进行同步(其中同步寄存器级数等都是可配置的参数)。如有更高级的需求,可以参见 XPM_CDC_HANDSHAKE
等模块
异步 FIFO¶
对于分隔于两个时钟域的生产者——消费者模型,可以通过具有两个端口的 FIFO 来进行同步,每端使用自己的时钟进行 enqueue
和 dequeue
即可。
Vivado 中 IP Core 为 FIFO Generator
(PG057),XPM 中也有相应的 XPM_FIFO_ASYNC
模块。
异步双口 RAM¶
对于更一般的需求,可以通过具有两个时钟域的两个读写端口的 Block RAM 来传递数据,每端使用自己的时钟进行操作。
Vivado 中 IP Core 为 Block Memory Generator
(配置时同样可选前述两种模式),XPM 中有相应的 XPM_MEMORY_SDPRAM
和 XPM_MEMORY_TDPRAM
模块。