01signal.com

multi-cycle paths용Timing constraints

이 페이지는 timing에 대한 일련의 페이지 에 속합니다. 이전 페이지에서는 timing 계산에 대한 이론을 설명하고 여러 timing constraints를 작성하는 방법을 보여주고 timing closure의 원리에 대해 논의했습니다. 이 페이지에서는multi-cycle paths용 timing constraints 에 대해 설명합니다 .

소개

multi-cycle paths 에 대해 알아야 할 첫 번째 사항은 일반적으로 나쁜 생각이라는 것입니다. 이 페이지에서는 multi-cycle path constraints를 사용하는 방법을 설명하지만 결론은 이 기술을 모두 피해야 한다는 것입니다. ASIC 세계에서 이 기술을 사용하는 데에는 이유가 있지만 FPGA design 에서는 일반적으로 대신 clock을 추가하는 것이 좋습니다.

즉, 이러한 종류의 timing exception이 언제 관련이 있는지 봅시다.

Verilog 코드의 다음 예를 고려하십시오.

reg foo, bar;
   reg en, pre_en;

   always @(posedge clk)
     begin
	pre_en <= !pre_en;
	en <= pre_en;

	if (en)
	  begin
	     foo <= !foo;
	     bar <= foo;
	  end
     end

이 예제는 불완전합니다. @pre_en 및 @en에 synthesis attributes를 추가해야 할 수도 있습니다. 그렇지 않으면 synthesizer의 최적화로 인해 예기치 않은 일이 발생할 수 있습니다. 아래에서 자세히 알아보세요.

@pre_en은 모든 clock cycle에서 '0' 와 '1' 사이를 번갈아가며 바꿉니다. @en 도 마찬가지지만, 약간의 delay이 있습니다.

"if (en)" 부분은 @en이 "begin"와 "end" 사이의 모든 항목에 대해 clock enable 역할을 수행함을 의미합니다. @en이 낮을 때 Verilog 코드의 이 부분에서는 아무 일도 일어나지 않습니다. 즉, @foo 및 @bar는 @en이 낮을 때 clock edge가 존재하지 않는 것처럼 동작합니다.

이 예에서 @en은 두 개의 clock cycles마다 한 번씩 높습니다. 따라서 @foo 와 @bar는 clock의 frequency가 실제의 절반인 것처럼 동작합니다. 따라서 timing 요구 사항은 그에 따라 완화될 수 있습니다. tsetup 에 대한 계산은 두 배 큰 clock period 로 수행할 수 있습니다.

thold의 경우 변경 사항이 없습니다. 이 timing 요구 사항에 대한 계산에서는 동일한 clock edge가 두 flip-flops모두에 도달한다고 가정합니다. 따라서 thold 분석 의 예에서 이미 논의한 바와 같이 clock period는 의미가 없습니다. 따라서 더 느린 clock 라는 환상은 thold와 관련하여 아무런 차이가 없습니다.

clock enable을 사용해야 하는 경우

clock enable을 사용하는 좋은 이유는 두 가지뿐입니다.

clock enable이 FPGA의 전력 소비를 향상시키는지는 확실하지 않습니다. 틀림없이 추가 clock은 전력을 낭비합니다. 하지만 clock enable은 fan-out가 높은 signal이 기도 합니다. 평균적으로 clock enable은 대체하는 clock 만큼 자주 값을 변경합니다. 따라서 소비전력의 주범인 logic state 의 변화에 대해서는 별반 차이가 없다.

multi-cycle paths를 사용해야 하는 특별한 이유가 없다면 이 페이지를 건너뛰셔도 됩니다. 기술적으로 적합한 design 에 clock enable이 있더라도 해당 timing exception을 사용하지 않는 것이 좋습니다. 특히 이 timing exception없이도 timing constraints가 쉽게 달성된다면 실수할 위험을 감수할 가치도 없다.

timing exception

위의 Verilog 코드와 관련하여 다음은 Vivado용 multi-cycle path constraints 입니다.

set en_regs [all_fanout -endpoints_only -only_cells -flat [get_nets en]]
set_multicycle_path -setup -from $en_regs -to $en_regs 2
set_multicycle_path -hold -from $en_regs -to $en_regs 1

