저는 타이밍이 중요한 부분에서 모든 레지스터가 I/O 셀(cell)에 들어가도록 만들어 I/O 타이밍을 처리하는 편을 선호합니다.
Quartus 에서는 I/O 레지스터 패킹(register packing)이 기본값이 아닌 것 같습니다. 어쨌든, 여기 게으른 사람을 위한 방법을 소개합니다.
이 글의 이전 버전에서는 모든 I/O에 대한 타이밍 검사를 비활성화하라고 권했었습니다. 모든 I/O에 대해 허위 경로(false path) 제약을 거는 방식이었습니다. 이렇게 하면 구현 중에 제약이 없는 경로(unconstrained path) 경고가 나오지 않게 되고, 특히 Quartus 의 리포트 창에서 "TimeQuest Timing Analyzer" 섹션이 빨간색으로 변하지 않게 됩니다:
set_false_path -from [get_ports]
set_false_path -to [get_ports]
알고 보니 이것은 그리 좋은 생각이 아니었습니다. 특히 입력 포트의 경우가 그렇습니다. 이 내용은 아래에서 더 자세히 설명합니다.
그렇더라도 fitter 가 레지스터를 I/O 블록에 배치하도록 해야 합니다. QSF 파일에 다음을 추가하세요:
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to * set_instance_assignment -name FAST_INPUT_REGISTER ON -to * set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to *
모든 레지스터에 이러한 할당을 적용하는 것은 다소 공격적이지만 효과는 있습니다. fitter 는 이 제약 조건을 적용하지 못한 I/O 소자에 대해 경고를 내보내는데, 이것은 오히려 좋은 기능입니다.
얼마나 잘 적용되었는지 확인하려면 fitter 리포트의 "Resource Section"을 보고, "Input Registers" 등의 해당 항목을 찾아보세요(Quartus 의 리포트 창에서 찾을 수 있습니다).
차이는 I/O 셀을 포함하는 경로(path)의 타이밍 리포트에서 분명하게 드러납니다. 예를 들어, I/O 레지스터가 포함된 이 경로를 비교해 보세요:
+----------------------------------------------------------------------------------+ ; Data Arrival Path ; +---------+---------+----+------+--------+-----------------------+-----------------+ ; Total ; Incr ; RF ; Type ; Fanout ; Location ; Element ; +---------+---------+----+------+--------+-----------------------+-----------------+ ; 2.918 ; 2.918 ; ; ; ; ; data path ; ; 0.000 ; 0.000 ; ; ; 1 ; DDIOOUTCELL_X3_Y0_N32 ; rst ; ; 0.465 ; 0.465 ; RR ; CELL ; 1 ; DDIOOUTCELL_X3_Y0_N32 ; rst|q ; ; 0.465 ; 0.000 ; RR ; IC ; 1 ; IOOBUF_X3_Y0_N30 ; RESETB~output|i ; ; 2.918 ; 2.453 ; RR ; CELL ; 1 ; IOOBUF_X3_Y0_N30 ; RESETB~output|o ; ; 2.918 ; 0.000 ; RR ; CELL ; 0 ; PIN_P3 ; RESETB ; +---------+---------+----+------+--------+-----------------------+-----------------+
DDIOOUTCELL 소자와 레지스터와 IOOBUF 사이의 배선 증가량이 0이라는 점에 주목하세요.
비교를 위해, I/O 레지스터가 적용되지 않은 경로(path)도 보겠습니다(로직 때문에 적용하지 못한 경우입니다):
+--------------------------------------------------------------------------------+ ; Data Arrival Path ; +---------+---------+----+------+--------+-----------------+---------------------+ ; Total ; Incr ; RF ; Type ; Fanout ; Location ; Element ; +---------+---------+----+------+--------+-----------------+---------------------+ ; 8.284 ; 8.284 ; ; ; ; ; data path ; ; 0.000 ; 0.000 ; ; ; 1 ; FF_X3_Y0_N17 ; Dir_flop_sig ; ; 0.496 ; 0.496 ; RR ; CELL ; 8 ; FF_X3_Y0_N17 ; Dir_flop_sig|q ; ; 2.153 ; 1.657 ; RR ; IC ; 1 ; IOOBUF_X3_Y0_N9 ; DATA[7]~output|oe ; ; 8.284 ; 6.131 ; RF ; CELL ; 1 ; IOOBUF_X3_Y0_N9 ; DATA[7]~output|o ; ; 8.284 ; 0.000 ; FF ; CELL ; 1 ; PIN_T3 ; DATA[7] ; +---------+---------+----+------+--------+-----------------+---------------------+
여기서는 범용 플립플롭이 신호를 생성하면서 1.657 ns 에 달하는 배선 지연이 발생하는 모습을 볼 수 있습니다. 핵심 문제는 이 배선 지연이 구현(implementation)마다 달라진다는 것입니다. 따라서 보드에 신호 무결성(signal integrity) 문제가 있을 때, FPGA 설계 버전을 바꿀 때마다 문제가 해결되거나 다시 나타나는 것처럼 보이기 때문에 FPGA 탓으로 돌려질 수 있습니다.
타이밍 제약
입력 포트와 출력 포트 모두 타이밍 제약 조건(timing constraints)을 빡빡하게 잡아서, I/O 레지스터를 최대한 활용하지 않고서는 제약을 달성할 수 없도록 해야 합니다. 이렇게 하면 원하는 레지스터 패킹이 잘못되었을 때 타이밍 위반이 발생하여 문제를 드러내 줄 뿐만 아니라, 다음에 설명하는 것처럼 입력에서 레지스터까지의 지연을 최소로 줄이는 데에도 필요합니다.
아래 논의는 레지스터를 구동하는 클록이 외부 클록과 직접적인 관련이 있는 경우에만 적용됩니다(예: PLL 이 클록을 정수배하는 경우). 레지스터를 구동하는 클록이 외부 클록과 실질적으로 관련이 없다면 상황은 훨씬 복잡해지며, 이 글에서 다룹니다.
이 문제를 설명하기 위해 다음 Verilog 코드를 살펴보겠습니다:
module top
(
input clk,
input in,
output reg out
);
reg in_d, in_d2;
wire pll_clk;
always @(posedge pll_clk)
begin
in_d <= in;
in_d2 <= in_d;
out <= in_d2;
end
/* Here comes an instantiation of a phase-compensating PLL, which
doesn't change the frequency */
endmodule
또한 SDC 파일에 다음 제약 조건이 있다고 가정해 보겠습니다:
create_clock -name main_clk -period 10 -waveform { 0 5 } [get_ports {clk}]
derive_pll_clocks
derive_clock_uncertainty
set_input_delay -clock main_clk -max 8.5 [get_ports in*]
set_input_delay -clock main_clk -min 0 [get_ports in*]
이 글에서 설명했듯이, set_input_delay 는 신호 소스의 클록 엣지에서 유효한 논리 상태가 될 때까지의 최대 지연입니다. 클록 주기가 10 ns 로 설정되어 있으므로, 지연 제약을 8.5 ns 로 지정하면 다음 클록 엣지(10 ns)까지 1.5 ns 의 여유가 남습니다. 즉, FPGA 핀에서의 셋업 시간(setup time)이 1.5 ns 를 초과하지 못하도록 제약이 걸리는 셈입니다.
참고로 set_max_delay 도 같은 목적으로 사용할 수 있습니다(경우에 따라서는 그것이 유일한 방법입니다). 이와 관련해서는 이 글을 참조하세요.
이를 컴파일하면(위에 보인 FAST_INPUT_REGISTER ON QSF 할당과 함께) 타이밍 리포트에 다음과 같은 부분이 나타납니다:
+----------------------------------------------------------------------------------+
; Data Arrival Path ;
+---------+---------+----+------+--------+-------------------+---------------------+
; Total ; Incr ; RF ; Type ; Fanout ; Location ; Element ;
+---------+---------+----+------+--------+-------------------+---------------------+
; 0.000 ; 0.000 ; ; ; ; ; launch edge time ;
; 0.000 ; 0.000 ; ; ; ; ; clock path ;
; 0.000 ; 0.000 ; R ; ; ; ; clock network delay ;
; 8.500 ; 8.500 ; F ; iExt ; 1 ; PIN_F2 ; in ;
; 9.550 ; 1.050 ; ; ; ; ; data path ;
; 8.500 ; 0.000 ; FF ; IC ; 1 ; IOIBUF_X0_Y22_N15 ; in~input|i ;
; 9.308 ; 0.808 ; FF ; CELL ; 1 ; IOIBUF_X0_Y22_N15 ; in~input|o ;
; 9.308 ; 0.000 ; FF ; IC ; 1 ; FF_X0_Y22_N17 ; in_d|d ;
; 9.550 ; 0.242 ; FF ; CELL ; 1 ; FF_X0_Y22_N17 ; in_d ;
+---------+---------+----+------+--------+-------------------+---------------------+
출력 레지스터의 경우와 달리 목록에는 "DDIOINCELL" 유형의 플립플롭이 없고, 대신 일반 플립플롭처럼 보이는 것이 있습니다. 하지만 이 플립플롭으로 연결되는 배선의 지연이 0이라는 점에 주목하세요. 이는 플립플롭과 입력 버퍼가 하나로 융합되어 있다는 분명한 증거입니다.
이 입력에 대한 데이터시트 보고서는 다음과 같습니다:
+---------------------------------------------------------------------------------------------------+ ; Setup Times ; +-----------+------------+-------+-------+------------+---------------------------------------------+ ; Data Port ; Clock Port ; Rise ; Fall ; Clock Edge ; Clock Reference ; +-----------+------------+-------+-------+------------+---------------------------------------------+ ; in ; main_clk ; 1.282 ; 1.461 ; Rise ; altpll_component|auto_generated|pll1|clk[0] ; +-----------+------------+-------+-------+------------+---------------------------------------------+ +-----------------------------------------------------------------------------------------------------+ ; Hold Times ; +-----------+------------+--------+--------+------------+---------------------------------------------+ ; Data Port ; Clock Port ; Rise ; Fall ; Clock Edge ; Clock Reference ; +-----------+------------+--------+--------+------------+---------------------------------------------+ ; in ; main_clk ; -0.683 ; -0.862 ; Rise ; altpll_component|auto_generated|pll1|clk[0] ; +-----------+------------+--------+--------+------------+---------------------------------------------+
요구된 대로, FPGA 가 필요로 하는 셋업 시간(setup time)은 제약 조건에 설정된 1.5 ns 한도보다 낮습니다.
이제 입력 셋업 지연 제약을 2 ns 느슨하게 풀고, 다른 모든 것은 그대로 둔 채 컴파일을 다시 실행해 보겠습니다:
set_input_delay -clock main_clk -max 6.5 [get_ports in*]
set_input_delay -clock main_clk -min 0 [get_ports in*]
타이밍 리포트의 해당 부분은 이제 다음과 같습니다:
+----------------------------------------------------------------------------------+
; Data Arrival Path ;
+---------+---------+----+------+--------+-------------------+---------------------+
; Total ; Incr ; RF ; Type ; Fanout ; Location ; Element ;
+---------+---------+----+------+--------+-------------------+---------------------+
; 0.000 ; 0.000 ; ; ; ; ; launch edge time ;
; 0.000 ; 0.000 ; ; ; ; ; clock path ;
; 0.000 ; 0.000 ; R ; ; ; ; clock network delay ;
; 6.500 ; 6.500 ; F ; iExt ; 1 ; PIN_F2 ; in ;
; 8.612 ; 2.112 ; ; ; ; ; data path ;
; 6.500 ; 0.000 ; FF ; IC ; 1 ; IOIBUF_X0_Y22_N15 ; in~input|i ;
; 7.308 ; 0.808 ; FF ; CELL ; 1 ; IOIBUF_X0_Y22_N15 ; in~input|o ;
; 8.370 ; 1.062 ; FF ; IC ; 1 ; FF_X0_Y22_N17 ; in_d|d ;
; 8.612 ; 0.242 ; FF ; CELL ; 1 ; FF_X0_Y22_N17 ; in_d ;
+---------+---------+----+------+--------+-------------------+---------------------+
어? 배선 지연이 갑자기 1.062 ns 로 늘어났습니다?! 레지스터의 배치 위치는 바뀌지 않았으므로 in_d 가 I/O 레지스터라는 점에는 의심의 여지가 없습니다. 그렇다면 이 지연은 어디서 생긴 것일까요?
이에 답하려면 설계를 더 자세히 들여다봐야 합니다. 전체 컴파일을 마친 다음 Tools > Netlist Viewers > Technology Map Viewer (Post-Fitting)를 선택하면 아래와 같은 다이어그램이 나타납니다(아래는 일부만 표시했으며, 클릭하면 확대됩니다):
in_d 레지스터를 오른쪽 클릭하고 Locate Node > Locate in Resource Property Editor 를 선택하면 다음 화면이 나타납니다(클릭하면 확대됩니다):
이 그림의 오른쪽(위에는 표시되지 않음)에는 "Input Pin to Input Register Delay" 속성이 2 로 설정되어 있습니다. 이것이 지연의 원인입니다. 제약 조건을 느슨하게 하기 전에는 이 값이 0 이었습니다. 여기서 얻는 교훈은 분명합니다.
셋업 제약 조건을 기술적으로 가능한 최선의 값으로 설정하지 않으면, Quartus 는 그 여유를 이용해 지연을 추가할 수 있습니다.
하지만 Quartus, 도대체 왜?
그러면 왜 Quartus 가 입력 패드와 레지스터 사이에 이 지연을 집어넣는지 궁금할 것입니다. 목적이 가능한 한 빨리 샘플링(sampling)하는 것이 아니었나요? 이 질문에 답하기 위해 갱신된 데이터시트 보고서를 살펴보겠습니다:
---------------------+ ; Data Port ; Clock Port ; Rise ; Fall ; Clock Edge ; Clock Reference ; +-----------+------------+-------+-------+------------+---------------------------------------------+ ; in ; main_clk ; 2.205 ; 2.523 ; Rise ; altpll_component|auto_generated|pll1|clk[0] ; +-----------+------------+-------+-------+------------+---------------------------------------------+ +-----------------------------------------------------------------------------------------------------+ ; Hold Times ; +-----------+------------+--------+--------+------------+---------------------------------------------+ ; Data Port ; Clock Port ; Rise ; Fall ; Clock Edge ; Clock Reference ; +-----------+------------+--------+--------+------------+---------------------------------------------+ ; in ; main_clk ; -1.570 ; -1.882 ; Rise ; altpll_component|auto_generated|pll1|clk[0] ; +-----------+------------+--------+--------+------------+---------------------------------------------+
입력 지연 제약에서 2 ns 를 줄였던 것을 기억하세요. 따라서 허용되는 최대 셋업 시간(setup time)은 1.5 ns 에서 3.5 ns 로 늘어났습니다. 이 요건이 약 1 ns 의 슬랙(slack)을 두고 충족된다는 것을 쉽게 알 수 있습니다.
Quartus 는 대략 이렇게 생각한 셈입니다. "셋업 요건은 2 ns 나 여유를 두고 쉽게 맞출 수 있겠군. 셋업 시간에 1 ns 를 더 주고, 홀드 시간 요건(0 ns)에도 1 ns 를 더 주자." 실제로 이 지연으로 1.062 ns 를 추가하자 홀드 시간이 -0.683 ns 에서 -1.570 ns 로 개선되었습니다(차이가 정확하지 않은 이유에 대해서는 따지지 말아 주세요).
결론적으로, Quartus 는 셋업과 홀드 양쪽의 마진을 넓혀서 입력이 지터(jitter)에 더 강건해지도록 만들었습니다. 이는 상당히 합리적인 동작이기는 하지만, 사용자가 원하거나 기대하는 결과는 아닌 경우가 많습니다.
결론: 입력에서 레지스터까지의 지연을 정말 최소로 만들고 싶다면, 일부러 제약 조건을 위반하도록 설정하고 컴파일한 다음, 위반이 해결될 만큼만 제약을 느슨하게 풀어 보세요. 그러면 Quartus 가 더 나은 홀드 시간을 위해 입력 지연을 추가하면서 타이밍을 "개선"하려는 시도를 하지 않게 됩니다.
DDR 프리미티브 사용하기
인텔 FPGA 는 I/O 셀 내부 또는 그 근처에, 출력을 만들거나 입력을 두 배의 클록 속도로 샘플링하는 전용 논리를 갖추고 있습니다. 이 주제는 관련 사용자 가이드인 ug_altddio.pdf에 자세히 나와 있습니다. DDR 프리미티브(primitive)를 인스턴스화(instantiation)하거나 ALTDDIO_BIDIR 메가펑션(megafunction)을 사용하는 것은 도구가 레지스터를 I/O 셀에 배치하도록 강제하는 매력적인 방법처럼 보입니다. 하지만 반드시 좋은 생각인 것은 아닙니다.
예를 들어, 다음과 같은 인스턴스화가 있다고 합시다:
altddio_bidir ioddr ( .padio(pin), .aclr (1'b0), .datain_h(datain_h), .datain_l(datain_l), .inclock(clk), .oe(oe), .outclock(clk), .dataout_h(dataout_h), .dataout_l(dataout_l), .oe_out (), .aset (1'b0), .combout(), .dqsundelayedout(), .inclocken(1'b1), .outclocken(1'b1), .sclr(1'b0), .sset(1'b0)); defparam ioddr.extend_oe_disable = "OFF", ioddr.implement_input_in_lcell = "OFF", ioddr.intended_device_family = "Cyclone IV E", ioddr.invert_output = "OFF", ioddr.lpm_hint = "UNUSED", ioddr.lpm_type = "altddio_bidir", ioddr.oe_reg = "REGISTERED", ioddr.power_up_high = "OFF", ioddr.width = 1;
이 코드는 실제로 양방향 DDR 인터페이스를 구현하는 논리를 만들어 냅니다. 하지만 타이밍 측면에서는, 적어도 Cyclone IV 에서는 부분적으로만 성공합니다. 클록-출력(clock-to-output) 타이밍은 I/O 셀에 패킹된 일반 출력 레지스터와 완전히 같지만, 입력 경로(path)의 지연은 위의 인스턴스화를 사용할 때 오히려 더 나쁩니다. 다른 인텔 FPGA 계열에서는 결과가 다를 수 있습니다.
DDR 프리미티브(primitive)로 일반 SDR 레지스터처럼 동작하게 하려면 datain_h 포트와 datain_l 포트를 같은 배선에 연결해야 합니다. 그래야 클록의 하강 엣지에서도 값이 바뀌지 않습니다. 마찬가지로 dataout_l 포트의 값은 무시해야 합니다. 하강 엣지에서 샘플링되기 때문입니다. 또한 출력 인에이블 포트(oe)는 SDR 입력이라는 점도 유의하세요. 제가 이해한 범위에서는 인텔 FPGA 로 DDR 속도로 high-Z 를 켜고 끄는 것은 불가능합니다. 적어도 제공되는 로직 프리미티브로는 불가능합니다.
그렇다면 왜 출력 레지스터에서는 잘 동작하고 입력에서는 그렇지 않은지 살펴보겠습니다. 힌트는 위의 타이밍 리포트에 있습니다. 일반 I/O 셀 레지스터에서도 레지스터로 DDIOOUTCELL_Xn_Ym_Nk 컴포넌트가 사용됩니다. 즉, 단일 속도 출력에서도 DDR 출력 레지스터가 사용되며, 다만 한 클록 엣지만 사용할 뿐입니다. 입력 경로(path)의 경우, 위의 타이밍 리포트는 로직 패브릭 레지스터(FF_Xn_Ym_Nk)가 사용됨을 보여 줍니다. 여기가 핵심입니다. DDR 입력 로직도 역시 로직 패브릭에 구현됩니다. 설상가상으로, DDR 을 사용하는 경우에는 I/O 셀과 플립플롭 사이에 조합 논리(combinational logic) 블록이 끼어들게 됩니다. 솔직히 그 이유를 이해할 수 없습니다. 각각의 조합 논리 블록은 단일 입력에서 단일 출력으로 가는 단순한 통과(pass-through)일 뿐인데 말이죠.
이러한 관찰은 타이밍 리포트와 Quartus 의 Post-Fit Technology Map Viewer 가 보여 주는 도면을 통해서도 뒷받침됩니다. 특히, 그 쓸데없는 조합 논리 블록들은 이런 정보 소스에서 분명하게 드러납니다.
이 문제는 FPGA 계열마다 다를 가능성이 큽니다. Cyclone IV 의 경우에는 출력에만 DDR 프리미티브를 사용하는 것이 합리적입니다.
더 중요한 점은, 출력 레지스터가 필요할 때 DDR 프리미티브의 출력이 사용된다는 사실 덕분에, 다른 출력들과 정렬된 출력 클록을 만들 수 있다는 것입니다. 이를 위해 DDR 출력 프리미티브의 datain_h 포트와 datain_l 포트에 각각 상수 '1'과 '0'을 공급하면 됩니다. 다른 출력들은 출력 레지스터 패킹을 사용하도록 요구하세요. 그러면 다른 출력들의 토글(toggle)은 DDR 출력에서 나오는 클록의 상승 엣지와 정렬됩니다.
음, 거의 정렬됩니다. 출력 클록의 타이밍 분석은 좀 다릅니다. 클록이 두 출력 레지스터 중 어떤 것이 출력을 구동할지 선택하는 먹스(mux)를 토글하기 때문입니다(자세한 내용은 좌우로 스크롤하세요):
+------------------------------------------------------------------------------------------------------------------------------------+
; Data Arrival Path ;
+---------+---------+----+------+--------+-------------------------+-----------------------------------------------------------------+
; Total ; Incr ; RF ; Type ; Fanout ; Location ; Element ;
+---------+---------+----+------+--------+-------------------------+-----------------------------------------------------------------+
; 0.000 ; 0.000 ; ; ; ; ; launch edge time ;
; 0.000 ; 0.000 ; ; ; ; ; clock path ;
; 0.000 ; 0.000 ; R ; ; ; ; clock network delay ;
; 0.000 ; 0.000 ; R ; ; 1 ; PIN_B12 ; osc_clock ;
; 5.610 ; 5.610 ; ; ; ; ; data path ;
; 0.000 ; 0.000 ; RR ; IC ; 1 ; IOIBUF_X19_Y29_N8 ; osc_clock~input|i ;
; 0.667 ; 0.667 ; RR ; CELL ; 2 ; IOIBUF_X19_Y29_N8 ; osc_clock~input|o ;
; 0.853 ; 0.186 ; RR ; IC ; 1 ; CLKCTRL_G12 ; osc_clock~inputclkctrl|inclk[0] ;
; 0.853 ; 0.000 ; RR ; CELL ; 165 ; CLKCTRL_G12 ; osc_clock~inputclkctrl|outclk ;
; 1.971 ; 1.118 ; RR ; IC ; 1 ; DDIOOUTCELL_X16_Y29_N11 ; sram_controller_ins|ddr_clk|auto_generated|ddio_outa[0]|muxsel ;
; 3.137 ; 1.166 ; RR ; CELL ; 1 ; DDIOOUTCELL_X16_Y29_N11 ; sram_controller_ins|ddr_clk|auto_generated|ddio_outa[0]|dataout ;
; 3.137 ; 0.000 ; RR ; IC ; 1 ; IOOBUF_X16_Y29_N9 ; sram_clk~output|i ;
; 5.610 ; 2.473 ; RR ; CELL ; 1 ; IOOBUF_X16_Y29_N9 ; sram_clk~output|o ;
; 5.610 ; 0.000 ; RR ; CELL ; 0 ; PIN_E10 ; sram_clk ;
+---------+---------+----+------+--------+-------------------------+-----------------------------------------------------------------;
이 분석은 레지스터에서 핀까지가 아니라 클록에서 핀까지의 경로라는 점에 유의하세요. 그럼에도 set_output_delay 제약 조건에는 이 경로(path)가 포함됩니다. 하지만 레지스터에서 포트로의 set_max_delay 제약 조건을 사용하는 경우에는 이 경로가 포함되지 않으므로 별도로 처리해야 합니다. 즉, set_max_delay 를 사용한다면 다음과 같은 형태가 되어야 합니다:
set_max_delay -from [get_clocks main_clk] -to [get_ports sram_clk] 3.8
이제 동일한 전압 표준 등을 사용하는 다른 핀을 하나 비교해 보겠습니다. 차이점은 레지스터가 구동한다는 점뿐입니다:
+----------------------------------------------------------------------------------------------------------------------+ ; Data Arrival Path ; +---------+---------+----+------+--------+-------------------------+---------------------------------------------------+ ; Total ; Incr ; RF ; Type ; Fanout ; Location ; Element ; +---------+---------+----+------+--------+-------------------------+---------------------------------------------------+ ; 0.000 ; 0.000 ; ; ; ; ; launch edge time ; ; 2.507 ; 2.507 ; ; ; ; ; clock path ; ; 0.000 ; 0.000 ; ; ; ; ; source latency ; ; 0.000 ; 0.000 ; ; ; 1 ; PIN_B12 ; osc_clock ; ; 0.000 ; 0.000 ; RR ; IC ; 1 ; IOIBUF_X19_Y29_N8 ; osc_clock~input|i ; ; 0.667 ; 0.667 ; RR ; CELL ; 2 ; IOIBUF_X19_Y29_N8 ; osc_clock~input|o ; ; 0.853 ; 0.186 ; RR ; IC ; 1 ; CLKCTRL_G12 ; osc_clock~inputclkctrl|inclk[0] ; ; 0.853 ; 0.000 ; RR ; CELL ; 165 ; CLKCTRL_G12 ; osc_clock~inputclkctrl|outclk ; ; 1.970 ; 1.117 ; RR ; IC ; 1 ; DDIOOUTCELL_X37_Y29_N11 ; sram_controller_ins|dq_wr_data[6]|clk ; ; 2.507 ; 0.537 ; RR ; CELL ; 1 ; DDIOOUTCELL_X37_Y29_N11 ; sram_controller:sram_controller_ins|dq_wr_data[6] ; ; 5.645 ; 3.138 ; ; ; ; ; data path ; ; 2.717 ; 0.210 ; ; uTco ; 1 ; DDIOOUTCELL_X37_Y29_N11 ; sram_controller:sram_controller_ins|dq_wr_data[6] ; ; 3.182 ; 0.465 ; RR ; CELL ; 1 ; DDIOOUTCELL_X37_Y29_N11 ; sram_controller_ins|dq_wr_data[6]|q ; ; 3.182 ; 0.000 ; RR ; IC ; 1 ; IOOBUF_X37_Y29_N9 ; sram_dq[6]~output|i ; ; 5.645 ; 2.463 ; RR ; CELL ; 1 ; IOOBUF_X37_Y29_N9 ; sram_dq[6]~output|o ; ; 5.645 ; 0.000 ; RR ; CELL ; 1 ; PIN_G14 ; sram_dq[6] ; +---------+---------+----+------+--------+-------------------------+---------------------------------------------------;
전체 클록-출력 시간은 후자의 경로(path)가 겉보기에는 완전히 다름에도 불구하고 35 ps 이상 차이가 나지 않습니다. 이것은 우연이 아닙니다. FPGA 는 분명히 이러한 유사성이 나타나도록 설계되었습니다. 좀 더 구체적으로 말하면, 위 타이밍 분석은 100°C, 1200 mV 에서의 slow 모델입니다. 하지만 이 작은 차이는 다른 분석 조건에서도 일관되게 나타납니다.

