01signal.com

타이밍 클로저를 위한 전략

이 페이지는 타이밍(timing)에 관한 연재 글 모음의 일부입니다. 지금까지의 페이지에서는 타이밍 계산의 이론, 클록 주기 제약 조건에 대한 논의, 그리고 타이밍 클로저(Timing Closure)의 개념을 소개했습니다. 그런데 제대로 설계하려고 노력했는데도 여전히 타이밍 문제가 생기면 어떻게 해야 할까요? 이 페이지는 그 질문에 답하려고 합니다.

서론

이전 페이지에서 저는 타이밍 클로저 문제를 해결하는 단일 방법은 없다는 점을 설명하려고 했습니다. 때로는 임계 경로(Critical Path)에 집중하는 것이 옳고, 때로는 그렇지 않습니다. 때로는 툴 설정을 조금만 바꾸면 문제가 쉽게 해결되기도 하고, 때로는 그보다 훨씬 어렵습니다. 문제의 근본 원인에 도달하기 위해 자신이 가진 모든 경험과 지혜를 동원하는 것에 대안은 없습니다. 타이밍 클로저를 체크리스트 하나로 요약할 방법은 없습니다.

그렇지만 가능한 전략 목록을 갖고 있으면 종종 도움이 됩니다. 그래서 이 페이지에는 타이밍 문제에 직면했을 때 생각해 볼 만한 주제들을 모아 두었습니다. 해결해야 할 특정 타이밍 문제가 있어서 이 글을 읽고 있다면, 이 아이디어 중 하나가 해결책으로 이끌 수도 있습니다. 다만 여기에서 해결책이 그대로 제시되리라고 기대하지는 마세요.

또한 이 연재가 여기서 끝나지 않는다는 점도 명심하세요. 저는 동기를 부여하기 위해 다른 많은 주제보다 타이밍 클로저를 먼저 다루기로 결정했습니다. 하지만 나중에 나오는 페이지들의 내용도 관련이 있습니다.

같은 이유로 I/O 타이밍 제약 조건에 대한 논의는 나중으로 미루겠습니다. 지금은 FPGA 내부에서 시작하고 끝나는 경로(path)에 초점을 맞추고 있습니다.

그럼 타이밍 클로저와 관련하여 고려할 만한 몇 가지 아이디어를 소개하겠습니다.

아이디어 #1: 로직 설계를 고쳐라

이것은 언제나 가장 매력적으로 느껴지지 않는 해결책입니다. 특히 설계가 이미 제대로 동작한다고 알려져 있다면 더욱 그렇습니다. 동작하는 것을 바꾸고 싶지 않기 때문입니다. 그런데도 문제의 근본 원인은 요구 성능에 맞게 Verilog 코드가 충분히 잘 작성되지 않았기 때문인 경우가 많습니다. 로직 설계를 바꾸면 계속 어려움을 겪는 대신 문제를 한 번에 해결할 수 있습니다.

빠른 로직을 작성하는 몇 가지 제안이 이전 페이지에 있습니다. 그리고 이것을 반복해서 말할 가치가 있습니다. 개발 과정 내내 항상 타이밍을 염두에 두세요. 타이밍 문제를 나중에 고치는 것은 처음부터 Verilog 코드를 제대로 작성하는 것보다 훨씬 어렵습니다.

아이디어 #2: 팬아웃을 줄여라

네트(net)의 팬아웃(fan-out)이 높으면 주로 두 가지 이유 때문에 전파 지연(propagation delay)이 늘어납니다.

설계에서 동기 리셋(synchronous reset)을 사용한다면 그 신호는 팬아웃이 높을 가능성이 높습니다. 이 주제는 별도 페이지에서 다룹니다.

그러나 많은 로직 요소에 도달하는 모든 신호는 높은 팬아웃 때문에 잠재적으로 타이밍 문제를 일으킬 수 있습니다. 때로는 이런 높은 팬아웃이 명백하지만(예: 클록 인에이블(clock enable) 신호), 때로는 높은 팬아웃이 생길 것이라고 예상하기가 쉽지 않습니다. FPGA 툴은 대개 팬아웃이 가장 높은 네트 목록을 제공함으로써 도움을 줄 수 있습니다.

팬아웃을 낮게 유지하는 방법은 두 가지가 있습니다.

분명히 두 방법 모두 같은 결과에 도달합니다. 팬아웃이 높은 레지스터가 여러 레지스터로 복제되는 것입니다. 그렇다면 툴이 자동으로 해 줄 수 있는데(첫 번째 방법) 왜 직접 손으로(두 번째 방법) 그런 일을 할까요?