Quartus도 마찬가지입니다.

set en_regs [get_fanouts en]
set_multicycle_path -setup -from $en_regs -to $en_regs 2
set_multicycle_path -hold -from $en_regs -to $en_regs 1

Vivado 와 Quartus 의 차이점은 첫 번째 행에 있습니다. command "all_fanout"는 Vivado와 함께 사용되고, "get_fanouts"는 Quartus와 함께 사용됩니다. constraints는 SDC와 함께 작동하는 다른 도구와 유사합니다.

첫 번째 행은 @en에서 시작하는 모든 path 의 끝인 모든 synchronous elements (cells)를 찾습니다. 이 cell objects 목록은 $en_regs에 저장됩니다. 다음 몇 행은 이 목록에 있는 cells 에서 시작하고 끝나는 paths 에 대한 timing requirements를 변경합니다.

여기에는 많은 설명이 필요합니다. 왜 $en_regs 에 대한 정의를 이렇게 썼을까요? 왜 set_multicycle_path commands가 두 개일까요? 왜 thold를 위한 timing requirements는 multi-cycle paths에 영향을 받지 않는다고 말했는데, 두 번째 command에 "-hold"라고 적혀 있을까요?

set_multicycle_path commands부터 설명하겠습니다. 설명하기 쉬운 부분이니까요.

set_multicycle_path commands

위에 표시된 것처럼 commands는

set_multicycle_path -setup -from $en_regs -to $en_regs 2
set_multicycle_path -hold -from $en_regs -to $en_regs 1

위의 예를 어느 정도 일반화하기 위해 다음 사항도 고려하십시오. clock enable이 8개의 clock cycles마다 한 번씩 활성화된 경우 Verilog code는 다음과 같을 것입니다.

reg en;
   reg [2:0] pre_en;

   always @(posedge clk)
     begin
	pre_en <= pre_en + 1;
	en <= (pre_en == 0);
     end

@en은 strobe처럼 작동하며 매번 하나의 clock cycle 동안에만 활성화됩니다. clock divider의 MSb가 아닙니다.

이 가능성에 대한 multi-cycle constraints는 다음과 같습니다.

set_multicycle_path -setup -from $en_regs -to $en_regs 8
set_multicycle_path -hold -from $en_regs -to $en_regs 7

이 두 가지 예를 볼 때, 첫 번째 set_multicycle_path command 의 숫자는 단순히 clock enable의 분할 비율이라는 것이 분명합니다.

두 번째 command의 경우, 분할 비율은 같지만 마이너스 1입니다. 따라서 항상 N 와 N-1입니다.

첫 번째 command에 대해 설명할 내용은 많지 않습니다. clock enable이 N중 하나의 clock cycle 에서 활성화되면 허용되는 delay 에 N이 곱해집니다. 이는 tsetup의 timing 요구 사항과 관련이 있습니다.

하지만 왜 두 번째 command가 있을까요? thold에 대해 말할 필요가 있을까요? 답은 첫 번째 command 도 최소 delay에 대한 요구 사항을 변경하기 때문입니다. 즉, thold 에 대한 계산은 "-setup" 옵션이 있는 command 의 영향을 받습니다. 왜 그럴까요? 아마도 좋은 설명은 없을 것입니다.

두 번째 command는 이를 바로잡습니다. 최소 delay 에 대한 요구 사항을 원래 값으로 다시 변경합니다. 따라서 두 번째 command이후에 thold 에 대한 계산은 이전과 동일하게 수행됩니다.

설명서에는 두 번째 command에서 N-1을 사용하는 이유에 대한 긴 설명이 있습니다. 하지만 사실, 그 추가 정보에는 흥미로운 것이 없습니다. thold 와 관련된 set_multicycle_path 의 동작은 이상하고, 숫자가 N-1 여야 하는 이유를 이해한다고 해서 이상함이 덜해지는 것은 아닙니다.

그러나 set_multicycle_path는 쉬운 부분이었습니다. 이제 진짜 어려움이 옵니다. $en_regs로 사용할 올바른 cell objects 목록을 생성합니다.

registers선택

