01signal.com

FPGA의Asynchronous resets : 많은 사람들이 믿는 것처럼 쉽지 않다

이 페이지는 FPGAs의 resets에 대한 시리즈 세 개 중 첫 번째 페이지입니다. 많은 사람들이 예상대로 작동하지 않는다는 사실을 모른 채 asynchronous resets를 사용하기 때문에 이 첫 페이지에서 전체 주제가 생각만큼 쉽지 않은 이유를 설명합니다.

reset이 정말 작동합니까?

잘못된 state machine재설정에 대한 다음 예를 고려하십시오.

always @(posedge clk or negedge resetn)
     if (!resetn)
       state <= ST_START;
     else
       case (state)
	 ST_START:
	   begin
	      state <= ST_NEXT;
	      [  ... do some stuff maybe? ... ]
	   end

	 ST_NEXT:
	   begin
	      [ ... do something ... ]
	   end
       endcase

여기서 reset 의 문제점은 무엇입니까? 교과서에 나오는 그대로입니다! @state를 구현하는 register를 초기 상태로 만드는 active low asynchronous reset. 무엇이 잘못될 수 있습니까?

논의를 위해 @resetn signal 자체는 괜찮다고 가정해 보겠습니다. 즉, pushbutton 나 그에 비슷한 것에 직접 연결되어 있지 않습니다. 아마도 reset signal을 생성하도록 설계된 chip이 사용되었거나 reset이 FPGA에서 내부적으로 생성되었을 수 있습니다. 이런 식으로든 reset이 안정적으로 활성화되고 충분히 오랫동안 활성화된 다음 비활성화된다고 가정합니다. 여전히 틀렸습니다.

그리고 내가 틀렸다고 말하는 것은 FPGA가 명백한 이유 없이 때때로 이상하게 동작하게 만드는 종류의 잘못된 것을 의미합니다.

그래서 문제가 무엇입니까? 글쎄요, reset은 충분히 오랫동안 활성화되어 있기 때문에 @state를 초기 상태로 되돌릴 것입니다. 그러나 비활성화되면(즉, 위의 예에서 다시 '1' 로 변경) 어떻게 됩니까? 그 때 관련 flip-flops가 @clk의 rising edges 에 응답하기 시작해야 합니다.

하지만 flip-flop이 reset signal에서 복구되고 rising clock edges에서 data input을 샘플링하기 시작하는 데는 약간의 시간이 걸립니다. 그리고 reset은 정의상 비동기적이므로 @clk와 관련하여 언제든지 비활성화될 수 있습니다.

@clk 의 첫 번째 rising edge가 reset의 비활성화 후 너무 빨리 도착하면 flip-flop은 이 rising edge를 무시합니다. @clk 에 연결된 모든 flip-flops가 그렇게 하면 완벽합니다. 그러나 모든 flip-flops가 정확히 같은 것은 아니며 일부는 다른 것보다 조금 더 일찍 clock edge를 얻고 일부는 다른 것보다 늦게 reset을 비활성화합니다.

사실, 이 설명은 다소 단순합니다. 문제에 대한 보다 정확한 견해는 timing의 기본 사항을 설명하는 페이지 에서 Recovery 및 Removal 에 대한 부분을 참조하십시오.

따라서 다음과 같이 요약됩니다. 운이 좋지 않으면 reset이 clock의 rising edge에 충분히 가깝게 비활성화되어 일부 flip-flops가 첫 번째 rising edge에 응답하고 다른 일부는 무시할 수 있습니다. 실제로 일부 flip-flops는 수행할 작업을 결정하는 데 시간이 더 걸릴 수 있습니다. 동일한 chip 에서 flip-flops 의 차이점을 탓하거나 clock skew 와 reset skew를 탓하십시오. 결론은 일부 flip-flops가 다른 clock cycle 보다 앞서 있다는 것입니다.

