AXI Stream은 칩 내부에서 데이터를 주고받기 간단하고 유용한 프로토콜이지만, 실시간 데이터 소스와 출력 장치가 요구하는 속도를 보장하지 못한다. 이 글은 패킷이 막혔을 때 전송을 취소하는 ABORT 신호를 추가한 AXIN 프로토콜을 제안하고, FPGA 기반 네트워크 데이터 처리 설계에 적용한 경험을 소개한다.

AXI Stream의 한계

AXI Stream은 주소 없이 데이터 흐름을 전달하는 프로토콜이다. 송신 측의 TVALID과 수신 측의 TREADY가 모두 참이면 TDATA가 전달된다. TLAST는 패킷의 끝을 표시한다. 프로토콜은 수신 측이 얼마든지 오래 역압(backpressure)을 걸 수 있도록 하지만, 실시간 시스템에서는 이 때문에 데이터가 유실될 수 있다.

글은 스트림 구성 요소를 데이터 소스, 처리 장치, 싱크로 나눈다. 아날로그-디지털 변환기, 네트워크 PHY, 디지털 카메라 같은 소스는 정해진 속도로 데이터를 내보내므로 수신 측이 준비되지 않아도 데이터가 도착한다. 이를 처리할 방법이 프로토콜에 없으면 역압이 이어질 때 데이터가 버려진다. 글은 이를 ‘과도하게 빠른 소스’ 문제라고 부른다. 예를 들어 일부 필터는 N개 샘플마다 하나만 처리할 수 있어 입력 속도가 더 빠르면 문제가 생긴다.

반대로 디지털-아날로그 변환기, 네트워크 PHY, 비디오 모니터 같은 싱크는 정해진 시점에 데이터가 필요하다. 데이터가 도착하지 않는 버퍼 언더런(buffer underrun)은 애플리케이션별로 감지하고 처리할 수 있지만, AXI Stream 자체가 해결책을 제공하지는 않는다. DAC는 마지막 출력값을 반복하거나 오류를 표시할 수 있고, 네트워크 PHY는 패킷을 일찍 끝내 수신 측이 버리게 할 수 있다. 비디오는 검은 화면을 출력한 뒤 다음 프레임에서 동기화할 수 있다.

따라서 글의 주장은 AXI Stream이 속도 요건이 없는 처리 장치에는 잘 맞지만, 실시간 소스와 싱크에는 별도의 속도 관리와 데이터 유실 처리가 필요하다는 것이다. 또 TLAST 같은 메타데이터를 메모리에 저장할 때 패킷 경계를 어떻게 보존할지도 문제로 지적한다.

패킷 취소를 위한 AXIN

글에서 소개하는 사례는 수중 SONAR 센서 데이터를 압축하고 패킷으로 만들어 UDP와 이더넷을 통해 보내는 FPGA 설계다. 이전 설계에서는 DE10-Nano의 ARM CPU가 요구 데이터 속도를 처리하지 못한 경험이 있었고, 이에 따라 네트워크 패킷 처리를 CPU가 아닌 FPGA 로직에서 자동으로 수행하는 방향을 택했다. 당시 접근 방식은 이전 네트워크 설계였으며, CPU로 데이터를 옮기는 방법에도 문제가 일부 있었다고 덧붙인다(관련 글).

혼잡으로 버퍼가 가득 차거나 출력 패킷이 다른 패킷에 막히면 AXI Stream에는 패킷을 버리는 기본 기능이 없다. 이를 보완하기 위해 글은 ABORT 신호를 추가한 ‘AXI network’, 줄여서 AXIN을 제안한다. 송신 측은 수신 측이 TREADY를 너무 오래 내리지 않는 등 필요할 때 진행 중인 패킷을 취소할 수 있다.

  • ABORT는 TVALID이나 TREADY의 상태와 관계없이 올라갈 수 있고, 역압 외의 이유로도 사용할 수 있다.
  • 취소 뒤 스트림의 다음 샘플은 다음 패킷의 첫 샘플이어야 한다.
  • ABORT && !TVALID이면 ABORT를 바로 내릴 수 있다. ABORT && TVALID이면 ABORT && TVALID && TREADY가 될 때까지 신호를 유지해야 한다.
  • TVALID && TREADY && TLAST로 패킷 끝을 수신한 뒤에는 송신 측이 해당 패킷을 취소할 수 없다.

