verilog中一文搞懂有限状态机(FSM)Mealy和Moore状态机(及一段式,二段式,三段式)

1.什么是有限状态机

如果一个系统在有限数字的内部状态下转换,就可以用有限状态机来描述这个系统。网上比较经典的例子就是校验固定序列 100010这种。 状态机一般有两种书写方式分别是Mealy状态机Moore状态机

2.Mealy 状态机

在这里插入图片描述
Mealy状态机的输出是由当前状态当前输入一起决定的。

2.Moore FSM

在这里插入图片描述
Moore状态机的输出只与当前状态相关。

3.Mealy 和 Moore的区别

  • 如上述已经说过的Mealy是由当前输入和当前状态state确定的所以Mealy是一种“asynchronousmachine”,而Moore是只有当前状态决定的所以它是一种“synchronous machine”。
  • Mealy需要的状态比Moore少
  • Moore状态机适合于不太在于毛刺(glitches)的情况。
  • Mealy状态机适合于无毛刺 无延时的情况,但是对于Mealy的异步设计需要注意,所以Mealy相对于Moore的设计会更复杂。

4.Encoding 风格

因为需要在数字电路中使用FSM,所以状态机的风格有4种写法

  • Binary : 状态由binary格式表示(000,001,010…)
  • Gray :状态由格雷码风格表示(000,001,011…)
  • One Hot : 只有1个bit是high,reset是low(0001,0010,0100…)
  • One Cold : 只有1个bit是low,reset是high(1110,1101,1011…)

设计原则

binary和gray-code适用于触发器资源较少,组合电路资源丰富的情况(CPLD),对于FPGA,适用one-hot code。这样不但充分利用FPGA丰富的触发器资源,还因为只需比较一个bit,速度快,组合电路简单

在这里插入图片描述

5. 一段式状态机

module top_module(
    input clk,
    input areset,    // Asynchronous reset to state B
    input in,
    output out);//  

    parameter A=0, B=1; 
    reg state, next_state;

    always @(posedge clk, posedge areset) begin    // This is a sequential always block
        if(areset) begin
            state <= B;
        	out <= 1;
        end
        else begin
            case(state)
             	 A: 
                    if (in) begin
                    state <= A;
                    out <= 0;
                    end
                    else begin
                     state <= B;
                     out <= 1;
                    end
                 end
                B: 
                    if (in) begin
                    state <= B;
                    out <= 1;
                	end
                    else begin
                     state <= A;
                     out <= 0;
                    end
            endcase
        end
  	end

    // Output logic
    // assign out = (state == ...);

endmodule

上述是一种Mealy的写法 输出是由 in和当前状态共同决定的所以这种写法state和output会同时到达。
在这里插入图片描述

module top_module(
    input clk,
    input areset,    // Asynchronous reset to state B
    input in,
    output out);//  

    parameter A=0, B=1; 
    reg state, next_state;



    always @(posedge clk, posedge areset) begin    // This is a sequential always block
        if(areset) begin
            state <= B;
        	out <= 1;
        end
        else begin
            case(state)
             	 A: begin out <= 0;
                    if (in) begin
                    state <= A;
                end
                    else begin
                     state <= B;
                    end
                 end
                B: begin out <= 1;
                    if (in) begin
                    state <= B;
                end
                    else begin
                     state <= A;
                    end
                end
            endcase
        end
  		  end

    // Output logic
    // assign out = (state == ...);

endmodule

上述这种写法是Moore写法区别是在case语句中 out是放在if判断中还是放在if判断外。 判断写法也可以写成 一下这种形式

state <= in ? A : B;

在这里插入图片描述

6. 二段式状态机

控制current state 写法