두 번째 방법은 더 많은 노력이 필요하지만 한 가지 중요한 장점이 있습니다. 레지스터를 분별력 있게 복제할 수 있습니다. 목표는 단순히 팬아웃을 줄이는 것만이 아니라는 점을 명심하세요. 각 레지스터의 출력이 로직 패브릭에서 작은 영역 안에 배치된 로직 요소들로 분배되는 것도 중요합니다. 그렇지 않으면 물리적 거리 때문에 라우팅 지연이 커집니다. 따라서 팬아웃을 염두에 두고 Verilog 코드를 작성하면 로직 요소 사이의 연결을 짧게 유지할 수 있습니다. 이것은 다른 페이지에서 동기 리셋 신호를 예로 들어 설명합니다.

반면 FPGA 툴이 레지스터 복제를 담당하면 결과가 그만큼 효율적이지 않을 수 있습니다. 라우팅 지연의 개선은 복제된 각 레지스터를 어떻게 사용할지 결정하는 알고리듬에 달려 있습니다. 결과의 품질은 어떤 FPGA 툴을 사용하는지에 따라 달라집니다.

참고로, 합성기(synthesizer)는 기본적으로 똑같이 동작하는 레지스터 두 개를 감지하면 자동으로 하나의 레지스터로 합칩니다. 따라서 Verilog 코드에서 레지스터를 복제하면 합성기가 그 복제본들을 전부 하나의 레지스터로 대체할 것입니다. 서로 다른 모듈에 동등한 레지스터들이 정의되어 있어도 이런 일이 자주 일어납니다. 이렇게 합쳐지는 것을 피하려면 이 기능을 명시적으로 꺼야 합니다. 이를 수행하는 일반적인 방법은 "dont_touch", "dont_merge" 또는 "keep" 같은 합성 속성(synthesis attributes)을 사용하는 것입니다.

아이디어 #3: 플로어플래닝을 점검하라

기본적으로 로직 패브릭 위의 로직 요소 배치는 FPGA 툴(보다 정확히는 플레이서(placer))이 자동으로 결정합니다. 그런데 특정 로직 요소를 FPGA의 특정 영역에 배치하도록 요청할 수도 있습니다. 특정 로직 요소를 특정 위치에 배치하도록 요청하는 것도 가능합니다. 이러한 종류의 요청을 플로어플래닝(floorplanning)이라고 합니다. 이러한 요청은 배치 제약 조건(placement constraints)을 통해 이루어지며, 대개 타이밍 제약 조건과 비슷한 문법을 가진 Tcl 명령입니다.

대부분의 경우 배치 제약 조건은 타이밍 제약 조건 달성을 오히려 더 어렵게 만듭니다. 첫 번째 이유는 명백합니다. 플레이서의 선택 폭이 제한되면 그 결과는 제한이 없을 때보다 나빠질 수밖에 없습니다. 하지만 여기에는 더 구체적인 이유가 있습니다.

대부분의 설계에서는 플로어플래닝을 피해서 플레이서가 로직 요소 배치를 자유롭게 최적화하도록 하는 것이 가장 좋습니다. 그러나 배치 제약 조건이 흔히 사용되는 경우도 있습니다. 예를 들면 다음과 같습니다.

타이밍 클로저 관점에서는 배치 제약 조건이 문제의 잠재적 원인이라는 점을 인식하는 것이 중요합니다. 특히 라우팅 지연이 예상보다 크다면, 근본 원인은 플레이서가 로직 요소의 위치를 최적화하지 못했기 때문일 수 있습니다. 플로어플래닝은 배치가 제한된 로직 요소와 무관한 경로에도 부정적인 영향을 줄 수 있음을 기억하세요.

아이디어 #4: 타이밍 제약 조건을 점검하라

타이밍 제약 조건(timing constraints)은 FPGA의 안정적인 동작에 매우 중요합니다. 따라서 프로젝트 구현 전에 이를 검증해야 합니다. 그런데도 타이밍 제약 조건이 잘못된 것으로 드러날 때가 있습니다. 실수는 타이밍 클로저 과정에서 분명해질 수 있습니다. 이런 일은 없어야 하지만, 발생했다면 당연히 문제를 고치는 것이 낫습니다.

타이밍 제약 조건 검증에 관한 전체 페이지가 있습니다. 여기서는 타이밍 클로저 문제로 이어질 수 있는 두 가지 흔한 실수만 다루겠습니다.

먼저 무관한 클록에 대해 말하겠습니다. 클록 도메인 크로싱(clock domain crossing) 주제는 앞서 이미 논의했습니다. 어떤 클록들이 관련 클록(related clocks)이고 어떤 클록들이 그렇지 않은지를 타이밍 제약 조건이 반영하는 것이 왜 중요한지에는 여러 이유가 있습니다. 가장 중요한 이유는 로직의 올바른 동작을 보장하기 위한 것이지만, 타이밍 클로저도 영향을 받습니다. 두 클록 쌍이 툴에서 불필요하게 관련 클록으로 취급되면, 이 두 클록 사이의 경로에 타이밍 요구사항이 불필요하게 적용됩니다. 그 결과 툴은 정말 그 노력이 필요한 경로들을 희생하면서 이 경로들에 힘을 낭비합니다.

이 문제를 해결하는 타이밍 제약 조건은 이 연재의 뒤부분에서 설명합니다.

비동기 리셋에 관해서는, 대부분의 경우 비동기 리셋에서 끝나는 경로에 타이밍 제약 조건을 적용할 필요가 있습니다. 하지만 때로는 그럴 필요가 없습니다. 예를 들어 리셋이 비활성 상태로 바뀔 때 클록이 동작하지 않는다는 보장이 있는 경우입니다. 또 다른 가능성은 비동기 리셋을 받는 플립플롭이 클록 도메인 크로싱 때처럼 타이밍 위반을 막는 보호 메커니즘을 갖춘 경우입니다. 이런 상황에서는 툴이 타이밍 요구사항을 맞추려고 애쓰는 것이 무의미합니다.

이런 종류의 문제가 타이밍 클로저 달성을 어렵게 만든다는 사실을 깨닫기 어려울 수 있습니다. 때로는 임계 경로가 불필요하게 관련 클록으로 취급되는 두 클록과 전혀 관련이 없습니다. 비동기 리셋이 툴의 노력을 다른 곳으로 돌려 놓는다면 그것은 알아차리기가 훨씬 더 어렵습니다. 이런 상황에서는 임계 경로에 집중하여 그 타이밍을 개선하려는 시도가 헛수고가 될 수 있습니다.

물론 타이밍 제약 조건은 다양한 다른 방식으로도 잘못될 수 있습니다. 여기서 설명한 상황은 그중 한 가지 가능성일 뿐입니다. 그러므로 타이밍 문제는 전체적인 타이밍 제약 조건을 다시 검토할 좋은 기회가 될 수 있습니다.

아이디어 #5: 그냥 다시 시도하라

배치 및 배선(place and route) 과정은 로직 요소들을 로직 패브릭 위에 상당히 임의적으로 흩뜨리는 것에서 시작한다는 점을 기억하세요. 그런 다음 툴은 반복적인 시도를 통해 타이밍을 개선합니다. 따라서 이 과정의 성공에는 어느 정도 운이 작용합니다. 또한 배치 및 배선 알고리듬의 동작이 아주 조금만 달라져도 더 나은 결과를 얻을 수 있습니다. 그것이 왜 그런지 논리적으로 설명할 수 없어도 말입니다.

그러므로 타이밍 제약 조건이 실패했는데 음의 슬랙(slack)이 비교적 작다면(총 지연의 약 10~20%), 그냥 다시 시도하는 것만으로 충분할 수 있습니다. 하지만 그냥 구현을 다시 실행하는 것은 아무 도움이 되지 않을 것입니다. 대부분의 FPGA 소프트웨어는 같은 입력으로 실행하면 그 결과를 정확히 반복하도록 설계되어 있기 때문입니다. 따라서 다시 실행하기 전에 무언가를 바꿔야 합니다. 그 변경은 임계 경로와 관련될 필요가 없습니다. 핵심은 이전 구현이 정확히 반복되는 것을 피하는 것입니다.

예를 들어 Vivado에서는 각 실행(run)에 "strategy"라는 속성이 있습니다. 이름이 뜻하듯이 이 속성은 구현 과정에서 툴이 적용하는 전략을 제어합니다. 이 속성을 바꾸면 다음 구현이 이전 구현과 동일해지지 않습니다. 또한 특정 로직 설계에 대해 다른 전략이 더 합리적일 수도 있습니다.

모든 FPGA 툴은 구현 과정의 매개변수를 수정할 수 있는 비슷한 기능을 제공합니다. 설계 목표를 달성하기 위해 더 높은 수준의 노력을 요청할 수 있는 경우가 많습니다. 때로는 정말 더 높은 노력이 필요하지만, 종종 더 높은 노력을 요청하면 툴이 다른 방식으로 동작하기 때문에 도움이 됩니다.

