应用场景:编写一个自动售货机,功能如下:
共有三种纸币入口,分别支持10元,20元,50元。货物售价为80元。需要支持找钱功能。
分析:状态转换图如下所示,使用三段式状态机将如下状态图描述出来
代码如下:
//三段式moore状态机(输出只与当前状态有关)
module aotu_vending(
input clk,
input rst_n,
input Ten,
input Twnty,
input Fifty,
output Ok,
output Ten_back,
output Twnty_back,
output Thirty_back,
output Fourty_back
);
//用格雷编码表示转态
localparam IDLE = 4'b0000,
S_10 = 4'b0001,
S_20 = 4'b0011,
S_30 = 4'b0010,
S_40 = 4'b0110,
S_50 = 4'b0111,
S_60 = 4'b0101,
S_70 = 4'b0100,
S_80 = 4'b1100,
S_90 = 4'b1101,
S_100 = 4'b1111,
S_110 = 4'b1110,
S_120 = 4'b1010;
reg [3:0] current_state,next_state;
always@(posedge clk,negedge rst_n)begin
if(!rst_n)
current_state <= IDLE;
else
current_state <= next_state;
end
always@(*)begin
case(current_state)
IDLE :begin
if(Ten) next_state<=S_10;
else if(Twnty) next_state<=S_20;
else if(Fifty) next_state<=S_50;
else next_state<=IDLE;
end
S_10 :begin
if(Ten) next_state<=S_20;
else if(Twnty) next_state<=S_30;
else if(Fifty) next_state<=S_60;
else next_state<=S_10;
end
S_20 :begin
if(Ten) next_state<=S_30;
else if(Twnty) next_state<=S_40;
else if(Fifty) next_state<=S_70;
else next_state<=S_20;
end
S_30 :begin
if(Ten) next_state<=S_40;
else if(Twnty) next_state<=S_50;
else if(Fifty) next_state<=S_80;
else next_state<=S_30;
end
S_40 :begin
if(Ten) next_state<=S_50;
else if(Twnty) next_state<=S_60;
else if(Fifty) next_state<=S_90;
else next_state<=S_40;
end
S_50 :begin
if(Ten) next_state<=S_60;
else if(Twnty) next_state<=S_70;
else if(Fifty) next_state<=S_100;
else next_state<=S_50;
end
S_60 :begin
if(Ten) next_state<=S_70;
else if(Twnty) next_state<=S_80;
else if(Fifty) next_state<=S_110;
else next_state<=S_60;
end
S_70 :begin
if(Ten) next_state<=S_80;
else if(Twnty) next_state<=S_90;
else if(Fifty) next_state<=S_120;
else next_state<=S_70;
end
S_80 : next_state<=IDLE;
S_90 : next_state<=IDLE;
S_100: next_state<=IDLE;
S_110: next_state<=IDLE;
S_120: next_state<=IDLE;
default: next_state<=IDLE;
endcase
end
assign Ok = (current_state[3]==1'b1)?1'b1:1'b0;
assign Ten_back = (current_state==S_90) ?1'b1:1'b0;
assign Twnty_back = (current_state==S_100) ?1'b1:1'b0;
assign Thirty_back = (current_state==S_110) ?1'b1:1'b0;
assign Fourty_back = (current_state==S_120) ?1'b1:1'b0;
endmodule
产生随机测试向量,测试电路
`timescale 1ns/1ns
//============================================================
module aotu_vending_tb;
parameter cycle_time=10;
integer i;
reg clk,rst_n,Ten,Twnty,Fifty;
wire Ok,Ten_back,Twnty_back,Thirty_back,Fourty_back;
reg [2:0]random_in;
reg [3:0]in_time;
always #(cycle_time/2) clk=~clk;
initial begin
clk=0;
rst_n=0;
random_in=3'b001;
#(2*cycle_time);
rst_n=1;
end
initial begin
Ten=0;
Twnty=0;
Fifty=0;
#(4*cycle_time);
repeat(30)begin
in_time = 2+{$random}%3; //产生2到4的随机整数min+{$random}%(max-min+1)
for(i=0;i
//(使用 index one-hot + reverse case + synopsys FSM 语法)
module aotu_vending1(
input clk,
input rst_n,
input Ten,
input Twnty,
input Fifty,
output reg Ok,
output reg Ten_back,
output reg Twnty_back,
output reg Thirty_back,
output reg Fourty_back
);
localparam [3:0] // synopsys enum code
IDLE = 4'd0,
S_10 = 4'd1,
S_20 = 4'd2,
S_30 = 4'd3,
S_40 = 4'd4,
S_50 = 4'd5,
S_60 = 4'd6,
S_70 = 4'd7,
S_80 = 4'd8,
S_90 = 4'd9,
S_100 = 4'd10,
S_110 = 4'd11,
S_120 = 4'd12,
ERROR = 4'd13;
// synopsys state_vector state
reg [13:0] // synopsys enum code
current_state,next_state;
always@(posedge clk,negedge rst_n)begin
if(!rst_n)
current_state <= 14'd0;
current_state[IDLE] <= 1'b1;
else
current_state <= next_state;
end
always@(*)begin
next_state = 14'd0;
case(1'b1) // synopsys full_case parallel_case
current_state[IDLE] :begin
if(Ten) next_state[S_10]<=1'b1;
else if(Twnty) next_state[S_20]<=1'b1;
else if(Fifty) next_state[S_50]<=1'b1;
else next_state[IDLE]<=1'b1;
end
current_state[S_10] :begin
if(Ten) next_state[S_20]<=1'b1;
else if(Twnty) next_state[S_30]<=1'b1;
else if(Fifty) next_state[S_60]<=1'b1;
else next_state[S_10]<=1'b1;
end
current_state[S_20] :begin
if(Ten) next_state[S_30]<=1'b1;
else if(Twnty) next_state[S_40]<=1'b1;
else if(Fifty) next_state[S_70]<=1'b1;
else next_state[S_20]<=1'b1;
end
current_state[S_30] :begin
if(Ten) next_state[S_40]<=1'b1;
else if(Twnty) next_state[S_50]<=1'b1;
else if(Fifty) next_state[S_80]<=1'b1;
else next_state[S_30]<=1'b1;
end
current_state[S_40] :begin
if(Ten) next_state[S_50]<=1'b1;
else if(Twnty) next_state[S_60]<=1'b1;
else if(Fifty) next_state[S_90]<=1'b1;
else next_state[S_40]<=1'b1;
end
current_state[S_50] :begin
if(Ten) next_state[S_60]<=1'b1;
else if(Twnty) next_state[S_70]<=1'b1;
else if(Fifty) next_state[S_100]<=1'b1;
else next_state[S_50]<=1'b1;
end
current_state[S_60] :begin
if(Ten) next_state[S_70]<=1'b1;
else if(Twnty) next_state[S_80]<=1'b1;
else if(Fifty) next_state[S_110]<=1'b1;
else next_state[S_60]<=1'b1;
end
current_state[S_70] :begin
if(Ten) next_state[S_80]<=1'b1;
else if(Twnty) next_state[S_90]<=1'b1;
else if(Fifty) next_state[S_120]<=1'b1;
else next_state[S_70]<=1'b1;
end
current_state[S_80] : next_state[IDLE]<=1'b1;
current_state[S_90] : next_state[IDLE]<=1'b1;
current_state[S_100]: next_state[IDLE]<=1'b1;
current_state[S_110]: next_state[IDLE]<=1'b1;
current_state[S_120]: next_state[IDLE]<=1'b1;
current_state[ERROR]: next_state[IDLE]<=1'b1;
endcase
end
always@(posedge clk,negedge rst_n)begin
if(!rst_n)begin
Ok<=1'b0;
Ten_back<=1'b0;
Twnty_back<=1'b0;
Thirty_back<=1'b0;
Fourty_back<=1'b0;
end
else begin
case(1'b1)
next_state[S_80]: begin OK<=1'b1;end
next_state[S_90]: begin OK<=1'b1;Ten_back<=1'b1;end
next_state[S_100]:begin OK<=1'b1;Twnty_back<=1'b1;end
next_state[S_110]:begin OK<=1'b1;Thirty_back<=1'b1;end
next_state[S_120]:begin OK<=1'b1;Fourty_back<=1'b1;end
default:begin
Ok<=1'b0;
Ten_back<=1'b0;
Twnty_back<=1'b0;
Thirty_back<=1'b0;
Fourty_back<=1'b0;
end
endcase
end
end
endmodule