要求:简化考虑,假设饮料只有一种价格为2.5元。硬币有0.5元和1.0元两种,考虑找零。
Design Spec:
- 输入信号:clk、rst
- 输入信号:操作开始:op_start; //定义为1时开始执行操作,只影响初始状态,对后续状态没有影响。
- 输入信号:投币币值:coin_val; //2‘b01时为0.5元,2‘b10时为1元。
- 输入信号:取消操作:cancel_flag; //定义为1时取消操作。
- 输出信号:机器是否占用:hold_in; //定义0为不占用,1为占用。
- 输出信号:取饮料信号:drinktk_ind; //定义1为取走
- 输出信号:找零退币信号:charge_val; //定义3‘b001为0.5元,3‘b010为1元,3’b011为1.5元,3‘b100为2元,3’b101为2.5元,3‘b110为3元。
状态转移图:
Verilog 代码:
RTL:
module AutoDrinkFSM(
input clk,
input rst,
input op_start,
input [1:0] coin_val,
input cancel_flag,
output hold_in,
output reg drinktk_ind,
output reg [2:0] charge_val
);
reg [2:0] state, next_state;
parameter S0 = 3'b000, S1 = 3'b001;
parameter S2 = 3'b010, S3 = 3'b011;
parameter S4 = 3'b100, S5 = 3'b101;
parameter S6 = 3'b110;
always@(posedge clk) begin
if(rst) begin
state <= S0;
end
else begin
state <= next_state;
end
end
always@(*) begin
case(state)
S0: begin
if(op_start) begin
if(coin_val == 2'b01) begin
next_state = S1;
end
else if(coin_val == 2'b10) begin
next_state = S2;
end
else next_state = S0;
end
else begin
next_state = S0;
end
end
S1: begin
if(cancel_flag) begin
next_state = S0;
end
else begin
if(coin_val == 2'b01) begin
next_state = S2;
end
else if(coin_val == 2'b10) begin
next_state = S3;
end
else next_state = S1;
end
end
S2: begin
if(cancel_flag) begin
next_state = S0;
end
else begin
if(coin_val == 2'b01) begin
next_state = S3;
end
else if(coin_val == 2'b10) begin
next_state = S4;
end
else next_state = S2;
end
end
S3: begin
if(cancel_flag) begin
next_state = S0;
end
else begin
if(coin_val == 2'b01) begin
next_state = S4;
end
else if(coin_val == 2'b10) begin
next_state = S5;
end
else next_state = S3;
end
end
S4: begin
if(cancel_flag) begin
next_state = S0;
end
else begin
if(coin_val == 2'b01) begin
next_state = S5;
end
else if(coin_val == 2'b10) begin
next_state = S6;
end
else next_state = S4;
end
end
S5: next_state = S0;
S6: next_state = S0;
endcase
end
assign hold_in = (state == S0)?1'b0:1'b1;
always@(*) begin
if(state == S5 || state == S6) begin
if(cancel_flag) begin
drinktk_ind = 1'b0;
end
else begin
drinktk_ind = 1'b1;
end
end
else begin
drinktk_ind = 1'b0;
end
end
always@(*) begin
if(cancel_flag) begin
case(state)
S1: charge_val = S1;
S2: charge_val = S2;
S3: charge_val = S3;
S4: charge_val = S4;
S5: charge_val = S5;
S6: charge_val = S6;
default: charge_val = S0;
endcase
end
else begin
charge_val = S0;
end
end
endmodule
TB:
module AutoDrinkFSM_tb;
reg clk;
reg rst;
reg op_start;
reg [1:0] coin_val;
reg cancel_flag;
wire hold_in;
wire drinktk_ind;
wire reg [2:0] charge_val;
AutoDrinkFSM u_AutoDrinkFSM(
.clk(clk),
.rst(rst),
.op_start(op_start),
.coin_val(coin_val),
.cancel_flag(cancel_flag),
.hold_in(hold_in),
.drinktk_ind(drinktk_ind),
.charge_val(charge_val)
);
initial begin
clk = 0;
rst = 1;
op_start = 0;
coin_val = 2'b01;
cancel_flag = 0;
#30 rst = 0;
end
always #10 clk = ~clk;
always@(posedge clk) begin
if(({$random()}%3)<1) begin
op_start = 1'b1;
end
else begin
op_start = 1'b0;
end
if(({$random()}%4)<1) begin
coin_val = 2'b01;
end
else if(({$random()}%4)<1) begin
coin_val = 2'b10;
end
else begin
coin_val = 2'b00;
end
if(({$random()}%10)<1) begin
cancel_flag = 1;
end
else begin
cancel_flag = 0;
end
end
initial begin
#20000 $finish;
end
endmodule
波形: