01signal.com

Xilinx 부분 재구성(Partial Reconfiguration): 리셋과 디커플링

이 글은 Xilinx Vivado의 부분 재구성(Partial Reconfiguration), 즉 DFX(Dynamic Function eXchange)에 관한 네 편짜리 시리즈의 세 번째 글입니다. 앞선 두 글이 FPGA 설계를 설정하는 방법을 보여 주었다면, 이 글은 정적 로직(static logic)이 재구성 로직(reconfigurable logic)이 사라졌다가 다시 나타나는 상황을 어떻게 대처할 수 있는지 다룹니다.

개요

부분 비트스트림(partial bitstream)을 로드하는 과정은 물리적 하드웨어의 핫 스와프(hot swap)와 비슷합니다. 특정 부품이 갑자기 제거되고 다른 부품으로 교체된 다음 전원이 켜지는 것과 같습니다. 이 글에서는 이러한 전환이 원활하고 확실하게 이루어지도록 하는 데 필요한 수단을 다룹니다.

이 글은 부분 재구성(Partial Reconfiguration)이 FPGA 내부의 정적 로직(static logic)에 의해 수행된다고 가정합니다. 원활한 동작을 보장하려면 다음 단계를 거쳐 수행해야 합니다. 자세한 설명은 아래에 이어집니다.

디커플링이 필요한 이유

부분 비트스트림(partial bitstream)을 로드하는 과정에서 정적 로직(static logic)과 재구성 로직(reconfigurable logic) 사이의 연결은 예측할 수 없는 상태가 됩니다. 그 결과 재구성 모듈(reconfigurable module)의 출력 포트가 임의의 패턴이나 허용 범위를 벗어난 값을 만들어 낼 수 있습니다. 모든 출력 포트가 항상 그런 것은 아니지만, 어떤 형태로든 비정상적인 동작이 나타날 가능성이 높습니다.

부분 비트스트림을 로드하는 동안에도 정적 로직(static logic)은 계속 동작하므로, 바람직하지 않은 영향을 피하려면 재구성 모듈에서 들어올 수 있는 예측 불가능한 신호를 무시해야 합니다. Xilinx 사용자 가이드 UG909는 이를 디커플링(decoupling)이라고 부릅니다.

디커플링을 구현하는 방법은 재구성 모듈(reconfigurable module) 출력 포트의 특성에 따라 달라집니다. 각 포트가 정적 로직(static logic)에 미치는 영향을 분석하고, 필요에 따라 예방 조치를 취해야 합니다. 예를 들어 재구성 과정 중에 출력 포트를 중립값과 멀티플렉싱하거나, 응답하지 말아야 할 로직에 클록 인에이블(clock enable)을 추가하거나, 정적 로직의 일부를 리셋 상태로 유지하는 방법이 여기에 해당합니다.

재구성 로직(reconfigurable logic)이 I/O 패드에 직접 연결되어 있다면, 해당 패드를 하이 임피던스(high-Z) 모드로 만들거나 I/O 로직의 클록 인에이블(clock enable)을 비활성화해야 할 수 있습니다. 해당 I/O 로직에 출력 레지스터가 있는 경우입니다. 또한 재구성 로직이 외부 부품과 연결되어 있다면, 재구성 전에 이러한 부품을 안전한 상태로 만들어 두어야 할 수도 있습니다.

Vivado의 IP 카탈로그에는 AXI 연결을 디커플링하기 위한 부분 재구성용 디커플러 IP(Partial Reconfiguration Decoupler IP)가 있습니다.

재구성 모듈(reconfigurable module)의 입력 포트는 이러한 처리가 필요하지 않습니다. 정적 로직(static logic)이 구동하는 신호가 소비되지 않는다 해도 정적 로직은 신경 쓸 것이 없기 때문입니다.

Ultrascale 디바이스의 경우, clearing bitstream을 로드하기 전에 디커플링이 필요합니다. clearing bitstream은 재구성 로직(reconfigurable logic)을 종료시키기 때문입니다.

STARTUP 시퀀스에 대한 몇 가지 이야기