반복을 피하는 또 다른 방법은 Verilog 코드를 변경하는 것입니다. 다시 말하지만, 그 변경은 임계 경로와 관련될 필요가 없습니다. 레지스터 이름을 바꾸는 것만으로도 이전 구현과 충분히 다른 구현을 얻을 수 있는 경우가 있습니다.

이 아이디어는 극단적으로도 활용할 수 있습니다. 여러 대의 컴퓨터에서 각각 매개변수를 조금씩 다르게 하여 구현을 병렬로 실행할 수 있습니다. FPGA의 단가가 중요할 때는 이 방법이 합리적일 수 있습니다. 이 시나리오에서는 더 저렴한 FPGA에서 타이밍 제약 조건을 달성하기 위해 컴퓨터들을 열심히 돌려도 가치가 있습니다.

요약하면, 이 방법은 대부분 운에 의존합니다. 기대치도 그에 맞춰야 합니다. 다시 시도하는 것은 툴이 타이밍 제약 조건을 달성하는 데 가끔 실패할 때만 도움이 됩니다. 하지만 가능하다면 다른 방법으로 타이밍을 개선하는 것이 항상 더 낫습니다.

아이디어 #6: FPGA가 꽉 찼는가?

타이밍 제약 조건에 문제가 생기기 시작하는 시점은 FPGA의 사용률이 약 70%에 도달할 때인 경우가 꽤 흔합니다. 여기에는 세 가지 주요 이유가 있습니다.

위에서 든 세 가지 이유 중 세 번째만이 어느 정도 해결책이 있습니다. 예를 들어 어떤 로직이 FPGA의 블록 RAM이나 그와 비슷한 자원을 사용할지 수동으로 결정하는 것이 도움이 될 수 있습니다. 이 외에 FPGA가 꽉 찬 경우의 유일한 해결책은 더 큰 FPGA를 선택하는 것입니다. 하지만 그것이 항상 가능한 것은 아닙니다. 따라서 로직이 추가될수록 타이밍 클로저가 더 어려워질 것임을 미리 예상하는 것이 중요합니다.

아이디어 #7: 다른 FPGA가 필요할 수도 있다

때로는 해당 FPGA가 그 일을 감당하기에 부족하다는 사실을 인정할 수밖에 없습니다. 같은 FPGA가 더 높은 속도 등급으로 제공된다면, 더 빠른 FPGA로 업그레이드하기로 결정하는 것이 해결책일 수 있습니다. 이 결정은 당연히 구매 비용을 증가시키지만, 예상하지 못한 또 다른 결과도 있을 수 있습니다. 더 높은 속도 등급의 FPGA는 공급이 부족할 수 있습니다. 특정 시점에 이런 더 빠른 FPGA가 풍부하더라도, 수요가 공급을 초과할 때 시장에서 먼저 사라지는 것은 대개 더 빠른 FPGA입니다.

이것은 아주 자연스러운 일입니다. 더 빠른 FPGA는 테스트를 더 잘 통과한 FPGA이므로, 언제나 더 느린 FPGA 대신 사용할 수 있습니다. 때로는 제조사가 더 빠른 FPGA를 생산하지 못하기도 하고, 때로는 자신이 작업할 수 있는 모든 것을 사들이는 대형 소비자가 있기도 합니다.

그러므로 오랜 기간 양산할 제품을 작업하고 있다면, 항상 설계가 동작할 수 있는 가장 낮은 속도 등급을 선호하세요. 돈이 문제가 되지 않을 때도 마찬가지입니다.

완전히 다른 유형의 업그레이드는 더 최근 FPGA 제품군에서 FPGA를 선택하는 것입니다. 아니면 다른 제조업체의 FPGA를 선택할 수도 있습니다. 이 변경은 더 급진적이지만, 프로젝트가 초기 단계라면 고려해 볼 만합니다. 우리는 모두 익숙한 툴과 부품에 애정을 갖게 되는 경향이 있습니다. 하지만 모든 것이 너무 익숙하게 느껴진다면, 대안을 둘러볼 좋은 때입니다.

그렇긴 해도, 경험 많은 FPGA 엔지니어들은 가장 최신의 새 FPGA와 그 툴을 선택하는 것이 위험한 도박이라는 것을 압니다. 하지만 대개는 현재 선택한 FPGA보다 훨씬 나은, 꽤 검증된 대안이 있습니다. 그런 상황이라면 안전지대에서 벗어나 새로운 것을 시도하는 것이 좋습니다.

아이디어 #8: 온도 범위를 줄여라

이 가능성을 거의 마지막에 둔 데에는 이유가 있습니다. 이것은 모든 해결책 중 가장 지저분한 방법입니다. 하지만 때로는 다른 선택지가 없습니다.

기본적으로 툴이 타이밍 제약 조건을 적용하는 것은 FPGA가 데이터시트에 정의된 전체 온도 범위에서 안정적으로 동작함을 보장하기 위한 것입니다. 일부 FPGA 툴은 프로젝트에 다른 온도 범위를 선택하도록 허용합니다(예: Quartus에는 "MAX_CORE_JUNCTION_TEMP"라는 속성이 이 목적에 쓰입니다). 이것은 전체 온도 범위를 지원할 필요가 없다는 것을 툴에 알리는 데 사용할 수 있습니다.

일반적으로 FPGA의 로직 요소 지연은 온도가 올라갈수록 증가합니다. 최대 온도를 낮추면 타이밍 계산에서 지연 값이 더 작아집니다. 그러면 툴이 tsetup 요구사항을 달성하기가 더 쉬워집니다. 때로는 이것이 툴이 타이밍 제약 조건을 달성하게 만드는 유일한 방법입니다.

이 방법을 사용할 때의 위험을 이해하는 것이 중요합니다. 특히, 여기서 말하는 것은 접합 온도(junction temperature)라는 점에 유의하세요. 다시 말해 FPGA의 실리콘 칩 위의 온도입니다. 이것은 주변 온도(ambient temperature)가 아닙니다.

따라서 최대 온도가 85°C라고 해서 FPGA가 그 온도의 오븐 안에서 동작한다는 뜻은 아닙니다. 그 온도는 실온(25°C)에서도 도달할 수 있습니다. 특히 FPGA에 방열판이 없으면 그렇습니다. 접합부의 온도와 주변 온도 사이에는 항상 차이가 있습니다. 그 차이의 크기는 FPGA의 전력 소비와 냉각 방식에 따라 달라집니다.

상용 제품을 만든다면 FPGA의 주변 온도가 실온보다 크게 높아질 수 있다는 점에 유의하세요. 특히 FPGA가 공기 흐름이 나쁜 상자 안에 있으면, 상자 내부의 온도는 상자 외부의 온도보다 훨씬 올라갈 수 있습니다. 더 나쁘게도 대부분의 전자 제품은 약 0°C에서 40°C 사이의 온도에서 동작할 것으로 기대됩니다(대략적인 수치이며 제품마다 다릅니다). 따라서 최종 제품이 최고 온도에서 테스트될 때, 그리고 FPGA가 제품의 외함 안에 있을 때, 접합부의 온도는 얼마일까요? 그것이 물어야 할 질문입니다. 타이밍 계산은 그 온도(또는 그보다 높은 온도)를 기준으로 해야 합니다.

다시 말해, 타이밍 제약 조건을 달성하기 위해 최대 온도를 줄였고 실험실에서 모든 것이 잘 동작한다면, 그것은 아무 의미가 없습니다. 타이밍 제약 조건과 관련해서 FPGA 설계가 실험실에서 동작하는 것은 언제나 아무 의미가 없다는 점을 기억하세요. 하지만 최대 온도를 줄이는 것은 이런 관점에서 훨씬 더 나쁩니다. 온도 범위를 무심코 좁히는 것은 진짜 문제를 초대하는 것일 수 있습니다. 양산 전 최종 테스트는 최고 온도에서 수행되는데, 그것이 실패할 수 있고, 온도 범위를 다시 바로잡으면 타이밍 제약 조건을 달성하는 것이 불가능해질 수 있습니다. 이 문제를 해결하는 유일한 방법은 FPGA 설계를 처음부터 다시 작성하는 것입니다.

그러니 타이밍 클로저를 위해 온도 범위를 바꾸기 전에, 그렇게 해도 안전한지 확실히 하세요. 가능한 모든 동작 조건에서 접합부의 온도 범위를 엄격하게 평가하세요.

구현 매개변수를 변경해도 기본 온도 범위를 넘어서까지 확장하는 것은 불가능하다는 점에 유의하세요. 툴의 기본 온도 범위는 항상 데이터시트에 명시된 것과 같습니다. 따라서 이 기본 온도 범위를 넘어서는 FPGA의 안정적인 동작을 보장할 수는 없습니다.

아이디어 #9: 정렬되지 않은 관련 클록

이것은 다소 난해한 상황이며 이해하기도 조금 어렵습니다. 그래서 이 주제를 마지막에 두었습니다.

정렬되지 않은(un-aligned) 두 관련 클록 사이에 클록 도메인 크로싱이 있다고 가정해 보겠습니다. 다시 말해 두 클록이 같은 기준 클록에서 파생되었지만, 이 클록들 사이의 클록 스큐(clock skew)를 제어하는 메커니즘이 없는 상황입니다.

