FPGA 세션1 — 한선씨 합성 파이프라인 (yosys/nextpnr → 실 비트스트림)
개요
세션1-FPGA 브리프의 첫 단계 완료: 한선씨로 기술한 회로 → 합성가능 Verilog → yosys → nextpnr-ice40 → icepack → 실.bin 비트스트림. 오픈소스 툴체인을 끝까지 결선하고, 한선씨 에미터가 손-레퍼런스와 바이트 동일 비트스트림을 생성함을 왕복검증했다.무엇을 했는지
1. 툴체인 설치 + E2E 증명
brew install yosys nextpnr-ice40 icestorm(GHDL은 기설치). Yosys 0.66 / nextpnr-ice40 0.10 / icestorm 1.1.- 손으로 쓴 합성가능 Verilog 카운터(blinky)로 전체 플로우 증명: 29 LC / 1280, Max freq 191 MHz (PASS @12MHz), 32,220 B 비트스트림 (iCE40 싱크마커
ff00 00ff 7eaa 997e확인).
2. 회로합성.한선 — 순수 한선씨 Verilog 에미터 (신규 라이브러리)
libs/회로합성.한선. 문자열 누적만으로 합성가능 Verilog 생성 (VM 65535 캡 이하, 나눗셈/큐브설정 회피).- API:
폭표기v입력/v입력버스/v출력/v출력버스포트조립v모듈/v모듈끝v레지스터/v신호v항상상승v대입v슬라이스+ 고수준블링키생성(모듈명,클럭명,LED명,카운터폭,LED수). - 함정:
신호는 hanseonc_high 예약어 → 매개변수명 불가(버스로 회피).
3. 제약파일(.pcf) 생성기 (한선씨)
- 같은 라이브러리에
pcf핀pcf버스핀pcf블링키_icestick추가. iCEstick(HX1K-TQ144): clk=21, LED=99/98/97/96/95.
4. 원클릭 파이프라인 드라이버 + 회귀
rtl/fpga/합성.sh {emit|build|all|test}+ 동반합성플로우.한선(4단계 한선씨 기술)../합성.sh test→ PASS: 한선씨생성 .bin == 손-레퍼런스 .bin (바이트 동일, md56e874aa8...).
왕복검증 결과
| 산출물 | 결과 |
|---|---|
| 한선씨생성 .v vs 손-Verilog | 공백 1칸 차이만(의미 동일) |
| 한선씨생성 .v → 비트스트림 | 손-레퍼런스와 바이트 동일 |
| 한선씨생성 .v + .pcf → 비트스트림 | 손-레퍼런스와 바이트 동일 |
관련 파일
/Users/ef/CrownyOS/crownyc/libs/회로합성.한선— 에미터 라이브러리 (.v + .pcf)/Users/ef/CrownyOS/crownyc/rtl/fpga/블링키.한선— 데모 (RTL → .v/.pcf 출력)/Users/ef/CrownyOS/crownyc/rtl/fpga/합성.sh+합성플로우.한선— 파이프라인 드라이버/Users/ef/CrownyOS/crownyc/rtl/fpga/verilog/,pcf/,build/— 산출물- 손-레퍼런스:
verilog/blinky_ref.v,pcf/icestick.pcf
확장 (2026-06-20)
에미터 순차로직 확장 (회로합성.한선)
v항상상승블록(begin/end),v논블로킹(<=),v만약/v아니면(if/else),v접합({a,b}비트접합) 추가.- 고수준 합성기 2종:
카운터생성(동기리셋 업카운터),시프트레지스터생성(SIPO).
회로방언.한선 — .회로 → 합성가능 Verilog 트랜스파일러 (순수 한선씨, 신규)
- 브리프 핵심 문구 "회로방언 → 넷리스트 → 비트스트림" 실현. 기존
hanseonc_dialect.c는.회로를 시뮬레이션으로만 변환했으나, 이건 합성가능 Verilog 생성. examples/카운터.회로(모듈/입력/출력/신호/항상@상승/만약-아니면/신호읽기·신호설정) 파싱 →counter모듈 Verilog.- yosys 한글 식별자 거부 →
이름맵(클럭→clk, 리셋→rst, 값→val…)으로 ASCII 변환. 시뮬레이션 블록은 합성 비대상으로 무시. - 함정: 이
hanseonc_high는 인라인;주석을 코드로 파싱(구버전) → 인라인 주석/한 줄 다중문장 금지.
방언경로 == 직접경로 동등성 (왕복검증)
.회로 → Verilog(방언)와 직접 한선씨 카운터생성이 동일 하드웨어로 합성: 둘 다 2 SB_CARRY + 4 SB_DFFSR + 4 SB_LUT4 = 10 셀.통합 회귀 (./합성.sh regress)
4종 전부 비트스트림 PASS ✅: 블링키(29 LC) · 카운터(7 LC) · 시프트(5 LC) · 방언카운터(7 LC). 전부 32,220 B .bin, 모두 191~626 MHz PASS @12MHz.추가 파일: rtl/fpga/{카운터.한선, 회로방언.한선, 시프트.한선}, verilog/{카운터_gen,카운터회로_gen,시프트_gen}.v, pcf/{카운터_gen,시프트_gen}.pcf.
2단계: 합성가능성 보장 (2026-06-20)
합성검사.한선 — 합성가능 서브셋 가드 (순수 한선씨, 신규)
- yosys/nextpnr 넘기기 전 비합성 구조 검출. 오류(나눗셈
/, 초월함수 루트/사인/코사인/로그, always 내동안(while)) + 경고(yosys 거부하는 한글 식별자, 이름맵 필요). ./합성.sh 검사 <.회로>. 카운터.회로 → PASS(0/0), 나쁜회로.회로 → FAIL(오류 3, 경고 2).- 함정:
오류는 hanseonc_high 예약어(시도/오류 catch절) → 변수명 불가(오류수로 회피). 한글 env명은 bash 미전달 → ASCII(CIRCUIT).
룩업.한선 / 룩업생성 — 정적 case LUT (나눗셈/√ 합성가능 대안)
- 가드가 잡은 나눗셈/초월함수의 합성가능 대안. 미리 계산한 값 배열 → 조합 ROM(
always @(*) case). - 데모: ÷3 LUT(4비트 입력 → floor(i/3), 16엔트리) → 5 LC 비트스트림.
v출력reg버스/v케이스라인/룩업생성추가.
통합 회귀 5종 (./합성.sh regress)
블링키·카운터·시프트·룩업·방언카운터 전부 비트스트림 PASS ✅.추가 파일: rtl/fpga/{합성검사.한선, 룩업.한선}, examples/나쁜회로.회로, verilog/룩업_gen.v, pcf/룩업_gen.pcf.
방언 확장 + 전단 가드 자동연결 (2026-06-20)
회로방언.한선 v2 — 블록스택 트랜스리터레이션
- 줄단위 의미재구성 → 블록스택 기반 트랜스리터레이션 파서로 일반화. 다중 always, 중첩 선택(case)/만약(if), 조합
@*지원. - always
@*에서 대입되는 출력 =output reg자동 판정(reg출력스캔, 브레이스 깊이). - 신규 .회로: ALU(4연산 조합 case, 47 LC), FSM(3상태 순차+중첩 case/if, 5 LC), 이중카운터(다중 always, 11 LC) — 전부 비트스트림 PASS.
전단 합성가드 자동연결 (합성가드.한선 라이브러리)
- 가드 로직을
libs/합성가드.한선(검사→오류수)으로 추출.회로방언.한선이 변환 전에 자동 호출. - 오류>0 → ⛔ 차단, Verilog 미생성 → 잘못된 .회로가 yosys까지 못 감. 검증: 나쁜회로.회로 → 차단(/tmp/bad.v 미생성), 정상 → 변환.
합성검사.한선도 같은 라이브러리 래퍼로 단일화.
드라이버 확장 (합성.sh)
regress(9종: 직접 에미터 4 + 방언 4 + 카운터회로),dialect <.회로> <top> <base> [pcf](원클릭, 가드 자동),flash <base>(iceprog 실보드),검사.- README.md 추가(빠른시작·두 경로·실보드 워크플로·함정).
상태: "실보드 꽂고 디버깅만"
.회로 → (가드) → Verilog → yosys → nextpnr → icepack → .bin 전부 자동. iCEstick USB 연결 후 ./합성.sh flash <base>만 남음. iceprog 설치됨(보드 미연결 시 "Can't find iCE FTDI USB device" 정상).보드 생태계 + 원스탑 구동 (2026-06-20, 무하드웨어 사전구축)
하드웨어 미보유 상태에서 "보드 꽂으면 한 줄로 구동" 되도록 사전 구축. flash만 보드 대기, 나머지 전부 검증.보드 프로파일 레지스트리 (libs/보드.한선)
- 보드 → 디바이스/패키지/클럭핀/클럭MHz/LED핀들/리셋핀/프로그래머. icestick(hx1k/tq144/clk21/LED5)·icebreaker(up5k/sg48/clk35/LED2)·hx8k(ct256)·upduino(up5k). 보드별
보드pcf()생성. - 새 보드 = if-체인 한 줄 추가.
브링업.한선 — 보드별 blinky 생성기
- BOARD env → 보드 LED수에 맞춘 blinky + 보드 pcf +
META device pkg programmer ledn라인(shell 파싱용).
구동.sh — 원스탑 오케스트레이터
doctor(툴체인+보드 준비도+다음할일),boards(프로파일 목록),probe(iceprog -t 보드탐지: 0=연결/1=미연결/127=툴없음),bringup <board>(blinky→비트스트림→보드있으면 자동flash),flash <board>,run <design> <board>(.한선/.회로 원스탑, 가드 자동).하드웨어연결.md: 보드선택·물리연결·원스탑·디버깅 가이드.
무하드웨어 retarget 증명
- icestick(HX1K) 32,220B / icebreaker(UP5K, 다른 칩) 104,090B 비트스트림 — 크기 다름=진짜 보드별 합성. 칩 패밀리 retarget 동작.
- 보드 도착 시: USB 연결 →
./구동.sh probe→./구동.sh bringup icestick→ LED 깜빡이면 끝.
UART + ECP5 타깃 (2026-06-21)
UART 송신기 (회로합성.한선: 송신생성 / 송신헬로생성)
- 8N1 UART TX(DIV=클럭/보드레이트).
송신생성(모듈명, DIV)+ 보드데모송신헬로생성(주기적 'A' 전송). - iverilog 기능검증 PASS: 송신 0x41 == 수신 0x41 (시리얼 프레임 디코딩). 함정: output reg(tx/busy)
initial초기화 없으면 시뮬 x 전파. - uart_hello → icestick 비트스트림 79 LC. 보드선 tx핀→USB시리얼, 터미널 9600 baud로 'A' 확인.
ECP5 타깃 (보드 패밀리 분기)
- 보드.한선에 패밀리(ice40/ecp5) + ECP5 보드(ulx3s/orangecrab/ecp5-evn) +
.lpf생성기(LOCATE/IOBUF SITE). 프로그래머 openFPGALoader + 로더플래그. - 구동.sh 패밀리 분기: ice40=synth_ice40/nextpnr-ice40/icepack/iceprog(.bin), ecp5=synth_ecp5/nextpnr-ecp5/ecppack/openFPGALoader(.bit).
- 툴: synth_ecp5(yosys)·ecppack(prjtrellis)·openFPGALoader=brew. nextpnr-ecp5는 brew 미제공 → 소스빌드(cmake -B build -DARCH=ecp5 -DTRELLIS_INSTALL_PREFIX=/opt/homebrew) → /opt/homebrew/bin 설치.
- 무하드웨어 ECP5 풀 비트스트림 증명: ULX3S blinky → synth_ecp5 → nextpnr-ecp5(335MHz) → ecppack → 1.9MB .bit. doctor 전부 그린.
- boards 7종(iCE40 4 + ECP5 3).
bringup ulx3s(.bit)·bringup icestick(.bin) 둘 다 동작.
UART RX + 에코 + 기능 시뮬 회귀 (2026-06-21)
UART 수신기 + 에코 (회로합성.한선: 수신생성 / 에코생성)
- 8N1 UART RX(중간샘플 DIV/2, case FSM idle/start/data/stop) + 에코 top(rx→tx 루프백, uart_rx+uart_tx 인스턴스).
- iverilog 양방향 기능검증: 에코 5/5 바이트 PASS(0x55·0xA3·0x00·0xFF·0x41 입력==에코). RX 디코딩+TX 재인코딩 왕복.
- uart_echo 비트스트림: iCE40(icestick 134 LC, .bin) + ECP5(ulx3s 160MHz, 1.9MB .bit) 둘 다.
시뮬.sh — 기능 시뮬 회귀 (iverilog)
- 합성("만들어지는가")에 더해 동작("올바로 동작하는가")을 상시 검증. uart_tx(송수신 일치)·uart_echo(5/5) 테스트벤치 자동 실행. 하드웨어 없이 가능한 최강 검증.
- 하드웨어연결.md에 시리얼 에코 테스트(screen/minicom 9600 8N1) 워크플로 추가.
PWM + 호흡등 (회로합성.한선: 변조생성 / 호흡생성)
- PWM(카운터<duty → out=1) + 호흡등(duty 자동 0..max..0 램프 → LED 밝기 숨쉬듯). iverilog 기능검증: duty=64 → 64/256 high(25%) PASS. breathe 합성 74 LC.
- 시뮬.sh 기능 회귀 3종(uart_tx·uart_echo·pwm) 전부 PASS.
BRAM 블록 메모리 (회로합성.한선: 메모리생성)
- 단일포트 동기 RAM(write→sync read). yosys 블록RAM 추론 확인: 256x8 → 1× SB_RAM40_4K(LUT 아님). write→read 3/3 PASS(addr 5/10/200). iCE40 .bin + ECP5 .bit.
- 시뮬.sh 기능 회귀 4종(uart_tx·uart_echo·pwm·bram) 전부 PASS.
자동 재개 (레이트리밋 대비)
- 세션에 60초 자동 깨어남 설정 — 레이트리밋 시 백오프 후 다음 미완 작업(.회로 폭추론/orangecrab DFU) 자동 이어감.
잔여 이슈 (다음 단계)
- 회로방언(.회로) → 회로합성.한선 연결: 현재
hanseonc_dialect.c는.회로를 시뮬레이션(하드웨어.한선)으로만 트랜스파일..회로→ 합성가능 Verilog 경로 추가 필요(카운터.회로를 에미터로 흡수). - 합성가능 서브셋 보장: 나눗셈/뉴턴랩슨 → 정적 LUT, 클럭/리셋 규약 강제, 회귀 확장.
- 실보드 검증: iCEstick에
iceprog로.bin플래싱 → LED blink 육안 확인 (하드웨어 필요). - ECP5/UP5K 타겟: nextpnr-ecp5, UP5K(sg48) 핀맵 추가.
- 더 큰 회로(UART/ALU/FSM): 에미터 always-블록/case 문 확장.