어떤 registers가 $en_regs에 나열되어야 하는지 선택하려면 path가 multi-cycle path로 적합한 이유를 이해해야 합니다. 그래서 이것은 규칙입니다: clock enable이 양쪽을 모두 제어하는 경우에만 path 의 timing requirement를 완화할 수 있습니다. 즉, clock enable이 비활성화된 경우 두 sequential elements 중 어느 것도 clock edge이후에 값을 변경하지 않는다는 것이 보장됩니다.

clock domains 의 관점에서 생각해 보십시오. clock enable 에 의해 제어되는 모든 sequential elements는 가상의 clock domain에 속합니다. 이 가상의 clock domain 내부의 clock은 더 낮은 frequency를 가지고 있으므로 이 clock domain 내부의 timing 요구 사항을 조정할 수 있습니다.

그러나 path의 측면 중 하나가 이 가상의 clock domain에 속하지 않는 경우 이것은 두 related clocks 사이의 가상 clock domain crossing 입니다. 기존 timing constraints에서 이미 관리하고 있기 때문에 이러한 path에 대해 특별한 작업을 수행할 필요가 없습니다. 그러나 이런 종류의 path 에 multi-cycle exception을 적용하는 것은 올바르지 않습니다.

위에 표시된 timing constraints는 이 아이디어를 반영합니다. @en 에 의해 제어되는 모든 sequential elements는 $en_regs 에 cell objects로 나열됩니다. 그런 다음 두 개의 set_multicycle_path commands가 이 목록에 속하는 sequential elements 에서 시작하고 끝나는 paths 에 적용됩니다.

multi-cycle paths 에서 가장 어려운 부분은 이 sequential elements 목록이 올바른지 확인하는 것입니다. 이 목록에는 clock enable이 제어하는 모든 sequential elements가 포함되어야 합니다. 그러나 다른 sequential elements는 이 목록에 없어야 합니다.

이 목록에서 sequential element가 누락된 경우 관련 paths 에 대한 timing 적용이 필요 이상으로 엄격해집니다. 이것은 재앙은 아니지만 timing exception 의 효율성을 떨어뜨립니다.

그러나 목록에 있어서는 안 되는 sequential element가 실수로 목록에 추가되면 심각한 결과가 발생할 수 있습니다. 이는 timing requirements가 충분히 엄격하지 않은 paths를 초래합니다. 즉, 도구는 sequential elements의 적절한 작동 요구 사항을 보장하지 않습니다. 그리고 timing 요구 사항이 충족되지 않으면 이상한 일이 발생할 수 있습니다 .

저는 sequential elements목록을 만들기 위해 "all_fanout" command (또는 "get_fanouts")를 사용하기로 했습니다. 이것이 항상 올바르게 작동한다는 보장은 없습니다. 다음에 논의할 내용입니다. 그 후에 이 목록을 만드는 다른 옵션에 대해 논의하겠습니다. 이러한 다른 옵션은 특히 FPGA tools가 "all_fanout" 또는 이와 유사한 commands를 지원하지 않을 때 관련이 있습니다.

all_fanout 및 get_fanouts의 가능한 문제

multi-cycle constraint 에서 가장 가능성이 높은 실수는 clock enable 자체(예: @en)가 목록(예: $en_regs)에 포함된다는 것입니다. 이 경우 multi-cycle exception은 @en 자체에서 제어하는 sequential elements 까지 모든 paths 에 적용됩니다. 이것은 사실상 이러한 paths 의 timing 요구 사항이 보장되지 않는다는 것을 의미합니다. 이는 clock enable이 fan-out가 높은 signal 인 경우가 많기 때문에 눈에 띄는 효과가 있을 수 있습니다.

위의 예에서는 @pre_en을 사용하여 이를 방지합니다. @en이 다음과 같이 정의되지 않은 이유를 스스로에게 물었을 수 있습니다.

always @(posedge clk)
  en <= !en; // Wrong!

@en이 이런 식으로 정의되었다면 @en 에서 자체로 path가 있었을 것입니다. 결과적으로 @en은 $en_regs에 포함되었을 것입니다.

