HDLBits练习-有限状态机FSM

Exams/ece241 2013 q4-水位问题

1、输入是什么?

2、现态是什么?

3、次态是什么?

4、转换条件是什么?

5、输出是什么?

HDLBits练习-有限状态机FSM_第1张图片

 在这个问题中,输入是3个传感器,现态和次态是4个水位状态(water level),转换条件是3个传感器的值是什么情况,输出是水阀的开关状态。其中水阀分两类,一类是固定水阀(nominal flow),一类是辅助水阀(supplemental flow)。

module top_module (
    input clk,
    input reset,	//同步复位,高有效
    input [3:1] s,
    output fr3,
    output fr2,
    output fr1,
    output dfr
); 
    parameter a=1,b=2,c=3,d=4;
    
    reg		[2:0]	state,state_n;    	
    //状态转换
    always@(posedge clk)begin
        if(reset)
            state <= a;
        else
            state <= state_n;
    end
    
    //转换条件
    always@(*)begin
        case(state)
            a:state_n = s[1]? b:a;
            b:state_n = s[2]? c:(s[1]? b:a);
            c:state_n = s[3]? d:(s[2]? c:b);
            d:state_n = s[3]? d:c;
        endcase
    end
    
    //输出结果
    always@(*)begin
        case(state)
            a:{fr3,fr2,fr1} = 3'b111;
            b:{fr3,fr2,fr1} = 3'b011;
            c:{fr3,fr2,fr1} = 3'b001;
            d:{fr3,fr2,fr1} = 3'b000;
        endcase
    end
    
    always@(posedge clk)begin
        if(reset)
            dfr <= 1;
        else begin
            if(state > state_n)
                dfr <= 1;
        	else if(state 

其中,辅助水阀的开关取决于当前状态和前一状态的值,所以用时序逻辑+比较器实现。如果现在的状态是a,下一状态是b。那么当下一个时钟来临时,a就变成了上一个状态,b就变成了当前状态,再通过比较得出水是上升还是下降,从而实现dfr的赋值。

答案中给出的程序如下:

module top_module (
	input clk,
	input reset,
	input [3:1] s,
	output reg fr3,
	output reg fr2,
	output reg fr1,
	output reg dfr
);


	// Give state names and assignments. I'm lazy, so I like to use decimal numbers.
	// It doesn't really matter what assignment is used, as long as they're unique.
	// We have 6 states here.
	parameter A2=0, B1=1, B2=2, C1=3, C2=4, D1=5;
	reg [2:0] state, next;		// Make sure these are big enough to hold the state encodings.
	


    // Edge-triggered always block (DFFs) for state flip-flops. Synchronous reset.	
	always @(posedge clk) begin
		if (reset) state <= A2;
		else state <= next;
	end



    // Combinational always block for state transition logic. Given the current state and inputs,
    // what should be next state be?
    // Combinational always block: Use blocking assignments.    
	always@(*) begin
		case (state)
			A2: next = s[1] ? B1 : A2;
			B1: next = s[2] ? C1 : (s[1] ? B1 : A2);
			B2: next = s[2] ? C1 : (s[1] ? B2 : A2);
			C1: next = s[3] ? D1 : (s[2] ? C1 : B2);
			C2: next = s[3] ? D1 : (s[2] ? C2 : B2);
			D1: next = s[3] ? D1 : C2;
			default: next = 'x;
		endcase
	end
	
	
	
	// Combinational output logic. In this problem, a procedural block (combinational always block) 
	// is more convenient. Be careful not to create a latch.
	always@(*) begin
		case (state)
			A2: {fr3, fr2, fr1, dfr} = 4'b1111;
			B1: {fr3, fr2, fr1, dfr} = 4'b0110;
			B2: {fr3, fr2, fr1, dfr} = 4'b0111;
			C1: {fr3, fr2, fr1, dfr} = 4'b0010;
			C2: {fr3, fr2, fr1, dfr} = 4'b0011;
			D1: {fr3, fr2, fr1, dfr} = 4'b0000;
			default: {fr3, fr2, fr1, dfr} = 'x;
		endcase
	end
	
endmodule

答案中直接分配了6个状态,包括了上升和下降的信息(b1b2,c1c2),所以结构更为精简。这里给出了状态机的默认值‘x。

Lemmings1

碰到左边就往右走,碰到右边就往左走。

所以状态只有两个:向右、向左;输入为碰左边、碰右边。

module top_module(
    input clk,
    input areset,    // Freshly brainwashed Lemmings walk left.
    input bump_left,
    input bump_right,
    output walk_left,
    output walk_right); //  

    parameter LEFT=0, RIGHT=1;
    reg state, next_state;

    always @(*) begin
        // State transition logic
        case(state)
            LEFT:next_state = bump_left? RIGHT:LEFT;
            RIGHT:next_state = bump_right? LEFT:RIGHT;
            default:next_state = 'x;           
        endcase
    end

    always @(posedge clk, posedge areset) begin
        // State flip-flops with asynchronous reset
        if(areset)
            state <= LEFT;
        else
            state <= next_state;
    end

    // Output logic
    assign walk_left = (state == LEFT);
    assign walk_right = (state == RIGHT);

endmodule

Lemmings2

比上面多了一个“坠落”的效果,并会发出“aaah”,掉落时不再受碰撞影响,地重新出现的时候继续上一方向。

新状态:坠落;转入条件:ground=0;输出:aaah

module top_module(
    input clk,
    input areset,    // Freshly brainwashed Lemmings walk left.
    input bump_left,
    input bump_right,
    input ground,
    output walk_left,
    output walk_right,
    output aaah ); 
    
    parameter WL=0,WR=1,WLF=2,WRF=3;
    
    reg	[1:0]	state,state_n;
    
    always@(posedge clk or posedge areset)begin
        if(areset)
            state <= WL;
        else 
            state <= state_n;
    end
    
    always@(*)begin
        case(state)
            WL:state_n = ground? (bump_left? WR:WL):WLF;
            WR:state_n = ground? (bump_right? WL:WR):WRF;
            WLF:state_n = ground? WL:WLF;
            WRF:state_n = ground? WR:WRF;
            
               
        endcase
    end
    
    assign	walk_left = (state == WL);
        assign	walk_right = (state == WR);
    assign	aaah = (state == WRF)||(state == WLF);

endmodule

Lemmings3

新增状态:挖洞

转入条件:ground=1&&dig=1

转出条件:ground=0

优先级:坠落>挖洞>选方向

module top_module(
    input clk,
    input areset,    // Freshly brainwashed Lemmings walk left.
    input bump_left,
    input bump_right,
    input ground,
    input dig,
    output walk_left,
    output walk_right,
    output aaah,
    output digging ); 
    
    parameter WR=0,WL=1,WLF=2,WRF=3,DIGL=4,DIGR=5;
    
    reg	[2:0]	state,state_n;
    
    always@(posedge clk or posedge areset)begin
        if(areset)
            state <= WL;
        else 
            state <= state_n;
    end
    
    always@(*)begin
        case(state)
            WL:state_n = ground? (dig? DIGL:(bump_left? WR:WL)):WLF;
            WR:state_n = ground? (dig? DIGR:(bump_right? WL:WR)):WRF;
            WLF:state_n = ground? WL:WLF;
            WRF:state_n = ground? WR:WRF;
            DIGL:state_n = ground? DIGL:WLF;
            DIGR:state_n = ground? DIGR:WRF;
        endcase
    end
        
    assign walk_left = state == WL;
    assign walk_right = state == WR;
    assign aaah = (state == WLF)||(state == WRF);
    assign digging = (state == DIGR)||(state == DIGL);

endmodule

Lemmings4

新增状态:飞溅

转入条件:下落时间>20clk && 有地面出现

输出:全部输出为0

通过debug我发现,aaah是在下落过程中一直出现,并不会在splatter的状态下终止。这就意味着在下落过程中,只有t>20且ground=1时,输出才会改变。

module top_module(
    input clk,
    input areset,    // Freshly brainwashed Lemmings walk left.
    input bump_left,
    input bump_right,
    input ground,
    input dig,
    output walk_left,
    output walk_right,
    output aaah,
    output digging ); 
    
    parameter WL=0,WR=1,DIGL=2,DIGR=3,WLF=4,WRF=5,SPL=6,OVER=7;
    
    reg	[3:0]	state,state_n;
    
    reg [4:0]	cnt_20;
    wire		add_cnt_20;
    wire		end_cnt_20;
    wire		full_cnt_20;
    
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            cnt_20 = 5'b0;
            full_cnt_20 = 0;
        end
        else begin
            if(add_cnt_20)begin
                if(end_cnt_20)begin
                    cnt_20 = 5'b0;
                	full_cnt_20 = 1;
                end
                else	begin
                    cnt_20 = cnt_20 + 1;
                    full_cnt_20 = full_cnt_20;
                end
            end
            else begin
                cnt_20 = 5'b0;//无地计数,有地清零
                full_cnt_20 = 0;
            end
        end
    end
    
    assign add_cnt_20 = ~ground;
    assign end_cnt_20 = add_cnt_20 && cnt_20 == 20;
    
    always@(posedge clk or posedge areset)begin
        if(areset)
            state = WL;
        else 
            state = state_n;
    end
    
    always@(*)begin
        case(state)
            WL:state_n = ground?(dig?DIGL:(bump_left?WR:WL)):WLF;
            WR:state_n = ground?(dig?DIGR:(bump_right?WL:WR)):WRF;
            DIGL:state_n = ground?DIGL:WLF;
            DIGR:state_n = ground?DIGR:WRF;
            WLF:state_n = ground?(full_cnt_20?OVER:WL):WLF;
            WRF:state_n = ground?(full_cnt_20?OVER:WR):WRF;
            OVER:state_n = OVER; 
        endcase
    end
    
    assign walk_left = state == WL;
    assign walk_right = state == WR;
    assign aaah = state == WLF || state == WRF ;
    assign digging = state == DIGL || state == DIGR;


endmodule

Fsm onehot

HDLBits练习-有限状态机FSM_第2张图片

 只写状态转换逻辑和输出

module top_module(
    input in,
    input [9:0] state,
    output [9:0] next_state,
    output out1,
    output out2);
    
    assign	next_state[0] = (state & 10'b1110011111)&&(~in);
    assign 	next_state[1] = (state[0] & in) | (state[8] & in)|(state[9] & in); 
    assign 	next_state[2] = (state[1] & in); 
    assign 	next_state[3] = (state[2] & in); 
    assign 	next_state[4] = (state[3] & in);
    assign 	next_state[5] = (state[4] & in);
    assign 	next_state[6] = (state[5] & in);
    assign 	next_state[7] = (state[7] & in) | state[6] & (in);
    assign 	next_state[8] =  state[5] & (~in);
    assign 	next_state[9] =  state[6] & (~in);
        	
    assign 	out1 = (state[8] | state[9]) ? 1:0;
    assign 	out2 = (state[9] | state[7]) ? 1:0;

endmodule

我发现除了s5s6,其他状态下当in=0时,都会回到s0。所以将state输入按位与,消去s5s6的影响,再逻辑与上~in,只要其他位有1,则状态回到s0。

其他状态与之前的独热码状态机无差别,独热码的使用让逻辑转换式更加简单,利于消除毛刺。

Fsm ps2

HDLBits练习-有限状态机FSM_第3张图片

 这里的BYTE1、BYTE2、BYTE3,对应每一组信号的bit[3]、bit[2]、bit[1]

HDLBits练习-有限状态机FSM_第4张图片

 这里in[3]的数据只表示第3位,即标志位。当in[3]=1时,输出3位数据,完成后标志位done=1。这里最下面一行的byte1、byte2、byte3对应的是输出信号,不是done。

HDLBits练习-有限状态机FSM_第5张图片

这里一组信号输出完成后,下一个in[3]还未来临,所以状态维持在byte1,;当in[3]=1时,下一状态变成byte2. 

module top_module(
    input clk,
    input [7:0] in,
    input reset,    // Synchronous reset
    output done); //
    
    reg			[3:0]	state,state_n;
    parameter			BYTE1=0,BYTE2=1,BYTE3=2,DONE=3;	

    // State transition logic (combinational)
    always@(*)begin
        case(state)
            BYTE1:state_n = in[3]?BYTE2:BYTE1;
            BYTE2:state_n = BYTE3;
            BYTE3:state_n = DONE;
            DONE: state_n = in[3]?BYTE2:BYTE1;
        endcase
    end

    // State flip-flops (sequential)
    always@(posedge clk)begin
        if(reset)
            state = BYTE1;
        else
            state = state_n;
    end
        
    // Output logic
    assign done = (state == DONE)? 1:0;
endmodule

Fsm ps2data

与上一题的主要区别在于提供了数据的存储路径,这里的思路是当下一状态改变时,意味着数据满足要求,在下一个时钟到来的时候,一方面state=state_n;一方面输入数据被存储起来。

module top_module(
    input clk,
    input [7:0] in,
    input reset,    // Synchronous reset
    output [23:0] out_bytes,
    output done); //

    // FSM from fsm_ps2
    reg			[3:0]	state,state_n;
    parameter			BYTE1=0,BYTE2=1,BYTE3=2,DONE=3;	

    // State transition logic (combinational)
    always@(*)begin
        case(state)
            BYTE1:state_n = in[3]?BYTE2:BYTE1;
            BYTE2:state_n = BYTE3;
            BYTE3:state_n = DONE;
            DONE: state_n = in[3]?BYTE2:BYTE1;
        endcase
    end

    // State flip-flops (sequential)
    always@(posedge clk)begin
        if(reset)
            state = BYTE1;
        else
            state = state_n;
    end
        
    // Output logic
    assign done = (state == DONE);

    // New: Datapath to store incoming bytes.
	//下一状态为BYTE2时,BYTE1记录完成;
    //下一状态为BYTE3时,BYTE2记录完成;
    //下一状态为DONE时,BYTE3记录完成;
    reg	[23:0]	out_reg;
    always@(posedge clk)begin
        if(reset)
            out_reg <= 24'b0;
        else
            case(state_n)
                BYTE2:out_reg[23:16] <= in[7:0];
                BYTE3:out_reg[15:8]	 <= in[7:0];
                DONE: out_reg[7:0]	 <= in[7:0];
                default:out_reg[23:0]<= 24'b0;
            endcase
    end
    
    assign out_bytes = (state == DONE)?out_reg[23:0]:24'b0;


endmodule

你可能感兴趣的:(HDLBits,verilog,fpga)