Menu

Verilog For 루프: 컴파일 시점에 unroll됨

Verilog의 for 루프가 소프트웨어 사촌과 어떻게 다른지 - 런타임에 반복 실행되지 않고 synthesizer가 병렬 하드웨어로 unroll합니다.

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

소프트웨어 닮은꼴

Verilog의 for 루프는 C의 사본입니다.

for (i = 0; i < 8; i = i + 1) begin
    // 본문
end

같은 세 부분: initializer, condition, increment. 조건이 유지되는 동안 본문이 재실행됩니다.

testbench에서는 소프트웨어에서 기대하는 그대로 동작합니다. 시뮬레이터가 각 반복을 차례로 진행합니다.

네 번 반복, 네 줄 출력. 놀랄 일 없음.

놀라움은 synthesizable 코드 안에 for 루프를 넣을 때 옵니다.

Unroll

synthesizable always 블록의 for 루프는 하드웨어에서 런타임 루프가 되지 않습니다. synthesizer가 elaboration 시점에 그것을 unroll 합니다 - 본문을 N개 사본으로 펼칩니다.

루프처럼 보입니다. 시뮬레이션에서 시뮬레이터는 여덟 반복을 진행합니다. synthesis에서는 루프가 data[0]에서 data[7]까지의 여덟 병렬 검사로 unroll되어 모두 동시에 일어납니다. synthesizer가 보는 것은

count = 0;
if (data[0]) count = count + 1;
if (data[1]) count = count + 1;
if (data[2]) count = count + 1;
...
if (data[7]) count = count + 1;

…이고, 시퀀스를 adder tree로 변환합니다. 런타임 동작은 "단일 조합 단계에서 8비트를 동시에 보고 1의 개수를 세기"입니다.

함의: synthesizable Verilog의 for 루프는 공짜가 아닙니다. 64번 반복하는 루프는 본문 64개 사본의 하드웨어가 됩니다. 본문이 복잡하면 막 큰 조합 블록을 만든 셈입니다. N이 작을 때(몇 개에서 몇 십개) 루프를 사용하세요. 더 큰 카운트라면 보통 clocked 카운터와 상태 머신을 원합니다.

상수 경계 필수

synthesizer가 루프를 unroll할 수 있으려면 N을 elaboration 시점에 알아야 합니다. 즉 루프 경계가 상수여야 합니다.

// 동작 - 경계가 상수
for (i = 0; i < 8; i = i + 1) ...

// 동작 - 경계가 parameter
for (i = 0; i < WIDTH; i = i + 1) ...

// Synthesize 안 됨 - 경계가 런타임 신호에 의존
for (i = 0; i < dynamic_count; i = i + 1) ...

마지막 형태는 시뮬레이션에서는 동작할 수 있지만 synthesizer가 거부합니다. 런타임 카운트 루프가 정말로 필요하다면 clocked 상태 머신과 카운터 register로 만드는 겁니다 - 하드웨어에는 소프트웨어처럼 가변 trip-count 루프가 없습니다.

generate for vs procedural for

별개지만 관련된 구조가 generate for입니다. genvar를 쓰고 always 블록 밖에 살죠.

genvar i;
generate
    for (i = 0; i < 8; i = i + 1) begin : g
        bit_inverter inv(.x(in[i]), .y(out[i]));
    end
endgenerate

bit_inverter의 8 인스턴스 를 찍어 냅니다(Module Instantiation에서 다룸). 구조적입니다 - "이 서브모듈을 8번 복제하라"고 말하는 것이지 행동을 기술하는 게 아닙니다.

간단한 구분.

  • Procedural for(always 안) - 단일 행동 블록 안에서 문장을 unroll.
  • Generate for(always 밖) - 인스턴스, assign 문, 이름 있는 블록 같은 구조 전체를 복제.

복제하는 대상에 맞는 것을 쓰세요.

for가 빛나는 곳: vector 연산

루프는 vector의 모든 비트에 같은 연산을 할 때 최고입니다. population count, parity, 바이트 reversal, lookup-table 생성:

32번 반복, 각각 1비트 대입 - 손으로 적은 32개 wire 대입보다 훨씬 읽기 쉽습니다. synthesizer가 깔끔하게 unroll합니다.

