08. KWS NPU — XC7Z020 실리콘 검증
이 페이지가 eulernpu 의 silicon 정석입니다. 음성 인식 (Keyword Spotting) NPU를 QMTECH XC7Z020 보드에 실제로 올린 전체 흐름을 다룹니다. 이후 09 / 10 silicon 데모는 모두 이 패턴의 변형입니다.
두 가지 silicon 패턴을 함께 다룹니다:
- L2 (단일 op 오프로드) —
matmul_systolic한 op만 PL에 올리고 나머지는 ARM. cycle model 잠금 + "핸드오프 증명" 용. - L3 (전체 그래프 단일 IP) —
kws_npu_top한 IP에 conv→GRU→fc 모두 넣음. ARM이 input 준비 + softmax + argmax 만. Apple-ANE / Edge-TPU 패턴.
| 패턴 | 결과 | 의미 |
|---|---|---|
| L2 (matmul만) | 11/11 MATCH, NPU 2.5× 느림 | DMA dominate, "데이터 경로 증명" |
| L3 (풀 그래프) | 11/11 MATCH, NPU 2.11M cyc vs ARM 17M cyc = 8.07× 가속 | 진짜 NPU |
모델
examples/silicon_kws/ 의 DS-CNN + GRU 키워드 스포터 (11 commands).
- 입력: 40-mel × 101-frame log-mel spectrogram (INT8)
- 그래프:
conv2d → depthwise_conv2d → pointwise_conv2d → batchnorm → global_avgpool2d → 16-step gru_cell → fc1 → fc2 → softmax - 출력: 11-way logits (silence + unknown + 9 commands)
학습 + 양자화 + golden 생성은 examples/silicon_kws/ 에서 끝나 있고,
P06 는 그 모델을 silicon으로 가져가는 일 만 합니다.
7-단계 silicon 흐름 (전체)
프로젝트 위치: examples/silicon_kws/
Step 1 — Host CPU smoke
silicon 가기 전에 host gcc로 같은 C 코드를 컴파일해서 정확도가 맞는지 봅니다. 수학이 host에서 깨지면 silicon에서도 깨집니다 (그 역은 아님).
bash examples/silicon_kws/tests/build_host_smoke.sh
기대: 11/11 PASS — 모든 키워드 정답.
Step 2 — HLS C-synth
bash examples/silicon_kws/scripts/run_hls_synth.sh
이 단계가 eulernpu/hls/kernels/ 의 템플릿 (matmul_systolic.h,
conv2d_sliding.h, recurrent.h 등)을 instantiate 해서 RTL IP를 만듭니다.
L2 모드의 합성 보고서:
- Fmax: 114 MHz (target 100 MHz 초과)
- DSP: 64 (220개 중 29%)
- BRAM: < 5%
L3 모드의 합성 보고서:
- Fmax: 91.33 MHz (90 MHz target)
- DSP: 99 (45%)
- BRAM: 24% (weight ROM 포함)
- LUT: < 50%
L3가 더 무거운 이유는 전체 그래프 + 가중치 ROM 모두 onchip 이라.
Step 3 — Vivado bitstream
vivado -mode batch \
-source examples/silicon_kws/scripts/01_create_vivado_project.tcl
이 TCL이 Block Design을 자동으로 만듭니다:
processing_system7_0
├── M_AXI_GP0 → IP s_axilite (control)
├── S_AXI_HP0 ← IP m_axi (data, if any)
└── EMIO UART1 → external pin (printf 채널, P05 패턴)
IP (kws_npu_top 또는 matmul_systolic)
Vivado impl 결과:
- L2: WNS +0.412 ns @ 100 MHz, 0 critical warnings
- L3: WNS +0.301 ns @ 90 MHz, 0 critical warnings
Step 4 — Vitis platform + ELF
vitis -s examples/silicon_kws/scripts/02_create_app.py
이 Python script가:
- XSA 로부터 SDT (System Device Tree) 플랫폼 생성
- ARM standalone BSP 컴파일
- EMIO UART MIO 48/49 routing patch 적용 (P05 X-1 carry-over)
- demo1 / demo2 ELF 2개 빌드
ELF 위치: ~/Developments/vitis_ws/kws_npu/llm_demo{1,2}/build/*.elf
Step 5 — Silicon run (xsdb + UART)
보드가 just-reset 상태여야 합니다 (P07 X-10 함정):
bash examples/silicon_kws/scripts/run_npu_test.sh
이 harness가:
xsdbconnect + 비트스트림 fpga -file- ps7_init.tcl source + EMIO UART 재라우팅
- ELF dow + con
- 동시에
pyserial이/dev/ttyUSB1캡처 (P06 X-8 함정:cat은 burst loss) - RESULT: PASS / FAIL 자동 grading
Step 6 — 결과 측정
examples/silicon_kws/docs/results/ 에 캡쳐 파일 + SUMMARY.md.
demo1 (정확성 게이트):
demo1: 11/11 CPU=NPU agreement
"yes" pred=yes conf=0.998 cyc_cpu=17,492,310 cyc_npu=2,114,832 → MATCH
"no" pred=no conf=0.999 cyc_cpu=17,489,221 cyc_npu=2,114,977 → MATCH
... (× 11)
RESULT: PASS
demo2 (200 프레임 스트림):
demo2: 200 frames / 182 keywords detected / 5,166 ms wall
NPU avg 25.83 ms per frame, CPU avg 209 ms per frame
(8.07× 가속 — Apple-ANE 패턴)
Step 7 — Cycle model 회귀 잠금
P06 측정값이 eulernpu/hls/cycle_model.py 의 matmul_systolic lambda
와 ±1% 일치합니다 (예측 456 vs 측정 460):
def test_matmul_systolic_matches_p06_silicon():
cycles = matmul_systolic_cycles(M=32, K=48, N=8, T=8)
assert 414 <= cycles <= 506 # ±10% tolerance
이 lock-test가 CI에 들어가 있어서, cycle model 식이 미래에 drift 하면
CI가 fail합니다. P06 silicon 측정값이 모든 후속 npu_sim profile 의
신뢰성 anchor입니다.
두 silicon 함정 (P05/P06 X-항)
X-8 — cat /dev/ttyUSB1 은 burst loss
UART 115200 baud + IP가 빠른 burst printf 시 cat 는 일부 라인을 놓칩니다.
→ Fix: pyserial 기반 capture_uart.py 사용. run_npu_test.sh 가 자동으로
pyserial 우선 + fallback 처리.
X-10 — JTAG DAP sticky-error
직전 데모가 보드를 halted 상태로 남기면 다음 xsdb attach 가 fail합니다 (DAP status 0x30000021).
→ Fix: 보드 RESET 버튼 한 번 push (또는 USB 전원 cycle). test_xsdb.tcl 가
이 상황을 감지하면 명시적 RESET 안내 출력.
재현 — 한 줄
# (보드가 just-reset 상태)
bash examples/silicon_kws/scripts/run_npu_test.sh
기대: 약 2-3분 후
demo1 : PASS
demo2 : PASS
상세 비디오 + SUMMARY:
왜 P06이 정석인가
세 silicon 단계의 ladder:
- P06 (KWS) — 첫 silicon, 8.07× 가속, cycle model 잠금. 가장 깔끔한 "이게 가능하다" 증명.
- P07 (Bearing) — 같은 L3 패턴, 더 깊은 그래프. 11.13× 가속. 리소스 한계 (II=64) 에서 어떻게 회복하는지 보여줌.
- P08 (LLM) — L2 hybrid 로 deliberately 떠남 (큰 모델 BRAM 안 들어감). NPU가 CPU보다 느린 정직한 결과.
P06이 "FPGA NPU 가 의미 있다" 의 가장 분명한 증명이고, P07/P08은 그 패턴이 어디까지 변형 가능한가의 확장입니다.
다음 단계
- 09. bearing_silicon — P06 패턴을 더 깊은 1D-CNN으로
- 10. llm_silicon_hybrid — P06 패턴을 의도적으로 떠난 L2 hybrid