그 결과 툴이 이 두 클록 사이의 경로에 대한 타이밍 요구사항을 충족시키기가 더 어려워집니다. 두 가지 종류의 어려움이 있을 수 있습니다(tsetup과 thold앞서 설명했습니다).

툴이 이러한 어려움을 극복하기 위해 평소보다 더 열심히 일해야 할 때, 그 희생으로 다른 경로의 최적화가 소홀해질 수 있다는 점을 주목하는 것이 중요합니다.

하지만 정렬되지 않은 관련 클록은 오류가 아니며 때로는 불가피합니다. 이 상황은 단지 툴이 더 열심히 일해야 한다는 뜻일 뿐입니다. 타이밍 제약 조건이 달성되었다면 설계에 문제가 없는 것입니다. 그렇지만 합리적인 노력으로 피할 수 있다면 언제나 피해야 합니다.

위의 "아이디어 #4"에서 언급한 실수는 이와 다릅니다. 둘 다 툴을 불필요하게 힘들게 만들고 둘 다 클록 도메인 크로싱과 관련이 있지만, 성격이 다릅니다.

정렬되지 않은 관련 클록 상황을 해결하는 가장 좋은 방법은 이 클록들을 정렬하는 것입니다. 이는 대개 PLL을 추가하거나 기존 PLL에 클록 출력을 추가함으로써 이루어집니다. 목표는 문제의 두 클록이 모두 같은 PLL의 출력이 되도록 하는 것입니다.

또 다른 가능한 해결책은 두 클록을 무관한 클록으로 취급하는 것입니다. 이것은 로직 설계 자체의 변경과 타이밍 제약 조건의 변경을 모두 필요로 합니다. 그렇게 하는 것이 너무 어렵지 않다면 노력할 가치가 있습니다. 이 주제는 나중에 더 자세히 다룹니다.

이제 정렬되지 않은 관련 클록 사이의 클록 도메인 크로싱 예를 살펴보겠습니다.

   wire       pll_clk;

   reg [24:0] result;
   reg [11:0] x, y, x1, y1;

   clk_wiz_0 pll_i
   (.clk_in1(clk),
    .clk_out1(pll_clk));

   always @(posedge clk)
     begin
	x1 <= x;
	y1 <= y;
     end

   always @(posedge pll_clk)
     result <= x1 * y1;

PLL(clk_wiz_0)이 있다는 점에 주목하세요. 이 PLL은 @clk를 기준 클록으로 사용하며, @clk의 주파수는 250MHz입니다. 이것은 이전 페이지 맨 위의 예에서 보여 준 것과 같은 PLL입니다. @pll_clk의 주파수는 125MHz입니다.

이 예에서 중요한 부분은 두 관련 클록(@clk와 @pll_clk) 사이의 클록 도메인 크로싱입니다. PLL이 생성한 클록은 @pll_clk뿐이므로 이 두 클록은 정렬되어 있지 않습니다. 따라서 @result로 가는 경로(@x1과 @y1에서 오는)에는 클록 스큐가 있습니다. 이 클록 스큐에도 불구하고 두 클록은 여전히 관련 클록이며, 툴은 타이밍 요구사항을 충족시키려고 시도할 것입니다.

만약 @clk를 사용하는 유일한 이유가 250MHz 주파수의 클록이 필요하기 때문이라면, 올바른 해결책은 PLL로 다른 클록을 하나 더 생성하는 것입니다. 기준 클록과 같은 주파수의 클록을 만드는 것은 자원 낭비가 아닙니다. 반대로 그렇게 하면 툴의 수고를 크게 덜어 줍니다. 예제처럼 @clk를 직접 사용하는 데는 딱 하나 좋은 이유가 있습니다. @clk를 사용하는 로직이 PLL이 동작 가능한 클록을 만들기 전에 작동해야 하는 경우입니다.

Vivado가 생성한 타이밍 리포트는 다음과 같습니다. 이 특정 사례에서는 tsetup 요구사항에만 문제가 있었습니다.