while, repeat, forever

for 외에도 Verilog에는 세 가지 다른 루프 구조가 있습니다 - 주로 testbench용.

// 조건이 실패할 때까지 실행
while (~done) begin
    @(posedge clk);
    cycles = cycles + 1;
end

// N번 실행 - 카운터가 필요 없을 때 for보다 단순
repeat (8) @(posedge clk);

// 영원히 실행 - 클럭 생성기, 모니터링 루프
always #5 clk = ~clk;
forever begin
    @(posedge clk);
    $display("count=%0d", count);
end

while, repeat, forever는 좁은 경우에만 synthesizable입니다(특히 상수 카운트의 repeat과 clocked 본문). testbench에서는 유용한 도구이고, synthesizable RTL에서는 카운트된 for와 명시적 상태 머신을 선호하세요.

testbench의 procedural for

testbench에서 for 루프는 소프트웨어처럼 동작합니다. 자유롭게 쓰세요.

중첩 루프가 2비트 입력 두 개의 모든 조합을 sweep합니다. 시뮬레이터가 반복을 순차적으로 실행합니다. unrolling 걱정 없음 - testbench는 synthesize되지 않습니다.

흔한 실수

상수가 아닌 경계로 synthesizable 코드에서 for 루프 사용. synthesizer가 거부합니다. 경계가 런타임이라면 카운터와 상태 머신을 만드세요.

루프 본문이 병렬 하드웨어가 됨을 잊기. 본문에 곱셈기가 있는 64번 반복 루프는 64개 병렬 곱셈기입니다 - 아마도 원치 않을 것입니다. 넓은 datapath라면 곱셈기 하나를 만들어 순차적으로 공급하세요.

integer ii라는 이름의 reg 혼동. 둘은 다른 스코프이고 루프 안에서는 integer가 이깁니다. 혼란을 피하려면 명확한 이름을 고르세요.

다음에 볼 내용

이제 Verilog이 제공하는 모든 procedural 구조를 갖췄습니다. 다음 장은 디지털 설계자가 실제로 출하하는 패턴들로 모두 모읍니다: Clocked Logic - 플립플롭, register, 파이프라인 - 과 Finite State Machines - 여러 동작 모드를 가진 컨트롤러의 표준 idiom.

자주 묻는 질문

Verilog에서 for 루프는 어떻게 동작하나요?

문법적으로는 C와 비슷해 보입니다: for (i = 0; i < N; i = i + 1) statement;. 하지만 synthesizable 코드에서는 루프가 elaboration 시점에 unroll됩니다 - synthesizer가 본문을 N개 사본으로 펼칩니다. 하드웨어에는 런타임 루프 카운터도 루핑도 없습니다. testbench의 경우 시뮬레이터가 순차적으로 단계 진행할 수 있어 for 루프가 소프트웨어 사촌처럼 동작합니다.

Verilog의 for 루프는 synthesizable인가요?

네, 하지만 elaboration 시점에 알 수 있는 상수 경계일 때만입니다. synthesizer가 본문을 N개의 병렬 사본으로 unroll합니다. 경계가 런타임 신호에 의존하면 루프는 synthesizable이 아닙니다 - clocked 순차 설계로 변환해야 합니다.

Verilog의 for와 generate for의 차이는?

always 블록 안의 for 루프는 unrolling으로 synthesize되는 procedural 구성요소입니다. generate for 루프(genvar 사용)는 structural 하드웨어를 찍어내는 명시적 elaboration-time 구성요소 - 여러 모듈 인스턴스, 여러 wire, 여러 assign 문. procedural 블록 안에서는 for를, 구조를 복제할 때는 그 밖에서 generate for를 사용하세요.

Verilog에 while 루프가 있나요?

네 - while (condition) statement;. synthesizer가 루프가 제한된 반복 횟수로 종료됨을 증명할 수 있을 때만 synthesizable입니다. 실전에서는 드물어서 while은 주로 testbench와 시뮬레이션 전용 코드에서 등장합니다. synthesizable iteration에는 카운트된 for 루프를 쓰세요.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기