Menu

Verilog Initial 블록: 시뮬레이션 시작 시 setup 실행하기

initial 블록이 always와 어떻게 다른지, 왜 시뮬레이션 전용인지, 그리고 자극, waveform 설정, 로그 헤더 등 그것이 쓰이는 흔한 패턴들.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

한 번 실행되는 procedural 블록

initial begin ... endalways의 형제입니다. 차이는: initial은 시간 0부터 정확히 한 번 실행되고 종료합니다. sensitivity list도 없고 루프도 없습니다.

이건 한 가지 이유로 존재합니다: testbench 설정. 초기값 설정, 자극 시작, 로그 파일 열기, 고정 시뮬레이션 시간 뒤에 $finish 호출 - 실행 시작 시 알려진 순서로 한 번 일어났으면 하는 모든 것.

시뮬레이터가 무엇을 하는지 단계별로.

  1. 시간이 0으로 진행.
  2. initial 블록 시작. 첫 $display가 출력.
  3. data8'hA5로 설정됨.
  4. #10이 시뮬레이션 시간을 10 단위 진행시킴.
  5. 두 번째 $display가 출력.
  6. $finish가 시뮬레이션 종료.

블록이 한 번 실행됐고 두 번째 패스는 없습니다.

정석 testbench 골격

여러분이 작성할 거의 모든 testbench는 이런 initial 블록을 사용합니다.

모양을 보세요 - 매번 손에 쥐게 될 testbench 템플릿입니다.

  1. VCD dump 파일 열기($dumpfile, $dumpvars) - Dumpfile and VCD에서 다룸.
  2. 초기값을 두고 몇 사이클 동안 reset 유지.
  3. 자극 구동 - # 지연 사이에 변경.
  4. $finish 로 시뮬레이션 깔끔히 종료.

이게 전부입니다. 벤더 예제를 포함해 여러분이 보게 될 모든 Verilog 테스트가 이 패턴을 따릅니다.

여러 initial 블록은 병렬

같은 모듈의 여러 initial 블록은 모두 시간 0에서 동시에 시작합니다. 각각 자기 time slice에서 자기 문장을 실행합니다.

시뮬레이터는 두 블록을 시간 0에서 시작합니다. 블록 B의 첫 $display가 즉시 실행됩니다. 블록 A는 5단위 기다린 뒤 출력합니다. 블록 B가 시간 2에 다시 출력합니다. 블록 A의 두 번째 print는 시간 15에 발사됩니다. 블록 B의 $finish가 시간 22에 시뮬레이션을 죽입니다.

setup, 클럭 생성, 자극을 별도 initial 블록으로 나누는 건 흔한 스타일입니다 - 각 블록이 짧고 한 가지 일만 합니다.

선언에서의 인라인 초기화

흔한 컴팩트 형태: 선언 시점에 reg를 바로 초기화. 대부분의 시뮬레이터가 이것을 initial과 동일하게 다룹니다.

reg clk = 0;
reg reset = 1;
reg [7:0] count = 0;

이는 다음과 등가입니다.

reg clk;
reg reset;
reg [7:0] count;

initial begin
    clk = 0;
    reset = 1;
    count = 0;
end

testbench에서 보게 될 컴팩트 형태입니다 - 초기값을 선언 바로 옆에 두면 한눈에 들어옵니다.

initial은 시뮬레이션 전용

synthesis 도구는 initial 블록을 무시합니다. 실제 하드웨어에는 setup 코드가 실행되는 "0의 순간"이 없습니다 - power-on, reset 신호, 그리고 그 이벤트들에서 오는 설정이 있을 뿐입니다. 실제 하드웨어에서 register를 알려진 상태로 시작해야 한다면, always @(posedge clk) 안에서 reset 신호로 구동하세요.

always @(posedge clk) begin
    if (reset) state <= IDLE;
    else       state <= next_state;
end

if (reset) 분기가 initial state = IDLE의 synthesizable 등가물입니다. reset이 "실제 하드웨어에서 register를 어떻게 초기화하나"의 답입니다.

일부 FPGA flow는 register reset 값을 위한 제한된 initial을 받아들이지만(예: Xilinx 도구), 그건 벤더별 확장입니다. 이식 가능한 코드에서는 의존하지 마세요.

