01signal.com

제대로 된 FPGA 설계를 위한 황금 규칙

들어가며

FPGA 설계자가 되려면 다양한 기술이 필요하며, 그걸 한 페이지에 다 요약할 수는 없다. 하지만 이 직업에서 특히 중요하게 적용되는 몇 가지 일반 지침이 있다. 그 지침을 FPGA 설계의 다섯 가지 황금 규칙으로 정리해 봤다.

규칙 #1: 지금 무엇을 하고 있는지 알아야 한다

이 첫 번째 규칙은 가장 지키기 어렵다. 코드 한 줄, 제약 조건(constraint) 하나, 설정 명령 하나가 각각 무엇을 의미하고 어떤 결과를 가져오는지 이해하는 일이다. 논리 설계의 기저 이론과, 설계 도구가 우리가 입력한 내용에 어떻게 반응하는지 이해하는 것이기도 하다.

이는 시행착오(trial and error) 방식과는 정반대되는 태도다. 그런데 모든 하이테크 개발 도구 업체들은 디버거, 시뮬레이터, 그리고 '쉽게 할 수 있어요'라고 광고되는 수많은 도구를 제공하면서 시행착오 방식을 암묵적으로 부추기기도 한다.

사실 소프트웨어 개발은 이렇게 하는 경우가 드물지 않다. 대충 코드를 끼적거려 보고, 디버거로 테스트 실행을 해 보고, 결과를 확인한 다음, 고치고 다시 반복한다. 그 사이에 인터넷 예제에서 찾은 코드 조각을 그대로 복사해 붙이는 일도 있다. 이런 반복적 작업 방식은 웹사이트나 스마트폰 앱 개발 같은 단순한 소프트웨어에서는 꽤 생산적일 수 있다. 작은 버그는 그리 심각하지 않고, 나타나면 그때그때 고치면 된다는 것이 흔한 태도이기 때문이다.

하지만 소프트웨어가 정교해질수록 이런 방식은 더 빨리 막다른 길에 부딪힌다. FPGA 설계에 있어서라면, 반복적인 개발 방식은 빠르고 강하게 되갚아주기 마련이다. FPGA 설계 도구는 심각한 실수를 막아주거나 경고해 주는 데 전혀 도움이 되지 않는다. 완전히 엉망으로 만들어도 좋다. 도구가 결코 방해하지 않을 테니.

규칙 #2: 동작을 보장하라

혹은: '동작한다'는 말만으로는 충분하지 않다.

