Vivado下有限状态机的实现


处理相对复杂的逻辑时就会用到有限状态机,设定好不同的状态,根据触发条件跳转到相应的状态,然后在不同的状态下做相应的处理。有限状态机主要用到 always 语句和 case 语句。


1011状态机的实现

文章 Quartus II下设计一个用于识别2进制序列“1011”的状态机 是在 Quartus II 软件中设计的一个识别2进制序列“1011”的状态机,这里在 Vivado 中对该例子再进行实现。
设计源代码如下。

module timing(
    input  clk, 
    input  rst, 
    input  en,
    input  in, 
    output reg out
);

parameter ST0 = 0;
parameter ST1 = 1;
parameter ST2 = 2;
parameter ST3 = 3;
parameter ST4 = 4;

reg [2:0] state;
reg [2:0] next_state;

initial
begin
    next_state = ST0;
end

always @ (in or en or state)
begin
  case (state)
    ST0:
    begin 
		if(en == 1 && in == 1) 
			next_state = ST1;
		else 
			next_state = ST0;
	end
    ST1:
    begin 
		if(en == 1 && in == 0) 
		    next_state = ST2; 
		else if(en == 1 && in == 1) 
		    next_state = ST1;
		else 
		    next_state = ST0;
		end
    ST2:
    begin 
		if(en == 1 && in == 1) 
		    next_state = ST3; 
		else 
		    next_state = ST0;
		end
    ST3:
    begin 
		if(en == 1 && in == 1)
		    next_state = ST4;           
		else if(en == 1 && in == 0) 
		    next_state = ST2;
		else 
		    next_state = ST0;
		end
	//ST4:
	   //next_state = ST0;
   endcase 
end

always @ (posedge clk or negedge rst)
begin
  if(!rst)
    state <= ST0;
  else
    state <= next_state;
end

always @ (state or posedge clk) 
begin
  if(state == ST4)
    begin
        state = ST1;
        out = 1;
    end
  else 
     out = 0;
end

endmodule

仿真测试源代码如下。

module sim_timing();
reg clk;
reg rst;
reg en;
reg in;
wire out;

initial
begin
    en = 0;
    clk = 0;
    rst = 1;
    #50 
    en = 1;
    #400
    rst = 0;
    #50
    rst = 1;
end

initial
begin
    in = 0;
    forever
    begin
    #20
    in = {
    
    $random}%2;
    end 
end

always #10 clk = ~clk;

timing uut_timing(
    .clk(clk),
    .rst(rst),
    .en(en),
    .in(in),
    .out(out)
);
endmodule

仿真输出结果如下图所示。
在这里插入图片描述
通过上图可知,每输入一个“1011”序列,输出 out 就置为1,持续一个时钟周期后清零,输出结果与预想的一致。


四状态下的移位操作

下图中给出了四个状态,初始状态是 Idle,在此状态下判断移位开始信号 shift_start 是否为高,如果为高就进入Start 状态,在Start 状态下延迟若干个周期,进入 Run 状态,然后进行移位处理,如果移位停止信号shift_stop有效,进入Stop 状态,把存储器中的值清零然后返回到 Idle 状态。
在这里插入图片描述
Mealy 有限状态机的输出不仅与当前状态有关,也与输入信号有关。
Mealy 有限状态机的设计源代码如下。

module timing(
    input  clk, 
    input  rst, 
    input  in,
    input  shift_start, 
    input  shift_stop, 
    output reg[7:0] out
);

parameter Idle = 0;
parameter Start = 1;
parameter Run = 2;
parameter Stop = 3;

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

