Verilog 状态机
状态机类型
状态机? 有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
Moore 型状态机
输出只与当前状态有关,与当前输入无关 输入对输出的影响要在下一个时钟周期才能反映出来,输出在一个完整的时钟周期内保持稳定,即使此时输入变化,输出也不会变化。 输入与输出是隔离开的
Melay 状态机
输出不仅与当前状态有关,还和当前的输入信号有关
状态机的输出是在输入信号变化后立刻发生变化,且输入变化可能出现在任何时刻的时钟周期内。
Mealy状态机比Moore状态机早一个时钟周期
根据设计需求画出状态转移图,确定使用状态机类型,并标注出各种输入输出信号,更有助于编程 一般的使用最多的就是:Mealy型3段式状态机
自动贩卖机
设计流程:
- 根据状态机的个数确定状态机编码,利用编码给状态寄存器赋值,代码可读性更好
- 第一段:时序逻辑,非阻塞赋值,传递寄存器的状态
- 第二段:组合逻辑,阻塞赋值,根据当前状态和当前输入,确定下一个状态机的状态
- 第三段:时序逻辑,非阻塞赋值,因为是Melay状态机,根据当前状态和输入,确定输出信号
module vending_machine_p3(
input clk,
input rstn,
input [1:0] coin,
output [1:0] change,
output sell
);
parameter IDLE = 3'd0;
parameter GET05 = 3'd1;
parameter GET10 = 3'd2;
parameter GET15 = 3'd3;
reg [2:0] st_next;
reg [2:0] st_cur;
always @(posedge clk or negedge rstn) begin
if(!rstn) begin
st_cur <= 'b0;
end
else begin
st_cur <= st_next;
end
end
always @(*) begin
case(st_cur)
IDLE:
case(coin)
2'b01: st_next = GET05;
2'b10: st_next = GET10;
default: st_next = IDLE;
endcase
GET05:
case(coin)
2'b01: st_next = GET10;
2'b10: st_next = GET15;
default: st_next = GET05;
endcase
GET10:
case(coin)
2'b01: st_next = GET15;
2'b10: st_next = IDLE;
default: st_next = GET10;
endcase
GET15:
case(coin)
2'b01,2'b10:
st_next = IDLE;
default: st_next = GET15;
endcase
default: st_next = IDLE;
endcase
end
reg [1:0] change_r;
reg sell_r;
always @(posedge clk or negedge rstn)begin
if(!rstn) begin
change_r <=2'b0;
sell_r <= 1'b0;
end
else if ((st_cur == GET15 && coin ==2'h1)
||(st_cur == GET10 && coin == 2'd2))begin
change_r <= 2'b1;
sell_r <= 1'b1;
end
else begin
change_r <= 2'b0;
sell_r <= 1'b0;
end
end
assign sell = sell_r;
assign change = change_r;
endmodule
状态机修改:2段式
2、3段合并
reg [1:0] change_r;
reg sell_r;
always @(*) begin
case(st_cur)
IDLE:begin
change_r = 2'b0;
sel_r = 1'b0;
case(coin)
2'b01: st_next = GET05;
2'b10: st_next = GET10;
default : st_next = IDLE;
endcase
end
GET05:begin
change_r = 2'b0;
sell_r = 1'b0;
case(coin)
2'b01: st_next = GET10;
2'b10: st_next = GET15;
default: st_next = GET05;
endcase
end
GET10:
case (coin)
2'b01: begin
st_next = GET15 ;
change_r = 2'b0 ;
sell_r = 1'b0 ;
end
2'b10: begin
st_next = IDLE ;
change_r = 2'b0 ;
sell_r = 1'b1 ;
end
default: begin
st_next = GET10 ;
change_r = 2'b0 ;
sell_r = 1'b0 ;
end
endcase // case (coin)
GET15:
case (coin)
2'b01: begin
st_next = IDLE ;
change_r = 2'b0 ;
sell_r = 1'b1 ;
end
2'b10: begin
st_next = IDLE ;
change_r = 2'b1 ;
sell_r = 1'b1 ;
end
default: begin
st_next = GET15 ;
change_r = 2'b0 ;
sell_r = 1'b0 ;
end
endcase
default: begin
st_next = IDLE ;
change_r = 2'b0 ;
sell_r = 1'b0 ;
end
endcase
end
1段式
reg [1:0] change_r ;
reg sell_r ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
st_cur <= 'b0 ;
change_r <= 2'b0 ;
sell_r <= 1'b0 ;
end
else begin
case(st_cur)
IDLE: begin
change_r <= 2'b0 ;
sell_r <= 1'b0 ;
case (coin)
2'b01: st_cur <= GET05 ;
2'b10: st_cur <= GET10 ;
endcase
end
GET05: begin
case (coin)
2'b01: st_cur <= GET10 ;
2'b10: st_cur <= GET15 ;
endcase
end
GET10:
case (coin)
2'b01: st_cur <= GET15 ;
2'b10: begin
st_cur <= IDLE ;
sell_r <= 1'b1 ;
end
endcase
GET15:
case (coin)
2'b01: begin
st_cur <= IDLE ;
sell_r <= 1'b1 ;
end
2'b10: begin
st_cur <= IDLE ;
change_r <= 2'b1 ;
sell_r <= 1'b1 ;
end
endcase
default: begin
st_cur <= IDLE ;
end
endcase // case (st_cur)
end // else: !if(!rstn)
end
状态机修改:Morre型
module vending_machine_moore(
input clk,
input rstn,
input [1:0] coin,
output [1:0] change,
output sell
);
parameter IDLE = 3'd0;
parameter GET05 = 3'd1;
parameter GET10 = 3'd2;
parameter GET15 = 3'd3;
parameter GET20 = 3'd4;
parameter GET25 = 3'd5;
reg [2:0] st_next;
reg [2:0] st_cur;
always @(posedge clk or negedge rstn)begin
if(!rstn) begin
st_cur<='b0;
end
else begin
st_cur <= st_next;
end
end
always @(*) begin //all case items need to be displayed completely
case(st_cur)
IDLE:
case (coin)
2'b01: st_next = GET05 ;
2'b10: st_next = GET10 ;
default: st_next = IDLE ;
endcase
GET05:
case (coin)
2'b01: st_next = GET10 ;
2'b10: st_next = GET15 ;
default: st_next = GET05 ;
endcase
GET10:
case (coin)
2'b01: st_next = GET15 ;
2'b10: st_next = GET20 ;
default: st_next = GET10 ;
endcase
GET15:
case (coin)
2'b01: st_next = GET20 ;
2'b10: st_next = GET25 ;
default: st_next = GET15 ;
endcase
GET20: st_next = IDLE ;
GET25: st_next = IDLE ;
default: st_next = IDLE ;
endcase // case (st_cur)
end // always @ (*)
reg [1:0] change_r;
reg sell_r;
always @(posedge clk or negedge rstn)begin
if(!rstn) begin
change_r <= 2'b0;
sell_r <= 1'b0;
end
else if(st_cur == GET20) begin
sell_r <= 1'b1;
end
else if(st_cur == GET25) begin
sell_r <= 1'b1;
change_r <=2'b1;
end
else begin
change_r <= 2'b0;
sell_r <= 1'b0;
end
end
assign sell = sell_r;
assign change = change_r;
endmodule
输出信号赋值时,用阻塞赋值,则可以提前1个周期
reg [1:0] change_r;
reg sell_r;
always @(*) begin
change_r = 'b0;
sell_r = 'b0;
if(st_cur==GET20)begin
sell_r = 1'b1;
end
else if(st_cur == GET25) begin
chage_r = 2'b1;
sell_r = 1'b1;
end
end