이것이 얼마나 나쁜지 이해하려면 위의 예를 고려하십시오. synthesizer가 이것이 state machine임을 인식한다면 one-hot encoding와 함께 state variable을 구현할 가능성이 높습니다. 즉, 각 state에 대해 single-bit register를 할당합니다. 이러한 registers 각각은 state machine이 관련 state에 있을 때 활성화됩니다. synthesizer가 ST_START라는 이름의 state 에 대해 hot_state_0 라는 register를 할당하고 ST_NEXT에 hot_state_1을 할당했다고 가정해 보겠습니다. 분명히 reset은 hot_state_0을 활성화하고 hot_state_1을 비활성화합니다.

이제 state machine은 ST_START 에서 ST_NEXT로 무조건 이동합니다. 따라서 reset이 출시된 후 첫 번째 clock 에서 hot_state_0이 비활성화되고 hot_state_1이 활성화됩니다.

그러나 reset이 불운한 타이밍으로 비활성화되어 일부 flip-flops가 첫 번째 clock edge를 놓치고 다른 clock edge는 놓치면 어떻게 될까요? 한 가지 가능성은 hot_state_0이 첫 번째 clock을 놓치고 hot_state_1이 이에 응답한다는 것입니다. 결과적으로 둘 다 활성 상태가 되며 이는 one-hot encoding에서 잘못된 조건입니다. 반대의 경우 두 registers가 모두 비활성화되므로 실제로 state machine 의 모든 one-hot registers가 비활성화됩니다. 어느 쪽이든 state machine은 합법적인 상태로 절대 복구할 수 없습니다.

실제로 이것이 어떻게 보일까요? 물론 응용 프로그램에 따라 다르지만 reset을 FPGA 에 다시 적용할 때까지 무언가가 제대로 작동하지 않을 가능성이 큽니다. 이 동작의 이유를 찾는 것은 매우 어려울 수 있습니다. 이 문제는 무작위로 나타나고 반드시 자주 나타나는 것은 아니기 때문입니다. 또한 FPGA design 마다 compilation 에서 다르게 동작할 가능성이 높고, board 마다 다를 수 있습니다. 간단히 말해서, 이것은 여러분을 미치게 할 수 있는 종류의 버그입니다. 이 토론에서는 그다지 나쁘지 않게 들릴 수도 있는데, 문제의 근원이 이 토론의 주제이기 때문입니다. 그러나 실제로 그러한 불안정성이 발생하면 무엇이든 될 수 있으며 종종 FPGA 에 유령이 있는 것처럼 느껴집니다 .

하지만 나는 항상 이것을 하고 있고 그것은 효과가 있다!

물론. 대부분의 경우 일부 flip-flops가 reset이후 첫 번째 clock을 놓치더라도 그다지 중요하지 않습니다.

위의 state machine 예제가 실패할 수 있는 주된 이유는 첫 번째 clock cycle에서 초기 상태를 유지하기 때문입니다. 실제 designs 의 대부분의 state machines 에는 초기 상태에서 벗어나는 규칙이 있으므로 처음 몇 개의 clock cycles동안 항상 이 상태를 유지합니다. 그래서 사람은 이 실수를 잊게 됩니다.

그러나 여기에 또 다른 예가 있습니다. 간단한 counter:

reg [15:0] counter;

   always @(posedge clk or negedge resetn)
     if (!resetn)
       counter <= 0;
     else
       counter <= counter + 1;

이 경우, @counter는 16개의 flip-flops로 구성됩니다. 이러한 각 flip-flops는 다음 clock cycle 에 대한 counter 값을 data input에서 받고, @resetn은 asynchronous reset input에서 받습니다.

@resetn이 활성화되면 @counter는 값 0을 얻고 다음 clock cycle 의 counter 값은 1입니다. 따라서 counter[0]을 제외한 모든 flip-flops는 첫 번째 clock edge를 놓쳤는지 여부에 관계없이 0으로 유지됩니다. 따라서 어느 쪽이든 올바르게 계산을 시작합니다. 이와 같은 코드가 작성된 대부분의 경우 counter가 첫 번째 clock cycle을 놓쳤는지 여부는 중요하지 않습니다.

