三段状态机程序编写练习

三段状态机结构

下面是一个状态机的样例,在写三段式状态机程序时我们只需要模仿着写即可

    /* 有限状态机,三过程块建模风格 ***************************************** */
    // 状态编码
    localparam IDLE  = 3'b001,
               DELAY = 3'b010,
               GENE  = 3'b100;
    
    reg [2:0] now_state = IDLE, next_state = IDLE;
    
    // 1.实现状态转换
    always @ (posedge clk) begin//: trans_state
        if (rst)
            now_state <= IDLE;
        else
            now_state <= next_state;
    end//: trans_state
    
    // 2.产生下一个状态
    always @ (*) begin//: set_next_state
        //next_state = now_state; // 下面分支的缺省状态
        case (now_state)
        IDLE  : if (valid )
							begin
                    if (delay=='b0)
                        next_state = GENE;
                    else
                        next_state = DELAY;
						  end
                else
                    next_state = IDLE;
        DELAY : if (delay_cnt >= delay)
                    next_state = GENE;
                else
                    next_state = DELAY;
        GENE  : if (nop_cnt >= nop)
                    next_state = IDLE;
                else
                    next_state = GENE;
		 default:
						next_state=IDLE;
        endcase
    end//: set_next_state
    
    // 3.产生状态机的输出值
    always @ (posedge clk) begin//: set_out_proc
        case (next_state)
        IDLE  : begin
                nop_cnt     <= 'b0;
                delay_cnt   <= 'b0;

                end
        DELAY : begin
                delay_cnt   <= delay_cnt + 1'b1;
                end
        GENE  : begin
                if (pulse_dec)
                    nop_cnt <= nop_cnt + 1'b1;
                else
                    nop_cnt <= nop_cnt;
                end
        default: ;
        endcase
    end//: set_out_proc

在写状态机程序时,每个状态最好用独热码来定义状态,上面程序就是采用独热码,这种定义从资源和布线都是比较优的。独热码是对于任一状态,状态向量中只有一位为1,其余位为0.

已知程序流程图,怎么用状态机写程序

问题:设计一个能求出一个32bit字中两个相邻1之间最大间隙的电路。即求两个1之间最多夹了多少个0
流程图:
在这里插入图片描述
解:系统化分为状态机控制器和数据通路,信号的接口关系可参考下图(a)所示:
在这里插入图片描述
这个controller就是三段状态机的第二段,datapath就是三段状态机的第三段。数据通路包括一个位计数器(k)、一个存储寄存器(tmp)、一个间隙寄存器(Gap)。控制器产生的控制信号包括:
flush_tmp:清空tmp寄存器
incr_tmp: 增加tmp寄存器
store_tmp:用tmp加载Gap
incr_k: 增加k计数器

module homework2(data,clk,rst,gap);
 input clk,rst;
 input [31:0] data;
 output[5:0]gap;
 
 reg [5:0] gap,tmp,k;
 reg flush_tmp,store_tmp,incr_k,incr_tmp, flush_gap;
 parameter s_0=0,s_1=1,s_2=2,s_done=3;
 reg [1:0] state,next_state;
 wire Bit=data[k];
 
	always @(posedge clk,posedge rst)
        begin
		if(rst)
		  state<=s_0;
		  else
		  state<=next_state;
        end
          
	always @(state or Bit or k)
	  begin
	   // next_state=state;
		 incr_tmp=0;
		 incr_k=0;
		 store_tmp=0;
		 flush_tmp=0;
         flush_gap=0;
			case(state)
			  s_0:if(k==31)
                    next_state=s_done;
                  else begin
                    if(!Bit)
                        begin
                            next_state=s_1;
                            incr_k=1;
                        end
                    else
                        begin
                            next_state=s_0;
                            incr_k=1;
                        end
                  end
            s_1:if(k==31)
                    next_state=s_done;
				else
                begin
				  if(!Bit)
                    begin
                        next_state=s_2;
                        incr_k=1;
                        incr_tmp=1;
                    end
				  else
                    begin
                        next_state=s_1;
                        incr_k=1;
                    end
                end
			s_2:if(k==31)
                    begin
                        if(!Bit)
                            next_state=s_done;
                        else
                        begin
                            if(tmp>gap)
                                begin
                                    store_tmp=1;
                                    next_state=s_done;
                                end
                            else
                                    next_state=s_done;
                        end
                    end
                    
				else
                begin
                    if(!Bit)
                        begin
                            incr_tmp=1;
                            incr_k=1;
                            next_state=s_2;
                        end
                    else
                        begin
                            if(tmp>gap)
                                begin
                                    store_tmp=1;
                                    flush_tmp=1;
                                    incr_k=1;
                                    next_state=s_1;
                                end
                            else
                                begin  
                                    next_state=s_1;
                                    incr_k=1;
                                    flush_tmp=1;
                                end
                        end
                end 
				s_done:
				begin
                    next_state=s_0;
                     flush_gap=1;
				end
				default:
                    next_state=s_0;
				endcase
	end
            
		always @(posedge clk,posedge rst) begin
			begin
				if(rst)
				begin
					k<=0;
					tmp<=0;
					gap<=0;
				end
				else
				begin
					if(flush_tmp)
					tmp<=0;
					if(store_tmp)
					gap<=tmp;
					if(incr_k)
					k<=k+1;
					if(incr_tmp)
					tmp<=tmp+1;
                    if(flush_gap)
                        begin
                            gap<=0;
                            k<=0;
                            tmp<=0;
                        end
				end
			end
        end
endmodule

不同于传统的用状态转换图来写状态机,假如已知流程图就可以直接用编程语言描述流程图,就可以写出三段状态机的第二段。但是现实情况是,很少有直接知道流程图的,而且自己去画这个流程图也挺复杂。更多情况的写状态机还是画状态转化图,然后写程序。本例的第三段状态机也不像传统第三段,它没有按在不同的状态时有不同的操作,而是无论现在是什么状态,只有标志位变化,就进行操作。

©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页