
FSM은 현재 상태(Current State) 와 입력(Input) 에 따라
다음 상태(Next State) 와 출력(Output) 을 결정하는 논리 회로
module fsm_example (
input clk, reset, in,
output reg out
);
// 1. 상태 정의
typedef enum reg [1:0] {S0, S1, S2} state_t;
state_t state, next_state;
// 2. 상태 레지스터 (현재 상태 저장)
always @(posedge clk or posedge reset) begin
if (reset)
state <= S0;
else
state <= next_state;
end
// 3. 다음 상태 결정 (전이 조건)
always @(*) begin
case (state)
S0: next_state = (in) ? S1 : S0;
S1: next_state = (in) ? S2 : S0;
S2: next_state = (in) ? S2 : S0;
default: next_state = S0;
endcase
end
// 4. 출력 결정 (상태에 의존)
always @(*) begin
case (state)
S0: out = 0;
S1: out = 0;
S2: out = 1;
default: out = 0;
endcase
end
endmodule
typedef enum reg [1:0] {S0, S1, S2} state_t;
typedef: 새로운 자료형 정의
enum: 열거형-여러 상태 이름을 나열
logic [1:0]: 각 상태를 2비트로 표현
{S0, S1, S1}: 상태이름 나열
state_t: 새로만든 상태 자료형의 이름
S0, S1, S2라는 이름을 가진 3가지 상태를
2비트(reg [1:0])로 표현하는 새로운 타입 state_t를 정의한다.
옛날 스타일(verilog)
parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10;
reg [1:0] state, next_state;
새 스타일(systemverilog)
typedef enum logic [1:0] {S0, S1, S2} state_t;
state_t state, next_state;
이제 state와 next_state는 “state_t 타입” 변수라서
state <= S1; 처럼 “이름으로 상태를 할당”할 수 있다
@(*)는 “입력 신호가 바뀔 때마다” 이 블록을 자동으로 다시 계산하라는 뜻
즉, 여기서는 현재 상태(state) 나 입력(in) 이 변할 때마다 “다음 상태(next_state)” 를 즉시 갱신
조합논리 블록 : clock에 의존하지 않고 입력 → 출력 즉시 반응
도로 교차로의 신호등 제어기
동서 방향, 남북 방향의 신호등을 교차로 제어

+-----+ +-----+ +-----+ +-----+
| S0 | ---> | S1 | ---> | S2 | ---> | S3 |
| G/R | | Y/R | | R/G | | R/Y |
+-----+ +-----+ +-----+ +-----+
^---------------------------------------|
module traffic_control(
input logic clk, reset,
output logic [1:0] EW_light,
output logic [1:0] NS_light
);
typedef enum logic [1:0] {S0, S1, S2, S3} state_t;
state_t state, next_state;
logic [3:0] timer;
// 1) 상태 저장
always_ff @(posedge clk or posedge reset) begin
if (reset)
state <= S0;
else
state <= next_state;
end
// 2) 타이머 업데이트
always_ff @(posedge clk or posedge reset) begin
if (reset)
timer <= 0;
else if (next_state != state)
timer <= 0; // 상태 바뀌면 초기화
else
timer <= timer + 1; // 상태 유지 중 카운트 증가
end
// 3) next_state 계산
always_comb begin
next_state = state; // 기본값
case (state)
S0: if (timer == 3) next_state = S1;
S1: if (timer == 1) next_state = S2;
S2: if (timer == 3) next_state = S3;
S3: if (timer == 1) next_state = S0;
endcase
end
// 출력
always_comb begin
case (state)
S0: begin EW_light = 2'b00; NS_light = 2'b10; end
S1: begin EW_light = 2'b01; NS_light = 2'b10; end
S2: begin EW_light = 2'b10; NS_light = 2'b00; end
S3: begin EW_light = 2'b10; NS_light = 2'b01; end
default: begin EW_light = 2'b10; NS_light = 2'b10; end
endcase
end
endmodule
module traffic_tb;
reg clk, reset;
wire [1:0] EW_light, NS_light;
traffic_control uut(clk, reset, EW_light, NS_light);
initial begin
clk = 0;
forever #5 clk = ~clk; // 10ns period
end
initial begin
reset = 1;
#10;
reset = 0;
#300;
$finish;
end
initial begin
$monitor("Time=%0t | EW=%b | NS=%b", $time, EW_light, NS_light);
end
endmodule
모르는 코드
initial begin
$monitor("Time=%0t | EW=%b | NS=%b", $time, EW_light, NS_light);
end
"Time=%0t | EW=%b | NS=%b" -> 출력을 이렇게 해달라고 요청, 그리고 그자리에 time, EW_light, NS_light를 넣겠다는 말
그러면 아래와 같이 출력이 나옴
Time=0 | EW=00 | NS=10
Time=5 | EW=01 | NS=10
Time=10 | EW=10 | NS=10
Time=15 | EW=10 | NS=00

