FPGA之FSM有关问题

一、首先明确FSM编码方法

  • 二进制编码(Binary code)
  • 格雷码(Gray code)
  • 独热码(one-hot code)

二进制编码不用介绍,很熟悉,主要介绍格雷码和独热码;

1、独热码(one-hot code)

parameter idle = 4'b1000,
          start = 4'b0100,
          stop = 4'b0010,
          clear = 4'b0001;

每个状态有独立的寄存器位,任意时刻只有1位寄存器为1,即为one hot point。

优点:减少状态寄存器之间的组合逻辑数,提高了运行速度;

缺点:编码位数过多,牺牲寄存器逻辑资源,成本高。

独热码适用于目标器件有较多寄存器资源,寄存器之间组合逻辑较少时。

2、格雷码(Gray code)

相邻性编码,是一种循环码,相邻数只有一位不一样。


三种编码比较:

二进制码、格雷码使用最少的触发器,较多的组合逻辑,独热码反之。

FPGA有更多的触发器资源,多使用独热码;CPLD提供更多的组合逻辑,多使用格雷码;

对于小型设计使用格雷码和二进制码更高效;大型状态机使用独热码更高效。

二、状态机写法

  • 一段式(1个always)
  • 二段式(2个always)
  • 三段式(3个always)

一般一段式和三段式较多使用,主要介绍三段式:

//第一个always,同步时序always模块
always @(posedge clk or negedge rst_n)
       if(!rst_n)
          current_state <= idle;
       else 
          current_state <= next_state;
//第二个always,组合逻辑模块,描述状态转移条件判断
always @(current_state)
    begin
       next_state = x;
       case(current_state)
          s1: if(...)
                next_state <= s2;
          ....
       endcase
     end
//第三个always,同步时序always模块
always @(posedge clk or negedge rst_n)
     ....
       case(next_state)
          s1:
            out1 <= 1'b1;
          s2:
             out2 <= 1'b1;
          default:...
        endcase
         

三、几个例子

1、序列检测“10010”:当x输入10010后,y输出1(三段式)

贴代码:

`define simulation
module seqdet (
					input clk ,
					input rst_n ,
					input x ,
					output reg y 
) ;


`ifdef simulation 
parameter IDLE = "IDLE" ;
parameter A = "A" ;
parameter B = "B" ;
parameter C = "C" ;
parameter D = "D" ;
parameter E = "E" ;
parameter state_length = 32 ;
`elsif
parameter IDLE = 3'd0 ;
parameter A = 3'd1 ;
parameter B = 3'd2 ;
parameter C = 3'd3 ;
parameter D = 3'd4 ;
parameter E = 3'd5 ;
parameter state_length = 3 ;
`endif
reg [state_length - 1:0] current_state ;
reg [state_length - 1:0] next_state ;
//状态寄存
always @ (posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		current_state <= IDLE ;
	end
	else begin
		current_state <= next_state ;
	end
end
//组合逻辑
always @ (*)
begin
		next_state  = IDLE ;
	case (current_state)
		IDLE :begin
				if(x == 1)begin
					next_state = A ;
				end
				else begin
					next_state = IDLE ;
				end
		end
		A    :begin
				if(x == 0)begin
					next_state = B ;
				end
				else begin
					next_state = A ;
				end	
		end
		B    :begin
				if(x == 0)begin
					next_state = C ;
				end
				else begin
					next_state = A ;
				end
		end
		C    :begin
				if(x == 1)begin
					next_state = D ;
				end
				else begin
					next_state = IDLE ;
				end
		end
		D    :begin
				if(x == 0)begin
					next_state = E ;
				end
				else begin
					next_state = A ;
				end
		end
		E    :begin
				if(x == 1)begin
					next_state = A ;
				end
				else begin
					next_state = C ;
				end
		end
		default :begin
					next_state = IDLE;
					y = 0 ;
		end
	endcase
end

always @ (posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		y <= 0 ;
	end
	else begin
		case (current_state)
			D :begin
				if(x == 0)begin
					y <= 1 ;
				end
				else begin
					y <= 0 ;
				end
			end
			E :begin
					y <= 0 ;
			end
			default :begin
					y <= 0 ;
			end
		endcase
	end
end
endmodule 

2、自动售货机


`define simulation
module sell(
				input clk ,
				input rst_n ,
				input half_dollar ,
				input one_dollar ,
				output reg dout ,   //售出
				output reg half_out //找零
);

`ifdef simulation
parameter IDLE = "IDLE"  ;
parameter half =  "half";
parameter one = "one";
parameter state_length = 32;
`elsif
parameter IDLE = "IDLE"  ;
parameter half =  "half";
parameter one = "one";
parameter state_length = 2 ;
`endif

reg [state_length-1:0] ns ;
reg [state_length-1:0] cs ;

always @ (posedge clk or negedge rst_n ) 
begin
	if(!rst_n)begin
		cs <= IDLE ;
	end
	else begin
		cs <= ns ;
	end
end

always @ (*)
begin
	ns = IDLE ;
	case(cs)
		IDLE:begin
			if(half_dollar)begin
				ns = half ;
			end
			else begin
				ns = one ; 
			end
		end
		half:begin
			if(half_dollar)begin
				ns = one ;
			end
			else begin
				ns = IDLE ;
			end
		end
		one:begin
				ns = IDLE ;	
		end
		default:begin
				ns = IDLE ;
		end
	endcase
end

always @ (*)
begin
	half_out <= 0 ;
	dout <= 0 ;
	case(cs)
		half:begin
			if(half_dollar)begin
				dout <= 0 ;
				half_out <= 0 ;
			end
			else begin
				dout  <= 1 ;
				half_out <= 0 ;
			end
		end
		one:begin
			if(half_dollar)begin
				dout <= 1 ;
				half_out <= 0 ; 
			end
			else begin
				dout <= 1 ;
				half_out <= 1 ;
			end
		end
	endcase
end
endmodule
重点是状态图,状态机的灵魂;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值