FSM(Traffic Light Controller)

Seungyun Lee·2025년 11월 11일
post-thumbnail

FSM 이란?

FSM은 현재 상태(Current State) 와 입력(Input) 에 따라
다음 상태(Next State) 와 출력(Output) 을 결정하는 논리 회로

Moore FSM 기본구조

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

모르는 코드

1. Typedef enum

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; 처럼 “이름으로 상태를 할당”할 수 있다

2. always @(*)

@(*)는 “입력 신호가 바뀔 때마다” 이 블록을 자동으로 다시 계산하라는 뜻
즉, 여기서는 현재 상태(state) 나 입력(in) 이 변할 때마다 “다음 상태(next_state)” 를 즉시 갱신
조합논리 블록 : clock에 의존하지 않고 입력 → 출력 즉시 반응

Traffic Light Controller

도로 교차로의 신호등 제어기
동서 방향, 남북 방향의 신호등을 교차로 제어

State Diagram

     +-----+      +-----+      +-----+      +-----+
     | S0  | ---> | S1  | ---> | S2  | ---> | S3  |
     | G/R |      | Y/R |      | R/G |      | R/Y |
     +-----+      +-----+      +-----+      +-----+
         ^---------------------------------------|

Verilog Code

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

Testbench

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

결과

profile
RTL, FPGA Engineer

0개의 댓글