Community코딩 & 개발github.com

Verilog → draw.io:架构图 / 结构框图 / 状态机 / 控制结构

Verilog 및 SystemVerilog 코드(또는 논문, 특허, 구술 설명)를 편집 가능한 draw.io 다이어그램 네 가지 관점(아키텍처 다이어그램, 구조 블록도, 상태 머신도, 제어 구조도)으로 자동 변환합니다.

结构框图 / 状态机 / 控制结构란 무엇인가요?

이 스킬은 Verilog/SystemVerilog 하드웨어 설계를 네 가지 시각적 다이어그램으로 변환하는 전문 도구입니다. 첫 번째 관점인 아키텍처 다이어그램(arch2drawio.py)은 코드 개요를 분석하여 핵심 설계 포인트를 추출하고, 파이프라인 스테이지를 점선으로 분할하며, 피드백 경로를 강조하는 논문 스타일의 다이어그램을 생성합니다. 두 번째 관점인 구조 블록도(rtl2drawio.py)는 Yosys 합성 결과를 기반으로 레지스터, MUX, 연산 유닛, 게이트 등 게이트 수준의 세부 데이터 경로를 보여줍니다. 세 번째 관점인 상태 머신도(fsm2drawio.py fsm)는 case(state) 형태의 FSM을 동일한 크기의 원으로 표시하고 전이 조건을 원래 표현식 그대로 유지합니다. 네 번째 관점인 제어 구조도(fsm2drawio.py ctrl)는 제어 신호만 추출하여 여러 상태 머신 간의 상호 구동 관계를 시각화합니다. 이 스킬은 Claude Code, Cursor, Codex 등 다양한 AI 에이전트 플랫폼에서 사용 가능하며, PyYAML, Yosys, sv2v, Graphviz, drawio-skills에 의존합니다. 생성된 .drawio 파일은 완전히 편집 가능하며, SVG/PNG로 내보내기가 지원됩니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/BeenLi/claude-skills/tree/HEAD/skills/verilog-diagram

Installed? Explore more 코딩 & 개발 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Verilog → draw.io:아키텍처 다이어그램 / 구조 블록도 / 상태 머신 / 제어 구조

네 가지 관점, 문제에 따라 선택: 설계 사상이 무엇인가 (사람에게 설명, 논문/보고서 게재) → arch2drawio.py (0절, 기본값); 게이트 수준은 어떻게 생겼는가 (유닛별 데이터 경로) → rtl2drawio.py; 어떻게 동작하는가 (단일 FSM) → fsm2drawio.py fsm; 누가 누구를 지휘하는가 (전체 제어 구조) → fsm2drawio.py ctrl. 제어 위주 모듈(FSM, 디코더, 중재 컨트롤러)은 블록도가 복잡해지므로 후자 두 가지를 사용합니다.

의존성: PyYAML; PNG/SVG 내보내기는 drawio 필요 (탐색 순서 $DRAWIO_BIN → PATH → macOS 앱 → ~/.local/opt/drawio; Linux에서 $DISPLAY가 없으면 자동으로 xvfb-run 사용, 루트 권한이 없는 서버는 저장소의 tools/install-drawio-linux.sh로 설치). 내보내기가 없어도 모든 명령은 정상적으로 .drawio 파일을 생성하며, PNG만 빠지고 stderr에 한 줄 경고를 출력합니다. 블록도/제어 구조는 추가로 yosys, sv2v (SystemVerilog), dot (Graphviz), 그리고 설치된 drawio-skill이 필요합니다. (기본 ~/.claude/skills/drawio-skill, 환경 변수 DRAWIO_SKILL_DIR로 재정의 가능; autolayout.py만 호출하며 수정하지 않음). 세 가지 생성 스크립트 모두 --png / --svg / --scale N을 지원합니다 (PNG 기본 scale 3, 약 1 model unit = 3 px; $DRAWIO_SCALE로 기본값 변경 가능). 또한 개별 내보내기: python3 $S/scripts/drawio_export.py X.drawio --png --svg. Markdown/Obsidian에 넣을 때는 SVG를 우선 사용합니다 (깨지지 않음). $S는 이 스킬 디렉토리를 나타냅니다. examples/에 두 가지 비교 예제가 있습니다: wrr_arbiter.v (단일 스테이지 + 상태 레지스터), load_pipe.v (replay가 있는 다단계 파이프라인).

