PREPROCESS 스테이지¶
PREPROCESS 스테이지는 ACP 포트에서 들어온 BF16 fmap 액티베이션을 W4A8 GEMM 어레이가 요구하는 형식으로 변환한다. 현재 운용 경로는 BF16 → 27-bit fixed-point 변환이며, signed INT8 양자화기 후보 두 개(Option A / Option B)는 TODO.md §A-1에 열린 결정으로 기록되어 있다.
데이터 흐름¶
ACP 포트에서 128-bit 스트림으로 유입된 BF16 fmap은
preprocess_fmap 내부의 XPM block FIFO에서 256-bit 폭으로
버퍼링된다. 이후 두 경로가 병렬로 실행된다.
지수 사이드밴드: 256-bit 워드 두 개를 한 쌍으로 묶어 32개 원소의
e_max그룹을 구성하고, 1024-깊이emax_cache_mem에 저장한다. 읽기 시작 신호(i_rd_start)가 들어오면o_cached_emax로 브로드캐스트 된다.가수 정렬 경로:
preprocess_bf16_fixed_pipeline이 16-비트 BF16 원소 16개(256-bit)씩 두 클럭에 걸쳐 32개 블록을 수신하고, 블록 내 globale_max를 기준으로 각 가수를 right-shift 정렬한 뒤 27-bit two’s-complement fixed-point 값 16개(432-bit)를 출력한다. 이 파이프라인은 3단always_ff스테이지로 구성된다.
flowchart LR
ACP["ACP AXIS\n128-bit BF16"] --> FIFO["XPM FIFO\n256-bit block"]
FIFO --> EMAX["e_max 추출\n& emax_cache_mem"]
FIFO --> PIPE["preprocess_bf16\n_fixed_pipeline\n3-stage"]
PIPE --> CACHE["fmap_cache\nBRAM 27-bit×2048"]
EMAX --> OUT["o_cached_emax\n→ MAT_CORE"]
CACHE --> OUT2["o_fmap_broadcast\n→ MAT_CORE"]
fmap_cache에 전달된 432-bit 데이터(16 × 27-bit)는 7-bit 기록 주소를
통해 비대칭 포트 BRAM에 기록되고, i_rd_start 이후 2048 원소를
하나씩 읽어 ARRAY_SIZE_H개 레인에 동일하게 공급한다.
양자화 옵션¶
현재 preprocess_bf16_fixed_pipeline.sv가 출력하는 27-bit fixed-point
값은 하위 8비트를 truncate하여 GEMM systolic array에 임시로 공급하는
자리표시자 경로다. v002 W4A8 datapath가 요구하는 올바른 형식은
signed INT8 activation이다(DSP48E2 Port B signed 8-bit 입력).
TODO.md §A-1은 양자화기 교체를 위한 두 가지 후보를 정의한다.
Option A — power-of-two scale (블록 부동소수점 기반)
32-원소 블록의 global e_max를 재사용해 스케일을 2의 거듭제곱으로 결정한다.
기존 e_max 탐색 구조를 그대로 재사용하므로 RTL이 단순하고
400 MHz timing closure에 유리하다. 반면 스케일이 2의 거듭제곱으로
제한되어 activation 분포에 따라 saturation 또는 underflow가 증가할 수 있다.
Option B — true symmetric INT8 양자화
블록 내 max_abs를 기준으로 실수 스케일을 결정한다.
INT8 표현 범위를 더 효율적으로 사용하며 Python golden model과의
bit-exact 비교가 명확하다. 다만 하드웨어에서 max_abs, 역수 연산,
곱셈/반올림을 처리해야 하므로 RTL 비용이 크다.
현실적으로는 driver/compiler가 S_a를 미리 계산해
Constant Cache에 MEMSET으로 적재하는 구조가 자연스럽다.
두 후보에 대한 결정은 pccx-FPGA-NPU-LLM-kv260 저장소의
TODO.md §A-1에서 추적된다. 현재 RTL의
bf16_to_INT8_pipeline_power_of_two_scale.sv와
bf16_to_INT8_pipeline_true_symmetric_INT8.sv는 각 옵션에 대응하는
자리표시자 파일이며 본문은 미구현 상태다.
fmap 캐시¶
fmap_cache는 preprocess_bf16_fixed_pipeline 출력(432-bit, 16 × 27-bit)을
수신해 2048-깊이 BRAM에 스테이징하고, i_rd_start 이후 MAT_CORE(GEMM)에
1워드씩 순차적으로 공급하는 버퍼다.
파라미터 |
값 |
설명 |
|---|---|---|
|
27 |
Fixed-point 가수 비트 폭 |
|
16 |
클럭당 기록 워드 수 |
|
2048 |
1 × 2048 feature map 수용 |
|
32 |
읽기 브로드캐스트 레인 수 |
기록 포트 주소 폭은 7-bit(2048 ÷ 16 = 128), 읽기 포트 주소 폭은
11-bit(2048 원소 직접 접근)다. BRAM READ_LATENCY_B = 2이므로
유효 신호는 3단 파이프라인(rd_valid_pipe_1 → rd_valid_pipe_2 → rd_valid)을
거쳐 정렬된다.
마지막 검증 대상
커밋 8c09e5e @ pccxai/pccx-FPGA-NPU-LLM-kv260 (2026-04-29).