들어가며
FPGA 에서는 모든 I/O 포트가 로직 패브릭(logic fabric) 위에 자신만의 작은 영역을 가집니다. 이 영역을 IOB(Input / Output Block)라고 부르며, 해당 I/O 포트의 기능을 지원하는 데 필요한 모든 것, 즉 I/O 핀의 전압과 전류를 정확하게 유지하는 아날로그 회로와 몇 가지 특수 논리 요소가 들어 있습니다.
참고로 "IOB"라는 용어는 AMD(구 Xilinx)가 쓰는 용어입니다. FPGA 제조사마다 이 영역을 부르는 이름이 다릅니다.
IOB 내부에는 거의 항상 IOB 레지스터(register)가 있습니다. 이 레지스터는 I/O 포트의 핀에 직접 연결된 플립플롭(flip-flop)입니다.
일부 플립플롭은 핀이 입력 포트로 사용될 때 쓰입니다. 이 플립플롭들의 D 입력은 I/O 포트의 핀에 연결되어 있습니다. 따라서 이런 플립플롭은 외부에서 들어오는 신호를 샘플링(sampling)합니다.
다른 플립플롭은 핀이 출력 포트로 사용될 때 전용으로 쓰입니다. 이 플립플롭들의 Q 출력은 핀에 연결됩니다.
IOB 의 구조는 FPGA 마다 다릅니다. 어떤 IOB 는 기능이 풍부하고 복잡한 반면, 어떤 IOB 는 비교적 단순한 구조를 가집니다. 또한 IOB 레지스터는 흔히 SERDES 같은 더 큰 논리 요소에 포함되어 있는 경우도 많습니다. 따라서 FPGA 문서의 IOB 설명 그림에 플립플롭이 명시적으로 그려져 있지 않더라도, 해당 FPGA 의 I/O 핀에는 IOB 레지스터가 존재할 수 있습니다.
IOB 레지스터를 사용해야 하는 이유
IOB 레지스터를 사용하는 가장 큰 동기는 타이밍 때문입니다. 이 레지스터가 I/O 포트의 핀과 매우 가까이 있기 때문에, 이렇게 구성했을 때의 clock-to-output 지연은 다른 어떤 방법으로도 따라잡을 수 없을 만큼 좋습니다. 입력 포트의 경우에도 IOB 레지스터라야 요구되는 타이밍을 달성할 가능성이 가장 높습니다.
하지만 타이밍 요구사항을 충족하기 쉬운 상황에서도 IOB 레지스터를 고집해야 할 좋은 이유가 하나 더 있습니다. 바로 반복성(repeatability)입니다. IOB 레지스터를 사용하지 않으면 I/O 포트의 핀과 플립플롭 사이의 지연이 FPGA 프로젝트를 구현할 때마다 달라질 수 있습니다. 합성/구현 도구는 플립플롭을 매번 다른 위치에 배치할 수 있고, 타이밍 제약 조건(timing constraints)을 만족하는 한 라우팅 지연(routing delay)도 바꿀 수 있기 때문입니다. PCB 설계가 올바르고 외부 부품과의 인터페이스가 제대로 계획되어 있다면 이런 차이는 문제가 되지 않습니다. 하지만 그러한 설계/인터페이스 문제가 실제로 존재한다면, 구현할 때마다 지연이 조금씩 달라져서 혼란스러울 수 있습니다. 예를 들어, 무언가가 동작하지 않아서 설계의 어딘가를 고쳤더니 문제가 해결된 것처럼 보이는데, 실제로 차이를 만든 것은 어딘가의 I/O 타이밍이 미세하게 바뀐 것일 수 있습니다.
IOB 레지스터를 사용하면 FPGA 내부 로직을 개발하는 과정에서 외부 부품과의 전기적 인터페이스가 의도치 않게 변하지 않도록 보장할 수 있습니다. 문제가 발생했을 때 원인을 분리하기도 훨씬 쉬워집니다.
IOB 레지스터 사용 요청하기
경우에 따라서는 FPGA 도구에 IOB 레지스터를 사용하라고 명시적으로 알려 주어야 합니다. 이 작업은 주로 합성 도구(synthesizer)가 담당하므로, Vivado 에서는 다음과 같은 합성 속성(synthesis attribute)을 사용할 수 있습니다.
(* IOB = "TRUE" *) input the_input,
XDC 파일에서도 같은 설정을 할 수 있습니다.
set_property IOB true [get_ports the_input]
또 다른 방법은 입력에 연결된 레지스터에 합성 속성을 추가하는 것입니다.
(* IOB = "TRUE" *) reg the_input_samp;
XDC 파일에 넣는 속성만으로는 부족할 수 있다는 점에 유의해야 합니다. IOB 안에 플립플롭을 배치하려면 합성 도구가 레지스터를 복제해야 하는 경우가 많습니다. 이는 플립플롭의 출력이 FPGA 내부의 일반 로직에서도 사용될 때 필요한 작업입니다. IOB 안에 있는 플립플롭의 출력은 해당 포트를 위해서만 쓸 수 있기 때문에, 같은 출력을 로직 패브릭(logic fabric) 쪽에서도 사용하려면 플립플롭을 하나 더 만들어야 합니다. 이런 상황에서는 위에 보인 것과 같은 합성 속성이 필요한 경우가 많습니다.
Quartus 에서는 QSF 파일에 다음과 같은 명령을 추가하면 됩니다.
set_instance_assignment -name FAST_INPUT_REGISTER ON -to the_input set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to the_output
이 기능을 설정하는 방법은 도구마다 조금씩 다릅니다.
타이밍 제약 조건
IOB 레지스터를 사용하는 포트에 타이밍 제약 조건(timing constraints)을 작성할 이유가 있을까요? 어차피 IOB 레지스터가 놓일 수 있는 위치는 하나뿐입니다. 그렇다면 타이밍 제약 조건을 쓰든 쓰지 않든 타이밍은 항상 같다고 생각해도 안전할까요?
사실 IOB 레지스터를 사용하더라도 타이밍 제약 조건을 작성해야 할 이유는 크게 두 가지입니다.
첫 번째 이유는 IOB 레지스터가 실제로 사용되도록 보장하기 위함입니다. 가끔은 로직 설계를 변경하는 과정에서 의도치 않게 모든 포트 또는 일부 포트에 IOB 를 사용하지 못하게 될 수 있습니다. 이런 일이 생겨도 도구가 경고를 해 주는 경우는 거의 없습니다. 대신 IOB 안에 있지 않은 플립플롭이 조용히 사용됩니다. 타이밍 제약 조건은 이런 상황을 막아 줍니다. 관련된 모든 플립플롭이 각자의 IOB 안에 있을 때만 타이밍 제약 조건을 만족할 수 있게 해 두면, 플립플롭이 IOB 밖으로 밀려나도 조용히 넘어가지 않습니다. 제약 조건을 위반하게 되기 때문입니다.
두 번째 이유는 도구가 I/O 포트 핀과 IOB 레지스터 사이에 의도적인 지연을 추가할 수 있기 때문입니다(물론 이 기능을 지원하지 않는 FPGA 가 있습니다). 이 지연은 thold 와 관련된 타이밍을 개선하기 위해 추가됩니다(Quartus 에서의 예 참조). 이런 바람직하지 않은 조작은, 추가 지연이 없을 때만 만족할 수 있는 타이밍 제약 조건을 설정해 두면 막을 수 있습니다.
IOB 레지스터가 일관되게 사용되도록 보장하는 데에는 보통 set_max_delay 명령이 적합한 타이밍 제약 조건입니다. FPGA 도구가 이 명령의 "datapath_only" 옵션(또는 이와 유사한 기능)을 지원한다면 더욱 편리합니다.
결론
IOB 레지스터는 가능하면 반드시 사용하는 것이 좋습니다. FPGA 도구가 스스로 해 주지 않을 수도 있으므로 이 목표를 달성하려면 약간의 노력이 필요할 수 있습니다. 그 노력에 대한 보상은 최적의 타이밍뿐 아니라, I/O 포트가 항상 반복 가능한(repeatable) 동작을 보인다는 점입니다.