따라서 @pre_en은 이 문제를 해결합니다. 그러나 최적화를 위해 synthesizer가 이 register를 제거하지 않도록 하는 것이 중요합니다. 예를 들어, Quartus의 synthesizer는 @pre_en 의 유일한 용도가 @en 에 값을 제공하는 것임을 감지합니다(이 페이지 상단의 Verilog 코드에서). 따라서 synthesizer는 @pre_en을 제거하고 "en <= !en"라고 표시된 것처럼 계속합니다. 결과적으로 @en은 $en_regs에 포함됩니다. 가능한 해결책은 다음과 같이 @pre_en을 선언하는 것입니다.

reg pre_en /* synthesis preserve */;

이 간단한 예는 synthesizer 에 의한 예기치 않은 최적화가 어떻게 비참한 결과를 초래할 수 있는지 보여줍니다. 솔루션은 간단하지만 이러한 최적화를 방지해야 할 필요성을 간과하기 쉽습니다.

clock enable 의 또 다른 가능한 사고는 이 signal이 종종 높은 fan-out를 갖는다는 사실과 관련이 있습니다. 따라서 도구는 register를 자동으로 복제하여 각 복제본이 특정 제한보다 낮은 fan-out를 가질 수 있습니다. 그러나 이것이 $en_regs에 어떤 영향을 미칠까요? 이 목록에 포함되는 기준은 특정 net을 기반으로 합니다. 따라서 @en 의 복제본에 의해 제어되는 sequential elements는 포함되지 않습니다.

그러나 이와 같은 상황의 결과는 재앙이 아닙니다. 이미 언급했듯이 이것은 일부 paths 에 대한 timing 적용이 필요 이상으로 엄격하다는 것을 의미합니다. design의 안정성은 영향을 받지 않습니다.

registers 의 복제는 높은 fan-outs 의 맥락에서 이미 논의되었습니다. 거기에서 언급했듯이 synthesizer가 복제할 때까지 기다리는 것보다 @en을 수동으로 복제하는 것이 좋습니다. 놀라움을 피하기 위해 항상 이 register의 복제를 허용하지 않는 synthesis attribute을 추가하세요. 높은 fan-out가 나중에 timing closure 에 문제를 일으키는 경우 수동 복제로 해결하세요. 이렇게 하면 문제의 근원을 더 쉽게 이해할 수 있습니다. 프로젝트가 커져서 synthesizer가 갑자기 @en을 복제하는 경우 timing constraints가 달성되지 않은 이유를 깨닫기가 쉽지 않습니다.

어느 쪽이든 $en_regs를 정의하는 command를 업데이트하여 @en 의 복제본이 포함되도록 해야 합니다.

말하자면, $en_regs 의 정의는 net의 이름에 의존한다는 점에 유의하십시오. 이미 논의한 바와 같이 이는 synthesizer가 net 의 이름을 "en"가 아닌 다른 이름으로 변경하는 경우 $en_regs가 빈 목록이 됨을 의미합니다. 결과적으로 multi-cycle path constraints는 완전히 무용지물이 됩니다. 이 가능성도 재앙이 아닙니다. design은 여전히 안정적이지만 timing constraints를 달성하는 것은 더 어렵습니다.

또 다른 가능한 문제는 $en_regs가 정의된 방식 때문에 @en을 clock enable이외의 용도로 사용해서는 안 된다는 것입니다. 예를 들어 다음 Verilog 코드를 고려하십시오.

reg [7:0] counter;

always @(posedge clk)
  if (en)
    counter <= counter + 1;

이 예에서 @en은 분명히 clock enable로 사용됩니다. 따라서 @counter 와 관련된 모든 paths가 multi-cycle paths인 것은 괜찮습니다. 그러나 이것은 어떻습니까?

reg [7:0] counter;

always @(posedge clk)
  if (en)
    counter <= counter + 1;
  else
    counter <= counter - 1;

여기서 @en은 모든 register처럼 사용됩니다. @counter 의 값은 모든 clock cycle에서 변경됩니다. 따라서 @counter는 확실히 multi-cycle path의 후보가 되어서는 안 됩니다. 그러나 @counter 의 모든 flip-flops는 $en_regs에 포함됩니다. @en 에서 이 모든 flip-flops까지 paths가 있습니다.

이것은 @en의 복제본을 생성하여 비교적 쉽게 해결할 수 있습니다.

reg [7:0] counter;
reg non_ce_en;