ABORT는 TUSER와 달리 TVALID 없이도 표시할 수 있으며, TVALID && !TREADY로 채널이 정지된 동안에도 올릴 수 있다. 글은 Josh Tyler의 DROP 신호와 패킷 FIFO도 비슷한 접근이라고 설명한다. 다만 DROP은 스트림 안에서 전달되는 반면 AXIN의 ABORT는 TVALID 없이도 전달되는 신호다. 글은 DROP 방식이 구현하기 쉬워 보인다고 평가하면서, 해당 구현이 FIFO보다 큰 패킷을 받으면 멈출 가능성이 있다고 주장한다.

FIFO와 메모리 처리

글은 AXIN 규칙을 형식 검증 속성으로 정의한 뒤 ABORT를 지원하는 FIFO를 만들었다. 여러 패킷이 FIFO에 들어 있는 상태에서 다음 패킷이 취소되거나, 패킷 일부만 들어 있는 채 FIFO가 가득 찬 경우를 처리해야 해 구현이 까다로웠다고 설명한다. 이후 UDP 변환기, 멀티플렉서, 브로드캐스트 요소도 만들었다.

예를 들어 네트워크 PHY가 리셋 상태인 동안 생성된 패킷은 FIFO에서 버리고, PHY가 패킷을 받기 시작하면 처리를 재개했다. 또 패킷 헤더에 데이터와 연결된 타임스탬프가 필요해 헤더를 즉시 만들 수 없는 상황에서는, 데이터 소스와 패킷 생성기 사이에 FIFO를 두어 샘플이 연달아 도착해도 헤더를 준비할 시간을 확보했다.

패킷을 메모리에 저장할 때는 TLAST를 데이터와 함께 저장하거나 별도 메모리에 보관할 수 있다. 글은 별도 메모리를 쓰면 데이터 메모리보다 먼저 가득 차는 문제가 생길 수 있다고 지적한다. 대안으로 AXIN을 TLAST 없는 AXI Stream으로 바꾸면서 패킷의 첫 32비트 워드에 바이트 단위 길이를 넣는 변환기를 만들었다. 이 방식으로 일반 AXI Stream 구성 요소와 메모리를 사용하면서 패킷 경계를 유지할 수 있었다.

다만 당시 변환기는 패킷 전체를 블록 RAM에 저장하므로 패킷 크기가 해당 메모리 용량에 제한된다. 외부 메모리 인터페이스를 추가해 제한을 없애는 일은 향후 과제로 남겨뒀다. 대신 패킷을 블록 RAM에 모두 담은 뒤 전송하면 PHY에 보내기 전에 패킷이 완성됐는지 보장할 수 있다고 설명한다.

완성된 처리 흐름은 데이터와 타임스탬프, 프레임 번호를 묶고 헤더를 붙여 이더넷(Ethernet), IPv4(IPv4), UDP(User Datagram Protocol) 패킷을 만든다. 이를 버퍼링하고 AXI Stream으로 변환한 뒤 비동기 FIFO를 거쳐 네트워크 컨트롤러로 보냈다. 글은 32비트 데이터와 네트워크 속도의 4분의 1보다 빠른 클록을 사용했으며, 사용한 Artix A7-200T에 LUT와 LUT RAM 자원이 80% 넘게 남아 있었다고 보고한다.

적용 시 고려할 점

글은 AXI Stream을 폐기해야 한다고 결론짓지 않는다. 필요한 데이터 속도를 설계가 보장할 수 있는 애플리케이션에는 여전히 적합하다. 다만 역압에는 한계가 있으므로, 그 한계를 넘었을 때 데이터 소스가 처리 방식을 제어하거나 데이터 유실을 표시해야 한다는 주장이다.

네트워크 패킷처럼 일부 손실을 허용할 수 있는 경우에는 혼잡 시 패킷 전체를 버리는 것이 한 방법이다. 손실은 프레임 카운터나 타임스탬프로 감지할 수 있고, 요청에 대한 응답이 제때 오지 않는 경우에는 재시도하거나 요청을 포기할 수 있다. ABORT는 이런 패킷 단위 취소를 구현하는 선택지지만, 글은 이를 다른 애플리케이션에 그대로 적용할 수 있다고 단정하지 않는다. AXIN FIFO와 변환기 구현에는 형식 검증과 여러 경계 조건 처리가 필요했고, 메모리 변환기에는 패킷 크기 제한도 남아 있다.

프로토콜 설명의 참고 자료로 AXI Stream 문서, AXI 핸드셰이크 규칙, 역압 설명이 제시됐다. 글은 AXIN의 영감이 된 Josh Tyler의 계정과 성경 구절(잠언 14:23, 시편 2:1)도 링크한다.