01signal.com

FPGA의Resets : 동기, 비동기 또는 전혀?

FPGAs의 resets에 대한 시리즈 의 두 번째 페이지입니다. asynchronous resets가 이전 페이지 에서 많은 사람들이 생각하는 것과 다른 이유를 설명한 후 이 페이지에서는 resets 에 대한 다양한 옵션과FPGA 초기화에 대해 설명합니다 .

맨 먼저: reset은 무엇입니까?

자, 우리 모두 reset이 무엇인지 알고 있습니다! PC의 버튼과 같으며, 누르면 모든 것이 깨끗하게 시작됩니다. chip 로 들어가는 신호는 이전에 무슨 일이 있었든 지금부터 모든 것이 잘 될 것임을 보장합니다. 어떤 사람들은 reset을 시스템을 알려진 상태로 만드는 신호라고 합니다.

FPGA designers에서 reset은 종종 모든 module 에 추가하고 반복되는 코드 패턴에서 사용하기 위한 추가 input 입니다. 이 reset 신호가 실제로 보장하는 사항에 주의를 기울이지 않고 그냥 하는 것입니다.

가장 흔한 오해는 reset 신호가 시스템을 알려진 상태로 만든다는 사실에 초점을 맞추는 것입니다. 물론 사실이지만 중요한 부분은 reset이 비활성화된 후 발생하는 일입니다. logic은 예측 가능한 방식으로 작동을 시작해야 합니다. 또는 적어도 제대로 작동하도록 충분히 예측 가능합니다. reset을 비활성화한 후 시스템의 동작이 확실하지 않은 경우 시스템을 재설정하는 것은 무의미합니다.

이 주제를 특히 어렵게 만드는 것은 운이 관련되어 있다는 것입니다. 일반적으로 reset이 활성화되었을 때의 시스템 상태는 알 수 없고 임의적이며 reset의 비활성화 시기도 마찬가지입니다. 따라서 reset 신호를 부적절하게 처리하면 무작위로 나타나는 드문 오작동이 발생할 수 있으며 이는 완전히 다른 종류의 문제처럼 보일 수 있습니다. 마찬가지로, 일반적으로 마법으로 처리되는 가끔 문제를 제외하고는 가시적인 결과 없이 이 문제를 무시하는 것이 가능합니다.

적절한 timing constraints와 마찬가지로 clocks 및 clock domains의 적절한 처리와 마찬가지로 FPGA의 웨이크업 및 리셋에 대한 적절한 처리는 FPGA가 안정적으로 작동하도록 하는 데 필요합니다. 이 모든 주제에 공통된 것은 이러한 주제를 소홀히 하는 것으로 일종의 탈출구를 만들 수 있다는 것입니다. 그리고 상당수의 엔지니어는 그렇게 하지만 불행히도 때때로 귀신이 나오는 것처럼 행동 하는 FPGA를 희생해야 합니다.

시뮬레이션 대 하드웨어

이 페이지는 resets 에 대한 결정이 FPGA에 로드될 때 design 에 어떤 영향을 미치는지에 중점을 둡니다. 그러나 분명히 이러한 결정은 logic의 시뮬레이션에도 영향을 미칩니다.

이 두 상황을 구별하는 것이 중요합니다. 시뮬레이터는 X (알 수 없음) 초기값을 모든 registers, 특히 behavioral simulation에 할당합니다. 이러한 X 값은 logic function의 X 값에 의존하는 모든 register 로 전파됩니다. 따라서 X 값이 있는 단일 register 라도 전체 design을 X's로 압도하고 시뮬레이션이 무용지물이 되는 일이 발생합니다.

이 문제에 대한 일반적인 잘못된 솔루션은 모든 X's를 제거하기 위해 design의 모든 registers 에 asynchronous reset을 배치하는 것입니다. 이것은 일반적으로 시뮬레이션 시작 시 잠시 reset을 활성화하여 수행됩니다. 결과적으로 모든 registers는 알려진 값을 얻고 모든 것이 완벽해 보입니다. 불행히도 이 잘못된 솔루션은 이전 페이지 에서 논의한 문제를 숨김으로써 깨끗한 시작의 착각을 일으키는 경우가 많습니다.

resets가 올바르게 사용되더라도 시뮬레이션에서 X 값의 소스를 쫓는 것을 피하기 위해 모든 registers를 재설정하는 것은 여전히 게으른 선택입니다. 이것은 리소스를 낭비할 뿐만 아니라 timing constraints를 달성하기 어렵게 만들 수도 있습니다. registers를 불필요하게 재설정하면 버그를 숨길 수도 있습니다. X 값의 홍수가 한 register 에서 다른 register 로의 의도하지 않은 종속성에서 비롯될 수 있기 때문입니다. 따라서 X's 의 홍수는 design에 문제가 있다는 경고가 될 수 있습니다.