initial 안에서 보게 될 것

표준 testbench 골격을 넘어선 흔한 패턴 몇 가지.

시간 지연 종료

initial begin
    #1000 $finish;   // 안전망: 1000 시간 단위 뒤에 시뮬레이션 죽이기
end

오직 시뮬레이션의 상한을 부여하는 일만 하는 별도 initial. 메인 자극 블록이 결코 오지 않을 신호를 기다리며 deadlock해도 이 블록이 발사돼 실행을 종료시킵니다.

Waveform 설정

initial begin
    $dumpfile("dump.vcd");
    $dumpvars(0, test);   // `test` 스코프 아래 모든 것을 dump
end

이 두 줄이 시뮬레이터에게 test 스코프의 모든 신호를 VCD 파일로 쓰라고 알립니다. 없으면 파형이 없습니다.

초기 메모리 이미지

reg [7:0] memory [0:255];

initial begin
    $readmemh("image.hex", memory);
end

$readmemh는 hex 포맷 파일을 array로 로드합니다. CPU testbench에서 명령어 메모리를 미리 로드하는 데 쓰입니다. 시뮬레이션 전용.

흔한 실수

Synthesizable 로직에 initial을 사용. Synthesize되지 않습니다. 대신 reset 신호를 쓰세요.

$finish를 잊는 것. 없으면 시뮬레이터가 다른 무언가가 멈추기 전까지(기본 시간 제한, 수동 인터럽트 등) 계속 진행합니다. 빠른 테스트면 괜찮지만 regression 스크립트라면 항상 $finish.

자극 대입 사이에 #delay 잊기. a = 0; b = 1;을 지연 없이 쓰면 둘 다 같은 시뮬레이션 시간에 일어나고, DUT가 별도 이벤트가 아니라 동시에 보게 됩니다. 다른 자극 이벤트 사이에는 #1 이상을 넣으세요.

initial에서 wire를 구동하려 함. always와 같은 규칙: reg만 합법 타겟.

다음에 볼 내용

procedural-block 두 종류를 봤습니다. 다음 문서는 초보 Verilog에서 가장 헷갈리는 주제를 다룹니다: Blocking vs Non-blocking Assignment. =<=를 언제 쓸지 아는 것이 동작하는 플립플롭과 race condition 혼란의 차이입니다.

자주 묻는 질문

Verilog의 initial 블록이란?

initial begin ... end는 시뮬레이션 시작 시 시간 0에서 정확히 한 번 실행되는 procedural 블록입니다. testbench 상태를 설정하는 표준 자리입니다: 신호 초기화, 로그 파일 열기, $dumpfile/$dumpvars 호출, 자극 구동, 그리고 $finish로 시뮬레이션 종료. 한 모듈에 여러 initial 블록이 공존할 수 있고, 모두 시간 0에서 병렬로 시작합니다.

initial과 always의 차이는?

initial은 시간 0에서 한 번 실행되고 종료합니다. always는 영원히 재실행합니다 - sensitivity list가 있고 나열된 신호가 변할 때 깨어납니다. initial은 거의 testbench에서만 사용됩니다. always는 testbench와 synthesizable RTL 양쪽의 일꾼입니다.

initial 블록은 synthesizable인가요?

일반 Verilog에서는 아닙니다. synthesis 도구는 initial 블록을 무시합니다. 실제 하드웨어에는 setup 코드가 실행되는 '시간 영(零)'이 없기 때문입니다. 일부 FPGA toolchain은 register reset 값을 설정하기 위한 제한된 형태를 받아들이지만, 일반적인 경우는 시뮬레이션 전용입니다. initial 블록은 testbench에 남기고, synthesizable 로직 초기화에는 reset 신호를 쓰세요.

한 모듈에 initial 블록을 여러 개 둘 수 있나요?

네. 각 initial 블록은 시간 0에서 시작해 독립적으로 끝까지 실행됩니다. setup을 여러 블록으로 나누는 것은 흔한 testbench 패턴입니다 - 클럭 생성용 하나, 자극용 하나, waveform dump용 하나. 모두 시간 0부터 동시 실행되고, 시간이 진행되면서 시뮬레이터가 그 문장들을 인터리브합니다.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기