CI untuk FPGA ML tidak cukup berhenti di compile firmware atau menjalankan unit test software. Untuk proyek machine learning di FPGA, kualitas pipeline ditentukan oleh seberapa cepat tim bisa memvalidasi perubahan HDL, test vector, hasil inferensi, dan artefak bitstream tanpa membuat build harian menjadi terlalu lambat.
Pendekatan yang paling masuk akal adalah memisahkan fast checks dan full synthesis. Fast checks berjalan di setiap pull request atau merge request: format, lint HDL, simulasi ringan, dan verifikasi golden output. Full synthesis dijalankan lebih selektif: pada branch tertentu, jadwal malam, tag release, atau saat ada perubahan yang memang menyentuh path hardware kritikal. Dengan pola ini, tim mendapat feedback cepat tanpa mengorbankan validasi sebelum release.
Mengapa CI untuk FPGA ML berbeda dari pipeline software biasa
Pada proyek software murni, sebuah test biasanya selesai dalam hitungan detik dan hasil build relatif deterministik. Pada FPGA ML, ada beberapa lapisan tambahan:
- HDL dan testbench harus lolos lint dan simulasi.
- Model ML sering dikonversi menjadi fixed-point, LUT, atau ROM initialization yang harus cocok dengan ekspektasi numerik.
- Tool synthesis/P&R berat, lama, dan kadang tidak sepenuhnya deterministik jika constraint, seed, atau environment tidak dikontrol.
- Output release bukan hanya binary software, tetapi juga bitstream, laporan timing, resource utilization, checksum, dan metadata model.
Karena itu, tujuan CI bukan sekadar “apakah kode bisa dibangun”, tetapi “apakah perubahan ini menjaga perilaku model, tidak merusak HDL, dan layak dipromosikan ke synthesis atau release”.
Struktur repository yang memudahkan CI
Struktur repo yang baik mengurangi logika khusus di pipeline. Pisahkan sumber HDL, model, test vector, script konversi, dan hasil build. Contoh yang cukup praktis:
repo/
├─ rtl/ # HDL inti
├─ tb/ # testbench
├─ sim/ # script simulasi, waveform config
├─ constraints/ # timing / pin constraints
├─ models/
│ ├─ source/ # model training/export
│ ├─ quantized/ # model hasil kuantisasi
│ └─ manifests/ # metadata versi model
├─ vectors/
│ ├─ inputs/
│ ├─ expected/
│ └─ golden/ # output referensi untuk regresi
├─ scripts/
│ ├─ gen_vectors.py
│ ├─ compare_outputs.py
│ ├─ package_release.sh
│ └─ env_check.sh
├─ ci/
│ ├─ Dockerfile.sim
│ ├─ Dockerfile.synth
│ └─ rules/
├─ build/ # artefak lokal, biasanya di-ignore
├─ Makefile
├─ justfile
└─ .github/workflows/ atau .gitlab-ci.ymlBeberapa prinsip penting:
- Jangan commit artefak synthesis besar kecuali memang ada alasan audit atau kebutuhan vendor flow tertentu.
- Simpan test vector dan golden output dalam format stabil, misalnya CSV, NPY, atau file heksadesimal dengan metadata yang jelas.
- Model manifest sebaiknya mencatat hash model sumber, metode kuantisasi, skala fixed-point, dan generator commit yang menghasilkan ROM/weight HDL.
Target Makefile atau just untuk menyatukan local dev dan CI
Salah satu penyebab DX buruk di tim hardware adalah CI menjalankan perintah yang berbeda dari lingkungan lokal developer. Solusinya: definisikan target yang sama untuk lokal dan CI. Mau pakai Makefile atau justfile, yang penting konsisten.
Contoh Makefile:
.PHONY: fmt lint sim sim-regression vectors compare synth package clean
fmt:
python scripts/env_check.sh --format
lint:
verilator --lint-only -Wall rtl/*.sv tb/*.sv
vectors:
python3 scripts/gen_vectors.py \
--model models/quantized/model.json \
--out vectors/generated
sim:
./sim/run_smoke.sh
sim-regression:
./sim/run_regression.sh
compare:
python3 scripts/compare_outputs.py \
--actual build/sim_outputs \
--golden vectors/golden \
--tolerance 1
synth:
./scripts/run_synth.sh
package:
./scripts/package_release.sh
clean:
rm -rf build/Mengapa ini efektif:
- Developer cukup menghafal beberapa target inti:
make lint,make sim,make compare. - CI tinggal memanggil target yang sama, sehingga hasil lokal dan pipeline lebih selaras.
- Perubahan tool atau opsi command cukup diubah di satu tempat.
Jika tim lebih nyaman dengan just, keuntungannya adalah sintaks yang lebih ramah dan dukungan parameter yang lebih enak dibaca. Namun Makefile masih paling universal di runner Linux.
Lint HDL sebagai quality gate paling murah
Lint adalah garis pertahanan pertama. Untuk FPGA ML, error yang sering lolos tanpa lint adalah:
- lebar sinyal tidak cocok saat packing/unpacking data tensor,
- implicit net atau typo nama sinyal,
- signed/unsigned mismatch pada operasi fixed-point,
- case yang tidak lengkap sehingga inferensi latch terjadi tanpa sengaja,
- penggunaan konstruksi simulasi yang tidak cocok untuk synthesis.
Tool lint yang umum dipakai tergantung stack tim. Jika ingin pipeline cepat dan relatif terbuka, lint berbasis Verilator sering cukup untuk pemeriksaan awal. Jika flow Anda bergantung pada vendor tool, tetap baik menjalankan lint generik lebih dulu karena startup time lebih rendah.
Yang penting bukan hanya menjalankan lint, tetapi menjadikannya gating check sebelum merge. Jangan biasakan warning kritikal yang diabaikan terus-menerus. Lebih baik definisikan daftar warning yang diizinkan secara eksplisit daripada membiarkan semua warning menumpuk.
Praktik yang berguna: pisahkan “warning yang diterima sementara” ke file waiver yang ditinjau berkala. Jika waiver dibiarkan liar, lint kehilangan nilai sebagai quality gate.
Simulasi, test vector, dan golden output untuk menjaga perilaku model
Di proyek FPGA ML, simulasi bukan hanya memeriksa bahwa state machine berjalan, tetapi juga bahwa jalur inferensi masih menghasilkan output yang masuk akal. Ini penting saat ada perubahan kecil seperti penyesuaian pipeline latency, quantization scale, atau reordering channel.
Jenis simulasi yang sebaiknya dipisahkan
- Smoke simulation: testbench singkat untuk memverifikasi reset, handshake, dan satu-dua sampel input.
- Functional regression: batch test vector yang lebih banyak untuk memeriksa kesesuaian output terhadap golden.
- Corner-case simulation: input minimum/maksimum, overflow fixed-point, NaN yang sudah dipetakan sebelum hardware path, atau kondisi backpressure streaming.
Untuk developer experience, smoke test sebaiknya selesai cepat dan berjalan di setiap PR. Regression test bisa tetap jalan di PR bila ukurannya terkendali; jika mahal, jalankan subset di PR dan full set di branch utama atau job terjadwal.
Golden output: simpan ekspektasi, bukan tebakan
Golden output sebaiknya dihasilkan dari referensi yang jelas, misalnya model kuantisasi final yang sama dengan yang dipakai untuk menghasilkan bobot HDL. Jangan menghasilkan golden dari simulator hardware yang sedang diuji, karena itu hanya memverifikasi dirinya sendiri.
Skema yang umum:
- Model sumber diekspor ke representasi kuantisasi stabil.
- Script menghasilkan test vector input dan expected output referensi.
- Simulator HDL menghasilkan output aktual dari testbench.
- Script pembanding memeriksa kesamaan exact atau toleransi tertentu.
Contoh sederhana pembanding output:
python3 scripts/compare_outputs.py \
--actual build/sim_outputs/out.csv \
--golden vectors/golden/out.csv \
--tolerance 1Tolerance penting bila representasi fixed-point atau rounding mengizinkan selisih kecil. Namun toleransi yang terlalu longgar akan menyembunyikan regresi nyata. Praktik yang lebih aman adalah:
- gunakan exact match untuk sinyal kontrol dan metadata,
- gunakan toleransi kecil untuk nilai numerik inferensi,
- log sampel pertama yang gagal beserta indeks tensor atau frame.
Memisahkan fast checks dan full synthesis di pipeline
Kesalahan umum di tim FPGA adalah menjalankan synthesis di setiap commit kecil. Hasilnya, antrean runner penuh dan feedback harian menjadi lambat. Solusi praktisnya adalah membuat dua kelas pipeline.
Fast checks
Biasanya dijalankan pada setiap pull request atau merge request:
- checkout source,
- validasi environment dan script,
- format/lint HDL dan script pendukung,
- generate atau validasi test vector ringan,
- smoke simulation,
- compare terhadap golden output kecil.
Targetnya adalah memberi jawaban cepat: apakah perubahan aman untuk direview.
Full synthesis
Dijalankan lebih selektif:
- pada push ke branch utama,
- pada tag release,
- pada jadwal malam,
- atau ketika file tertentu berubah, misalnya
rtl/,constraints/, atau generator weight ROM.
Selain synthesis, job ini biasanya mencakup:
- implementasi/place-and-route,
- timing report,
- resource utilization report,
- packaging bitstream dan metadata release.
Dengan model ini, synthesis tidak menghambat iterasi kecil, tetapi tetap menjadi gerbang wajib sebelum release.
Contoh GitHub Actions untuk CI FPGA ML
Contoh berikut memisahkan job cepat dan synthesis berat. Nama tool dibuat generik agar mudah disesuaikan dengan stack Anda.
name: fpga-ml-ci
on:
pull_request:
push:
branches: [main]
workflow_dispatch:
schedule:
- cron: '0 1 * * *'
jobs:
fast-checks:
runs-on: ubuntu-latest
container:
image: ghcr.io/acme/fpga-sim:latest
steps:
- uses: actions/checkout@v4
- name: Cache vectors
uses: actions/cache@v4
with:
path: |
.cache
build/cache
key: vectors-${{ runner.os }}-${{ hashFiles('models/manifests/*', 'scripts/gen_vectors.py') }}
- name: Lint HDL
run: make lint
- name: Generate vectors
run: make vectors
- name: Smoke simulation
run: make sim
- name: Compare outputs
run: make compare
- name: Upload sim artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: sim-logs
path: |
build/**/*.log
build/**/*.csv
synth:
if: github.event_name != 'pull_request'
runs-on: [self-hosted, linux, fpga]
needs: fast-checks
steps:
- uses: actions/checkout@v4
- name: Restore build cache
uses: actions/cache@v4
with:
path: build/cache
key: synth-${{ runner.os }}-${{ hashFiles('rtl/**', 'constraints/**', 'models/manifests/*') }}
- name: Run synthesis
run: make synth
- name: Package release artifacts
run: make package
- name: Upload bitstream and reports
uses: actions/upload-artifact@v4
with:
name: synth-artifacts
path: |
build/release/*
build/reports/*Poin desain yang penting:
- Container untuk fast checks menjaga tool simulasi lebih konsisten.
- Self-hosted runner untuk synthesis umum dipilih karena tool vendor sering berat, berlisensi, atau sulit dijalankan di runner hosted standar.
- Dependency graph sederhana memastikan synthesis tidak berjalan jika lint atau simulasi dasar sudah gagal.
Contoh GitLab CI dengan stage yang jelas
stages:
- lint
- sim
- synth
- release
lint_hdl:
stage: lint
image: registry.example.com/fpga-sim:latest
script:
- make lint
smoke_sim:
stage: sim
image: registry.example.com/fpga-sim:latest
script:
- make vectors
- make sim
- make compare
artifacts:
when: always
paths:
- build/
full_synth:
stage: synth
tags:
- fpga
- licensed
script:
- make synth
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_TAG'
release_pkg:
stage: release
tags:
- fpga
- licensed
script:
- make package
dependencies:
- full_synth
rules:
- if: '$CI_COMMIT_TAG'Untuk GitLab, runner tags sangat berguna membedakan job yang cukup dijalankan di runner Linux umum versus job yang butuh host dengan lisensi dan storage besar.
Strategi runner, durasi build, dan kapan synthesis dijalankan
Untuk CI FPGA ML, memilih runner sama pentingnya dengan menulis pipeline.
Hosted runner untuk fast checks
Cocok untuk:
- lint,
- simulasi ringan,
- script Python penghasil vector,
- pemeriksaan metadata dan packaging dasar.
Keuntungannya: setup sederhana dan elastis. Kekurangannya: waktu startup container dan batas resource tertentu.
Self-hosted runner untuk synthesis
Cocok untuk:
- vendor tools,
- place-and-route,
- bitstream generation,
- job yang memerlukan lisensi floating atau node-locked.
Keuntungannya: kontrol environment penuh. Kekurangannya: perlu dirawat, dibersihkan, dan dipantau kapasitas disk serta status lisensi.
Kapan synthesis sebaiknya dijalankan
Pola yang umum dan seimbang:
- Setiap PR: tidak perlu full synthesis, kecuali untuk modul yang sangat kritikal atau perubahan yang menyentuh clocking/constraints utama.
- Setiap merge ke main: synthesis minimal satu target utama agar branch utama selalu punya status hardware yang valid.
- Nightly build: full regression synthesis untuk beberapa board/konfigurasi.
- Tag release: synthesis final, packaging, checksum, laporan timing, dan penandaan versi bitstream/model.
Jika antrean synthesis panjang, gunakan filter path. Misalnya, perubahan dokumentasi atau script non-hardware tidak perlu memicu build penuh.
Caching yang aman dan yang berbahaya
Caching bisa memangkas waktu pipeline, tetapi di FPGA toolchain ada jebakan.
Yang aman untuk di-cache
- dependency Python atau environment script,
- hasil generate test vector yang diturunkan dari hash model manifest,
- file intermediate simulasi yang jelas tergantung pada hash source,
- download tool umum atau image container.
Yang perlu hati-hati
- hasil synthesis incremental lintas branch,
- database implementasi yang sangat sensitif terhadap perubahan constraint kecil,
- artefak yang dihasilkan tool dengan path absolut atau metadata host tertentu.
Jika memakai cache synthesis, kunci cache harus ketat: source HDL, constraints, seed, manifest model, dan script generator yang relevan. Bila terlalu longgar, Anda berisiko memakai hasil lama yang tidak lagi valid.
Menjaga determinisme: hal kecil yang sering merusak kepercayaan pada CI
Pipeline hardware cepat kehilangan nilai jika hasilnya tidak konsisten. Determinisme harus dijaga di beberapa level:
1. Kunci environment
Gunakan container atau image yang dipin untuk simulasi dan tooling script. Untuk synthesis, minimal dokumentasikan versi tool, patch, lisensi, dan OS host.
2. Kunci input model
Setiap bitstream sebaiknya dapat ditelusuri ke:
- commit HDL,
- commit generator script,
- hash model kuantisasi,
- konfigurasi fixed-point atau quantization,
- constraint target board.
3. Hindari test vector acak tanpa seed tetap
Jika random dipakai untuk fuzzing atau stress test, simpan seed di log atau metadata artefak. Tanpa itu, bug sulit direproduksi.
4. Simpan metadata release
Bitstream release sebaiknya disertai file metadata, misalnya JSON, berisi versi model, commit hash, board target, tanggal build, dan checksum artefak.
{
"bitstream_version": "2026.08.06-main-abc1234",
"rtl_commit": "abc1234",
"model_manifest": "kan_edge_v3.json",
"model_hash": "sha256:...",
"target_board": "board-x",
"timing_status": "pass"
}Versioning model dan bitstream
Pada proyek FPGA ML, satu release sebenarnya menggabungkan dua domain versi: perangkat keras dan model.
Pendekatan yang praktis:
- Versi model mengikuti manifest terpisah, misalnya
model-name + revision + hash. - Versi bitstream mencantumkan target board dan commit pendek.
- Release bundle mengikat keduanya dalam satu artefak yang tidak ambigu.
Contoh isi release bundle:
top.bitatau artefak setara,timing_summary.txt,utilization.txt,manifest.json,golden_test_report.txt.
Hindari nama file seperti final.bit atau latest_working.bit. Nama semacam ini cepat membingungkan saat perlu audit atau rollback.
Quality gate sebelum merge dan sebelum release
Tidak semua gate harus sama. Sebaiknya ada dua level.
Gate sebelum merge
- lint HDL pass,
- smoke simulation pass,
- golden output subset pass,
- script generator model/vector tidak mengubah file tracked tanpa disengaja,
- review minimal satu engineer yang memahami RTL atau jalur data numerik.
Gate sebelum release
- full synthesis pass,
- timing pass pada target board,
- resource utilization masih dalam batas aman,
- regression vector lengkap pass,
- metadata model dan bitstream lengkap,
- artefak release tersimpan dan dapat diunduh ulang,
- checksum dan versi tercatat.
Jangan menyamakan “synthesis selesai” dengan “release aman”. Banyak bug inferensi muncul bukan karena timing gagal, tetapi karena perubahan numerik kecil yang lolos tanpa regression vector yang memadai.
Failure mode umum dan cara debug yang efisien
Mismatch output setelah perubahan kecil RTL
Biasanya disebabkan oleh salah satu dari berikut:
- latency pipeline berubah tetapi testbench atau comparator belum disesuaikan,
- pergeseran fixed-point salah satu bit,
- urutan channel atau packing bus berubah,
- signedness berubah saat cast.
Debug tip: log sampel pertama yang gagal, indeks tensor, nilai expected/actual dalam bentuk desimal dan heksadesimal, lalu telusuri dari boundary modul, bukan langsung dari output akhir.
Simulasi lolos, synthesis gagal
Sering terjadi karena kode valid secara simulasi tetapi buruk untuk synthesis, atau constraint/clocking baru menimbulkan masalah. Pastikan lint mencakup peringatan yang relevan untuk synthesizability, dan review penggunaan construct HDL yang mungkin ambigu.
Synthesis pass, tetapi hasil berbeda antar runner
Periksa versi tool, patch level, environment variable, seed implementasi, dan path dependency. Bila perlu, jalankan synthesis hanya pada satu pool runner yang homogen untuk release resmi.
CI lambat dan developer mulai mengabaikannya
Ini masalah desain pipeline, bukan hanya resource. Kurangi pekerjaan di PR, pecah regression menjadi subset, cache hasil yang aman, dan upload artefak log yang cukup agar orang tidak perlu rerun hanya untuk melihat penyebab gagal.
Checklist implementasi CI untuk FPGA ML
- Buat struktur repo yang memisahkan RTL, testbench, model, vector, dan script.
- Satukan perintah lokal dan CI lewat
Makefileataujustfile. - Terapkan lint HDL sebagai gate wajib sebelum merge.
- Siapkan smoke simulation yang cepat dan stabil.
- Buat test vector dan golden output dari referensi model yang jelas.
- Pisahkan pipeline fast checks dan full synthesis.
- Gunakan hosted runner untuk job ringan, self-hosted untuk synthesis vendor.
- Terapkan caching hanya pada artefak yang aman dan memiliki key yang ketat.
- Simpan metadata model, hash input, dan versi bitstream di artefak release.
- Definisikan gate sebelum merge dan gate sebelum release secara terpisah.
- Upload log simulasi, laporan timing, dan manifest agar debugging tidak bergantung pada rerun.
- Tinjau waiver lint, seed test, dan reproducibility secara berkala.
Penutup
CI untuk FPGA ML yang efektif bukan pipeline yang menjalankan semua hal di setiap commit, melainkan pipeline yang memberi feedback cepat untuk developer dan validasi berat pada waktu yang tepat. Mulailah dari lint HDL, smoke simulation, test vector, dan golden output sebagai gerbang merge. Setelah itu, tambahkan full synthesis, packaging artefak, dan versioning model/bitstream sebagai gerbang release.
Jika tim software dan hardware berbagi target command, metadata yang jelas, serta aturan gate yang konsisten, pengalaman developer meningkat signifikan: bug numerik lebih cepat terlihat, synthesis tidak menjadi bottleneck harian, dan setiap release lebih mudah dilacak serta direproduksi.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!