시뮬레이션과 비교할 때 하드웨어는 resets를 사용하지 않는 것에 대해 훨씬 더 관대합니다. 그러나 resets를 잘못 사용하거나 필요할 때 전혀 사용하지 않으면 하드웨어가 예기치 않게 작동할 수 있습니다.

결론적으로 resets는 하드웨어를 염두에 두고 사용해야 하며 시뮬레이션 중에 성가신 X's를 제거하기 위한 것이 아닙니다. 그리고 초점이 하드웨어에 있어야 하기 때문에 이 몇 마디만 시뮬레이션에 대해 말할 수 있습니다.

재설정 전략

registers 에 resets를 적용할지 여부와 적용 방법을 결정하려면 각 register 의 경우를 별도로 고려해야 합니다. 이렇게 하면 reset 신호의 불필요하게 높은 fan-out를 피할 수 있을 뿐만 아니라 logic이 이전 상태에 관계없이 reset이후에 올바르게 시작되도록 보장되는지 여부를 생각할 수 있는 좋은 기회이기도 합니다.

원칙적으로 네 가지 옵션이 있습니다.

내 의견

이러한 각 옵션은 아래에 설명되어 있으므로 먼저 올바른 방법이라고 생각하는 방법을 제시한 다음 자세히 설명하겠습니다.

이러한 제안은 오늘날 FPGA 공급업체가 권장하는 것과 거의 일치합니다.

매우 일반적인 지침도 추가하겠습니다. 항상 control logic을 명시적으로 재설정하고 data paths가 초기 junk data에서 스스로를 플러시하도록 합니다.

이제 각 옵션에 대한 긴 논의가 있습니다.

옵션 1: 알 수 없는 초기 값

일부 registers는 reset 나 초기 값이 필요하지 않습니다. 이것은 특히 shift registers 및 기타 delay elements에 적용됩니다. 일반적으로 data paths가 이 옵션에 적합할 것입니다.

다음 스니펫을 고려하세요.

reg [31:0] d0, d1, d2, d3, d4;

always @(posedge clk)
  begin
    d4 <= d3;
    d3 <= d2;
    d2 <= d1;
    d1 <= d0;
    d0 <= orig_data;
  end

이것은 각각 32 bits가 있는 5개의 delay registers 입니다. 일부 FPGAs (특히Xilinx )에서 synthesizer는 마지막 값(@d4)만 사용되고 이러한 registers에 reset이 없는 경우 이를 shift register 로 감지합니다. 이것은 logic 의 소비를 상당히 줄일 수 있습니다.

분명히, 이러한 delay registers 의 output 에 연결된 logic은 일부 초기 임의 데이터를 허용할 수 있어야 합니다. 이것이 문제가 되지 않는 일반적인 경우는 제대로 재설정되고 초기화되지 않은 값이 도착할 때 무시되도록 하는 다른 register 또는 state machine이 있는 경우입니다. 예를 들어, 이러한 delay lines가 pipeline와 관련된 경우 pipeline의 control logic은 자연스럽게 잘못된 데이터를 무시합니다.

더 일반적으로 말하면 register를 재설정하거나 초기화하지 않을 기회는 유효성을 나타내는 플래그 또는 상태가 수반될 때 쉽게 인식됩니다. 또는 먼저 register 에 값을 할당한 다음 이 값을 사용하는 명확한 순서가 있을 때. 간단히 말해서 register의 값은 적절한 값이 할당될 때까지 무시된다는 것을 쉽게 알 수 있습니다.

알 수 없는 초기 값의 또 다른 유형은 synthesizer에 종속될 수 있는 경우입니다. 예를 들어:

reg val;

always @(posedge clk)
  val <= 1;

synthesizer는 @val이 1의 상수 값을 갖는 wire 라고 결정할 수 있습니다. 또 다른 가능성은 register를 초기 값으로 0으로 지정하여 첫 번째 clock에서 1 로 변경하는 것입니다. 실제로 일어나는 일은 synthesizer에 따라 다릅니다. 따라서 @val 의 값은 항상 알려져 있지만 첫 번째 clock cycle을 제외하고는 초기 값을 알 수 없는 것으로 간주해야 합니다.

옵션 #2: FPGA의 초기값

FPGA (일반적으로 flip-flops, shift registers 및 메모리)에서 기본 synchronous elements 의 초기 값은 configuration bitstream에 제공됩니다. 이 기능의 잘 알려진 용도는 block RAM 에 초기 값을 할당하여 ROM을 만들고 절대 쓰지 않는 것입니다.

이 기능의 잘 알려진 또 다른 측면은 FPGA가 일반적으로 configuration 에서 깨어나고 분명히 모든 registers가 값이 0이라는 것입니다. synthesizer는 일반적으로 모든 registers를 초기 값으로 0으로 할당하지만 초기 값이 명시적으로 설정되지 않는 한 놀라움이 있을 수 있기 때문입니다.