그러나 이것은 다른 이야기입니다.

reg [15:0] counter;

   always @(posedge clk or negedge resetn)
     if (!resetn)
       counter <= 0;
     else
       counter <= counter - 1;

작은 차이지만 중요한 것: counter가 0에서 시작하여 카운트 다운 하면 다음 clock cycle 에서 counter 의 값은 0xffff입니다. 즉, 모든 flip-flops는 reset이후의 첫 번째 clock 에서 값을 변경해야 합니다. 따라서 일부는 reset이후의 첫 번째 clock edge 에 응답하고 다른 일부는 응답하지 않으면 counter는 사실상 임의의 임의의 값에서 시작할 수 있습니다.

하지만 counter를 0 값으로 재설정한 후 카운트다운을 하는 사람은 누구일까요?

다음은 보다 현실적인 예입니다. logic이 clock의 주파수를 절반으로 줄인 것처럼 동작하도록 하는 clock enable signal (필요한 경우 multi-cycle path 사용 가능):

reg en;

   always @(posedge clk or negedge resetn)
     if (!resetn)
       en <= 0;
     else
       en <= !en;

   always @(posedge clk)
     if (en)
       [ ... do something ... ]

여기에서는 아무 것도 잘못될 수 없다고 생각할 수 있습니다. clock enable, @en은 단일 register가 므로 언제 토글링이 시작되는지는 중요하지 않습니다. 아니면...? 문제는 clock enable signal이 높은 fan-out를 갖는 경향이 있으므로 synthesizer는 fan-out의 한계를 초과하지 않기 위해 복제할 수 있다는 것입니다.

Vivado synthesizer 에 대한 나의 일화적인 실험은 @en을 구현한 복제된 registers 각각이 자체 output signal에 의존한다는 것을 보여주었습니다. 다시 말해, 모든 flip-flops가 다음 output이 무엇인지 결정하는 데 사용한 단일 신호가 없었습니다. 오히려 clock의 rising edge 에서 항상 값을 변경하는 독립적인 flip-flops가 많이 있었습니다. 따라서 이러한 flip-flops가 동일한 clock cycle에서 토글을 시작하지 않으면 outputs가 무기한 다르게 유지됩니다.

이러한 사고가 발생하면 logic이 완전히 오작동할 수 있습니다. 따라서 asynchronous reset을 고집한다면 최소한 모든 clock enables가 다음과 같이 단일 소스에 의존하는지 확인하십시오.

reg pre_en; // Apply some don't-touch synthesis directive on this
   reg en;

   always @(posedge clk or negedge resetn)
     if (!resetn)
       pre_en <= 0;
     else
       pre_en <= !pre_en;

   always @(posedge clk or negedge resetn)
     if (!resetn)
       en <= 0;
     else
       en <= pre_en;

   always @(posedge clk)
     if (en)
       [ ... do something ... ]

비결은 @pre_en이 다음 값을 결정하는 register 라는 것입니다. flip-flop은 낮은 fan-out를 가지고 있고 아마도 synthesizer 에 건드리지 말라고 알려주는 attribute이 있을 것입니다. 이런 식으로, 그것은 확실히 단일 register입니다. @en을 구현하는 모든 flip-flops는 @pre_en에 의존하므로 모두 다음 clock에서 @en 의 값에 동의합니다. reset다음의 첫 번째 clock 의 경우, 첫 번째 clock cycle 에서 @en 의 값이 어쨌든 0이기 때문에 일부 flip-flops가 놓쳐도 문제가 없습니다.

따라서 결론은 logic이 일반적으로 reset이 clock에 대해 비활성화될 때의 불확실성에 대해 일반적으로 관대하기 때문에 asynchronous reset을 잘못 사용하는 것이 일반적 으로 괜찮을 것이라는 것입니다. 그럼에도 불구하고 asynchronous resets를 부주의하게 적용하면 해결하기가 매우 어려울 수 있는 가끔 오작동이 발생할 수 있습니다.