module top_module(
    input clk,
    input areset,    // Asynchronous reset to state B
    input in,
    output reg out);//  
 
    parameter A=1'b0, B=1'b1; 
    reg current_state, next_state;
    
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            current_state <= B;
        end
        else begin
            current_state <= next_state;
        end
    end
 
    always@(*)begin
        case(current_state)
            B:begin
                if(in == 1'b1)begin
                    next_state = B;
                end
                else begin
                    next_state = A;
                end
            end
            A:begin
                if(in == 1'b1)begin
                    next_state = A;
                end
                else begin
                    next_state = B;
                end
            end
        endcase
    end
    
    //combinational logic way
    always@(*)begin 
        if(current_state == B)begin
            out = 1'b1;
        end
        else begin
            out = 1'b0;
        end
    end

上述还是一种Moore的二段式写法但是这次的输出out不会延后一个时钟,是因为next_state 是由组合逻辑电路产生的这样输出只会慢next_state一个时钟。 这种写法属于控制current_state
在这里插入图片描述
如果用VHDL写的话,实际上输出是会慢state 1个 delta delay的。
在这里插入图片描述

控制 state写法

module top_module(
    input clk,
    input areset,    // Asynchronous reset to state B
    input in,
    output reg out);//  
 
    parameter A=1'b0, B=1'b1; 
    reg state;
    
    always@(posedge clk or posedge areset)begin
        if(areset)begin
           state <= B;
        end
        else begin
            case (state) 
            	A : if(in) begin
            		state <= A;
            		end
            		else begin
            		state <= B;
            		end
            	B : if (in) begin
            		state <= B;
            		end
            		else begin
            		state <= A;
            		end
        end
    end
 

    
    //combinational logic way
    always@(*)begin 
        if(state == B)begin
            out = 1'b1;
        end
        else begin
            out = 1'b0;
        end
    end

这种写法的在VHDL中依然有 output value 实际上依然有one delta delay的延时。

控制current state 和output

module top_module(
    input clk,
    input areset,    // Asynchronous reset to state B
    input in,
    output reg out);//  
 
    parameter A=1'b0, B=1'b1; 
    reg current_state, next_state;
    
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            current_state <= B;
        end
        else begin
            current_state <= next_state;
            case(state)
            A : out <= 0;
            B : out <= 1;
            endcase
        end
    end
 
    always@(*)begin
        case(current_state)
            B:begin
                if(in == 1'b1)begin
                    next_state = B;
                end
                else begin
                    next_state = A;
                end
            end
            A:begin
                if(in == 1'b1)begin
                    next_state = A;
                end
                else begin
                    next_state = B;
                end
            end
        endcase
    end
    

这种写法会消除one delta delay 。 因为这样能够确保state和output都是从register输出的,这样就不用管downstream(后面要接的电路)的情况,也没有了one delta delay了。 这种写法也相当于大家经常看到的普遍的二段式加上寄存器输出。

7.三段式状态机

Moore:

module adder(
clk,rst,q_out,key
)
input clk,rst,key;
out q_out;

localparam  S1 = 0, S2 = 1, S3 = 2;

reg[1:0] state, next_state;

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

always @(key or state)
	begin
		case(state)
		S1 : if(key) 
				next_state = S2;
			 else
			 	next_state = S1;
		S2 : if(key)
				next_state = S3;
			else
				next_state = S2;
		S3 : if(key)
				next_state = S1;
			else 
				next_state = S2;
		 default:
		 		next_state = 2'bxx;
		 endcase
	end	 		

always @(posedge clk or posedge rst)
	begin
		if(rst)
		q_out <= 0 ;
		else 
			case(next_state)
			S1 : q_out <= 0;
			S2 : q_out <= 1;
			S3 : q_out <= 0;
			default : q_out <= 1'bx;
		endcase
	end
endmodule
			

总结

三段式使用3个always块,第一个采用同步时序电路用来描述状态转移state->next_state,第二个用组合逻辑实现转换数值传递条件,最后再输出再增加一级触发器来实现时序逻辑输出,这样做的好处是:

  1. 有效除去因为组合逻辑输出产生的毛刺,利于时序计算和约束,利于布局布线实现高性能设计。
  2. 对于输出为总线模式的输出信号,容易使总线对齐,从而减少总线数据偏移,减少接收端数据采样出错的概率。

相较于一段式,一段式将组合逻辑和时序逻辑写在一起,容易造成混淆,不利于代码维护。二段式在组合逻辑特别复杂时适用,但要注意需在后面加一个触发器以消除组合逻辑对输出产生的毛刺。三段式没有这个问题,由于第三个always会生成触发器,但是这条路径的时序会比较紧张。

文中提到的delta delay 的问题可能就是VHDL与Verilog最本质的区别。

其实三段式和二段式的主要区别就是,在组合逻辑的时候要不要在使用register输出output,像我二段式中时序同时控制current state 和输出这种形式其实本质和三段式没有区别。所以还是要理解电路的时序问题再看采用怎样的代码。

Extra

在Xilin官网上有讨论提出,可能很多人喜欢用一段式,这样是最简单的。至于原因大家可以自己去瞅瞅,因为看过一遍之后,没能记下来所以不想在这个小细节上纠结。
https://forums.xilinx.com/t5/Synthesis/FSM-coding-1-vs-2-vs-3-process-style-which-one-is-preferred/td-p/746476

大家感兴趣可以参考 Verilog flaw这篇文章
https://insights.sigasi.com/opinion/jan/verilogs-major-flaw/

还有这一篇对VHDL如何写三种模式的状态机的方法,我使用的图是这个网站的,我相当于把VHDL翻译成Verilog,仿真之后也是符合我说的现象的。
https://vhdlwhiz.com/n-process-state-machine/

http://blog.sina.com.cn/s/blog_6f0eeb330101djzu.html

  • 10
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Verilog是一种硬件描述语言,可以用于实现状态机。下面是三段式二段式一段状态机Verilog实现示例: ## 三段式状态机 ```verilog module Three_State_Machine ( input clk, // 时钟信号 input reset, // 复位信号 input event, // 事件信号 output reg state_out // 输出状态信号 ); // 定义状态枚举类型 typedef enum logic [1:0] { STATE_IDLE, STATE_WAIT_EVENT, STATE_PROCESS_EVENT } state_type; // 定义状态变量和状态转移条件 reg [1:0] state, next_state; always @(*) begin case (state) STATE_IDLE: begin if (event) next_state = STATE_WAIT_EVENT; else next_state = STATE_IDLE; end STATE_WAIT_EVENT: begin next_state = STATE_PROCESS_EVENT; end STATE_PROCESS_EVENT: begin next_state = STATE_IDLE; end default: next_state = STATE_IDLE; endcase end // 状态机状态寄存器 always @(posedge clk, posedge reset) begin if (reset) state <= STATE_IDLE; else state <= next_state; end // 输出状态信号 always @(*) begin case (state) STATE_IDLE: state_out = 1'b0; STATE_WAIT_EVENT: state_out = 1'b1; STATE_PROCESS_EVENT: state_out = 1'b0; default: state_out = 1'b0; endcase end endmodule ``` ## 二段式状态机 ```verilog module Two_State_Machine ( input clk, // 时钟信号 input reset, // 复位信号 input event, // 事件信号 output reg state_out // 输出状态信号 ); // 定义状态枚举类型 typedef enum logic [0:0] { STATE_IDLE, STATE_PROCESS_EVENT } state_type; // 定义状态变量和状态转移条件 reg [0:0] state, next_state; always @(*) begin case (state) STATE_IDLE: begin if (event) next_state = STATE_PROCESS_EVENT; else next_state = STATE_IDLE; end STATE_PROCESS_EVENT: begin next_state = STATE_IDLE; end default: next_state = STATE_IDLE; endcase end // 状态机状态寄存器 always @(posedge clk, posedge reset) begin if (reset) state <= STATE_IDLE; else state <= next_state; end // 输出状态信号 always @(*) begin case (state) STATE_IDLE: state_out = 1'b0; STATE_PROCESS_EVENT: state_out = 1'b1; default: state_out = 1'b0; endcase end endmodule ``` ## 一段状态机 ```verilog module One_State_Machine ( input clk, // 时钟信号 input reset, // 复位信号 input event, // 事件信号 output reg state_out // 输出状态信号 ); // 定义状态枚举类型 typedef enum logic [0:0] { STATE_IDLE } state_type; // 定义状态变量和状态转移条件 reg [0:0] state, next_state; always @(*) begin next_state = STATE_IDLE; end // 状态机状态寄存器 always @(posedge clk, posedge reset) begin if (reset) state <= STATE_IDLE; else state <= next_state; end // 输出状态信号 always @(*) begin case (state) STATE_IDLE: state_out = 1'b0; default: state_out = 1'b0; endcase end endmodule ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值