이 페이지는 timing에 대한 일련의 페이지 에 속합니다. 이전 페이지에서는 다음과 같은 몇 가지 기본 주제에 대해 설명했습니다 . timing 계산 및 clock period timing constraint에 대한 이론. 몇 가지 timing reports 도 보여주고 설명했습니다. 이제 이 지식의 중요한 목적 중 하나인 timing 문제 해결에 대해 이야기할 시간입니다.
소개
FPGA 도구의 가장 큰 어려움은 timing constraints의 요구 사항을 달성하는 것입니다. 이것은 잘하면 성공하지만 때때로 실패합니다. 그리고 그것이 실패했을 때, 왜 그것이 실패했는지 알아내고 그것을 고칠 의무를 지는 것은 우리 인간들입니다. 이 작업의 이름은 다음과 같습니다. 우리는 그것을 Timing Closure 라고 부릅니다. 그리고 그것은 쉬운 일이 아닙니다.
timing closure가 어려운 이유는 무엇입니까? 문제는 도구에 FPGA의 리소스를 최적의 방식으로 사용하려고 시도하는 place and route 알고리즘이 있다는 것입니다. 일반적으로 이 알고리즘은 큰 노력을 기울이지 않고 FPGA 에 logic elements를 배치하는 것으로 시작합니다. 그런 다음 반복 프로세스가 시작됩니다. 도구는 모든 paths를 살펴보고 timing constraints를 충족하지 못하는 paths를 찾습니다. 이러한 실패를 바로잡기 위해 이러한 paths에 대한 시정 조치가 취해집니다. 가장 주목할 만한 것은 logic elements가 FPGA에서 다른 위치로 이동하고 routing이 조정된다는 것입니다. 보다 진보된 시정 조치의 경우 각 FPGA tool 마다 고유한 방법이 있습니다.
모든 paths가 timing constraints를 만나면 implementation은 완료된 것으로 간주됩니다. 하지만 implementation은 도구가 이 목표에 도달하지 못해 결국 시도를 포기했기 때문에 종료될 수도 있습니다. 이 상황에서 우리는 노력이 중단되었을 때 도구가 달성한 것을 얻습니다. 이 결과는 반드시 최적은 아닙니다. 개선할 수 있는 implementation 에 paths가 있을 수 있지만 도구는 다른 것을 수정하느라 바빴습니다. 그리고 그것이 실패했을 때 도구는 다른 것을 고치려고 시도하지 않고 포기했습니다. 도구가 말하는 것과 같습니다. " implementation이 어쨌든 실패할 경우 수리하는 데 시간을 낭비할 필요가 없습니다."
FPGA designers 로서 우리의 임무는 이 차선의 결과를 살펴보고 timing constraints 의 목표가 달성되지 않은 이유를 찾는 것입니다.
알고리즘은 시간이 지남에 따라 더 좋아집니다. timing constraints를 달성하지 못하는 일반적인 이유가 있는 경우 소프트웨어의 다음 버전에는 해당 상황에 대한 특정 솔루션이 있습니다. 따라서 도구가 실패하는 경우 일반적으로 타당한 이유가 있습니다.
그래서 우리는 도구가 무엇을 달성했는지 살펴보고 스스로에게 질문합니다. 도구가 실패한 이유는 무엇입니까? 불가능한 것을 요청했습니까? 더 중요한 것은 불필요한 것을 요청했습니까? 어쩌면 도구의 실패를 초래한 장애물이 우리에게 필요하지도 않은 것일 수도 있습니다. 아니면 최적화 알고리즘이 제대로 작동하지 않았습니까? 때때로 그것은 단지 불운의 문제입니다. logic elements 의 초기 배치가 너무 나빠서 성능을 개선하려는 후속 시도는 실패할 수 있습니다.
문제가 무엇이든 실패의 원인을 찾는 것은 범죄 현장을 수사하는 형사와 비슷합니다. 사실은 우리 앞에 있지만 그 이유는 종종 숨겨져 있습니다. 이러한 사실의 대부분은 timing reports에서 찾을 수 있지만 단서는 쉽게 사라지지 않습니다. 항상 물어봐야 하는 질문은 timing report에서 무엇이 잘못되었거나 비정상적이거나 비정상인지입니다. 범인을 찾으려는 형사처럼 목표는 문제로 이어지는 세부 사항을 찾는 것입니다.
그러나 비정상적인 것을 찾으려면 정상적인 것이 무엇인지 알아야 합니다. 예를 들어 특정 fan-out가 있는 net 에 대한 일반 delay은 무엇입니까? 특정 logic function을 구현하기 위해 몇 개의 logic levels가 정상입니까? 이러한 종류의 질문에 대한 답은 FPGA 마다 다릅니다. 따라서 모든 것이 정상인 경우에도 timing reports를 읽고 이해하여 경험을 쌓는 것이 필요합니다. timing report가 문제를 나타내는 위치를 찾으려면 모든 것이 정상일 때 timing report가 어떻게 보이는지 알 수 있어야 합니다. 이전 페이지에서 제가 왜 세세한 부분까지 들어갔는지 궁금하실 텐데요, 그게 그 이유 중 하나입니다.
Critical Path
도구가 timing constraints를 달성하지 못하는 경우 slack이 음수인 path가 하나 이상 있음을 의미합니다. slack이 가장 마이너스인 path를 Critical Path라고 합니다. 이 이름은 timing closure에 대한 일반적인 전략을 반영합니다. Critical Path 에 집중하는 것이 종종 timing 문제를 해결하는 방법입니다. 그러나 나는 이 전략이 또한 시간 낭비일 수 있다는 것을 아래에서 증명할 것이다.
timing constraints가 달성되면 Critical Path는 최소한의 slack이 있는 path 입니다. 이 path는 종종 흥미롭지 않은데, 도구가 긍정적인 slack로 paths를 개선하려고 시도하지 않기 때문입니다. 따라서 최악의 path가 긍정적인 slack을 가지고 있다면 이 path가 최악의 것으로 판명된 것은 우연일 수 있습니다.
하지만 slack이 양수이고 거의 0(예를 들어 0.2 ns보다 작음)인 경우, 이 path가 timing constraints에 도달하기 어렵다는 것을 나타낼 수 있습니다. 이런 종류의 Critical paths는 이러한 paths가 앞으로 문제를 일으킬 수 있다는 경고로 볼 수 있습니다(특히 FPGA가 더 많은 logic로 채워지면 도구의 노력이 다른 paths로 전환됩니다).
timing report는 일반적으로 각 clock에 대해 제한된 수의 critical paths를 포함합니다. 대부분의 FPGA 도구의 기본값은 slack이 양수(즉, timing constraints가 달성된 경우)인 경우에도 몇 개의 critical paths를 표시하는 것입니다. 이것이 권장되는 설정입니다.
critical path의 예
Critical Path분석의 예부터 시작하겠습니다. 이 예에서 Verilog 코드는 다음과 같습니다.
reg [24:0] calc, result;
reg [11:0] x, y, z;
always @(posedge clk)
begin
calc <= x * y + z;
result <= calc;
end
이 예에서 @clk의 주파수는 250 MHz가 고 PLL은 이 clock을 생성하는 데 사용되지 않습니다. 또한 @x, @y 및 @z가 @clk와 동기화된 registers 라고 가정합니다. 이러한 registers 에 값을 할당하는 Verilog 코드는 관련이 없기 때문에 표시되지 않습니다.
Vivado에서 이 코드를 시도했을 때 timing constraints가 달성되지 않았습니다. timing report 에서 이것은 Critical Path였습니다.
Slack (VIOLATED) : -0.239ns (required time - arrival time) Source: x_reg[1]__0_replica_2/C (rising edge-triggered cell FDRE clocked by clk {rise@0.000ns fall@2.000ns period=4.000ns}) Destination: calc_reg[23]/D (rising edge-triggered cell FDRE clocked by clk {rise@0.000ns fall@2.000ns period=4.000ns}) Path Group: clk Path Type: Setup (Max at Slow Process Corner) Requirement: 4.000ns (clk rise@4.000ns - clk rise@0.000ns) Data Path Delay: 4.180ns (logic 1.642ns (39.282%) route 2.538ns (60.718%)) Logic Levels: 7 (CARRY8=4 LUT3=1 LUT4=1 LUT6=1) Clock Path Skew: -0.087ns (DCD - SCD + CPR) Destination Clock Delay (DCD): 3.176ns = ( 7.176 - 4.000 ) Source Clock Delay (SCD): 3.864ns Clock Pessimism Removal (CPR): 0.601ns Clock Uncertainty: 0.035ns ((TSJ^2 + TIJ^2)^1/2 + DJ) / 2 + PE Total System Jitter (TSJ): 0.071ns Total Input Jitter (TIJ): 0.000ns Discrete Jitter (DJ): 0.000ns Phase Error (PE): 0.000ns Clock Net Delay (Source): 2.032ns (routing 0.396ns, distribution 1.636ns) Clock Net Delay (Destination): 1.748ns (routing 0.365ns, distribution 1.383ns) Location Delay type Incr(ns) Path(ns) Netlist Resource(s) ------------------------------------------------------------------- ------------------- (clock clk rise edge) 0.000 0.000 r AG12 0.000 0.000 r clk (IN) net (fo=0) 0.000 0.000 clk_IBUF_inst/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.738 0.738 r clk_IBUF_inst/INBUF_INST/O net (fo=1, routed) 0.105 0.843 clk_IBUF_inst/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.049 0.892 r clk_IBUF_inst/IBUFCTRL_INST/O net (fo=1, routed) 0.839 1.731 clk_IBUF BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.101 1.832 r clk_IBUF_BUFG_inst/O X2Y0 (CLOCK_ROOT) net (fo=106, routed) 2.032 3.864 clk_IBUF_BUFG SLICE_X54Y54 FDRE r x_reg[1]__0_replica_2/C ------------------------------------------------------------------- ------------------- SLICE_X54Y54 FDRE (Prop_HFF2_SLICEL_C_Q) 0.137 4.001 r x_reg[1]__0_replica_2/Q net (fo=21, routed) 0.371 4.372 x[1]_repN_2 SLICE_X56Y53 LUT6 (Prop_E6LUT_SLICEL_I1_O) 0.219 4.591 r calc[23]_i_101/O net (fo=2, routed) 0.550 5.141 calc[23]_i_101_n_0 SLICE_X54Y57 CARRY8 (Prop_CARRY8_SLICEL_DI[5]_CO[7]) 0.228 5.369 r calc_reg[23]_i_30/CO[7] net (fo=1, routed) 0.030 5.399 calc_reg[23]_i_30_n_0 SLICE_X54Y58 CARRY8 (Prop_CARRY8_SLICEL_CI_O[1]) 0.163 5.562 r calc_reg[23]_i_22/O[1] net (fo=3, routed) 0.351 5.913 calc_reg[23]_i_22_n_14 SLICE_X56Y57 LUT3 (Prop_C6LUT_SLICEL_I1_O) 0.146 6.059 r calc[23]_i_26/O net (fo=3, routed) 0.240 6.299 calc[23]_i_26_n_0 SLICE_X55Y58 LUT4 (Prop_A6LUT_SLICEM_I0_O) 0.089 6.388 r calc[23]_i_7/O net (fo=1, routed) 0.407 6.795 calc[23]_i_7_n_0 SLICE_X53Y57 CARRY8 (Prop_CARRY8_SLICEM_DI[2]_O[4]) 0.308 7.103 r calc_reg[23]_i_2/O[4] net (fo=1, routed) 0.538 7.641 P[20] SLICE_X54Y56 CARRY8 (Prop_CARRY8_SLICEL_S[4]_O[7]) 0.352 7.993 r calc_reg[23]_i_1/O[7] net (fo=1, routed) 0.051 8.044 P0_out[23] SLICE_X54Y56 FDRE r calc_reg[23]/D ------------------------------------------------------------------- ------------------- (clock clk rise edge) 4.000 4.000 r AG12 0.000 4.000 r clk (IN) net (fo=0) 0.000 4.000 clk_IBUF_inst/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.515 4.515 r clk_IBUF_inst/INBUF_INST/O net (fo=1, routed) 0.066 4.581 clk_IBUF_inst/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.034 4.615 r clk_IBUF_inst/IBUFCTRL_INST/O net (fo=1, routed) 0.722 5.337 clk_IBUF BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.091 5.428 r clk_IBUF_BUFG_inst/O X2Y0 (CLOCK_ROOT) net (fo=106, routed) 1.748 7.176 clk_IBUF_BUFG SLICE_X54Y56 FDRE r calc_reg[23]/C clock pessimism 0.601 7.777 clock uncertainty -0.035 7.741 SLICE_X54Y56 FDRE (Setup_HFF_SLICEL_C_D) 0.063 7.804 calc_reg[23] ------------------------------------------------------------------- required time 7.804 arrival time -8.044 ------------------------------------------------------------------- slack -0.239
이 path 의 slack은 –0.239 ns였으므로 timing constraints를 충족하는 데 약간 실패했습니다. 가장 먼저 살펴봐야 할 것은 이 path의 시작과 끝입니다. 보고서의 header에서 "Source" 및 "Destination"를 보고 x_reg 및 calc_reg을 찾습니다. 따라서 문제의 원인은 분명히 이 부분입니다.
calc <= x * y + z;
이것은 Verilog 코드에서 유일하게 의미 있는 작업이기 때문에 놀라운 일이 아닙니다. 실제 시나리오에서는 logic 의 어떤 부분이 문제를 일으켰는지 명확하지 않습니다.
또한 timing report 에서 많은 수의 logic levels가 있음이 분명합니다. 7. combinatorial path가 너무 깁니다. 즉, @clk의 두 clock edges 사이에 해야 할 일이 너무 많습니다.
하지만 실패의 실제 이유는 무엇일까요? 아마도 routing이 delay의 61%를 담당하고 있다는 사실일까요? routing delay은 일반적으로 전체 delay의 40% 라는 경험칙이 있다는 것을 기억하세요. 그렇다면 FPGA 도구를 사용하여 더 나은 성능을 내는 것이 어떨까요? 하지만 도구는 일반적으로 path의 timing constraints를 달성하려는 시도를 포기하기 전에 열심히 작동하기 때문에 성공적인 솔루션이 될 가능성은 낮습니다.
@x 와 @calc 사이에서 logic function을 변경하려고 시도하는 것도 마찬가지로 소용이 없습니다. 곱셈은 필수적이므로 대신 더 간단한 것을 넣을 방법이 없습니다.
나는 다음 페이지 에서 이와 같은 문제를 해결하기 위한 다른 가능한 접근법을 제시할 것입니다. 그러나 기술 목록을 살펴보는 것은 이 경우에 도움이 되지 않습니다. 이 간단한 예는 때때로 우리가 형사처럼 생각해야 한다는 것을 보여줍니다.
뇌를 대신할 것은 없다
timing report를 읽을 때 묻는 첫 번째 질문은 무엇이 비정상적인가입니다. 이 예에서 답은 combinatorial path가 slices로만 구성되어 있다는 것입니다. 사실상 모든 FPGAs 에는 곱셈이 요청될 때 사용되는 지정된 산술 단위(DSPs, ALUs, 이름은 다양함)가 있습니다. 실제로 multiply and add는 이렇게 지정된 logic에서 가장 일반적인 기능입니다. 따라서 대부분의 경우 가장 간단한 해결책은 도구가 지정된 산술 단위를 사용하도록 하는 것입니다. 이 솔루션의 timing report는 이 페이지 하단에 나와 있습니다.
그러나 우리가 물어야 할 진정한 질문은 slices가 지정된 산술 단위 대신 사용된 이유입니다. 가장 일반적인 이유는 FPGA의 사용 가능한 모든 산술 단위가 이미 design의 다른 부분에서 사용되고 있기 때문입니다. 이 경우 필요한 변경 사항은 critical path 와 전혀 관련이 없을 수 있습니다. design에서 logic 의 일부를 제거하여 몇 개의 산술 단위를 확보해야 할 수도 있습니다. 또 다른 가능성은 이러한 산술 단위를 design의 여러 부분 간에 다르게 할당하도록 도구에 지시하는 것입니다.
이 예에서는 산술 단위 대신 slices를 사용했습니다. 나는 의도적으로 산술 단위의 사용을 껐습니다( Vivado의 synthesizer parameters중 하나: 저는 max_dsp를 0으로 설정했습니다). 하지만 그렇다고 해서 이 예가 인위적인 것은 아닙니다. 때때로 잘못된 parameters가 FPGA tools와 함께 사용되어 정확히 이런 종류의 상황이 발생합니다. 사실, 산술 단위를 의도적으로 사용하지 않는 것이 옳을 때도 있는데, design의 다른 곳에서 더 필요하기 때문입니다.
따라서 쉬운 해결책은 지정된 산술 단위를 사용하는 것이었습니다. 하지만 slices를 사용해야 한다면 어떻게 될까요? 다시 한 번, 솔루션은 간접적입니다. 문제가 된 부분은 다음과 같습니다.
calc <= x * y + z;
그러나 이것은 바로 뒤에 나옵니다.
result <= calc;
@calc이 이 행에서만 사용되고 다른 곳에서는 사용되지 않는 경우 계산을 두 단계로 나눌 수 있습니다. 이 기술은 종종 pipelining라고 합니다. 따라서 Verilog 코드는 다음과 같이 변경됩니다.
reg [24:0] calc, result;
reg [11:0] x, y, z, z_d;
always @(posedge clk)
begin
z_d <= z;
calc <= x * y;
result <= calc + z_d;
end
이 솔루션에서 @calc은 곱셈 결과만 제공됩니다. @z 의 값은 다음 단계에서만 @calc 에 추가됩니다. 보다 정확하게는 플러스 연산은 @calc 와 @z_d사이에 있습니다. 이 연산은 한 clock cycle 이후에 발생하기 때문입니다. 따라서 @result 의 값은 이전과 동일합니다.
@result는 원래 Verilog 코드에서 @calc 의 지연된 복사본이었기 때문에 이 방법으로 문제를 해결하는 것은 쉬웠습니다. 실생활에서 우리는 보통 이렇게 운이 좋지 않습니다.
critical path 에는 @calc 와 @x만 포함되어 있습니다. @z는 path에서도 언급되지 않았습니다. 따라서 이 조작의 목적은 산술 연산의 부담을 줄이는 것입니다. 또는 더 정확하게는 logic levels의 수를 줄이기 위해서입니다.
critical path는 최적화 알고리즘 실행 후 최악의 path 임을 상기하십시오. 이 알고리즘은 문제의 원인을 묻지 않습니다. 오히려 slack이 마이너스인 paths를 개선하려고 합니다. 따라서 문제 해결을 위해서는 @z의 조작이 필요하지만 @z 와 관련된 path는 critical path가 아니었습니다. 우연의 일치일 뿐인데 이런 일이 많이 일어납니다.
이 솔루션의 critical path가 있는 timing report 도 이 페이지 하단에 나와 있습니다. logic levels 의 수가 7 에서 6로 줄어든 것을 보여줍니다. 결과적으로 data path delay은 0.715 ns만큼 줄어들었고, 이는 timing constraints를 충족하기에 충분했습니다.
이 예에서 배울 수 있는 교훈은 critical path가 항상 문제의 직접적인 원인은 아니라는 것입니다. 이 path가 실패한 이유를 묻는 것은 여전히 옳지만 해결책은 다른 곳에 있을 수 있습니다. 각 FPGA 도구에는 문제의 근본 원인을 찾는 데 도움이 되는 정보를 제공하는 고유한 유틸리티가 있습니다. 이러한 유틸리티를 탐색하고 설명서를 읽어보는 것은 시간을 투자할 가치가 있습니다.
나중에 문제를 해결하기보다 일찍 문제를 피하십시오.
logic design이 처음부터 올바르게 수행되면 timing closure 에 대한 많은 작업을 피할 수 있습니다. 이를 위해서는 logic design이 소프트웨어가 아니라는 사실을 지속적으로 인식해야 합니다. Verilog 코드의 목적은 simulation동안 올바른 결과를 생성하는 것이 아닙니다. 정말로 중요한 것은 Verilog 코드에서 synthesizer가 생성한 출력입니다.
좋은 logic design은 logic이 목적을 가장 잘 달성하는 방법을 생각하는 것에서 시작됩니다. 여기에는 timing와 관련된 잠재적 장애물 식별이 포함됩니다.
경험이 적은 FPGA designers는 종종 시행 착오를 통해 Verilog 코드를 개발합니다. simulation은 logic이 예상대로 작동하는지 확인하는 데 사용되며 simulation 의 출력이 정확할 때까지 점진적으로 수정됩니다. 결과는 하드웨어에서 사용할 수 없는 logic 일 수 있습니다. timing constraints를 구현하려면 Verilog 코드를 완전히 다시 작성해야 합니다.
Verilog 코드가 생성하는 combinatorial paths 에 대해 미리 생각하는 것이 중요합니다. 아이디어는 각 register를 보고 combinatorial path를 끝까지 따라가는 것입니다. combinatorial path는 항상 register 에서 시작하여 register에서 끝납니다.
이 예를 살펴보겠습니다.
reg [15:0] a, b;
wire [16:0] x, y;
reg [33:0] z;
assign x = a + 2;
assign y = b + 3;
always @(posedge clk)
z <= x * y;
@a관련: 이 register가 변경되면 combinatorial path는 첫 번째 단계로 @x 에 도달합니다. 하지만 @x는 register가 아닙니다. @x는 continuous assignment덕분에 업데이트됩니다. 따라서 path는 @z로 계속됩니다. 따라서 logic은 이 combinatorial path에서 두 가지 중요한 작업을 수행합니다. 산술 덧셈과 산술 곱셈. 너무 많은가요? pipelining덕분에 이것을 두 개의 clock cycles로 분할해야 합니까? 이는 clock frequency 와 사용되는 FPGA 에 따라 다릅니다.
또 다른 중요한 요소는 combinatorial paths를 더 짧게 만드는 것이 얼마나 어려운가입니다. 때로는 긴 combinatorial path가 불가피합니다. 그러나 path의 timing을 개선하는 것이 쉬울 때는 design에 훨씬 더 나쁜 paths가 있더라도 그렇게 하십시오. design에 문제가 있는 paths가 몇 개 있다면, 도구는 종종 이러한 paths에 노력을 집중함으로써 timing constraints를 달성할 수 있습니다. 다른 paths의 timing requirements를 쉽게 충족할 수 있을 때 많은 도움이 됩니다.
따라서 timing constraints를 달성하는 design을 얻기 위해 허용되거나 허용되지 않는 것에 대한 규칙이 없습니다. 이 분야에서 올바른 결정을 내리려면 FPGA design 에 대한 경험이 필요합니다. 특정 FPGA 도구에 대한 경험도 중요합니다. 항상 올바른 유일한 규칙은 다음과 같습니다. Verilog 코드의 간단한 변경으로 timing을 개선할 수 있을 때 그렇게 하십시오. 게으르지 말고 처음부터 변경하십시오. 항상 timing을 염두에 두십시오.
빠른 쓰기 logic
이미 언급했듯이 목표는 registers사이에서 짧은 combinatorial paths를 달성하는 것입니다. registers 의 다음 값을 계산하는 logic functions는 단순해야 합니다. 즉, 이러한 logic functions를 구현하려면 소수의 logic levels가 필요합니다.
FPGA designers 로서 우리의 임무는 Verilog 코드를 살펴보고 logic functions가 얼마나 복잡한지 평가하는 것입니다. 이를 위해서는 synthesizer가 Verilog을 logic elements (LUTs 및 기타 logic primitives)로 변환하는 방법에 대한 지식이 필요합니다. 이 지식은 timing reports를 분석하여 부분적으로 얻은 경험을 통해 습득합니다. 설상가상으로 이 변환은 FPGA 마다 다릅니다. 따라서 빠른 logic을 생성하는 Verilog 코드를 작성하는 것은 쉬운 일이 아닙니다.
FPGA 초보자라면 학습을 위해 implementation 의 결과를 살펴보는 데 시간을 할애하는 것이 좋습니다. timing report는 logic design이 간단한 logic elements로 어떻게 분류되는지에 대한 예를 보여줍니다. FPGA 도구는 낮은 수준의 logic elements를 보기 위한 다른 유틸리티도 제공합니다.
또한 도움이 될 수 있는 몇 가지 간단한 규칙이 있습니다.
- Pipelining: registers에 관대하세요. 가능하다면 logic의 작업을 작은 조각으로 나누고 각 단계 후에 register를 삽입하세요. FPGAs 에는 flip-flops가 많이 있습니다(종종 각 LUT옆에 flip-flop이 하나씩 있습니다). 따라서 registers를 이렇게 삽입해도 FPGA의 활용도는 증가하지 않습니다. pipelining을 피해야 하는 유일한 이유는 design을 너무 복잡하게 만들 때입니다.
- if-then-else를 사용하는 경우 많은 "else" 절을 연결하지 마십시오. "case" 문을 대신 사용할 수 있는 경우 일반적으로 더 좋습니다. "else" 절에는 종종 이 절 앞에 있는 모든 항목이 false인지 확인하는 logic function이 필요합니다. 따라서 여러 "else" 절에는 여러 logic levels가 필요할 수 있습니다.
- 불필요한 resets를 피하십시오. 특히 synchronous reset은 logic function에 약간의 복잡성을 추가합니다. 두 가지 유형의 resets는 routing의 난이도를 더합니다. 이들은 많은 logic elements에 도달해야 하는 signals가 기 때문입니다. 이 주제에 대한 별도의 페이지 시리즈가 있습니다.
- 거대한 state machines를 만들지 마십시오. states가 얼마나 많은지에 대한 엄격한 제한은 없습니다. 그러나 states 의 수가 20을 넘어선다면 design을 재구성하는 것을 고려해야 합니다. 또한 synthesizer가 대형 state machines 용 one-hot encoding을 사용하는지 확인하십시오(기본적으로 대부분의 synthesizers가 사용함). 이는 빠른 logic을 생성하는 데 도움이 됩니다.
- 일반적으로 RAM 다음에 추가 register가 더 좋습니다. 암시적으로 생성된 RAM 의 이 예를 살펴보겠습니다.
reg [7:0] array[0:127]; reg [7:0] val; reg [6:0] addr; always @(posedge clk) val <= array[addr];
이 Verilog 코드는 정확하지만 @val은 RAM의 synchronous output 입니다. 그래서 rising clock edge가 있으면 RAM 의 동작이 시작되고, @val은 array 에서 값을 얻어야만 업데이트 된다. 따라서 @val은 clock-to-output delay이 상대적으로 큽니다( flip-flop와 비교). 따라서 @val에서 시작하는 paths 에는 본질적인 단점이 있습니다. register를 추가하면 이 문제를 해결할 수 있습니다.
reg [7:0] array[0:127]; reg [7:0] val_d, mem_out; reg [6:0] addr; always @(posedge clk) begin mem_out <= array[addr]; val_d <= mem_out; end
이것은 기능적으로 동일하지 않습니다. 여기서 @mem_out는 RAM 의 output 입니다. 나중에 하나의 clock 만 이 output을 @val_d로 복사하므로 @val을 정확히 대체할 수는 없습니다. 그러나 @val_d는 clock-to-output delay이 낮은 실제 register입니다. 많은 FPGAs에서 이 추가 register는 block RAMs의 일부이므로 flip-flops를 낭비할 필요가 없습니다. flip-flops낭비에 대해 걱정하지 말라고 언급했습니까?
불행히도 이러한 register를 추가하면 종종 design이 상당히 복잡해집니다. 이 경우 register를 추가하지 않고 combinatorial path를 @val 에서 짧게 유지하는 것이 좋습니다.
두 개의 추가 timing reports
위에서 "당신의 두뇌를 대신할 수 있는 것은 없습니다"라는 섹션에서 두 개의 timing reports를 약속했습니다. 그것들은 길고 완전히 관련이 없기 때문에 언급된 곳이 아니라 여기에 넣었습니다.
이 두 timing reports는 각각 관련 시나리오의 critical path 입니다. 따라서 path는 위에 표시된 path 와 동일한 registers 에서 시작하고 끝나지 않습니다.
첫 번째 timing report는 첫 번째 Verilog 코드 예제와 관련이 있습니다. 위의 timing report 와 달리 도구는 지정된 산술 단위를 사용할 수 있었습니다. 그 결과 timing constraints가 쉽게 달성되었습니다.
이 timing report는 Kintex Ultrascale FPGA용으로 생성되었습니다. 이 FPGAs제품군에서 지정된 산술 단위를 DSP48E2라고 합니다. path는 동일한 DSP48E2 장치에서 시작하고 끝납니다. 따라서 logic delay은 100%입니다.
Slack (MET) : 1.406ns (required time - arrival time) Source: calc_reg/DSP_A_B_DATA_INST/CLK (rising edge-triggered cell DSP_A_B_DATA clocked by clk {rise@0.000ns fall@2.000ns period=4.000ns}) Destination: calc_reg/DSP_OUTPUT_INST/ALU_OUT[10] (rising edge-triggered cell DSP_OUTPUT clocked by clk {rise@0.000ns fall@2.000ns period=4.000ns}) Path Group: clk Path Type: Setup (Max at Slow Process Corner) Requirement: 4.000ns (clk rise@4.000ns - clk rise@0.000ns) Data Path Delay: 2.445ns (logic 2.445ns (100.000%) route 0.000ns (0.000%)) Logic Levels: 4 (DSP_ALU=1 DSP_M_DATA=1 DSP_MULTIPLIER=1 DSP_PREADD_DATA=1) Clock Path Skew: -0.010ns (DCD - SCD + CPR) Destination Clock Delay (DCD): 3.392ns = ( 7.392 - 4.000 ) Source Clock Delay (SCD): 4.096ns Clock Pessimism Removal (CPR): 0.694ns Clock Uncertainty: 0.035ns ((TSJ^2 + TIJ^2)^1/2 + DJ) / 2 + PE Total System Jitter (TSJ): 0.071ns Total Input Jitter (TIJ): 0.000ns Discrete Jitter (DJ): 0.000ns Phase Error (PE): 0.000ns Clock Net Delay (Source): 2.264ns (routing 0.756ns, distribution 1.508ns) Clock Net Delay (Destination): 1.964ns (routing 0.696ns, distribution 1.268ns) Location Delay type Incr(ns) Path(ns) Netlist Resource(s) ------------------------------------------------------------------- ------------------- (clock clk rise edge) 0.000 0.000 r AG12 0.000 0.000 r clk (IN) net (fo=0) 0.000 0.000 clk_IBUF_inst/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.738 0.738 r clk_IBUF_inst/INBUF_INST/O net (fo=1, routed) 0.105 0.843 clk_IBUF_inst/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.049 0.892 r clk_IBUF_inst/IBUFCTRL_INST/O net (fo=1, routed) 0.839 1.731 clk_IBUF BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.101 1.832 r clk_IBUF_BUFG_inst/O X2Y1 (CLOCK_ROOT) net (fo=80, routed) 2.264 4.096 calc_reg/CLK DSP48E2_X11Y34 DSP_A_B_DATA r calc_reg/DSP_A_B_DATA_INST/CLK ------------------------------------------------------------------- ------------------- DSP48E2_X11Y34 DSP_A_B_DATA (Prop_DSP_A_B_DATA_DSP48E2_CLK_A2_DATA[9]) 0.302 4.398 r calc_reg/DSP_A_B_DATA_INST/A2_DATA[9] net (fo=1, routed) 0.000 4.398 calc_reg/DSP_A_B_DATA.A2_DATA<9> DSP48E2_X11Y34 DSP_PREADD_DATA (Prop_DSP_PREADD_DATA_DSP48E2_A2_DATA[9]_A2A1[9]) 0.182 4.580 r calc_reg/DSP_PREADD_DATA_INST/A2A1[9] net (fo=1, routed) 0.000 4.580 calc_reg/DSP_PREADD_DATA.A2A1<9> DSP48E2_X11Y34 DSP_MULTIPLIER (Prop_DSP_MULTIPLIER_DSP48E2_A2A1[9]_U[10]) 0.994 5.574 f calc_reg/DSP_MULTIPLIER_INST/U[10] net (fo=1, routed) 0.000 5.574 calc_reg/DSP_MULTIPLIER.U<10> DSP48E2_X11Y34 DSP_M_DATA (Prop_DSP_M_DATA_DSP48E2_U[10]_U_DATA[10]) 0.164 5.738 r calc_reg/DSP_M_DATA_INST/U_DATA[10] net (fo=1, routed) 0.000 5.738 calc_reg/DSP_M_DATA.U_DATA<10> DSP48E2_X11Y34 DSP_ALU (Prop_DSP_ALU_DSP48E2_U_DATA[10]_ALU_OUT[10]) 0.803 6.541 r calc_reg/DSP_ALU_INST/ALU_OUT[10] net (fo=1, routed) 0.000 6.541 calc_reg/DSP_ALU.ALU_OUT<10> DSP48E2_X11Y34 DSP_OUTPUT r calc_reg/DSP_OUTPUT_INST/ALU_OUT[10] ------------------------------------------------------------------- ------------------- (clock clk rise edge) 4.000 4.000 r AG12 0.000 4.000 r clk (IN) net (fo=0) 0.000 4.000 clk_IBUF_inst/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.515 4.515 r clk_IBUF_inst/INBUF_INST/O net (fo=1, routed) 0.066 4.581 clk_IBUF_inst/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.034 4.615 r clk_IBUF_inst/IBUFCTRL_INST/O net (fo=1, routed) 0.722 5.337 clk_IBUF BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.091 5.428 r clk_IBUF_BUFG_inst/O X2Y1 (CLOCK_ROOT) net (fo=80, routed) 1.964 7.392 calc_reg/CLK DSP48E2_X11Y34 DSP_OUTPUT r calc_reg/DSP_OUTPUT_INST/CLK clock pessimism 0.694 8.086 clock uncertainty -0.035 8.050 DSP48E2_X11Y34 DSP_OUTPUT (Setup_DSP_OUTPUT_DSP48E2_CLK_ALU_OUT[10]) -0.104 7.946 calc_reg/DSP_OUTPUT_INST ------------------------------------------------------------------- required time 7.946 arrival time -6.541 ------------------------------------------------------------------- slack 1.406
두 번째 timing report는 Verilog 코드의 두 번째 예와 관련이 있습니다. 이 예에서는 pipelining덕분에 상황이 개선되었습니다.
Slack (MET) : 0.433ns (required time - arrival time) Source: y_reg[1]__0/C (rising edge-triggered cell FDRE clocked by clk {rise@0.000ns fall@2.000ns period=4.000ns}) Destination: calc_reg[23]/D (rising edge-triggered cell FDRE clocked by clk {rise@0.000ns fall@2.000ns period=4.000ns}) Path Group: clk Path Type: Setup (Max at Slow Process Corner) Requirement: 4.000ns (clk rise@4.000ns - clk rise@0.000ns) Data Path Delay: 3.465ns (logic 1.653ns (47.706%) route 1.812ns (52.294%)) Logic Levels: 6 (CARRY8=4 LUT4=2) Clock Path Skew: -0.129ns (DCD - SCD + CPR) Destination Clock Delay (DCD): 3.373ns = ( 7.373 - 4.000 ) Source Clock Delay (SCD): 4.040ns Clock Pessimism Removal (CPR): 0.538ns Clock Uncertainty: 0.035ns ((TSJ^2 + TIJ^2)^1/2 + DJ) / 2 + PE Total System Jitter (TSJ): 0.071ns Total Input Jitter (TIJ): 0.000ns Discrete Jitter (DJ): 0.000ns Phase Error (PE): 0.000ns Clock Net Delay (Source): 2.208ns (routing 0.756ns, distribution 1.452ns) Clock Net Delay (Destination): 1.945ns (routing 0.696ns, distribution 1.249ns) Location Delay type Incr(ns) Path(ns) Netlist Resource(s) ------------------------------------------------------------------- ------------------- (clock clk rise edge) 0.000 0.000 r AG12 0.000 0.000 r clk (IN) net (fo=0) 0.000 0.000 clk_IBUF_inst/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.738 0.738 r clk_IBUF_inst/INBUF_INST/O net (fo=1, routed) 0.105 0.843 clk_IBUF_inst/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.049 0.892 r clk_IBUF_inst/IBUFCTRL_INST/O net (fo=1, routed) 0.839 1.731 clk_IBUF BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.101 1.832 r clk_IBUF_BUFG_inst/O X2Y1 (CLOCK_ROOT) net (fo=121, routed) 2.208 4.040 clk_IBUF_BUFG SLICE_X54Y88 FDRE r y_reg[1]__0/C ------------------------------------------------------------------- ------------------- SLICE_X54Y88 FDRE (Prop_EFF2_SLICEL_C_Q) 0.138 4.178 r y_reg[1]__0/Q net (fo=25, routed) 0.505 4.683 y[1] SLICE_X53Y91 LUT4 (Prop_B6LUT_SLICEM_I0_O) 0.150 4.833 r calc[7]_i_28/O net (fo=1, routed) 0.344 5.177 calc[7]_i_28_n_0 SLICE_X53Y89 CARRY8 (Prop_CARRY8_SLICEM_DI[2]_CO[7]) 0.424 5.601 r calc_reg[7]_i_9/CO[7] net (fo=1, routed) 0.043 5.644 calc_reg[7]_i_9_n_0 SLICE_X53Y90 CARRY8 (Prop_CARRY8_SLICEM_CI_O[0]) 0.122 5.766 r calc_reg[23]_i_30/O[0] net (fo=3, routed) 0.402 6.168 calc_reg[23]_i_30_n_15 SLICE_X51Y88 LUT4 (Prop_C5LUT_SLICEL_I0_O) 0.169 6.337 r calc[15]_i_8/O net (fo=1, routed) 0.437 6.774 calc[15]_i_8_n_0 SLICE_X51Y92 CARRY8 (Prop_CARRY8_SLICEL_DI[1]_CO[7]) 0.422 7.196 r calc_reg[15]_i_1/CO[7] net (fo=1, routed) 0.030 7.226 calc_reg[15]_i_1_n_0 SLICE_X51Y93 CARRY8 (Prop_CARRY8_SLICEL_CI_O[7]) 0.228 7.454 r calc_reg[23]_i_1/O[7] net (fo=1, routed) 0.051 7.505 calc_reg[23]_i_1_n_8 SLICE_X51Y93 FDRE r calc_reg[23]/D ------------------------------------------------------------------- ------------------- (clock clk rise edge) 4.000 4.000 r AG12 0.000 4.000 r clk (IN) net (fo=0) 0.000 4.000 clk_IBUF_inst/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.515 4.515 r clk_IBUF_inst/INBUF_INST/O net (fo=1, routed) 0.066 4.581 clk_IBUF_inst/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.034 4.615 r clk_IBUF_inst/IBUFCTRL_INST/O net (fo=1, routed) 0.722 5.337 clk_IBUF BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.091 5.428 r clk_IBUF_BUFG_inst/O X2Y1 (CLOCK_ROOT) net (fo=121, routed) 1.945 7.373 clk_IBUF_BUFG SLICE_X51Y93 FDRE r calc_reg[23]/C clock pessimism 0.538 7.910 clock uncertainty -0.035 7.875 SLICE_X51Y93 FDRE (Setup_HFF_SLICEL_C_D) 0.063 7.938 calc_reg[23] ------------------------------------------------------------------- required time 7.938 arrival time -7.505 ------------------------------------------------------------------- slack 0.433
그 차이는 지정된 산술 단위를 사용했을 때만큼 극적이지 않습니다. 그러나 여전히 timing constraint를 달성하기에 충분합니다.
이것으로 timing closure에 대한 일반적인 논의를 마칩니다. 다음 페이지에서는 이 주제에 대한 몇 가지 실용적인 전략을 제안합니다.