비트스트림(bitstream)에서 중요한 부분 중 하나는 전체 비트스트림과 부분 비트스트림 모두에 포함된 START 구성 명령입니다. 이 명령은 STARTUP 시퀀스를 시작합니다. 이 시퀀스에는 로직을 일관되게 기동하기 위한 몇 가지 메커니즘이 포함되어 있습니다.

첫 번째는 구성(configuration)이 끝날 때 동기식 요소(synchronous element)에 기본값이 할당된다는 점입니다. 이는 Ultrascale FPGA 이상에서는 항상 성립합니다. Series-7 FPGA에서는 전체 구성, 즉 초기 비트스트림(initial bitstream)을 사용하는 경우와, RESET_AFTER_RECONFIG가 활성화된 부분 재구성(Partial Reconfiguration)에서 성립합니다.

두 번째는 GWE(Global Write Enable)입니다. 동기식 요소의 인에이블 입력이나 쓰기 인에이블 입력과 혼동해서는 안 됩니다. 이 신호는 플립플롭과 RAM이 값을 변경할 수 있게 해 줍니다. 전체 구성(Full configuration) 동안 GWE는 FPGA 전체에서 로우(Low) 상태를 유지하다가, 구성 시작 시퀀스 중 특정 단계에서 하이(High)로 바뀝니다. 부분 비트스트림을 로드할 때는 재구성된 로직에만 영향을 미칩니다.

당연하게도 GWE의 변화는 애플리케이션 로직이 공급하는 어떤 클록과도 비동기적입니다. 따라서 GWE 변화와 첫 번째 유효 클록 사이의 타이밍은 동기식 요소(synchronous element)의 관점에서 예측할 수 없습니다.

부분 재구성(Partial Reconfiguration) 시나리오에서도 전체 구성(Full configuration)과 마찬가지로, 이는 프로세스가 끝난 직후 모든 동기식 요소(synchronous element)가 초기값을 갖는다는 것을 의미합니다. Ultrascale 이상이거나 RESET_AFTER_RECONFIG가 설정된 경우에는 더욱 그렇습니다. 그런데 일부 동기식 요소는 애플리케이션 로직의 첫 번째 클록 사이클에 응답하고, 다른 요소는 응답하지 않을 확률적인 가능성이 있습니다. 이 임의적인 동작은 GWE가 하이(High)로 바뀌는 시점 대비 첫 번째 클록이 언제 도착하는지에 따라 달라집니다. 따라서 이러한 불확실성에 민감한 모든 로직에는 리셋을 제대로 적용하는 것이 중요합니다.

부분 비트스트림(partial bitstream)을 로드한 후 재구성 로직(reconfigurable logic)을 리셋해야 할 필요성은 FPGA 전체 구성을 마친 후와 같습니다. 다만 전체 구성(Full configuration)의 경우 리셋이 필요한 이유가 더 직관적입니다. 특히 MMCM이나 PLL이 록(Lock)되거나 외부 하드웨어가 준비될 때까지 리셋을 활성 상태로 유지하는 경우가 많기 때문입니다.

요약하면, 재구성 로직(reconfigurable logic)을 리셋할지, 아니면 그중 어느 부분을 리셋할지에 대한 단일한 답은 없습니다. 전체 구성(Full configuration)과 마찬가지로, 동기식 요소(synchronous element)는 기본값을 받고 클록에 응답하기 시작합니다. 어떤 상황에서는 이것으로 충분하지만, 다른 시나리오에서는 리셋이 필요합니다.

STARTUP 종료 감지

위에 나열한 단계 중에서 애플리케이션 로직의 제어를 벗어나는 유일한 부분은 STARTUP 시퀀스입니다. 그럼에도 그것이 언제 끝났는지 아는 것은 중요합니다.

각 FPGA 제품군의 Configuration Guide에는 STARTUP 시퀀스에 대한 설명이 있습니다. 간단히 말하면, 이 시퀀스에 걸리는 시간은 비트스트림(bitstream)의 옵션에 따라 크게 달라집니다. 예를 들어 이 시퀀스가 MMCM이 록(Lock)될 때까지 또는 DCI가 임피던스 정합을 완료할 때까지 기다리도록 구성할 수 있습니다.

