FPGA로 부활한 3dfx Voodoo: 레거시 하드웨어와 모던 RTL 툴링의 만남
90년대 PC 게임을 즐겼던 세대라면 3dfx Voodoo라는 이름에 가슴이 뛸 것이다. 하지만 오늘 다룰 이야기는 단순한 레트로 하드웨어의 향수가 아니다.
위 화면은 에뮬레이터나 오리지널 그래픽 카드가 아닌, 한 엔지니어가 SpinalHDL을 이용해 FPGA 위에서 처음부터 다시 구현한 Voodoo 1에서 렌더링된 Screamer 2의 모습이다.
시니어 엔지니어로서 이 프로젝트가 흥미로운 이유는 ‘어떻게 혼자서 이 거대한 그래픽 파이프라인을 설계하고 디버깅할 수 있었는가’에 있다. 결론부터 말하자면, 이것은 Modern RTL Tools 가 하드웨어 설계의 추상화 수준을 얼마나 끌어올렸는지 보여주는 훌륭한 쇼케이스다.
고정 기능(Fixed-Function) 칩의 숨겨진 복잡성
최신 GPU는 프로그래머블 셰이더에 복잡성이 집중되어 있다. 하지만 Voodoo는 다르다. Transform and Lighting도 없고, 텍스처 샘플링, 밉매핑, 바이리니어/트라이리니어 필터링, 안개 효과 등 모든 그래픽 동작이 실리콘에 고정되어 있다.
진짜 문제는 깊은 파이프라인에서 온다. 삼각형 A가 파이프라인을 통과하는 동안 CPU가 삼각형 B의 설정을 쓰기 시작하면 어떻게 될까? 상태가 너무 일찍 변경되면 삼각형 A의 픽셀이 삼각형 B의 텍스처 모드로 렌더링되는 미묘한 상태 오염이 발생한다.
결국 레지스터 쓰기는 단순한 설정 업데이트가 아니라, 머신의 타이밍 컨트랙트(Timing contract) 그 자체다.
SpinalHDL을 활용한 레지스터 의미론(Semantics) 인코딩
저자는 Voodoo의 레지스터를 4가지 아키텍처 카테고리로 분류했다.
- FIFO: 큐에 들어가고 순서대로 적용됨
- FIFO + Stall: 큐에 들어가지만 파이프라인이 비워진 후에만 적용됨
- Direct: 즉시 적용됨
- Float: 변환된 후 레지스터의 고정 소수점 형태로 기록됨
이걸 기존 Verilog로 짠다면 선언부, 버스 제어 로직, 파이프라인 핸들링 등 사방에 코드가 흩어질 것이다. 하지만 저자는 SpinalHDL의 RegIf를 확장하여 레지스터 선언부에 이를 직접 인코딩했다.
val startR = busif
.newRegAtWithCategory(0x020, "startR", RegisterCategory.fifoNoSync)
.field(AFix.SQ(24 bits, 12 bits), AccessType.WO, 255 << 12, "Starting red value")
.withFloatAlias()
.asOutput()
솔직히 이 코드를 처음 봤을 때 꽤 감탄했다. 하드웨어의 아키텍처적 의도가 코드 한 곳에 모여 있다는 것은 유지보수 측면에서 엄청난 이점이다.
다만 Hacker News 댓글에서도 지적되었듯, Float-to-Fixed 변환 로직을 메모리 맵 레지스터 뱅크에 포함시키는 것이 아키텍처적으로 완벽히 깔끔한가에 대해서는 논란의 여지가 있다. 컴퓨팅 유닛이 상태를 소유하고 레지스터 뱅크에서 데이터를 당겨오는(Pull) 구조가 더 이상적일 수 있다. 실제로 나 역시 과거에 비슷한 버스 인터페이스를 설계할 때 상태 소유권 문제로 골머리를 앓은 적이 있다. 하지만 혼자서 이 거대한 칩을 구현해야 하는 상황이라면, 컴포넌트 간 레지스터 중복을 줄이기 위한 저자의 실용적인 타협안에 전적으로 동의한다.
Waveform 스크롤링의 종말: Conetrace를 이용한 디버깅
이 글의 백미는 디버깅 과정이다. 반투명 오버레이와 텍스트에서 픽셀이 깨지는 버그가 발생했다.
대부분의 하드웨어 엔지니어는 이런 현상을 보면 십중팔구 메모리 해저드나 캐시 동기화 문제를 의심할 것이다. 저자 역시 그 가설을 파고들었지만 아티팩트는 사라지지 않았다.
여기서 저자는 전통적인 Waveform 뷰어 대신 conetrace라는 넷리스트 인식(Netlist-aware) 추적 툴을 사용했다. 실패한 픽셀을 래스터라이저부터 TMU, 컬러 컴바인 로직, 프레임버퍼 출력까지 스테이지별로 추적한 것이다.
$ conetrace rv path core_1.rasterizer_1.o core_1.writeColor.i_fromPipeline --track 5241000
...
ref: {S': 63.492, T': 14.031, lod: 1, texel: 0x6B}
...
결론적으로 메모리 버그가 아니었다. TMU 경로에서의 W 정밀도 손실, 밉 경계 근처에서의 원근 라운딩 오류, 블렌딩 팩터 계산 시의 미세한 색상 값 차이 등 여러 하드웨어 정확도 불일치가 겹쳐서 발생한 문제였다.
분산 시스템에서 Jaeger나 Zipkin 같은 트레이싱 툴 없이 마이크로서비스 버그를 잡는 것을 상상해 보라. 하드웨어 설계에서도 마찬가지다. 수백 개의 신호가 출렁이는 Waveform을 눈으로 쫓는 것은 이제 구시대적이다. 툴이 넷리스트의 구조를 이해하고 실행 흐름을 쿼리할 수 있게 해준다는 것은, 직관과 가설에 의존하던 디버깅을 완벽한 증거 기반의 디버깅으로 바꿔놓는다.
Hacker News 커뮤니티의 반응
HN 스레드에서는 향수에 젖은 댓글들이 넘쳐났다. Nvidia가 3dfx를 인수하자마자 드라이버 지원을 끊어버려 비싼 문진이 되어버렸다는 슬픈 사연도 있었다.
흥미로운 점은 글의 문체가 LLM이 생성한 것 같다는 지적이 있었다는 것이다. 이에 대해 한 유저는 “수학이나 엔지니어링에는 뛰어나지만 글쓰기에 약한 엔지니어가 LLM의 도움을 받아 자신의 지식을 명확하게 전달하는 것이 왜 문제인가?”라며 옹호했다. 나 역시 동의한다. 이 글은 절대 영혼 없는 AI 요약본이 아니다. 픽셀 하나를 잡기 위해 파이프라인을 뒤진 실제 피와 땀이 섞인 경험이 녹아 있다.
총평 (Verdict)
이 프로젝트는 단일 엔지니어가 현대적인 RTL 툴과 진보된 디버깅 툴을 활용해 얼마나 거대한 복잡성을 다룰 수 있는지 보여주는 완벽한 사례다.
하드웨어 설계의 진입 장벽은 여전히 높지만, 추상화의 수준이 올라가면서 우리가 머릿속에 한 번에 담아야 할 인지적 부하(Cognitive load)는 확실히 줄어들고 있다. 만약 당신이 여전히 Verilog와 씨름하며 Waveform 창에서 눈을 떼지 못하고 있다면, 이제는 툴체인을 업그레이드할 때가 된 것일지도 모른다.
References
- Original Article: https://noquiche.fyi/voodoo
- Hacker News Thread: https://news.ycombinator.com/item?id=47477284