always @(posedge clk)
  non_ce_en <= pre_en;

always @(posedge clk)
  if (non_ce_en)
    counter <= counter + 1;
  else
    counter <= counter + 2;

synthesizer가 @en 와 @non_ce_en을 하나의 register로 병합하는 것을 방지하려면 synthesis attribute이 필요합니다.

결론적으로 @en 에서 시작하는 모든 paths를 기반으로 하는 $en_regs 의 정의는 간단하고 간결합니다. 그러나이 정의는 또한 지뢰밭입니다. 따라서 몇 가지 대안을 살펴보겠습니다.

$en_regs를 생성하는 다른 방법

multi-cycle path timing exception 용 sequential elements 목록을 만드는 가장 안전한 방법은 design hierarchy에 의존하는 것입니다. clock enable 에 의해 제어되는 모든 logic은 별도의 module (및 가능하면 sub-modules)에 있어야 합니다. 이를 통해 cell object의 전체 이름을 기반으로 cells를 찾아 $en_regs를 생성할 수 있습니다. 예를 들어 Vivado의 경우:

set all_sync [all_fanout -endpoints_only -only_cells -flat \
  [get_nets -of_objects [get_clocks clk]]]
set en_regs [filter $all_sync {name =~ module_ins/multicycle_ins/* }]

첫 번째 command는 clock buffer 자체를 제외하고 @clk 에 연결된 모든 logic elements를 찾습니다(이 clock은 "clk"라는 이름의 clock object 로 표현됨). 결과는 $all_sync에 저장됩니다. 이는 관련성이 있을 수 있는 모든 synchronous elements를 포함하는 목록을 만드는 한 가지 가능한 방법입니다. 두 번째 command는 해당 별도의 module내부에 있는 $all_sync 의 모든 logic elements 목록을 만듭니다.

이 방법은 clock object 의 이름과 instantiations의 이름을 사용합니다. 이들은 변경되지 않을 것으로 예상됩니다. 이 방법을 사용하면 clock enable이 복제되는지 또는 synthesizer에 의해 이름이 변경되는지는 중요하지 않습니다.

module을 별도로 사용하는 또 다른 장점은 Verilog code로 작업하기가 더 쉽다는 것입니다. clock enable 에 의해 제어되는 sequential elements 와 그렇지 않은 sequential elements 사이에는 혼동의 가능성이 더 적습니다.

하지만 clock enable에 의존하는 logic을 분리하여 별도의 module에 넣는 것은 항상 자연스러운 일은 아닙니다. 게다가 Verilog code가 이미 작성되어 제대로 작동하는 것으로 알려져 있다면, 변경하는 것은 좋은 생각이 아닐 수 있습니다.

일부 상황에 적합할 수 있는 다른 대안도 언급하겠습니다. 모든 registers에 대한 명명 규칙. 예를 들어, clock enable이 제어하는 모든 registers 에 "MC_"로 시작하는 이름을 지정할 수 있습니다. 이 선택은 $en_regs를 만드는 command를 간단하게 만듭니다. cells objects를 이름으로 검색하면 됩니다. 다른 logic elements (예: block RAMs)도 instantiation의 이름을 적절히 선택하여 포함할 수 있습니다. 어떤 사람들은 이 방법이 Verilog code를 보기 흉하게 만든다고 말하고, 어떤 사람들은 이 방법이 작업을 더 쉽게 만든다고 말할 것입니다. 어떤 방법도 완벽하지는 않습니다.

-of_objects를 사용하지 않는 이유

간단한 기준에 따라 $en_regs를 정의하는 것이 매력적으로 보일 수 있습니다. 이름이 "en"인 net을 찾아 이 net에 연결된 모든 registers를 추가합니다. 예를 들어 Vivado 에 대해 다음과 같이 작성할 수 있습니다.

set en_regs [get_cells -of_objects [get_nets en]]

이것이 잘못된 이유는 여러 가지가 있습니다. 첫 번째 이유는 여기에 @en 자체가 포함되기 때문입니다. 따라서 multi-cycle constraints는 clock enable 자체에서 제어하는 sequential elements 까지 모든 paths 에 적용됩니다. 위에서 언급했듯이 이것은 심각한 실수입니다.

두 번째 이유는 일부 sequential elements가 간과될 수 있다는 것입니다. 위의 command 에 따르면 포함 기준은 cell이 특정 net (@en)에 연결되어야 한다는 것입니다. 이것은 이 net이 flip-flop의 CE input에 직접 연결될 때 작동합니다. 하지만 종종 synthesizer는 대신 @en 에 기반한 combinatorial function을 사용하기로 선택합니다.

예를 들어, synthesizer는 Verilog 코드가 다음과 같은 것처럼 @foo를 구현하도록 선택할 수 있습니다.

foo <= foo ^ en;

이는 원래 표현식과 기능적으로 동일합니다.

if (en)
  foo <= !foo;

이러한 종류의 최적화는 합법적이며 예상해야 합니다. synthesizer는 NOT gate를 구현하기 위해 어쨌든 LUT를 사용해야 합니다. 그렇다면 왜 이 LUT를 사용하여 flip-flop 의 next value를 직접 얻지 않습니까? 왜 flip-flop의 CE input에 또 다른 wire를 추가합니까?

이 최적화의 부작용은 flip-flop 자체가 @en에 직접 연결되지 않는다는 것입니다. 따라서 $en_regs에는 포함되지 않습니다. 이와 같은 상황의 의미는 이미 논의되었습니다.

synthesizer 에게 @en을 synchronous elements의 clock enable input로만 사용하도록 지시하는 것이 종종 가능합니다. 예를 들어 일부 synthesizers는 "direct_enable" 또는 이와 유사한 이름의 synthesis attribute을 지원합니다. 이 기능을 사용하면 logic을 최적화할 수 있는 synthesizer의 자유도가 줄어듭니다. 따라서 도구의 기술적 문제를 해결하기 위해 design의 성능에 부정적인 영향을 미칠 수 있습니다.

무엇보다도 @en을 복제하거나 이름을 바꾸면 위에서 언급한 것과 동일한 문제가 발생합니다.

따라서 이러한 모든 이유로 net 에 대한 직접 연결을 기준으로 사용하는 것은 나쁜 선택입니다.

reset와의 상호 작용

위의 Verilog 예제에 synchronous reset을 추가한다고 가정합니다.

always @(posedge clk)
     begin
	pre_en <= !pre_en;
	en <= pre_en;
     end

   always @(posedge clk)
     if (reset)
       begin
	  foo <= 0;
	  bar <= 0;
       end
     else if (en)
       begin
	  foo <= !foo;
	  bar <= foo;
       end

multi-cycle timing exception 의 아이디어는 모든 synchronous elements가 모두 가상의 clock domain의 일부인 것처럼 동작한다는 것이었습니다. 이 clock domain 내부의 가상의 clock은 @clk의 절반인 frequency를 갖습니다. 따라서 모든 registers는 @en이 낮을 때 @clk을 무시해야 합니다. 이는 Verilog 코드의 마지막 예에서는 사실이 아닙니다. @reset은 @en와 관계없이 효과가 있습니다.

예를 들어 @reset이 다음과 같이 정의되면 어떻게 되는지 생각해 보십시오.

assign reset = foo;

실용성이 없을지라도 합법적인 synchronous reset입니다. 그러나이 정의는 multipath exception의 문제를 보여줍니다. @en이 높으면 @foo가 그 후 clock cycle 에서 높아집니다. 하지만 @reset 도 높아집니다. 그래서 다음 clock cycle에서 @foo가 다시 낮아집니다. @foo는 모든 clock cycle에서 값을 변경합니다. 그래서 @foo 에서 multicycle path 로 넘어가면 이 path에서 충분히 타이트하지 않은 timing requirement가 발생합니다.

이것은 @en이 synchronous reset을 제어하도록 함으로써 쉽게 해결됩니다.

always @(posedge clk)
     if (en && reset)
       begin
	  foo <= 0;
	  bar <= 0;
       end
     else if (en)
       begin
	  foo <= !foo;
	  bar <= foo;
       end

이것은 맞지만 @reset은 @en와 함께 활성 상태여야 합니다. 간단한 해결책은 여러 clock cycles에 대해 @reset을 높게 유지하는 것입니다.

asynchronous reset에도 동일한 원칙이 적용됩니다. asynchronous resets에 대한 페이지 에 기록된 모든 내용은 여기에서도 관련이 있지만 multi-cycle path constraints에서는 훨씬 더 복잡합니다. 가장 쉬운 해결책은 아마도 다른 페이지 에서 제안한 대로 synchronizer를 사용하는 것입니다.

@en 및 asynchronous resets

@pre_en 의 이점 중 하나는 @en 의 모든 복제본이 항상 동일한 logic level을 갖도록 보장한다는 것입니다. 이것은 당연하게 들릴 수 있지만 asynchronous reset이 잘못 사용된 경우 보장되지 않습니다. 예를 들어 원래 Verilog 코드가 다음과 같다고 가정합니다.

reg en;

always @(posedge clk or posedge reset)
  if (reset)
    en <= 0;
  else
    en <= !en; // This is not recommended!

@en이 복제되면 결과는 다음과 같을 수 있습니다.

reg en, en_1, en_2;

always @(posedge clk or posedge reset)
  if (reset)
    begin
      en <= 0;
      en_1 <= 0;
      en_2 <= 0;
    end
  else
    begin
      en <= !en;
      en_1 <= !en_1;
      en_2 <= !en_2;
    end

@en_1 의 next value는 @en의 값이 아니라 자체 값에 따라 달라집니다. 이는 register복제의 현실적인 결과입니다.

asynchronous reset이 안전하지 않은 방식으로 비활성화되면 어떻게 됩니까? @en 의 일부 복제본이 reset이후의 첫 번째 clock edge 에 반응하고 다른 복제본은 이 clock edge를 무시할 수 있습니다. 그 결과 복제본의 logic state는 결코 동일하지 않을 것입니다(다음 reset까지).

@pre_en은 모든 복제본이 동일한 소스에서 next value를 복사하기 때문에 이 문제를 해결합니다. 이렇게 하면 시작이 좋지 않은 경우에도 장기적으로 적절한 작동이 보장됩니다.

요약

clock enable을 사용하는 것은 쉽습니다. set_multicycle_path를 command 로, timing exception로 사용하는 것은 쉽습니다. 하지만 이것을 안정적으로 작동하게 하는 것은 전혀 쉽지 않습니다. 잘못될 수 있는 일이 많고, 때로는 synthesizer가 성장하는 logic design에 대응하여 동작을 변경하기 때문입니다.

이러한 예기치 않은 문제의 결과로 multi-cycle path가 목적을 달성하지 못할 수 있습니다. 완화된 timing requirements가 일부 paths에 적용되지 않으면 이 방법의 이점은 의심스럽습니다. 더 나쁜 것은 multi-cycle path exception이 영향을 받지 않아야 할 paths 에 적용되면 실수로 인해 신뢰할 수 없는 logic design이 발생할 수 있습니다.

따라서 예기치 않은 일이 발생하지 않도록 관련 paths 에 대한 timing reports를 읽는 것이 중요합니다. 불행히도 이것은 미래의 놀라움을 막지 못합니다. synthesizer의 동작은 design이 발전함에 따라 예측하기 어렵습니다.

따라서 가능하면 clock enable을 사용하는 것보다 동일한 PLL 에서 추가 clock을 생성하는 것이 훨씬 좋습니다. 이 새로운 clock이 있는 clock domain crossings는 두 개의 clocks가 related clocks 이기 때문에 신뢰할 수 있습니다. 이 새로운 clock 용 timing constraints는 도구에 의해 자동으로 생성됩니다. 이런 식으로 놀라움의 위험이 없습니다.

따라서 design에 clock enable 와 multi-cycle exception을 추가하기 위해 이 글을 읽는다면 이 페이지가 생각해볼 만한 정보가 되었기를 바랍니다.


이것으로 FPGA내부에 있는 paths 용 timing constraints 에 대한 부분을 마칩니다. 그러나 I/O는 어떻습니까? 그것이 다음 페이지에서 논의하기 시작하는 것입니다.

이 페이지는 영어에서 자동으로 번역됩니다. 불분명한 사항이 있으면 원본 페이지를 참조하십시오.
Copyright © 2021-2024. All rights reserved. (b4b9813f)