FPGA는 STARTUP 시퀀스의 마지막 단계에서 하이(High)로 바뀌는 EOS(End Of Startup) 신호를 제공합니다. EOS에 의존하는 것은 재구성 로직(reconfigurable logic)을 다시 가동할 시점, 즉 리셋을 시작하고 출력 포트를 다시 연결(recoupling)하기 시작할 시점을 아는 공식적으로 올바른 방법입니다.

EOS 신호는 로직 패브릭(logic fabric) 내부에서만 얻을 수 있으며, STARTUPE2 프리미티브(primitive)를 인스턴스화(instantiation)하여 사용합니다. 예를 들어 다음과 같습니다.

wire eos;

STARTUPE2 #(.PROG_USR("FALSE")) startup_ins
  (
   .CLK(1'b0),
   .GSR(1'b0),
   .GTS(1'b0),
   .KEYCLEARB(1'b1),
   .PACK(1'b0),
   .USRCCLKO(1'b0),
   .USRCCLKTS(1'b0),
   .USRDONEO(1'b1),
   .USRDONETS(1'b1),
   .CFGCLK(),
   .CFGMCLK(),
   .EOS(eos),
   .PREQ());

따라서 비트스트림(bitstream)이 ICAP으로 로드되는 것을 마치면 EOS가 하이(High)가 될 때까지 기다린 다음, 리셋과 재연결(recoupling)을 시작하세요.

Ultrascale FPGA에는 STARTUPE3 프리미티브(primitive)가 있습니다. 하지만 Vivado는 이러한 FPGA에서도 STARTUPE2 프리미티브를 받아들이고, 이를 STARTUPE3로 올바르게 변환합니다. 따라서 위의 코드 예제는 모든 FPGA 제품군을 포괄합니다.

제가 몇 가지 비공식적인 실험을 통해, 비트스트림(bitstream)의 START 명령이 ICAP에 도달한 후 EOS가 하이(High)로 바뀌는 데 걸리는 시간을 측정해 보았습니다.

Kintex-7에서 비트스트림(bitstream)의 기본 설정을 사용하면 26클록 사이클이 걸렸습니다. 100MHz에서 약 260ns입니다. 비트스트림에는 NOP 등 추가 데이터가 있었으므로, EOS는 마지막 단어가 ICAP에 입력된 직후 하이(High)로 바뀌었을 가능성이 매우 높습니다.

그러나 Kintex Ultrascale FPGA에서 같은 실험을 하면 완전히 다른 결과가 나왔습니다. EOS가 하이(High)로 바뀌는 데 START 명령 후 0.8ms에서 4.5ms 사이로 무작위로 시간이 걸렸습니다.

위에 보인 것처럼 STARTUPE2 프리미티브(primitive)를 사용하는 것은 아주 쉽지만, 비트스트림(bitstream) 로드가 끝난 시점부터 고정된 시간이 지난 뒤에 재연결을 시작하는 방법도 가능합니다. 예를 들어 STARTUP 시퀀스가 100ms나 걸릴 일은 사실상 상상하기 어렵고, 그 정도 지연은 사람이 느끼기에도 거의 눈에 띄지 않습니다. 그렇지만 위의 두 실험 결과를 고려하면 STARTUPE2 프리미티브를 사용하는 것이 안전한 방법으로 보입니다.

Ultrascale FPGA의 경우 clearing bitstream을 로드한 뒤의 EOS 동작은 문서화되어 있지 않은 것으로 보입니다. 그런데 비공식 실험에서는 clearing bitstream을 로드한 후에도 EOS가 로우(Low) 상태로 있다가, 이후 로드한 부분 비트스트림(partial bitstream) 다음에 하이(High)로 바뀌었습니다.


세 번째 글은 여기서 끝납니다. 마지막 글에서는 Vivado가 OOC와 DCP를 통해 정적 로직(static logic)과 재구성 로직(reconfigurable logic) 사이의 관계를 어떻게 처리하는지 그 배후를 살펴보고, 이를 이해하는 것이 Remote Update(원격 업데이트) 시나리오용 부분 비트스트림(partial bitstream)을 안정적으로 만드는 길을 어떻게 열어 주는지 설명합니다.

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