reset 와 clock사이에서 timing constraint 사용

reset의 비활성화와 clock의 rising edge 사이의 불확실한 타이밍 관계를 피하는 겉보기에 명백한 방법은 reset signal에서 timing constraint를 사용하는 것입니다. 그러나 그렇게 하면 reset signal이 동기적으로 됩니다.

하지만 reset signal은 어떤 클록과 동기화되어 있을까요? 전체 logic design에 대해 하나의 글로벌 asynchronous reset을 갖는 것이 종종 편리합니다. 이 reset은 하나의 특정 clock와 동기화된 logic 로 생성됩니다. 이 reset이 다른 clock와 동기화된 logic 와 함께 사용되는 경우 clock domain crossing이 있습니다. 이는 그 자체로 주제 이지만 가장 중요한 점은 도구가 관련 paths에서 timing을 무시할 가능성이 있다는 것입니다.

따라서 asynchronous resets 에서 timing constraints를 사용하기 위한 출발점은 각 clock에 대해 별도의 asynchronous reset이 있어야 한다는 것입니다. 또는 related clocks의 각 그룹에 대해 별도의 asynchronous reset을 주장하는 경우. 그렇지 않으면 timing constraint에 의미가 없습니다. 이상하게 들린다면 asynchronous reset이 더 이상 비동기식이 아니기 때문입니다.

Verilog 코드가 asynchronous reset 에 대한 패턴을 사용한다는 사실은 차이가 없습니다. flip-flop의 asynchronous reset input이 사용되거나 flip-flop이 reset input을 비동기식으로 간주하도록 구성된 경우에도 중요하지 않습니다. reset이 clock와 동기식이고 timing constraint가 사용되는 경우 reset은 실질적으로 동기식입니다. 이 경우 Verilog 패턴을 직접 사용하는 것을 고려할 수 있습니다.

always @(posedge clk)
     if (!resetn)
       state <= ST_START;
[ ... ]

그럼에도 불구하고, timing closure에 대한Intel의 Youtube 비디오는 clock와 동기식인 asynchronous resets를 사용하도록 권장하고 있으며, timing constraints 도 사용해야 합니다. asynchronous reset을 선택한 것은 FPGA에서 global routing 에 대한 전용 리소스를 활용하기 위한 것입니다. 저는 이것이 꽤 이상하다고 생각합니다. 왜냐하면 global routing 조차도 특히 대형 FPGAs에서 대형 delay을 가질 수 있기 때문입니다. 하지만 이것이 말이 되는 시나리오도 분명 몇 가지 있습니다.

사실, asynchronous reset이 효과적인 동기일 때에도 asynchronous reset을 계속 사용하는 또 다른 이유가 있습니다. 이에 대해서는 다음 페이지 에서 설명합니다. 이를 통해 reset signal 의 활성화를 비동기적으로 전파할 수 있어 simulations 뿐만 아니라 ASICs테스트에도 유용합니다.

동기화된 asynchronous reset 와 함께 이 방법을 사용하는 경우 timing constraint가 flip-flops의 asynchronous reset inputs로 이동하는 모든 signal paths 에 적용되는지 확인하는 것이 중요합니다. reset이 대상의 flip-flop와 동일한 clock 와 동기화된 flip-flop 에 의해 생성된다는 사실 자체만으로는 그들 사이의 path가 시간이 정해진다는 것을 보장하지 않습니다. 기본적으로 일부 timing 도구는 asynchronous inputs로 끝나는 모든 path를 무시하므로 이 적용을 명시적으로 활성화해야 할 수 있습니다. 이러한 paths가 실제로 timing constraints에 포함되는지 timing reports 에서 확인하십시오. 이것에 빠지기 쉽습니다.

이것으로 resets에 대한 이 시리즈 의 첫 페이지를 마칩니다. 다음 페이지 에서는 resets 에 대한 다양한 옵션과FPGA 초기화에 대해 설명합니다 .

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