본문 바로가기

Verilog HDL 설계

Simple Finite State Machine implementation

Finite State Machine, 이하 FSM은 제어 회로에서 주로 사용된다. 레지스터 변수에 특정 상태(state) 값을 지정하고 그 값에 따라 제어신호를 변화시키는 방식이다. 아주 간단한 FSM을 구현해봤다.

 

module fsm_ex1(
    output [1:0] state_out,
    output reg done,
    input  clk, rst, start
);

reg [1:0] state;
reg [3:0] count;

assign state_out = state;

always @ (posedge clk) begin
    if (rst) begin
        state <= 3'b0;
        done  <= 1'b0;
        count <= 4'b0;
    end
    else if (start) begin
        count <= count + 4'b1;
        
        if (count == 4'd0) begin
            state <= 2'd0;
        end
        else if (count == 4'd4) begin
            state <= 2'd1;
        end
        else if (count == 4'd8) begin
            state <= 2'd2;
        end
        else if (count == 4'd12) begin
            state <= 2'd3;
            done <= 1'b1;
        end
    end
    else begin
        state <= 2'b0;
        count <= 4'b0;
        done  <= 1'b0;
    end
end

endmodule

 

카운터 값에 따라 상태 변수가 달라지는 코드다. 시간에 따라서 회로를 제어해야 한다면 카운터가 필수적이다. 왜냐하면 실제 합성을 하는 코드는 내부에 delay를 줄 수 없기 때문이다. initial 또한 불가능하다. 그래서 일정 clock cycle 마다 증감하는 카운터를 통해 제어를 하게 된다.

 

혼자서 모든 걸 다 만든다는 것은 힘들기 때문에, 혼자서 알아볼 수 있는 코드는 좋은 코드가 아니다. parameter와 같이 쓰이면 어느 상태인지 보기가 쉬워진다. 정확히는 어떤 state가 있는지, 어떻게 변화하는지를 알기 쉽게 해 준다.

 

module fsm_ex1(
    output [1:0] state_out,
    output reg done,
    input  clk, rst, start
);

parameter IDLE = 2'd0;
parameter STATE0 = 2'd1;
parameter STATE1 = 2'd2;
parameter STATE2 = 2'd3;

reg [1:0] state;
reg [3:0] count;

assign state_out = state;

always @ (posedge clk) begin
    if (rst) begin
        state <= 3'b0;
        done  <= 1'b0;
        count <= 4'b0;
    end
    else if (start) begin
        count <= count + 4'b1;
        
        if (count == 4'd0) begin
            state <= IDLE;
        end
        else if (count == 4'd4) begin
            state <= STATE0;
        end
        else if (count == 4'd8) begin
            state <= STATE1;
        end
        else if (count == 4'd12) begin
            state <= STATE2;
            done <= 1'b1;
        end
    end
    else begin
        state <= 2'b0;
        count <= 4'b0;
        done  <= 1'b0;
    end
end

endmodule

 

해당 코드는 그냥 state 변수를 output으로 내보냈지만, 제어 신호를 만들 수도 있을 것이다.

 

module fsm_ex1(
    output [1:0] state_out,
    output reg done, ctrl0, ctrl1, ctrl2,
    input  clk, rst, start
);

parameter IDLE = 2'd0;
parameter STATE0 = 2'd1;
parameter STATE1 = 2'd2;
parameter STATE2 = 2'd3;

reg [1:0] state;
reg [3:0] count;

assign state_out = state;

always @ (posedge clk) begin
    if (rst) begin
        state <= 3'b0;
        done  <= 1'b0;
        count <= 4'b0;
        ctrl0 <= 1'b0;
        ctrl1 <= 1'b0;
        ctrl2 <= 1'b0;
    end
    else if (start) begin
        count <= count + 4'b1;
        
        case (state)
        IDLE: begin
            ctrl0 <= 1'b0;
            ctrl1 <= 1'b0;
            ctrl2 <= 1'b0;
        end
        STATE0: begin
            ctrl0 <= 1'b1;
            ctrl1 <= 1'b0;
            ctrl2 <= 1'b0;
        end
        STATE1: begin
            ctrl0 <= 1'b0;
            ctrl1 <= 1'b1;
            ctrl2 <= 1'b0;
        end
        STATE2: begin
            ctrl0 <= 1'b0;
            ctrl1 <= 1'b0;
            ctrl2 <= 1'b1;
        end
        default: begin
            ctrl0 <= 1'b0;
            ctrl1 <= 1'b0;
            ctrl2 <= 1'b0;
        end
        endcase

        if (count == 4'd0) begin
            state <= IDLE;
        end
        else if (count == 4'd4) begin
            state <= STATE0;
        end
        else if (count == 4'd8) begin
            state <= STATE1;
        end
        else if (count == 4'd12) begin
            state <= STATE2;
            done <= 1'b1;
        end
    end
    else begin
        state <= 2'b0;
        count <= 4'b0;
        done  <= 1'b0;
        ctrl0 <= 1'b0;
        ctrl1 <= 1'b0;
        ctrl2 <= 1'b0;
    end
end

endmodule

 

여기선 ctrl0~2라는 임의의 신호로 출력을 내보내지만, 알아볼 수만 있다면 어떤 이름을 써도 문제없다.

state 값에 따라 제어신호가 변하기 때문에 state 값 변화에 1 clock cycle만큼 뒤쳐지는데, case(state)를 case(count)로 바꾸면 해결되는 문제다. 이건 그냥 예시라서 딱히 수정을 가하진 않았지만, clock cycle에 민감한 제어 로직이 필요한 경우 참고 해두길 바란다. 

 

구현할 수 있는 FSM은 매우 다양하고 복잡도도 각 로직마다 다르기 때문에, 예시는 예시로 알고 넘어가면 좋을 것 같다. 예를 들어 nested counter에 따라 변하기도 하고, 그 카운터의 트리거 역할을 하는 counter에 따라 변하게끔 모듈을 구현할 수도 있다.

경우의 수가 매우 커지기 때문에 복잡한 제어 로직에서는 제대로 제어신호를 발생시키는지 확인하는 과정은 필수적이라고 볼 수 있다.

만약 계획한 제어 신호 중 하나라도 어긋나면 민감한 회로의 경우 동작이 엉망으로 되는 것을 확인할 수 있을 것이다. 설계 시에는 주의하여 설계하길 바란다.

'Verilog HDL 설계' 카테고리의 다른 글

include의 필요성 및 사용법  (0) 2022.04.12
파라미터를 이용한 모듈 선언  (0) 2022.04.07
테스트벤치 작성 예시  (0) 2021.04.25
Countdown control & display  (0) 2021.04.23
BCD to 7 segment  (0) 2021.04.19