verilog 10 FSM/ASM

2023. 3. 17. 18:44Verilog

FSM : 지정된 수의 상태로 상태들 과의 천이에 의해 출력을 생성하는 회로

디지털 시스템의 제어회로 구성에 사용

 

무어 머신(Moore Machine) : 출력이 현재상태에 의해서만 결정, 동기형 출력

밀리 머신(Mealy Machine) : 출력이 현재상태와 입력에 의해서만 결정, 비동기형 출력

Moore 머신
밀리 머신

FSM은 보통 3부분으로 구성된다. 

  • 현재상태를 기억하는 레지스터
  • 다음상태를 계산하는 논리회로(조합회로)
  • 현재 출력을 계산하는 조합회로

Vivado의 FSM 상태할당 합성 설정

FSM의 코딩 가이드라인

  • FSM의 상태 이름을 Parameter 또는 localParam으로 정의해서 사용한다. 
module fsm_v1(
	input clk, rst, x,
	output reg y 
);
localparam [1:0] S0 = 2’b00, S1 = 2’b01, S2 = 2’b10, S3 = 2’b11 ;
reg [1:0] curr_st, nx_st;

...
endmodule
  • FSM이 비동기 리셋을 할 수 있게 설계한다. 리셋을 갖지 않으면 초기상태가 미정의되어 오류가 발생할 수 있다. 
  • FSM을 구성하는 3개의 블록(다음상태, 현재 상태 레지스터, 출력)을 분리된 always 또는 assign문으로 구현한다. 
  • 상태 레지스터는 플리플롭을 사용한다.
  • 다음상태 logic은 case문을 사용하고, 정의되지 않은 상태들은 default문으로 표현하고, 외부 입력은 case문에서 if~else를 사용한다. 

 

무어머신

 

`timescale 1ns / 1ps


module Moore(
        input clk, rst, x,
        output reg y
    );

    reg y_temp;

    reg [1:0] next_state, curr_state;
    localparam S0 = 2'b00, S1 = 2'b01, S2 = 2'b10, S3 = 2'b11;

    always @(posedge clk , posedge rst) begin
        if(rst) curr_state <= S0;
        else curr_state <= next_state;
    end

    always @(curr_state, x) begin
        case(curr_state)
            S0 : if(x) next_state = S1; else next_state = S0;
            S1 : if(x) next_state = S2; else next_state = S0;
            S2 : if(x) next_state = S3; else next_state = S1;
            S3 : next_state = S0;
            default : next_state = S0;
        endcase
    end

    always @(posedge clk,posedge rst) begin
        if(rst)
            y<= 0;
        else 
            y<= y_temp;
    end

    always @(*) begin
        if(next_state == S3)
            y_temp = 1'b1;
        else 
            y_temp = 1'b0;
    end

endmodule

무어 머신 테스트벤치

밀리머신

 

module mealy ( 
    input clk, rst, w,
    output reg [1:0] y
);

reg [2:0] curr_state, next_state;

localparam [2:0] S0 = 3'd0, S1 = 3'd1, S2 = 3'd2, S3 = 3'd3, S4 = 3'd4;

always @(posedge clk , posedge rst) begin
    if(rst) curr_state <= S0;
    else curr_state <= next_state;
end

always @(curr_state, w) begin
    y = 2'b00;
    case(curr_state)
        S0 : 
            if(w) begin
            y = 2'b10; next_state = S1;
            end
            else begin
            y = 2'b00; next_state = S0;        
            end
        S1 : 
            if(w) begin
            y = 2'b10; next_state = S2;
            end
            else begin
            y = 2'b00; next_state = S3;        
            end
        S2 : 
            begin
                y=2'b11; next_state = S0;
            end
        S3 : 
            if(w) begin
            y = 2'b01; next_state = S2;
            end
            else begin
            y = 2'b00; next_state = S4;        
            end
        S4 : 
            begin
                y=2'b01; next_state = S0;
            end
        default : next_state = S0;

    endcase
    
end
    
endmodule

 

패턴 검출(011011)

module pattern_detect (
    input clk, rst, x, 
    output reg y
);

localparam [3:0] S0 = 3'd0, S1 = 3'd1, S2 = 3'd2, S3 = 3'd3, S4 = 3'd4, S5 = 4'd5, S6 = 4'd6, S7 = 3'd7;
reg[2:0] curr_state, next_state;

always @(posedge clk, posedge rst) begin
    if(rst) curr_state <= 0;
    else curr_state <= next_state;
end

always @(x, curr_state) begin
    case (curr_state)
        S0 : 
            if(x) next_state = S0;
            else next_state = S1;
        S1 : 
            if(x) next_state = S2;
            else next_state = S1;
        S2: 
            if(x) next_state = S3;
            else next_state = S1;
        S3 : 
            if(x) next_state = S1;
            else next_state = S4;
        S4 : 
            if(x) next_state = S5;
            else next_state = S1;
        S5 : 
            if(x) next_state = S6;
            else next_state = S3;
        S6 : next_state = S7;
        S7 : next_state = S0;

        default: next_state = S0;
    endcase
end

always @(*) begin
    if(next_state == S7) y <= 1'b1;
    else y <= 1'b0;
end
    
endmodule

011011이 들어오면 출력으로 1이 나오는 코드이다. 

 

`timescale 1ns / 1ps

module tb_pattern;
parameter WD = 30;
reg clk, rst;
reg in;
reg [0:WD-1] arr = 30'b0001_0011_0101_1101_0110_1011_0110_10;
integer i;
wire y;

pattern_detect u1(.clk(clk), .rst(rst), .x(in), .y(y));

initial begin
clk = 0;  rst = 1; in = 0;
#50 rst = 0;

for(i=0; i<WD; i=i+1) begin
    #10 in = arr[i];
end
end

always #5 clk = ~clk;

endmodule

 

011011 검출 테스트벤치

 

011010 이 입력되었을 때

011011이 입력됐을 때는 S7로 넘어가 1이 출력되는 것을 볼 수 있고, 011010이 들어왔을 때는 패턴을 다시 검출해야 하지만, 01이 입력되었기 때문에 S6에서 다음 1을 검출하는 S3으로 천이한 뒤 다시 0이 나오자 S1로 되돌아가는 것을 볼 수 있다. 

 

위 코드는 0110_11_011 과같이 중복된 코드는 잡지 않는다. 

module pattern_detect (
    input clk, rst, x, 
    output reg y
);

localparam [3:0] S0 = 3'd0, S1 = 3'd1, S2 = 3'd2, S3 = 3'd3, S4 = 3'd4, S5 = 4'd5, S6 = 4'd6;
reg[2:0] curr_state, next_state;

always @(posedge clk, posedge rst) begin
    if(rst) curr_state <= 0;
    else curr_state <= next_state;
end

always @(x, curr_state) begin
    case (curr_state)
        S0 : 
            if(x) next_state = S0;
            else next_state = S1;
        S1 : 
            if(x) next_state = S2;
            else next_state = S1;
        S2: 
            if(x) next_state = S3;
            else next_state = S1;
        S3 : 
            if(x) next_state = S1;
            else next_state = S4;
        S4 : 
            if(x) next_state = S5;
            else next_state = S1;
        S5 : 
            if(x) next_state = S6;
            else next_state = S3;
        S6 : if(x) next_state =S0;
            else next_state = S4;

        default: next_state = S0;
    endcase
end

always @(*) begin
    if(next_state == S6) y <= 1'b1;
    else y <= 1'b0;
end
    
endmodule

011011_011011 ....을 넣었을 때 중복된 코드로도 패턴을 검출할 수 있게 만들었다. 

 

ASM

직렬가산기

 

직렬 가산기 구조
직렬 가산기 계층
Datapath

'Verilog' 카테고리의 다른 글

verilog 12 cpu설계-2  (0) 2023.03.27
verilog 11 cpu 제작_1  (0) 2023.03.20
verilog 9 카운터 실습  (0) 2023.03.15
verilog7  (0) 2023.03.14
verilog 5  (0) 2023.03.13