for 루프는 소프트웨어에서 가장 널리 사용되는 루프지만, Verilog에서는 주로 하드웨어 로직을 복제(replicate)하는 데 사용됩니다. for 루프의 핵심은 주어진 조건이 참인 동안 루프 내의 문장 집합을 반복하는 것입니다. 이는 while 루프와 매우 유사하지만, 반복자가 있고 조건이 이 반복자의 값에 의존하는 문맥에서 더 많이 사용됩니다.
문법
for (<초기_조건>; <조건>; <단계_할당>) begin
// 문장들
end
for 키워드는 이 루프 유형을 지정하며 세 부분으로 구성됩니다:
신호의 초기값을 지정하는 초기 조건
주어진 조건이 참인지 평가하는 검사
다음 반복을 위한 제어 변수 업데이트
초기 조건과 제어 변수 업데이트가 for 루프에 포함되어 있어 while 루프처럼 별도로 지정할 필요가 없습니다. while 루프는 더 범용적이며 주어진 조건 동안 문장을 반복해야 할 때 주로 사용됩니다. 반면 for 루프는 일반적으로 단계 변수에 의해 제어되는 명확한 시작과 끝을 가집니다.
다음은 for 루프 사용법을 보여주는 간단한 예제입니다.
module my_design;
integer i;
initial begin
// Verilog에는 ++ 연산자가 없음에 유의!
for (i = 0; i < 10; i = i + 1) begin
$display ("현재 루프 #%0d ", i);
end
end
endmodule
시뮬레이션 로그
ncsim> run
Current loop#0
Current loop#1
Current loop#2
Current loop#3
Current loop#4
Current loop#5
Current loop#6
Current loop#7
Current loop#8
Current loop#9
ncsim: *W,RNQUIE: Simulation is complete.
설계 예제
for 루프 없이 8비트 좌측 시프트 레지스터를 Verilog로 구현하는 방법과 for 루프를 사용한 코드를 비교하여 루프 구조의 유용성을 알아보겠습니다.
module lshift_reg (
input clk,
input rstn,
input [7:0] load_val,
input load_en,
output reg [7:0] op
);
always @ (posedge clk) begin
if (!rstn) begin
op <= 0;
end else begin
if (load_en) begin
op <= load_val;
end else begin
op[0] <= op[7];
op[1] <= op[0];
op[2] <= op[1];
op[3] <= op[2];
op[4] <= op[3];
op[5] <= op[4];
op[6] <= op[5];
op[7] <= op[6];
end
end
end
endmodule
같은 동작을 for 루프로 구현하면 코드가 줄어들고 레지스터 폭이 달라도 확장 가능해집니다. 레지스터 폭을 Verilog 파라미터로 만들면 설계 모듈이 확장 가능해지고, 같은 파라미터를 for 루프 안에서 사용할 수 있습니다.
module lshift_reg (
input clk,
input rstn,
input [7:0] load_val,
input load_en,
output reg [7:0] op
);
integer i;
always @ (posedge clk) begin
if (!rstn) begin
op <= 0;
end else begin
if (load_en) begin
op <= load_val;
end else begin
for (i = 0; i < 8; i = i + 1) begin
op[i+1] <= op[i];
end
op[0] <= op[7];
end
end
end
endmodule
테스트벤치
아래 테스트벤치 코드는 설계를 인스턴스화합니다.
module tb;
reg clk;
reg rstn;
reg [7:0] load_val;
reg load_en;
wire [7:0] op;
// DUT 클럭 설정
always #10 clk = ~clk;
// 설계 인스턴스화
lshift_reg u0 (
.clk(clk),
.rstn(rstn),
.load_val(load_val),
.load_en(load_en),
.op(op)
);
initial begin
// 1. 테스트벤치 변수 초기화
clk <= 0;
rstn <= 0;
load_val <= 8'h01;
load_en <= 0;
// 2. 설계에 리셋 적용
repeat (2) @ (posedge clk);
rstn <= 1;
repeat (5) @ (posedge clk);
// 3. load_en을 1클럭 동안 설정하여 load_val 로드
load_en <= 1;
repeat(1) @ (posedge clk);
load_en <= 0;
// 4. 20클럭 동안 실행 후 종료
repeat (20) @ (posedge clk);
$finish;
end
endmodule