Intel® Quartus® Prime Pro Edition用户指南: 设计建议

ID 683082
日期 9/28/2020
Public

本文档可提供新的版本。客户应 单击此处 前往查看最新版本。

文档目录

1.6.2. 时钟多路复用(Clock Multiplexing)

时钟多路复用有时用于操作不同时钟源的相同逻辑功能。 这种类型的逻辑可能会导致故障,从而产生功能性问题。组合逻辑中固有的延迟也可能导致时序问题。时钟多路复用器可通过各种设计规则检查和时序分析工具触发警告。

请使用专用硬件来执行时钟多路复用(如果可用),而不要使用多路复用逻辑。例如,您可以使用某些Intel FPGA器件中的Clock Switchover功能或者Clock Control Block。这些专用的硬件模块可避免故障,确保使用全局低偏斜布线,并避免由于时钟线上的逻辑延迟而导致器件上的保持时间问题。Intel FPGA器件也支持动态PLL重配置,这是在器件操作期间更改时钟速率的最安全,最可靠的方法。

如果设计中有太多时钟使用时钟控制模块,或者动态重配置对于设计而言过于复杂,那么可以在逻辑单元中实现时钟多路复用器。但是,如果使用此实现,那么请考虑同时切换输入并确保无干扰跳变。

图 2. 6-Input LUT中的简单时钟多路复用器

每个器件数据手册均描述了LUT输出如何在同时切换输入信号的过程中产生毛刺,与LUT功能无关。即使在同时进行数据输入切换期间4:1 MUX功能不会产生可检测到的毛刺,但是多路复用逻辑的某些单元实现也表现出明显的毛刺,因此不建议使用这种时钟多路复用器结构。这种实现方式的另一个问题是,在clk_select信号发生变化时,输出的行为会异常。此行为可能会在系统时钟馈送的所有寄存器上造成时序冲突,并可能导致亚稳态。

更复杂的时钟选择结构可以消除同时发生的翻转和切换问题。

图 3. 无毛刺时钟多路复用器结构

您可以对任意数量的时钟通道采用此结构。此设计确保在所有其他时钟都至少保持无效数个周期后才激活一个时钟,并且确保时钟为低电平时进行激活。此设计对右侧的AND gate应用synthesis_keep指令,以确保clk_out OR gate的输入上没有同时翻转。

注: 从时钟A切换到时钟B要求时钟A继续运行至少几个周期。如果时钟A立即停止,那么设计将停留。在此示例中,选择信号被实现为“one-shot”控制,但是您可以根据需要使用其他编码。输入端逻辑是异步的,并不重要。这种设计可以承受切换过程中的严重毛刺。

用于避免毛刺的Verilog HDL时钟多路复用设计

此示例适用于Verilog-2001。

module clock_mux (clk,clk_select,clk_out);

	parameter num_clocks = 4;

	input [num_clocks-1:0] clk;
	input [num_clocks-1:0] clk_select; // one hot
	output clk_out;

	genvar i;

	reg [num_clocks-1:0] ena_r0;
	reg [num_clocks-1:0] ena_r1;
	reg [num_clocks-1:0] ena_r2;
	wire [num_clocks-1:0] qualified_sel;

	// A look-up-table (LUT) can glitch when multiple inputs 
	// change simultaneously. Use the keep attribute to
	// insert a hard logic cell buffer and prevent 
	// the unrelated clocks from appearing on the same LUT.

	wire [num_clocks-1:0] gated_clks /* synthesis keep */;

	initial begin
		ena_r0 = 0;
		ena_r1 = 0;
		ena_r2 = 0;
	end

	generate
		for (i=0; i<num_clocks; i=i+1) 
		begin : lp0
			wire [num_clocks-1:0] tmp_mask;
			assign tmp_mask = {num_clocks{1'b1}} ^ (1 << i);

			assign qualified_sel[i] = clk_select[i] & (~|(ena_r2 & tmp_mask));

			always @(posedge clk[i]) begin
				ena_r0[i] <= qualified_sel[i];    	
				ena_r1[i] <= ena_r0[i];    	
			end

			always @(negedge clk[i]) begin
				ena_r2[i] <= ena_r1[i];    	
			end

			assign gated_clks[i] = clk[i] & ena_r2[i];
		end
	endgenerate

	// These will not exhibit simultaneous toggle by construction
	assign clk_out = |gated_clks;

endmodule