일부 synchronous elements, 특히 shift registers 및 전용 RAM blocks는 Verilog 또는 VHDL 에서 동작을 설명하여 생성할 수 있습니다( inference): synthesizer는 일반적으로 코드가 delay line처럼 보일 때 shift register를 생성합니다. 마찬가지로 RAM element는 array에 대한 응답으로 생성됩니다. 그러나 reset이 이러한 registers (synchronous reset 또는 asynchronous reset)에서 사용되는 경우 synthesizer는 이러한 방식으로 logic 리소스를 사용할 수 없습니다. shift registers 도 RAMs 도 내부 메모리 값을 설정하는 reset input이 없기 때문입니다.

그러면 초기 값은 어떻게 설정됩니까? configuration 프로세스 동안 모든 synchronous elements는 FPGA가 활성화되기 직전, 즉 synchronous elements가 clocks 및 asynchronous reset inputs에 응답하기 전에 초기 값이 제공됩니다. Xilinx 장치의 경우 이는 모든 synchronous elements를 초기 상태로 설정하는 Global Set Reset (GSR) 신호를 통해 구현됩니다. 이후 Global Write Enable (GWE)가 활성화되어 synchronous elements가 정상적으로 작동합니다.

configuration 프로세스는 FPGA의 application logic이 사용하는 clocks 와 상관없이 수행되기 때문에 FPGA의 작동 상태로의 전환은 이러한 clocks와 비동기식입니다. 결과적으로 synchronous elements는 clock에 관계없이 asynchronous reset이 비활성화된 것처럼 정확히 동작합니다. 즉, 일부 synchronous elements는 작동 상태로 전환된 후 도착한 첫 번째 clock edge 에 응답하고 다른 동기 요소는 timing위반으로 인해 이 clock edge를 놓칠 수 있습니다. 이것은 이 시리즈의 첫 페이지에서 논의된 것처럼 불쾌한 버그를 유발할 수 있습니다.

FPGA가 깨어났을 때 clocks가 반드시 안정적인 것은 아니라는 점에 유의하는 것이 중요합니다. FPGA의 자체 PLLs에서 생성된 경우 timing constraints를 심하게 위반할 수 있습니다. 위에서 논의한 바와 같이 clock이 안정될 때까지(예: clock enable덕분에) 무시되거나 FPGA가 깨어났을 때 안정적인 것으로 알려진 경우에는 문제가 되지 않습니다. 또한 design이 clock이 안정될 때까지 synchronous element가 값을 변경할 이유가 없음을 보장한다면 괜찮습니다. 그렇지 않으면 초기 값을 설정하는 것이 많은 것을 보장하지 않습니다.

초기값 설정의 한계에도 불구하고 많은 시나리오에서 충분하고 명시적 reset이 필요하지 않습니다. 그리고 어떤 경우에는 reset 신호를 사용할 수 없기 때문에 선택의 여지가 없습니다. 예를 들어, FPGA가 깨어난 직후 FPGA의 reset 신호를 생성하는 logic이 있습니다. 이러한 logic 의 예 는 이 시리즈의 세 번째 페이지에 나와 있습니다.

대부분의 synthesizers에서 register의 초기 값을 설정하는 것은 매우 간단합니다. Verilog의 "initial" 사용:

reg [15:0] counter;
initial counter = 1000;

"initial"가 synthesis용 Verilog 코드에서 사용될 수 있다는 사실이 놀라울 수도 있지만 알고 보면 이 사용법은 널리 지원 됩니다. 따라서 이 keyword는 synthesizer가 지원하는 경우 확실히 선호되는 방법입니다(즉, "initial"의 이 사용법은 문서에 명시적으로 언급되어 있습니다). 게다가 대체 방법은 공급업체에 따라 다르며 때로는 FPGA 제품군에만 해당되는 경우도 있습니다. 따라서 "initial"가 항상 휴대할 수 있는 것은 아니지만 여전히 가장 휴대하기 좋은 선택일 것입니다.

초기 값을 설정하는 다른 방법은 사용하는 FPGA 에 따라 다릅니다. 이 방법은 일반적으로 synchronous element 의 instantiation을 primitive로, 초기값을 instantiation parameter로 할당하는 방식으로 구성됩니다. 예를 들어, Xilinx의 flip-flop:

FDCE myflipflop (
  .C(clk),
  .D(in),
  .Q(out),
  .CLR(1'b0),
  .CE(1'b1)
);

defparam myflipflop.INIT = 1;

"initial"를 사용하는 것이 더 멋지지 않습니까?

옵션 #3: Asynchronous reset

asynchronous resets 가 자주 잘못 사용되는 이유에 대한 페이지를 읽지 않았다면 먼저 하는 것이 좋습니다. 어쨌든 이런 종류의 reset을 사용하지 않으려면.

어떤 이유로 많은 사람들이 asynchronous reset을 모든 목적에 적합한 솔루션으로 생각합니다. 코드 예제에 자주 나타나기 때문일 수도 있고 모든 synchronous elements에 도달하는 global reset을 달성하는 간단한 방법에 대한 환상 때문일 수도 있습니다. 아마도 이전 ASIC 세계에서 asynchronous reset은 전체 chip을 재설정하고 test vectors적용을 시작할 수 있기 때문에 제조 공정에서 chip test 에 유용했기 때문일 수 있습니다.

그래서 현실에: asynchronous reset을 사용하는 적절하고 깨끗한 방법은 clocks를 끈 상태에서 사용하는 것입니다. 그것이 바로 "asynchronous" 부분이 의미하는 바입니다. 실용적인 design에서 이것은 다음 단계로 구성됩니다.

이 시퀀스는 구현하기 어렵지 않지만 각 clock 의 첫 번째 edge가 제대로 형성되었는지 확인하는 것이 더 어려울 수 있으므로 glitches가 없습니다. clock buffers 의 일반적인 문제는 clock buffer의 output enable 활성화와 clock buffer를 통과하는 첫 번째 clock edge 사이의 타이밍에 대한 요구 사항이 있다는 것입니다. 이 타이밍 요구 사항이 위반되면 clock buffer는 glitch ( clock에 대한 FPGA의 요구 사항을 위반하는 짧은 pulse )를 출력할 수 있습니다. 이로 인해 이 clock에 의존하는 모든 synchronous elements 의 예측할 수 없는 동작이 발생할 수 있습니다.

불행히도 FPGA 공급업체에서 제공하는 문서가 이 타이밍 요구 사항을 보장하는 방법에 대한 설명을 항상 제공하지는 않습니다. 결과적으로 reset 이후 첫 번째 clock edge가 올바르게 작동하는지 확인하지 못할 수 있습니다. 그리고 첫 번째 clock edge에 대한 보증이 없으면 reset은 무의미합니다.

이 방법을 사용하는 경우 asynchronous reset와 관련된 paths 에 timing constraints가 적용되지 않도록 해야 합니다. 이러한 강제는 이 경우 불필요하며 기본적으로 활성화될 수 있습니다.

일반적으로 제안되는 asynchronous reset을 안정적으로 적용하기 위한 대체 방법이 있습니다. 이 방법은 clock gating을 포함하지 않으므로 clock buffers에 의존하지 않습니다. 아이디어는 asynchronous reset 신호의 활성화를 직접 통과하도록 하는 몇 개의 flip-flops를 추가하는 것이지만 이러한 flip-flops는 reset을 동기적으로 비활성화합니다. 즉, synchronized asynchronous reset.

예를 들어 원래 asynchronous reset이 @external_resetn인 경우 다음과 같은 종류의 reset이 생성됩니다.

reg pre_rstn1, pre_rstn2;
   reg resetn;

   always @(posedge clk or negedge external_resetn)
     if (!external_resetn)
       begin
         resetn <= 0;
         pre_rstn2 <= 0;
         pre_rstn1 <= 0;
       end
     else
       begin
         resetn <= pre_rstn2;
         pre_rstn2 <= pre_rstn1;
         pre_rstn1 <= 1;
       end

@clk은 @resetn에 의해 재설정되는 synchronous elements 에 의해 사용되는 clock 입니다.

@external_resetn이 활성화되면(즉, 낮음) 세 개의 registers가 모두 비동기적으로 활성화됩니다(즉, 0). 그러나 @external_resetn이 비활성화되면 @pre_rstn1 만 다음 clock edge에서 비활성화되고 이는 후속 clocks 의 @pre_rstn2 및 @resetn 로 전파됩니다.

두 개의 추가 registers 의 목적은 metastability로부터 보호하여 @resetn이 안전한 방식으로 비활성화되도록 하는 것입니다. 이것은 @external_resetn이 @clk에 비해 잘못된 타이밍으로 비활성화되어 @pre_rstn1 에서 metastable condition이 발생할 수 있는 경우에 필요합니다( 이 페이지 에서는 metastability에 대해 설명합니다).

이 synchronizer 의 이점은 @external_resetn을 asynchronous reset로 사용할 수 있다는 것입니다. clock이 활성화되지 않은 경우에도 작동합니다. 그럼에도 불구하고 synchronous elements는 동기적으로 비활성화되는 reset 신호를 수신하므로 timing을 보장할 수 있습니다.

말할 필요도 없이 각 clock 에는 고유한 synchronized asynchronous reset이 필요합니다.

위에 표시된 대로 @resetn을 생성하는 것만으로는 충분하지 않다는 점에 유의해야 합니다. @clk 용 timing constraints는 @resetn 에서 synchronous elements로 paths 에 적용되어야 합니다. 일부 FPGA 도구의 기본값은 synchronous element의 asynchronous reset input에서 끝나는 paths 의 timing을 무시하는 것입니다. 이를 위해 도구 설정을 변경해야 할 수도 있습니다.

따라서 @resetn이 일반 asynchronous reset로 사용되는 경우, 예를 들어

always @(posedge clk or negedge resetn)
    if (!resetn) // Are you sure this path is timed?
      the_register <= 0;
    else
      [ ... ]

그렇다면 위에 표시된 synchronizer는 reset에서 안정적인 복구를 보장하기에 충분하지 않습니다 . @resetn 에서 시작하여 flip-flops의 asynchronous reset inputs 에서 끝나는 paths가 실제로 시간이 맞춰졌는지 확인하는 것은 사용자의 책임입니다.

이 synchronizer는 @external_resetn의 glitches 에 대해 도움이 되지 않는다는 점도 중요합니다. @external_resetn의 active pulse 의 길이가 FPGA의 flip-flops의 사양보다 짧으면 어떤 일이 일어날 수 있습니다. 따라서 @external_resetn은 긴 pulse를 보장하는 일부 logic 또는 외부 전자 장치에 의해 생성되어야 합니다. 이것이 가능하지 않은 경우 유일한 해결책은 @sync_resetn에 대한 이 예와 같이 reset을 완전히 동기화하는 것입니다.

reg pre_rstn1, pre_rstn2;
   reg sync_resetn;

   always @(posedge clk)
     if (!external_resetn)
       begin
         sync_resetn <= 0;
         pre_rstn2 <= 0;
         pre_rstn1 <= 0;
       end
     else
       begin
         sync_resetn <= pre_rstn2;
         pre_rstn2 <= pre_rstn1;
         pre_rstn1 <= 1;
       end

그러나 이 싱크로나이저는 @clk이 비활성화된 경우 @external_resetn을 무시합니다. 이것은 logic이 @external_resetn을 asynchronous reset처럼 취급해야 하는 경우 문제가 됩니다. 즉, clocks가 활성화되지 않은 경우에도 작동해야 합니다.

첫 번째 synchronizer로 돌아가 보겠습니다. @resetn을 일반 synchronous reset로 사용하는 것은 어떻습니까? 이 같은:

always @(posedge clk) // @resetn not in sensitivity list!
    if (!resetn)
      the_register <= 0;
    else
      [ ... ]

@resetn의 비활성화는 timing constraints덕분에 확실히 시간이 지남에 따라 다소 괜찮습니다. 그러나 @resetn 의 비동기 활성화는 시간이 지정되지 않으므로 관련 synchronous elements는 reset이 적용되기 직전에 무작위로 작동할 수 있습니다. 이 목적을 위해 완전히 동기화된 reset을 사용하는 것이 좋습니다(예: 위에서 정의한 @sync_resetn ).

일반적인 의견으로 이 주제를 마치겠습니다. 위의 예에서 active-low resets를 사용하기로 선택했습니다. 주로 reset 신호가 resistor를 통해 power supply voltage 에 연결된 capacitor 로 생성되었던 시절부터 유래한 전통 때문입니다. capacitor 에는 처음에 voltage가 없었기 때문에 reset input은 '0'였습니다. 이 capacitor는 곧 충분한 charge를 구축했고 결과적으로 reset input은 '1'로 변경되었습니다. 이 고대 유형의 power-up reset은 오늘날까지 많은 resets가 active low 인 이유입니다.

결론적으로 asynchronous reset을 안정적으로 사용할 수는 있지만 이를 달성하는 것은 많은 사람들이 생각하는 것만큼 간단하지 않습니다. 안정적인 asynchronous reset을 보장하는 두 가지 방법을 제시했습니다. timing의 문제를 피하기 위해 일시적으로 clocks를 끄거나 timing을 보장하기 위해 synchronizer를 사용합니다. FPGAs와 마찬가지로 timing은 게임의 이름입니다.

실제 세계에서 asynchronous reset 에 의존하는 대부분의 designs 에서는 이러한 방법 중 어느 것도 사용되지 않습니다. 결과적으로 FPGA design 의 신뢰성은 순수한 운에 달려 있습니다.

옵션 #4: Synchronous reset

synchronous reset은 다음 코드 패턴으로 가장 잘 알려져 있습니다.

always @(posedge clk)
    if (reset)
      the_register <= 0;
    else
      [ ... ]

나는 더 나은 코드 패턴이라고 생각하는 것을 제안할 것이지만 지금은 이 패턴을 고수할 것입니다. 그럼에도 불구하고 여기에서 active-high reset을 선택했습니다. 이것이 synchronous resets에서 더 일반적인 선택이기 때문입니다. 또는 내 인상도 그렇습니다.

synchronous reset은 다음을 제외하고 거의 모든 측면에서 asynchronous reset 보다 낫습니다.

FPGAs는 활성 clock이 없는 상태에서 거의 사용되지 않기 때문에(전통적으로 테스트를 위해 이것을 필요로 하는 ASICs와 달리), routing 전용 리소스 문제가 존재하는지 확실하지 않기 때문에 주요 주제에 집중하겠습니다. Fan-out. 다행히도 이것은 쉽게 해결할 수 있습니다.

또한 위에서 제안한 synchronizer를 사용하는 경우 동일한 fan-out 문제가 asynchronous reset 에 똑같이 영향을 미친다는 점을 언급할 가치가 있습니다. 따라서 fan-out가 synchronous reset 의 단점이라고 진정으로 말할 수 있는 유일한 사람들은 clocks를 끈 상태에서 asynchronous reset을 사용하는 사람들입니다(즉, gated).

fan-out 문제를 해결하기 위해 가장 먼저 떠오르는 것은 synthesizer constraint 또는 attribute을 사용하여 fan-out를 제한하는 것입니다. 그러나 제한에 도달하면 synthesizer가 flip-flop을 복제하기 때문에 이것은 덜 선호되는 방법입니다. 따라서 복제된 flip-flops 의 output이 완전히 다른 목적으로 modules 로 이동하는 경우가 종종 발생하므로 이 output 의 대상이 FPGA전체에 흩어질 수 있습니다. 결과적으로 긴 routing 와 상당한 propagation delay이 생성됩니다.

간단하고 효율적인 솔루션은 logic의 각 중요한 부분에 대해 로컬 reset을 만드는 것입니다. 같은 것

module medium_sized_module (
  input clk,
  input reset,
  input [15:0] in_data
  output [15:0] out_data
);

  (* dont_touch = "true" *) reg local_reset;
  reg the_register;

  always @(posedge clk)
    local_reset <= reset;

  always (@posedge clk)
    if (local_reset)
      the_register <= 0;
    else
      [ ... ]

아이디어는 @local_reset이 @reset 의 로컬 복사본이라는 것입니다(하나의 clock지연됨). 이 module 이하에서 @reset 대신 @local_reset을 사용하면 fan-out를 합리적인 수준으로 유지할 수 있습니다. 이 로컬 reset 의 소비자는 어쨌든 긴밀하게 상호 연결될 것으로 예상되므로 FPGA의 특정 영역에 배치될 가능성이 있습니다. 따라서 로컬 reset은 logic fabric을 가로질러 장거리를 이동할 필요가 없습니다.

logic optimization을 위해 synthesizer가 로컬 reset registers를 제거하지 못하도록 하는 것이 중요합니다. 이것은 synthesizer가 다른 modules에 속하더라도 동일한 동작을 가진 registers가 있을 때 일반적으로 수행하는 것입니다. 위의 예에서는 Vivado의 synthesis attribute , 즉 "dont_touch"가 표시됩니다. 각 synthesizer 에는 이를 수행하는 고유한 방법이 있습니다( Quartus의 경우 "dont_merge"에서 synthesis attribute와 동일).

synthesizer가 실제로 모든 registers를 유지하고 있는지 확인하려면 이러한 모든 registers 에 동일한 이름(예: 위에서 제안한 local_reset )을 지정한 다음 implemented design에서 이 이름으로 registers를 검색하는 것이 좋습니다.

물론 모든 module에 대해 로컬 reset을 생성할 필요는 없습니다. 대략적인 수치로 fan-out는 로컬 reset에 적합하며 특히 FPGA의 작은 물리적 영역 내에서 logic elements 에 도달할 때 적합합니다.

fan-out를 줄이는 주제는 timing closure의 맥락에서도 논의됩니다 .

synchronous resets에 대한 추가 정보

synchronous resets 에 대한 일반적인 신화는 synthesizer가 synchronous reset와 일치하는 Verilog 코드 패턴을 만나면 reset 신호를 flip-flop의 synchronous reset input에 연결한다는 것입니다. 그럴 수도 있지만 그렇지 않은 경우가 많습니다.

이것은 flip-flop의 asynchronous reset input에 연결해야 하는 asynchronous reset와 다릅니다. 그렇지 않으면 reset은 clock없이 작동하지 않습니다.

Synthesizers는 코딩 패턴에 특별한 의미를 부여하지 않고 Verilog 코드에서 파생된 logic equation을 계산하는 경향이 있습니다. 다음 예를 고려하십시오.

always @(posedge clk)
    if (reset)
      the_register <= 0;
    else if (some_condition)
      the_register <= !the_register;
    else if (some_other_condition)
      the_register <= 0;

이 코드를 읽는 한 가지 방법은 always statement가 synchronous reset을 요청하는 표준 코드 패턴으로 시작하여 register의 동작에 대한 특정 정의가 나오는 것입니다. 결과적으로 @reset이 관련 flip-flop의 synchronous reset input 에 연결되고 logic function 의 output ( LUT로 구현됨)가 flip-flop의 data input에 연결될 것이라고 예상할 수 있었습니다.

실제로 synthesizers는 일반적으로 다음 clock 에서 @the_register 의 값을 최대한 간결하게 구현합니다. 예를 들어, flip-flop의 reset input은 (reset || (some_other_condition && !some_condition) )라는 표현을 구현하는 logic function (즉, LUT)에 연결될 수 있습니다.

그러나 더 흥미로운 가능성이 있습니다. flip-flop의 reset input은 전혀 사용되지 않을 수 있습니다. 대신 data input 만 사용되며 logic function은 @reset 신호를 inputs중 하나로 사용합니다. 따라서 @reset이 높으면 logic function의 output은 0입니다. 이 방법으로 @reset은 실제로 @the_register를 0으로 만들지만 다른 신호와 다르게 취급되지는 않습니다.

다시 말해서: flip-flop 에는 synchronous reset input이 있지만 synthesizers는 synchronous reset의 코드 패턴을 특별히 취급하지 않는 경향이 있으며 reset 신호를 다른 신호와 다르게 취급하지도 않습니다. flip-flop의 reset input은 Verilog 코드에 필요한 동작을 구현하는 가장 좋은 방법으로 사용됩니다. 이는 때로는 reset input을 reset 신호에 직접 연결하고 때로는 reset 신호를 포함할 수 있는 일부 logic function 에 연결하고 때로는 reset input을 전혀 사용하지 않음을 의미할 수 있습니다. synthesizer는 성능 목표를 더 잘 달성하는 데 도움이 되는 모든 작업을 수행합니다.

Xilinx의 Vivado 사용자는 두 개의 synthesis attributes( DIRECT_RESET 및 EXTRACT_RESET)를 사용하여 이 문제를 더 잘 제어할 수 있습니다.

asynchronous resets의 또 다른 단점으로 이것을 마무리하겠습니다. 대부분의 FPGAs에서 flip-flop 에는 reset/set input이 하나만 있습니다. 이 input은 동기식 또는 비동기식으로 작동할 수 있습니다. reset이 동기식이면 synthesizer는 요청된 동작을 수행하기 위해 더 적은 LUTs를 사용하기 위해 이 input을 사용하는 트릭을 찾을 수 있습니다. asynchronous reset이 있는 경우 이러한 종류의 단축키는 불가능합니다. 따라서 asynchronous reset은 synthesizer의 손을 묶고 더 많은 logic resources를 낭비하게 만듭니다.

registers의 우발적인 정지 방지

다음 코드 예제와 같이 resets를 구현하기 위해 일반적으로 사용되는 코드 패턴에는 함정이 있습니다.

always @(posedge clk or negedge resetn)
     if (!resetn)
       begin
         reg1 <= 0;
         reg2 <= 0;
         // Ayeee! Forgot to reset reg3 !
       end
     else
       begin
         reg1 <= [ ... ];
         reg2 <= [ ... ];
         reg3 <= [ ... ];
       end

주석에서 암시하듯이 @reg3은 활성 @resetn에 대한 begin-end 절에 나타나지 않습니다. 결과적으로 위의 Verilog 코드는 @resetn이 활성화되어 있는 한 @reg3이 값을 변경하지 않을 것을 요구합니다. @reg3이 다음과 같이 정의되는 것과 같습니다.

always @(posedge clk)
     if (resetn)
       reg3 <= [ ... ];

즉, @resetn은 @reg3용 clock enable 로 작동합니다. clock은 @resetn이 하이일 때만 유효합니다.

synchronous resets에서도 똑같은 일이 발생합니다.

always @(posedge clk)
     if (reset)
       begin
         reg1 <= 0;
         reg2 <= 0;
         // Ayeee! Forgot to reset reg3 !
       end
     else
       begin
         reg1 <= [ ... ];
         reg2 <= [ ... ];
         reg3 <= [ ... ];
       end

이것은 @reset이 비활성화된 경우에만 두 번째 조항이 적용되는 한 쌍의 begin-end 절이기 때문에 실제로 이해하기가 더 쉽습니다. 따라서 이 예에서 @reg3 의 정의는 명확합니다.

always @(posedge clk)
     if (!reset)
       reg3 <= [ ... ];

따라서 명백한(그리고 반드시 영리한 것은 아님) 결론은 reset에 대한 begin-end 절에서 register를 잊지 않는 것입니다. 실제로 많은 FPGA designers는 필요 여부에 관계없이 모든 registers를 재설정하는 것이 유일한 방법이라고 믿기 때문에 재설정합니다. 또는 각 register 에 고유한 "always" 문이 있는 코딩 스타일을 채택합니다.

그러나 의도적으로 일부 registers를 재설정하고 나머지는 재설정하지 않으려면 어떻게 해야 합니까?

asynchronous reset에서는 해당 registers를 별도의 "always" 문에 넣는 것만 선택할 수 있습니다. 그러나 synchronous reset에는 이를 해결하는 간단한 방법이 있습니다.

always @(posedge clk)
     begin
       reg1 <= [ ... ];
       reg2 <= [ ... ];
       reg3 <= [ ... ];

       if (reset)
         begin
           reg1 <= 0;
           reg2 <= 0;
           // I don't want to reset reg3, and that's fine!
         end
     end

처음에 "if (reset)" 문장 대신 "else" 문장 아래에 흥미로운 부분이 있는 "if (reset)"가 마지막에 놓이므로 reset 에 대한 할당은 그 앞에 오는 모든 것을 무시 합니다.

이것은 위의 예와 동일 하지 않습니다 . @reg1 및 @reg2는 @reset이 활성화되면 재설정되지만 @reg3은 reset 의 영향을 전혀 받지 않습니다.

synchronous reset을 적용하는 이 대안적인 방법이 불편하시다면 저는 그 점을 이해할 수 있으며 여기에는 몇 가지 이유가 있습니다. 우선, 일반적으로 FPGA design에서 일반적으로 사용되는 코딩 패턴을 고수하는 것이 좋습니다. 그렇지 않으면 synthesizer는 잘 정립된 코드 패턴에서 발생할 가능성이 훨씬 적은 이국적인 버그를 노출할 수 있습니다( 황금 규칙 #4 참조). 따라서 Verilog 표준에서 이 방법이 작동하도록 명시적으로 요구하더라도 이 기능에 의존하는 것이 반드시 좋은 생각은 아니라고 주장할 수 있습니다.

이것은 강력한 주장이지만 그 가치에 대해 저는 synthesizers의 넓은 범위와 함께 이와 같은 코드 패턴을 10년 넘게 많이 사용해 왔다는 것을 말씀드리고자 합니다. 특히 이것은 내 자신의 코드에서 synchronous resets를 정의하는 방법입니다. 나는 이것으로 단 한 번도 문제를 일으킨 적이 없다.

이 방법을 좋아하지 않는 또 다른 가능한 이유는 synthesizer가 일반 코드 패턴이 아니기 때문에 synchronous reset이 필요하다는 힌트를 놓칠 수 있다고 생각하기 때문입니다. 그러나 위에서 이미 언급했듯이 대부분의 synthesizers는 어쨌든 힌트를 받아들이지 않으며 synchronous reset을 logic의 필수 동작에 대한 또 다른 정의로 간주합니다. 따라서 이 이유는 근거가 없습니다.

따라서 안전하다는 내 말을 듣고 싶다면 두통을 덜 수 있을 것입니다.

asynchronous reset에서도 동일한 작업을 수행할 수 있습니까? 예를 들어 이것은 무엇을 할 것인가?

always @(posedge clk or negedge resetn)
      begin
        reg1 <= [ ... ];
        reg2 <= [ ... ];

        if (!resetn)
          reg1 <= 0;
      end

이것은 물론 asynchronous reset의 일반적인 코딩 패턴에서 벗어나는 것입니다. Vivado의 synthesizer 에 대한 일화적인 테스트에서 힌트를 얻었고 @reg1에 대해 비동기식 reset을 할당했음이 밝혀졌습니다.

그러나 @reg2 에 필요한 동작은 FPGA에서 달성할 수 없습니다. 위에서 설명한 것처럼 @clk 와 @resetn이 모두 clocks가 고 @reg2가 rising edges 와 falling edges에서 각각 새로운 값을 샘플링한다는 의미입니다. 2개의 clock inputs가 있는 flip-flops는 내가 아는 FPGA 에서 사용할 수 없기 때문에 @reg2의 정의 중 synthesis 에 대한 가능성은 없습니다.

Vivado의 synthesizer는 이에 대응하여 "negedge resetn" 부분을 무시하고 @clk 만 clock로 사용하는 flip-flop을 만들었습니다. syntheses의 결과에는 이 이상함의 흔적이 없었고 synthesizer 도 warning을 발행하거나 불평하지 않았습니다. synthesizer가 Verilog 코드에 정의된 대로 동작하지 않는 logic을 생성했음에도 불구하고 말입니다.

따라서 특히 Vivado의 synthesizer에서는 동일한 코드 패턴이 실제로 asynchronous reset에서도 작동하지만 이에 의존해서는 안 됩니다. Verilog 코드는 logic이 하기를 원하는 것을 말해야 합니다. 그렇지 않으면 synthesizer가 원하는 대로 잘못 해석할 수 있습니다.

이것으로 resets에 대한 이 시리즈 의 두 번째 페이지를 마칩니다. 다음 페이지 에서는 powerup 및 외부 reset이후에 FPGA를 시작하는 다양한 측면을 살펴봅니다.

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