FPGA는 컴퓨터가 아니라 전자 장치다. 그렇지만 특정 설계 원칙을 따른다면(규칙 #1 참고) 언제나 똑같이 동작하는 믿을 수 있는 장치가 된다. 그 원칙을 따르지 않으면 이유가 있든 없든 아주 교묘하게 문제를 일으킬 수 있다.

눈에 보이는 버그가 없다고 해서 문제가 없다는 뜻은 아니다. 이는 어느 분야에서나 마찬가지다. 배관공이 일을 마쳤을 때 지금 당장 수도관에서 물이 새지 않는다고 해도, 그 일을 제대로 했다고 보장할 수는 없다. 나중에 수압이 올라가거나 누군가 실수로 건드리기라도 하면 물이 새기 시작할 수 있다.

그런데도 우리는 모두 짧은 테스트든 조금 더 긴 테스트든 한 번 해 보고 모든 게 괜찮아 보이면 '됐다'고 넘어가는 함정에 빠지곤 한다. 물이 새는 수도관 정도의 일이라면, 그리고 단순한 웹사이트나 중요한 응용 분야가 아닌 소프트웨어를 개발하는 중이라면 그런 태도가 꽤 용납될 수도 있다. 하지만 FPGA에서는 그런 수준으로는 충분하지 않다.

FPGA용 설계를 개발한다는 것은 그 설계가 반드시 동작하리라는 것을 보장하는 일이다. 설계 도구가 바로 그 목적을 위해 제공하는 기법들을 활용해서, 도구가 절대 실패하지 않는 비트스트림(bitstream)을 만들도록 강제하는 일이기도 하다.

또한 '이런 일이 생기면 이렇게 하자'는 식으로 생각하는 대신, 수학적 증명처럼 논리 설계가 올바르다는 증명을 스스로에게 해 보는 것이다. 논리는 아주 기괴한 코너 케이스(corner case)에서도 동작해야 한다. 그런 경우들을 하나하나 따로 고려했기 때문이 아니라, 올바른 수학 표현식이 어떤 상황에서도 참인 것과 같은 이유로 동작해야 한다.

결국 잘 동작한다는 사실은 축하할 일이 아니다. 그것은 올바르게 작업했을 때 자연스럽게 나오는 결과다.

규칙 #3: 현명하게 시뮬레이션하라(또는 아예 하지 마라)

FPGA 초보자들이 가장 흔히 하는 불만 중 하나는 '시뮬레이션은 완벽하게 동작하니까 설계는 문제없고, 그럼 문제는 분명히 다른 데 있다'는 것이다. 물론 말도 안 되는 소리다.

먼저, 가장 중요한 사실을 분명히 해 두자. Verilog 코딩 스타일이 몇 가지 엄격한 규칙을 따르지 않으면 시뮬레이션과 실제 하드웨어는 완전히 다르게 동작할 수 있다. VHDL도 물론 마찬가지다. 규칙 #1을 보라.

게다가 시뮬레이션은 제대로 수행하더라도 다루는 시간과 시나리오가 제한적이다. 중간 규모 설계만 해도 FPGA 내부에서 예컨대 100 ms 동안 일어나는 일을 시뮬레이션하려면 엄청나게 오랜 시간이 걸린다. 그뿐 아니라 하드웨어에서 실제로 설계를 돌려 보면 설계자가 상상하지 못했고, 그래서 시뮬레이션하지도 못한 시나리오에 논리가 노출되기도 한다. 시뮬레이션을 완벽하게 통과한 설계가 하드웨어에서 처참하게 실패할 수 있는 것은 바로 그런 이유 때문이다. FPGA가 시뮬레이션으로 확인한 범위보다 훨씬 오래 동작하거나, 예상하지 못한 일이 실제로 일어났기 때문이다.

설상가상으로 하드웨어에서는 모든 것이 병렬로 일어나기 때문에 버그를 찾기가 어렵다. 소프트웨어 디버깅과 달리 따라갈 수 있는 이벤트 순서가 거의 없을뿐더러, 단일 스텝(single-step)으로 진행할 수 있는 여지는 더더욱 없다. 물론 FPGA 내부 신호를 추적하는 도구가 있기는 하다. 하지만 어떤 신호를 추적할지, 추적 데이터를 수집하기 위한 트리거(trigger) 조건을 무엇으로 할지 파악하는 것은 항상 쉽지 않다.

그러므로 시뮬레이션을 되도록 적게 쓰는 것을 목표로 삼아라. 설계를 '동작하게 만들기' 위해 시뮬레이션을 오가며 수정을 반복하고 있다면, 하드웨어에서 시도할 때 문제가 생길 확률이 높다.

대신 FPGA 설계가 처음부터 완벽하게 동작하도록 작성하려고 노력하라. 그러려면 코드의 첫 줄을 쓰기 전에 충분히 생각해 봐야 하고, 자기가 무엇을 하고 있는지도 알아야 한다(위 규칙 #1). 시뮬레이션은 설계를 제대로 했는지 확인하거나, 어쩌다 만든 사소한 오타를 찾아내는 역할이면 충분하다. 이 목표에 도달하는 것은 배움과 개선의 과정이지만, 그만한 값어치가 있다. 결국 시뮬레이션은 고칠 것을 찾아내지 못하기 때문에 시간 낭비가 된다.

이렇게 하면 시간이 절약될 뿐 아니라, 하드웨어에서 고쳐야 할 버그도 더 적어지고 찾기도 쉬워진다.

FPGA 설계의 흔한 첫 수업이 '먼저 시뮬레이션하고, 그다음에 하드웨어에서 돌려보자'라는 것임을 잘 알고 있다. 하지만 그건 첫 수업까지나 통하는 방식이다.

규칙 #4: 운에 기대지 마라

혹은: 이미 검증된 코딩 스타일을 고수하라.

합성에 사용될 때 Verilog는 프로그래밍 언어가 아니다. 가장 큰 차이점은 이렇다. 어떤 프로그래밍 언어에서건 문법적으로 올바른 코드를 작성하면, 컴파일러(또는 인터프리터)는 그 문법이 뜻하는 바를 정확히 실행하도록 보장한다. 최악의 경우에도 오류를 보고한다.

반면 합성 도구(synthesizer)는 제한된 논리 요소 집합을 바탕으로 논리를 생성한다. 따라서 Verilog 코드를 작성할 때, 그 결과로 신뢰할 수 없는 논리가 만들어지거나, 애초에 FPGA에 구현할 수 없는 코드가 될 가능성도 아주 쉽게 생긴다. 설상가상으로, Verilog 코드를 FPGA의 논리로 구현할 방법이 없을 때 합성 도구는 흔히 원래 의도와 다른 동작을 하는 논리를 만들어 낸다. 그리고 아주 자주, 경고 하나 없이 그렇게 해 버린다. 다시 말해 FPGA의 논리가 기대한 동작, 즉 시뮬레이션한 동작과 다르게 굴러가는데, 그 과정에서 아무런 경고도 발생하지 않는다.

게다가 합성 도구의 버그는 컴파일러의 버그보다 훨씬 흔하다. 창의적인 코딩 스타일은 그런 버그를 얼마든지 드러나게 할 수 있다.

물론 위에서 말한 모든 내용은 VHDL에도 그대로 적용된다.

따라서 이런 문제를 피할 수 있는 유일한 방법은 다른 사람들이 널리 쓰는 코딩 스타일을 채택하는 것이다. 마음에 새겨 둘 질문은 '이 코드 조각 때문에 합성 도구가 헷갈린다면, 나 말고도 얼마나 많은 사람이 피해를 볼까?'이다. 답이 '아주 많은 사람들'이라면 안전한 쪽에 있는 것이다.

검증된 코딩 스타일을 고수하면 또 하나의 장점, 이식성(portability)이 따라온다. 좋든 싫든 오늘은 한 합성 도구로 작업하다가, 내일은 완전히 다른 FPGA와 다른 개발 도구를 쓰게 될 수도 있다.

검증된 코딩 스타일이 어떤 모습인지 감을 잡으려면, 도구에 내장된 IP 코어(IP core)를 위해 도구가 생성해 주는 Verilog 코드를 살펴보라. 코드를 작성한 주체에 따라 스타일 차이가 조금 있겠지만, 다른 것보다 유독 자주 보이는 코딩 패턴이 있다. 바로 그런 패턴을 따라 하면 된다.

말할 필요도 없이 RTL 패러다임에 따라 작업해야 한다. 그것은 단지 검증된 코딩 스타일이라는 이유만이 아니라, FPGA 도구가 바로 그런 입력을 기대한다는 이유에서도 중요하다.

Verilog 관련 교과서나 튜토리얼은 오히려 혼란을 줄 수 있다. 그것들은 보통 모든 내용을 빠짐없이 다루려고 하기 때문이다. 그래서 문법적으로는 맞지만 실제로는 거의 쓰이지 않고, 때로는 합성에 부적합한 수많은 가능성을 설명하게 된다.

규칙 #5: 타이밍이 전부다

논리 설계는 소프트웨어 프로그래밍이 아니다. Verilog의 wire와 레지스터에 올바른 값이 들어가기만 하면 되는 게 아니다. 그 값이 올바른 장소에 올바른 시각에 나타나는 것이 그 못지않게 중요하다. 클록이 올바르게 처리되는 문제도 마찬가지로 중요하다.

핵심 주제는 대략 다음과 같다.

요컨대 논리 설계는 컴퓨터 프로그램과 달리 무슨 일이 일어날지뿐만 아니라, 그 일이 언제 일어날지도 중요하다.

요약

누구도 FPGA 설계가 쉽다고 말하지 않았다. 이 다섯 가지 규칙 역시 어느 하나도 지키기 쉽지 않다. 각 규칙은 지식과 일정 수준의 자기 훈련을 요구한다. 그런데도 이 규칙들을 지키려는 노력은 충분히 가치가 있다. 그렇게 하면 특히 프로젝트의 막바지, 모든 것이 그냥 동작해 주기를 기대하는 마지막 단계에서 겪게 되는 좌절을 크게 줄일 수 있다.

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