0. 아키텍처 스타일 다이어그램 (arch2drawio.py) — 기본값

입력은 코드 (또는 논문 / 특허 / 사용자 설명). Yosys 네트리스트는 너무 세밀하여 아키텍처 다이어그램에 적합하지 않으므로 여기서는 합성하지 않습니다: 스크립트가 소스 코드 개요를 제공하고, 사용자(agent)가 코드를 읽고, 핵심을 파악하여, 다이어그램 설명을 작성하면 스크립트가 결정론적으로 레이아웃하여 다이어그램을 생성합니다. 사용자는 설명 파일을 작성할 필요가 없으며, 사용자에게 다이어그램만 보여줍니다. 사용자가 직접 설명을 수정하려는 경우는 예외입니다.

python3 $S/scripts/arch2drawio.py outline src/*.sv --top gpu [--module core]   # 소스 코드 개요 (합성 안 함)
python3 $S/scripts/arch2drawio.py render  fig.yaml -o diagrams/arch_core.drawio --png

outline은 다음을 나열합니다: 계층 트리 (generate 복제 ×N), 포트, 스토리지 어레이 (깊이 × 너비, packed struct의 필드, 같은 깊이의 배열은 "동일한 테이블일 수 있음" 힌트), 스테이지 번호로 명명된 시퀀셜 레지스터 (s1_ / stage2_ / if_id_ …), 상태 머신, 의심되는 피드백 신호 (replay/kill/flush/stall/forward/refill…), 인스턴스 간 데이터 흐름 (공유 신호를 통해, clk/reset/루프 변수는 제거됨). 논문/특허/설명 입력 시 이 단계를 건너뜁니다.

다이어그램 작성 규칙 (설명 작성 시 준수)

  1. 핵심만 그리기: 먼저 한두 문장으로 설계의 핵심 사상을 설명하고, 이를 나타내는 구성 요소만 남깁니다; 접착 로직, clk/reset, 디버그 포트, 산발적인 제어는 모두 생략합니다. 일반적으로 8–20개의 상자; 초과하면 두 장으로 분할합니다 (최상위 1장 + 핵심 유닛 1장).
  2. 핵심 강조: 1–3개의 핵심 설계 포인트에 hl: true (대비색: 어두운 배경 흰색 글자) 또는 bold: true (굵게); 핵심 경로의 선도 | hl 가능. 영역을 강조해야 할 때는 groups + hl: true 사용 (밝은 배경색 상자).
  3. 모든 구성 요소에 번호를 붙이지 않음: 텍스트 대조가 필요할 때만 핵심 구성 요소에 num: N을 부여하고 callouts에 설명을 작성합니다.
  4. 유닛 상자는 간결하게: 상자 안에는 이름만 씁니다 (≤ 2줄), 의미는 모양으로 표현: 연산은 adder / mult / cmp / op 원형 기호 또는 alu, 선택은 mux (선택 단자 x.sel은 하단에서 입력), 저장소는 table, 큐는 fifo, 레지스터는 reg, 게이트는 and/or/xor/not.
  5. SRAM 테이블은 단일 entry의 필드 작성: table의 fields에 각 필드의 의미를 작성 (예: [V, Tag (20b), Data (32b)]), 다중 way 세트 연관은 stack: 4 사용 (겹쳐 쌓기 + ×4); 같은 깊이, 같은 주소의 병렬 배열은 하나의 테이블로 합치고, 각 배열은 하나의 필드가 됩니다.
  6. 파이프라인: stages로 스테이지 정의 (id + 기능 sub, 예: {id: S1, sub: 적중 판단}), 스크립트가 점선 경계와 스테이지 이름을 그림; 스테이지 간 레지스터 / FIFO는 between: [S0, S1]을 사용하면, 스크립트가 이를 경계선 위에 그립니다; 피드백 (대상이 더 이른 스테이지에 있는 경우)은 자동으로 하단 복도를 따라 돌아가며, | fb, | fb via=top (상단에서 우회)도 가능합니다. 여러 파이프라인은 lanes를 사용하며, 각 lane은 스테이지의 열을 공유하고, 시간적으로 대응되는 스테이지는 자동으로 정렬됩니다.
  7. 스테이지가 없는 블록 수준 다이어그램 (최상위, SoC)은 stages를 작성하지 않음; 복제되는 유닛은 stack: N을 사용하고, 스레드당/코어당 리소스는 groups로 묶습니다.

설명 형식 (YAML)

title: dcache_pipe:직접 매핑 D-Cache 검색 파이프라인
stages: [{id: S0, sub: 선택 / 배열 읽기}, {id: S1, sub: 적중 판단}, {id: S2, sub: 미스 / 재생}]
lanes:  [{id: ld, name: Load 파이프라인}, {id: st, name: Store 파이프라인}]     # 선택 사항, 여러 파이프라인일 때
nodes:
  - {id: arr, type: table, label: "캐시 배열 · 64 항목", fields: [V, "Tag (20b)", "Data (32b)"], stage: S0}
  - {id: r1, type: reg, label: addr, between: [S0, S1]}              # S0|S1 경계선 위에 위치
  - {id: tcmp, type: cmp, label: Tag 비교, stage: S1, hl: true}      # 원형 "=", 설명은 아래에
  - {id: rmux, type: mux, stage: S0, ports: 2}
edges:
  - "rmux => arr : idx | w=6"            # -> 데이터  => 버스(굵게)  ~> 제어(점선);w=N 비트 폭
  - "rpl -> rmux.sel : replay | fb hl"   # .sel/.en은 하단에서 입력, .top은 상단에서 입력;fb 피드백, hl 강조, via=top, pos=src|dst
groups: [{label: "스레드당 ×4", members: [rf, alu, lsu], hl: true}]
legend: {reg: 파이프라인 레지스터, fb: 피드백, ctrl: 제어, hl: 핵심 설계}      # 사용 가능한 키: data bus ctrl fb hl hl_edge hl_region reg
callouts: {1: "설명 대조가 필요할 때만 번호를 붙입니다."}

노드 유형: block reg fifo table(fields, rows, stack) array(dims, cell) mux(ports) adder mult cmp/op(sym) alu and or xor nand nor xnor not cloud mem xbar in out text dot. 공통 속성: stage / lane / between, hl bold num stack, 미세 조정용 row / col (스테이지 내 행/열, 음수 가능), dx / dy, w / h. 기타: array는 cell_labels (셀별 레이블, 예: T0..T3)와 cell_h (직사각형 셀, 스레드 채널 표시)를 지원; groups는 stack: N (전체 영역 겹쳐 쌓기, 예: "Core ×2" 및 내부 노출)와 label_align: right를 지원; lanes의 name을 비워두면 = 영역 분할만 하고 레이블은 그리지 않음; 에지의 | both는 양방향 화살표를 그림 (요청/응답); 같은 열의 상하 두 유닛 간 피드백은 밀착된 짧은 세로선으로 그림 (예: Dispatcher ⇅ Core).

프로세스

  1. outline + 핵심 소스 코드 읽기 (또는 논문/특허 읽기), 핵심 사상 정리 → 어떤 계층을 그릴지, 무엇이 중요한지 결정.
  2. 설명을 임시 디렉토리(scratchpad)에 작성, 각 노드에 stage 제공 (스테이지가 있을 때). 루프는 자동으로 끊김: 이름이 컨트롤러와 유사한 노드 (sched / ctrl / fsm / arbiter / dispatch / 스케줄러 / 컨트롤러 …, 다음으로 제어선 팬아웃이 큰 노드)에서 시작하며, 해당 노드의 출력은 오른쪽으로 가고, 다시 노드로 돌아오는 에지는 피드백으로 처리; 판단이 틀렸으면 해당 에지에 명시적으로 | fb를 작성합니다. 선택 사항: 구성 참조 (gpt-image-bridge, 사용자가 개별 확인 필요) — 그리드 레이아웃 도구는 연결을 보장하지만, "구성"을 하지는 않습니다. 모듈이 ≥ 10이거나 명확한 구분(제어 평면/데이터 평면/스토리지 계층)이 있을 경우, 먼저 draw.io 기준선을 출력한 다음, 코드에서 얻은 모듈 목록과 연결을 프롬프트에 작성합니다. (논문 삽화 스타일, 흰색 배경, 단일 강조 색상, 3구역 레이아웃, 텍스트 최소화, 영어 짧은 레이블), gpt-image-bridge로 1장의 스케치를 생성하고 Read. 레이아웃과 시각적 계층만 참고 (구분, 누가 누구 위에 있는지, 행렬, 여백, 중요 위치), lane / row / col / groups로 변환; 모듈, 연결, 이름은 항상 코드를 기준으로 함 — 스케치의 일반적인 오류: 잘못된 소스 연결, 모듈 누락/과다, 어두운 배경. 생성 전에 이 스킬 규정에 따라 이미지를 나열 (용도, 경로, 크기, 프롬프트 요약)하고 사용자가 명시적으로 동의할 때까지 기다림; 스케치는 diagrams/sketch_*.png에 저장, 설명 파일 헤더에 주석으로 참조.
  3. render --png → validate.py (error는 반드시 0이어야 함; 구분 점선이 스테이지 헤더/레지스터를 통과하는 overlap 경고는 의도된 설계) → PNG Read로 육안 검사, row / col로 최대 2회 미세 조정 (일반적: 메인 데이터 경로가 row 0을 직선으로 차지하도록, 바이패스 / 제어는 다음 행에 배치).
  4. .drawio + .png 전달; 설명 파일은 scratchpad에 남겨두며, 사용자가 직접 수정하려는 경우에만 제공.

예시: tiny-gpu 최상위 ~/hardware-project/tiny-gpu/diagrams/arch_gpu.* (스케치 sketch_gpu_top.png가 구성 안내, 스케치를 사용하지 않은 arch_gpu_baseline.png와 대조); examples/dcache_pipe.v → dcache_pipe.arch.yaml (코드에서 작성된 설명) → .png; arch_dual_issue.yaml (이중 파이프라인 정렬 + 포워딩 + 번호 주석), arch_mac.yaml (회로 수준: 곱셈/덧셈 기호, 누적 피드백, MUX 선택 단자). tiny-gpu core의 블록 수준 다이어그램은 ~/hardware-project/tiny-gpu/diagrams/arch_core.* 참조.

1. 구조 블록도 (rtl2drawio.py, 게이트 수준 세부 사항)

python3 $S/scripts/rtl2drawio.py src/*.sv --top gpu --list                     # 모듈 및 유닛 구성
python3 $S/scripts/rtl2drawio.py src/*.sv --top gpu --module alu -o diagrams/alu.drawio --png

프로세스: sv2v (.sv를 만나면 자동) → Yosys proc; opt; opt_dff; wreduce; memory -nomap → JSON 네트리스트 → 유닛 수준 파이프라인 분석 → 단순화 → 열 제약 레이아웃. 생성 후 python3 ~/.claude/skills/drawio-skill/scripts/validate.py X.drawio 실행 (error는 반드시 0이어야 함; 스테이지 구분선/레지스터가 경계선 위에 걸쳐서 발생하는 through-vertex / overlap 경고는 의도된 설계), 그런 다음 PNG Read로 육안 검사.

레이아웃 규칙 (--layout pipeline; 기본값 auto: 서브모듈 인스턴스가 주를 이루는 계층 모듈은 자유 레이아웃, 나머지는 파이프라인 스테이지 레이아웃 사용)

  • 입력은 왼쪽, 출력은 오른쪽, 로직은 조합 깊이에 따라 왼쪽에서 오른쪽으로 열 분할; 다단계 파이프라인은 S0 → Sn 왼쪽에서 오른쪽으로, 점선 구분, 열 머리에 스테이지 번호 표시.
  • 레지스터는 두 종류로 분류:
    • 파이프라인 레지스터 (좁은 세로 막대)는 스테이지 경계선 위에 배치; 마지막에 출력 포트에만 연결되는 한 줄은 출력 레지스터 (스테이지로 간주하지 않음, 구분선을 그리지 않음).
    • 상태 레지스터 (FSM / 카운터 / 포인터: 출력이 조합 로직만 거쳐 자기 입력으로 돌아옴)는 스테이지 내부에 배치, 출력은 피드백으로 처리.
    • 레지스터 이름에 스테이지 번호가 포함된 경우 (s2_x, x_s2, stage2_x, if_id_/id_ex_/ex_mem_/mem_wb_이며, 최소 두 가지 유형) 이름을 기준으로 함 — kill이 있는 valid 비트는 조합 루프가 있어도 여전히 파이프라인 레지스터. 설계가 스테이지별로 명명되지 않은 경우 구조로만 추론해야 하며, 입력 포트의 도달 시간을 알 수 없어 스테이지 번호가 너무 빠를 수 있습니다.
  • 스테이지 번호 추론: 스테이지 번호가 있는 레지스터에서 시작하여, 유닛의 스테이지 = 가장 늦게 도달하는 레지스터 오퍼랜드 (최대값 취함); 입력 포트만으로 구동되는 로직은 "어느 스테이지의 레지스터에 샘플링되는지"에 따라 스테이지 분류 (ALAP), 해당 입력 포트도 해당 스테이지의 시작 부분에 배치 (예: TLB 응답은 S1에 배치).
  • 피드백: 특정 스테이지 번호가 있는 레지스터의 입력 콘에 들어가지만, 더 이후 스테이지에서만 올 수 있는 신호 (replay→S0, kill→S1), 및 상태 레지스터의 루프백은 빨간 선으로 하단 외곽을 따라 돌아가며 그리며, 범위가 큰 것은 바깥쪽에; 동일한 스테이지 쌍 사이에 피드백이 3개 이상이면 하나의 굵은 선으로 묶어서 표시 (피드백 ×N:… 레이블).
  • 번들링: 동일한 경계선 위에 파이프라인 레지스터가 4개 이상이면 하나의 레지스터 그룹으로 병합 (세로 막대에 S1→S2 레지스터 ×N 및 총 비트 폭 레이블).
  • 단순화: 동일한 이름의 레지스터 슬라이스는 병합; 중첩 if/case의 MUX 체인은 하나의 N:1 MUX로 합성; 하나의 MUX 선택 단자 / 레지스터 인에이블만 구동하는 작은 디코딩 로직은 선택선 / 인에이블선으로 통합하여 그림; 3개 이하의 게이트는 AND/OR/NOT/XOR 게이트 기호로 그리고, 더 큰 것은 "조합 로직" 클라우드로 접음 (연산 유닛 사이에서 잘려서 가짜 루프를 방지); generate 루프로 풀린 동일 소스 (동일한 소스 코드 위치) 유닛 및 threads[i].x 인스턴스는 「×N」 (그림자 포함)으로 접음. 모든 병합은 동일한 스테이지 내에서만 수행됨. clk/reset은 기본적으로 숨겨짐.
  • 연결선: 실선=데이터 (굵음=다중 비트 버스, /N=비트 폭); 보라색 점선=MUX 선택; 파란색 점선=인에이블; 빨간색 선=피드백.

매개변수

매개변수역할
--list모듈 및 유닛 구성을 나열하고 종료
--module M어떤 모듈을 그릴지 (매개변수화된 변형은 첫 번째를 그리며, 힌트를 출력)
--layout auto|pipeline|free기본값 auto: 서브모듈 인스턴스가 있고 조합 로직 노드가 인스턴스보다 많지 않은 경우 (최상위 접착 모듈) free 사용 (블록 간 양방향 통신이 파이프라인 피드백이 아님), 그렇지 않으면 pipeline
--show-clockclk/reset 표시
--no-foldgenerate 인스턴스 / 동일 소스 유닛 접지 않음
--no-collapse제어/조합 로직 접지 않음
--sv2v auto|always|neverSV 프론트엔드 (압축되지 않은 배열 포트 등 구문에는 sv2v 필요)
--keep-json PATHYosys JSON 네트리스트 보존

2. 상태 머신도 (fsm2drawio.py fsm)

python3 $S/scripts/fsm2drawio.py list src/*.sv
python3 $S/scripts/fsm2drawio.py fsm  src/*.sv [--module M] -d diagrams --png [--no-actions]
  • 소스 코드를 직접 파싱하며, 전이 조건은 원래 표현식을 보존합니다. case (S) 분기에서 S (또는 S <= N의 다음 상태 변수 N)에 값을 할당하는 부분을 식별; 상태 이름은 localparam을 사용; 다른 FSM의 상태 변수와 비교하는 상수는 상대방 상태 이름으로 변환합니다 (core_state == 3'b001 → core_state == FETCH).
  • 전이 조건 = 상태 할당을 직접 감싸는 if/case/for; else if는 자신의 조건만 작성; for의 조건은 ∃j: …로 작성; 외부 for i가 전체 case를 감싸면 i에 따라 복제됨을 의미; case 외부의 가드 (enable, 읽기/쓰기 분기)는 주석 상자에 포함; 루프에서 1로 설정되는 지역 부울 변수는 주석 상자에 정의를 제공합니다.
  • 그리기 방식: 각 상태는 동일한 크기의 원 (이름은 _에서 줄바꿈, 아래쪽에 작은 글씨로 코딩 및 ⟳), 최종 상태는 이중 원, 검은 점=리셋 진입점. 메인 흐름이 대부분의 상태를 포함할 때는 U자형 루프로 배열 (윗줄 왼쪽→오른쪽, 아래로 꺾음, 아랫줄 오른쪽→왼쪽); 분기형은 초기 상태로부터의 단계 수에 따라 균등하게 열 분할. 인접 상태는 직선 연결; 다른 상태를 건너뛰는 전이는 위쪽/아래쪽으로 아치형으로 그리고, 레이블은 아치 꼭대기에; A↔B 왕복은 각각 한쪽으로 휨; 명시적 자체 루프는 원 위쪽에 그림. 열 간격은 가장 긴 레이블에 맞춰 자동 조정. / 뒤는 전이 시 할당 (최대 2개 표시).
  • 식별하지 않음: case(state) 구조가 없는 제어 (카운터 방식, 순수 조합 디코딩) — list에 나타나지 않으며, 예상된 동작.

3. 전체 제어 구조 (fsm2drawio.py ctrl)

python3 $S/scripts/fsm2drawio.py ctrl src/*.sv --top gpu --module core -o diagrams/ctrl_core.drawio --png
  • 모듈 L의 서브모듈 인스턴스를 그리고 (generate 인스턴스는 ×N으로 접음), 제어 신호만 유지: 주황색 굵은 선=FSM 상태 브로드캐스트; 파란색 선=valid/ready 핸드셰이크; 보라색 점선=start/done/인에이블/선택/리셋 등; 데이터 버스는 생략. FSM을 포함하는 인스턴스 상자는 상태 시퀀스를 나열하고, 하위 계층에 FSM이 있는 것은 "FSM 포함"으로 표시.
  • 제어 신호는 최대 3계층의 기본 유닛 (비교기, 게이트, 레지스터)을 관통하여 소스를 추적. 분류는 신호 이름에 의존하며, 명명 규칙이 잘못된 경우 누락/과다 그려질 수 있음.
  • 위에서 아래로 제안: 먼저 최상위 (누가 누구를 시작하는지, 누가 메모리와 핸드셰이크하는지) → 다음 계층 (메인 컨트롤 FSM이 어떻게 스케줄링하는지) → 핵심 FSM의 상태 머신도.

한계

  • 레이아웃은 Graphviz가 열 제약에 따라 자동으로 수행하며, 교차를 완전히 제거할 수 없음; 정밀 수정은 draw.io에서 드래그하여 수행 (모두 기본 편집 가능 객체).
  • 대규모 제어형 모듈 (수백 유닛)의 블록도는 여전히 복잡해질 수 있으므로, 위의 지침에 따라 상태 머신도 / 제어 구조도를 사용하거나, 서브모듈별로 개별적으로 그림.
  • 상태 머신도의 원/호는 좌표에 따라 직접 그려지므로, 상태를 드래그할 때 호의 꺾임점이 따라 움직이지 않으므로 함께 조정해야 합니다.

관련 스킬