三段状态机程序编写练习
三段状态机结构
下面是一个状态机的样例,在写三段式状态机程序时我们只需要模仿着写即可。
/* 有限状态机,三过程块建模风格 ***************************************** */
// 状态编码
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
不同于传统的用状态转换图来写状态机,假如已知流程图就可以直接用编程语言描述流程图,就可以写出三段状态机的第二段。但是现实情况是,很少有直接知道流程图的,而且自己去画这个流程图也挺复杂。更多情况的写状态机还是画状态转化图,然后写程序。本例的第三段状态机也不像传统第三段,它没有按在不同的状态时有不同的操作,而是无论现在是什么状态,只有标志位变化,就进行操作。