Slack (VIOLATED) :        -1.456ns  (required time - arrival time)
  Source:                 x1_reg[7]/C
                            (rising edge-triggered cell FDRE clocked by clk  {rise@0.000ns fall@2.000ns period=4.000ns})
  Destination:            result_reg/DSP_OUTPUT_INST/ALU_OUT[10]
                            (rising edge-triggered cell DSP_OUTPUT clocked by clk_out1_clk_wiz_0  {rise@0.000ns fall@4.000ns period=8.000ns})
  Path Group:             clk_out1_clk_wiz_0
  Path Type:              Setup (Max at Slow Process Corner)
  Requirement:            4.000ns  (clk_out1_clk_wiz_0 rise@8.000ns - clk rise@4.000ns)
  Data Path Delay:        3.012ns  (logic 2.677ns (88.878%)  route 0.335ns (11.122%))
  Logic Levels:           5  (DSP_A_B_DATA=1 DSP_ALU=1 DSP_M_DATA=1 DSP_MULTIPLIER=1 DSP_PREADD_DATA=1)
  Clock Path Skew:        -2.192ns (DCD - SCD + CPR)
    Destination Clock Delay (DCD):    0.998ns = ( 8.998 - 8.000 )
    Source Clock Delay      (SCD):    3.202ns = ( 7.202 - 4.000 )
    Clock Pessimism Removal (CPR):    0.012ns
  Clock Uncertainty:      0.148ns  ((TSJ^2 + DJ^2)^1/2) / 2 + PE
    Total System Jitter     (TSJ):    0.071ns
    Discrete Jitter          (DJ):    0.103ns
    Phase Error              (PE):    0.086ns
  Clock Net Delay (Source):      1.414ns (routing 0.002ns, distribution 1.412ns)
  Clock Net Delay (Destination): 1.184ns (routing 0.002ns, distribution 1.182ns)
  Clock Domain Crossing:  Inter clock paths are considered valid unless explicitly excluded by timing constraints such as set_clock_groups or set_false_path.

    Location             Delay type                Incr(ns)  Path(ns)    Netlist Resource(s)
  -------------------------------------------------------------------    -------------------
                         (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.738     4.738 r  clk_IBUF_inst/INBUF_INST/O
                         net (fo=1, routed)           0.105     4.843    clk_IBUF_inst/OUT
    AG12                 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O)
                                                      0.049     4.892 r  clk_IBUF_inst/IBUFCTRL_INST/O
                         net (fo=1, routed)           0.795     5.687    clk_IBUF
    BUFGCE_X1Y2          BUFGCE (Prop_BUFCE_BUFGCE_I_O)
                                                      0.101     5.788 r  clk_IBUF_BUFG_inst/O
    X2Y0 (CLOCK_ROOT)    net (fo=62, routed)          1.414     7.202    clk_IBUF_BUFGCE
    SLICE_X52Y45         FDRE                                         r  x1_reg[7]/C
  -------------------------------------------------------------------    -------------------
    SLICE_X52Y45         FDRE (Prop_HFF_SLICEM_C_Q)
                                                      0.138     7.340 f  x1_reg[7]/Q
                         net (fo=1, routed)           0.335     7.675    result_reg/A[7]
    DSP48E2_X8Y18        DSP_A_B_DATA (Prop_DSP_A_B_DATA_DSP48E2_A[7]_A2_DATA[7])
                                                      0.396     8.071 r  result_reg/DSP_A_B_DATA_INST/A2_DATA[7]
                         net (fo=1, routed)           0.000     8.071    result_reg/DSP_A_B_DATA.A2_DATA<7>
    DSP48E2_X8Y18        DSP_PREADD_DATA (Prop_DSP_PREADD_DATA_DSP48E2_A2_DATA[7]_A2A1[7])
                                                      0.182     8.253 r  result_reg/DSP_PREADD_DATA_INST/A2A1[7]
                         net (fo=1, routed)           0.000     8.253    result_reg/DSP_PREADD_DATA.A2A1<7>
    DSP48E2_X8Y18        DSP_MULTIPLIER (Prop_DSP_MULTIPLIER_DSP48E2_A2A1[7]_U[10])
                                                      0.994     9.247 f  result_reg/DSP_MULTIPLIER_INST/U[10]
                         net (fo=1, routed)           0.000     9.247    result_reg/DSP_MULTIPLIER.U<10>
    DSP48E2_X8Y18        DSP_M_DATA (Prop_DSP_M_DATA_DSP48E2_U[10]_U_DATA[10])
                                                      0.164     9.411 r  result_reg/DSP_M_DATA_INST/U_DATA[10]
                         net (fo=1, routed)           0.000     9.411    result_reg/DSP_M_DATA.U_DATA<10>
    DSP48E2_X8Y18        DSP_ALU (Prop_DSP_ALU_DSP48E2_U_DATA[10]_ALU_OUT[10])
                                                      0.803    10.214 r  result_reg/DSP_ALU_INST/ALU_OUT[10]
                         net (fo=1, routed)           0.000    10.214    result_reg/DSP_ALU.ALU_OUT<10>
    DSP48E2_X8Y18        DSP_OUTPUT                                   r  result_reg/DSP_OUTPUT_INST/ALU_OUT[10]
  -------------------------------------------------------------------    -------------------

                         (clock clk_out1_clk_wiz_0 rise edge)
                                                      8.000     8.000 r
    BUFGCE_X1Y2          BUFGCE                       0.000     8.000 r  clk_IBUF_BUFG_inst/O
                         net (fo=62, routed)          1.078     9.078    pll_i/inst/clk_in1
    MMCME3_ADV_X1Y0      MMCME3_ADV (Prop_MMCME3_ADV_CLKIN1_CLKOUT0)
                                                     -1.777     7.301 r  pll_i/inst/mmcme3_adv_inst/CLKOUT0
                         net (fo=1, routed)           0.422     7.723    pll_i/inst/clk_out1_clk_wiz_0
    BUFGCE_X1Y0          BUFGCE (Prop_BUFCE_BUFGCE_I_O)
                                                      0.091     7.814 r  pll_i/inst/clkout1_buf/O
    X2Y0 (CLOCK_ROOT)    net (fo=6, routed)           1.184     8.998    result_reg/CLK
    DSP48E2_X8Y18        DSP_OUTPUT                                   r  result_reg/DSP_OUTPUT_INST/CLK
                         clock pessimism              0.012     9.010
                         clock uncertainty           -0.148     8.862
    DSP48E2_X8Y18        DSP_OUTPUT (Setup_DSP_OUTPUT_DSP48E2_CLK_ALU_OUT[10])
                                                     -0.104     8.758    result_reg/DSP_OUTPUT_INST
  -------------------------------------------------------------------
                         required time                          8.758
                         arrival time                         -10.214
  -------------------------------------------------------------------
                         slack                                 -1.456

