复杂状态机complex_fsm
实验目的
在之前的简易的可乐机的基础上实现一个功能更复杂也更合理的可乐机器。
将可乐定价为2.5元,可以投入1元与0.5元的硬币,小于2.5元不出可乐,大于2.5元实现找零。
实验框图、状态图
根据上述实验条件可以分析得到输入除了时钟和复位信号,还有输入的两种钱币信号,输出就是找零和可乐。
接下来分析状态图的情况:
输入有三种情况:0元,0.5元,1元,分别对应输入状态:00,01,10
输出有三种情况:不出可乐/不找零,出可乐/不找零,出可乐/找零,分别对应输出状态:00,10,11
而状态机的状态有:0,0.5,1,1.5,2,2.5,3,设置分别对应 IDLE、HALF…
米利/穆尔型时序电路
米利型时序电路的输出信号O是状态变量S和输入信号I二者的函数,即O=h(I,S),这种时序电路在时钟脉冲的两个触发沿之间,输出信号随时可能受到非时钟同步的输入信号作用而发生变化,从而影响电路输出的同步性。
穆尔型时序电路是米利型时序电路的一种特例,它的输出信号O仅仅是状态变量S的函数,即O=h(S),穆尔型时序电路的输出信号只取决于与时钟同步的各触发器的状态,在时钟脉冲触发沿的间隔期间,不受非同步的输入信号影响。
在现代高速时序电路设计中,一般尽量采用穆尔型时序电路结构,以利于后线高速电路的同步。在米利时序电路的输出端增加一级存储电路,构成“流水线输出“形式,是将其转化为穆尔电路的最简单的方法。需要注意的是,流水线存储电路将把输出号延迟一个时钟周期。虽然流水线输出电路增加了一些逻辑元件,但它的输出信号同步特性好,具有更好的稳定性和抗干扰性能。在大规模集成电路技术成熟的今天,节省逻辑元件的数量经常不再是逻辑电路设计者追求的唯一目标,电路工作的稳定性和可靠性,以及工作速度的提才是更重要的要求。
即在上图的第一个状态图中状态THREE和TWO_HALF的下一个状态和输入无关了,所以可以节约元器件省略。得到下面的米利型电路
波形图
图中的输入为随意设定
实验代码
module complex_fsm
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire pi_money_one ,
input wire pi_money_half ,
output reg po_cola ,
output reg po_money
);
/* parameter IDLE = 5'b00001;
parameter HALF = 5'b00010;
parameter ONE = 5'b00100;
parameter ONE_HALF = 5'b01000;
parameter TWO = 5'b10000; */
//参数设定另一种写法
parameter IDLE = 5'b00001,
HALF = 5'b00010,
ONE = 5'b00100,
ONE_HALF = 5'b01000,
TWO = 5'b10000;
reg [4:0] state;
/* //也可以增加这个中间量,方便后期调试更改数据
wire [1:0] pi_money;
assign pi_money={pi_money_one,pi_money_half};
*/
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
state<=IDLE;
else case(state)
IDLE : if(pi_money_half==1'b1)
state<=HALF;
else if(pi_money_one==1'b1)
state<=ONE;
else state<=IDLE;
HALF : if(pi_money_half==1'b1)
state<=ONE;
else if(pi_money_one==1'b1)
state<=ONE_HALF;
else state<=HALF;
ONE : if(pi_money_half==1'b1)
state<=ONE_HALF;
else if(pi_money_one==1'b1)
state<=TWO;
else state<=ONE;
ONE_HALF : if(pi_money_half==1'b1)
state<=TWO;
else if(pi_money_one==1'b1)
state<=IDLE;
else state<=ONE_HALF;
TWO : if(pi_money_half==1'b1)
state<=IDLE;
else if(pi_money_one==1'b1)
state<=IDLE;
else state<=TWO;
default : state<=IDLE;
endcase
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
po_cola<=1'b0;
else if((state==ONE_HALF)&&(pi_money_one==1'b1)||
(state==TWO)&&(pi_money_half==1'b1)||
(state==TWO)&&(pi_money_one==1'b1))
po_cola=1'b1;
else po_cola<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
po_money<=1'b0;
else if((state==TWO)&&(pi_money_one==1'b1))
po_money=1'b1;
else po_money<=1'b0;
endmodule
仿真代码
`timescale 1ns/1ns
module tb_complex_fsm();
reg sys_clk ;
reg sys_rst_n ;
reg pi_money_one ;
reg pi_money_half ;
wire po_cola ;
wire po_money ;
reg random_data;//随机数,两个输入不能同时取1,一个输入为随机数,另一个取反即可避免
initial
begin
sys_clk=1'b0;
sys_rst_n<=1'b0;
#20
sys_rst_n<=1'b1;
end
always #10 sys_clk=~sys_clk;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
random_data<=1'b0;
else random_data<={$random}%2;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
pi_money_half<=1'b0;
else pi_money_half<=random_data;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
pi_money_one<=1'b0;
else pi_money_one<=~random_data;
wire [4:0] state=complex_fsm_inst.state;
initial
begin
$timeformat(-9,0,"ns",6);
$monitor("@time %t:pi_money_half:%b,pi_money_one:%b,state:%b,po_cola:%b,po_money:%b",$time,pi_money_half,pi_money_one,state,po_cola,po_money);
end
complex_fsm complex_fsm_inst
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n ),
.pi_money_one (pi_money_one),
.pi_money_half (pi_money_half),
.po_cola (po_cola ),
.po_money (po_money )
);
endmodule
值得注意的是,在仿真中由于投入0.5元硬币和1元硬币不能同时投入即不能同时为1,实验中设置random_data进行限制。