always @ (posedge clk or negedge rst)
begin
  if(!rst)
    begin
        state <= Idle;
        count <= 0;
        out <= 0;
    end
  else
  case(state)
    Idle:
        begin
            if(shift_start)
                state <= Start;
        end
    Start:
        begin
            if(count == 4'd10)
            begin
                count <= 0;
                state <= Run;
            end 
            else
                count <= count + 1'b1;   
        end
     Run:
        begin
            if(shift_stop)
                state <= Stop;
            else
                out <= {
    
    out[6:0],in};
        end
     Stop:
        begin
            out <= 0;
            state <= Idle;
        end
     default : state <= Idle;
     endcase 
end
endmodule

Moore 有限状态机的输出只与当前状态有关,与输入信号无关,输入信号只影响状态的改变,不影响输出。比如本例中的计数信号和输出信号。
Moore 有限状态机的设计源代码如下。

module timing(
    input  clk, 
    input  rst, 
    input  in,
    input  shift_start, 
    input  shift_stop, 
    output reg[7:0] out
);

parameter Idle = 0;
parameter Start = 1;
parameter Run = 2;
parameter Stop = 3;

reg [1:0] cur_state;
reg [1:0] next_state;
reg [3:0] count;

always @ (posedge clk or negedge rst)
begin
  if(!rst)
      cur_state <= Idle;
  else
      cur_state <= next_state;
end

always@(*)
begin
  case(cur_state)
    Idle:
        begin
            if(shift_start)
                next_state <= Start;
            else
                next_state <= Idle;
        end
    Start:
        begin
            if(count == 4'd10)
                next_state <= Run;
            else
                next_state <= Start;
        end
     Run:
        begin
            if(shift_stop)
                next_state <= Stop;
            else
                next_state <= Run;
        end
     Stop:
        next_state <= Idle;
     default : next_state <= Idle;
     endcase 
end

always@(posedge clk or negedge rst)
begin
    if(!rst)
        count <= 0;
    else if (cur_state == Start)
        count <= count + 1'b1;
    else
        count <= 0;
end

always@(posedge clk or negedge rst)
begin
    if(!rst)
        out <= 0;
    else if (cur_state == Run)
        out <= {
    
    out[6:0],in};
    else
        out <= 0;
end

endmodule

在上面两个程序中用到了两种方式的写法,第一种的 Mealy 状态机,采用了一段式的写法,代码中只用了一个 always 语句,所有的状态转移、判断状态转移条件、数据输出都在一个 always 语句里。这种写法的缺点是如果状态太多,会使整段程序显的冗长。第二种是 Moore 状态机,采用了三段式的写法,状态转移用了一个 always 语句,判断状态转移条件用了一个 always 语句,数据输出也用了一个 always 语句,这样写下来的代码比较直观清晰,状态很多时也不会显得繁琐。
两者的仿真测试代码是一样的,如下所示。

module sim_timing();
reg  clk;
reg  rst; 
reg  in;
reg  shift_start; 
reg  shift_stop; 
wire [7:0] out;

initial
begin
    clk = 0;
    rst = 0;
    in = 0;
    #100 
    rst = 1;
    forever
    begin
        #({
    
    $random}%100)
        in = ~in;
    end
end

initial
begin
    shift_start = 0;
    shift_stop = 0;
    #200
    shift_start = 1;
    #500
    shift_start = 0;
    shift_stop = 1;
    #50
    shift_stop = 0;
    shift_start = 1;
end

always #10 clk = ~clk;

timing uut_timing(
    .clk(clk),
    .rst(rst),
    .in(in),
    .shift_start(shift_start),
    .shift_stop(shift_stop),
    .out(out)
);
endmodule

仿真输出结果如下图所示。
在这里插入图片描述
由上图可以看到,在 Start 状态下,计数到 10 后就跳转到 Run 状态开始移位操作。上面的图是整体的仿真过程,移位操作看得不清楚,所以将输出 out 以二进制显示,放大图如下,可以看到在 shift_start 有效时,向左移位操作正确的进行。
在这里插入图片描述


以上就是 Vivado下有限状态机实现的所有内容了!
参考资料:
ZYNQ 开发平台 FPGA 教程 AX7020

猜你喜欢

转载自blog.csdn.net/weixin_42570192/article/details/130938824
今日推荐