TL;DR;
$finish;를 이용하세요.
기본적으로 Verilog의 always 블럭은 영원히 돌아가게 되어있다.
그런데 만약 테스트 벤치에 특정 클럭 시점까지의 행동들만 들어있다면 그 이후에는 의미없는 행동이 계속 돌아갈 것이다.
Vivado나 Modelsim을 이용하는 경우라면 시뮬레이션 때 특정 단위의 클럭만큼 나누어 실행할 수 있지만 리눅스에서 iverilog를 이용한다면 Ctrl+C를 누르지 않는 한 시뮬레이터인 vvp가 영원히 돌아갈 것이다. 따라서 코드 단계에서 return 0;와 같은 프로그램의 종료 시점을 명시해주는 것이 편하다.
아래는 5클럭 주기로 간단한 Moore FSM을 돌리는 프로그램의 코드이다.
약 130클럭까지의 행동을 정해준 후 $finish;를 호출해 프로그램이 종료되도록 하였다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
`timescale 1ns / 1ps module tb_moore( output reg clk, output reg reset, output reg x, input wire y); moore moore1(y, clk, reset, x); always begin #5 clk <= ~clk; end initial begin $dumpfile("output.vcd"); $dumpvars(0, tb_moore); #0 reset <= 1; x = 0; clk = 1; #5 reset <= 0; #5 reset <= 1; #10 x <= 0; #10 x <= 1; #10 x <= 0; #10 x <= 1; #10 x <= 1; #10 x <= 0; #10 x <= 1; #10 x <= 1; #10 x <= 1; #10 x <= 0; #10 x <= 1; #10 x <= 0; $finish; end endmodule |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
module moore( output reg y, input wire clk, input wire reset, input wire x); reg [1:0] currentState, nextState; localparam S1 = 2'b00; localparam S2 = 2'b01; localparam S3 = 2'b11; always @(posedge clk or negedge reset) begin if(~reset) begin currentState <= S1; end else currentState <= nextState; end always @(currentState, x) begin case(currentState) S1: if(x) begin nextState <= S2; end else begin nextState <= S1; end S2: if(x) begin nextState <= S3; end else begin nextState <= S1; end S3: if(x) begin nextState <= S3; end else begin nextState <= S1; end default: nextState <= S1; endcase y = (currentState == S3); end endmodule |