이 리포트는 툴이 타이밍 제약 조건을 달성하지 못했음을 보여 줍니다. 표시된 경로는 @clk의 상승 엣지인 4ns에서 시작하여 @pll_clk의 상승 엣지인 8ns에서 끝납니다. 문제는 입력 핀의 클록이 첫 번째 플립플롭의 클록 입력 핀에 도달하는 데 걸리는 시간이 3.2ns라는 점입니다. 따라서 이 클록 엣지의 도착 시각은 7.2ns입니다.

그런데 @pll_clk은 PLL이 생성하므로 이 클록은 @clk의 입력 핀에 정렬되어 있습니다. 따라서 그 지연은 1.0ns에 불과합니다. @pll_clk이 두 번째 플립플롭에 도착하는 시각은 따라서 9.0ns입니다. 데이터 경로에 남은 시간은 9.0 – 7.2 = 1.8ns입니다(클록 불확실성 등 때문에 대략적인 값입니다). 이것은 전용 산술 유닛을 사용하더라도 산술 곱셈을 수행하기에 충분하지 않습니다. 따라서 타이밍 요구사항을 충족할 수 없었습니다.

이 예에서는 클록 스큐 때문에 클록이 첫 번째 플립플롭에 늦게 도착합니다. 그 결과 tsetup 요구사항을 충족하지 못했습니다.

참고로 이것은 @pll_clk의 정렬을 조정하여 해결할 수 있습니다. 예를 들어 PLL의 기준 클록으로 @clk를 분배하는 글로벌 클록 버퍼의 출력을 사용할 수 있습니다. 더 나은 정렬을 얻기 위해 PLL의 위상 변이(phase shift)를 정의하는 것도 가능합니다. 그러나 이것들은 최후의 수단으로만 사용해야 하는 해결책입니다.

요약

다시 말하지만, 이것들은 타이밍 클로저 문제를 해결하는 데 도움이 될 수 있는 몇 가지 아이디어에 불과합니다. 안타깝게도 이런 종류의 문제를 해결하려면 그것보다 훨씬 많은 것이 필요할 수 있습니다. 사실 FPGA 분야에는 타이밍 클로저와 어떤 식으로든 관련되지 않은 주제가 하나도 없습니다.

이미 말했듯이, 가장 좋은 전략은 처음부터 로직 설계를 신중하게 작성하는 것입니다. 타이밍 클로저를 다루는 가장 좋은 방법은 애초에 타이밍 클로저가 필요 없게 만드는 것입니다.


지금까지 이 연재는 타이밍에 대해 논의했지만 타이밍 제약 조건 자체에 대해서는 많이 말하지 않았습니다. 이제 그것이 바뀔 것입니다: 다음 페이지부터는 논의가 더 기술적으로 변합니다.

이 페이지는 영어 원문을 기계 번역한 것입니다. 의문이 드는 부분이 있으면 원문을 참조하시기 바랍니다.
Copyright © 2021-2026. All rights reserved. (dcc38493)