状态机分为
摩尔状态机:组合逻辑的输出只取决于当前状态
米勒状态机:组合逻辑的输出不仅取决于当前状态,还取决于输入状态
三段式状态机的基本格式是:
第一个Always语句实现同步状态跳转(基本是固定的模板)
第二个Always语句采用组合逻辑判断状态转移条件(根据状态转移图写)
第三个Always语句描述状态输出(可以采用组合逻辑输出,也可以时序电路时输出)
Example:
例1.设计一个自动售饮料的逻辑电路。它的投币口每次只能投入一枚五角或一元的硬币。投入一元五角后给出饮料,投入两元硬币时给出饮料并找回五角。
分析:首先确定输入输出
投入一元硬币 A=1 ,投入五角硬币 B=1,给出饮料 Y=1 ,找回五角 Z=1 ;
然后确定电路的状态数,画出状态转移表
投币前初始状态为 S0 ,投入五角硬币为 S1 ,投入一元硬币为 S2 。
由于每次只能投一枚,因此除了AB=00, AB=01 , AB=10 三种状态为合法状态。画出状态转移表为:
画出状态转移图
最后根据状态转移图写出代码
Moudle Drink_sell(
input clk,rst_n;
input A,B;
output Y,Z;
);
reg [2:0] curr_st;
reg [2:0] next_st;
parameter S0 = 3'b001;
parameter S1 = 3'b010;
parameter S2 = 3'b100;
//第一个always块描述状态跳转
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
curr_st <= S0 ;
end
else begin
curr_st <= next_st;
end
end
//第二个always块采用组合逻辑判断状态转移条件
always @(*)begin
if(!rst_n)begin
next_st <= S0 ;
end
else begin
case(curr_st)
S0: if(A==0 && B==1) next_st = S1;
else if(A==1 && B==0) next_st = S2;
else next_st = S0;
S1: if(A==0 && B==1) next_st = S2;
else if(A==1 && B==0) next_st = S0;
else next_st = S1;
S2: if(A==0 && B==0) next_st = S2;
else next_st = S0;
default: next_st = S0;
endcase
end
end
//第三个always块描述状态输出
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
Y <= 1'b0;
Z <= 1'b0;
end
else bigin
case(curr_st)
S0: Y <= 1'b0;
Z <= 1'b0;
S1: if(A==1 && B==0)begin
Y <= 1'b1;
Z <= 1'b0;
end
S2: if(A==0 && B==1)begin
Y <= 1'b1;
Z <= 1'b0;
end
else(A==1 && B==0)begin
Y <= 1'b1;
Z <= 1'b1;
end
default: Y <= 1'b0;
Z <= 1'b0;
endcase
end
end
endmodule
例2:根据状态转移图写出Verilog代码(2020华为勇敢星FPGA岗位面试题)
代码如下:
module dec(
input clk,
input rst_n,
input Go,Ws,
output result
);
reg [3:0] curr_st;
reg [3:0] next_st;
parameter S_IDLE = 4'b0001;
parameter S_READ = 4'b0010;
parameter S_DELAY = 4'b0100;
parameter S_DONE = 4'b1000;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
curr_st <= S_IDLE ;
end
else begin
curr_st <= next_st;
end
end
always @(*)begin
if(!rst_n)begin
next_st = 4'b0000;
end
else begin
case (curr_st)
S_IDLE :if(Go) next_st = S_READ ;
else next_st = S_IDLE ;
S_READ : next_st =S_DELAY ;
S_DELAY:if(!Ws) next_st = S_DONE ;
else next_st = S_READ ;
S_DONE : next_st = S_IDLE ;
default: next_st = S_IDLE ;
endcase
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
result <= 1'0;
end
else begin
case(curr_st ==S_DONE )
result <= 1'b1;
endcase
end
end
end
endmodule