为什么使用状态机?
因为vreilog并行执行的,当需要顺序执行时(类似c语言),可以使用状态机
状态机概念
状态机(State Machine)
有限状态机(Finite State Machine,简称FSM)
在有限个状态之间按一定规律转换的时序电路
由两个组合逻辑电路和一个时序逻辑电路组成
状态机模型(抽象的状态机结构)
状态寄存器
由一组触发器组成,用来记忆当前状态机所处的状态,
状态寄存器状态的改变只发生在时钟的跳变沿
Mealy状态机如上(Moore状态机较为不同)
状态是否改变、如何改变取决于组合逻辑F的输出, F又取决于输入信号和当前状态
状态机的输出是由组合逻辑G提供的, G也取决于输入信号和当前状态
状态机设计
方法——四段论
1.状态空间定义
2.状态跳转
3.下个状态判断
4.各个状态下的动作
1.状态空间定义
//denfine state space
parameter SLEEP = 2'b00;
parameter STUDY = 2'b01;
parameter EAT = 2'b10;
parameter AMUSE = 2'b11;
//internal variable
reg [1:0] current_state;//bits match top parameter
reg [1:0] next_state;
/
独热码写法(每个状态对应一个寄存器),状态机推荐
//denfine state space
parameter SLEEP = 2'b1000 ;
parameter STUDY = 2'b0100 ;
parameter EAT = 2'b0010 ;
parameter AMUSE = 2'b0001 ;
//internal variable
reg [3:0] current_state;//bits match top parameter
reg [3:0] next_state;
2.状态跳转(时序逻辑–状态寄存器)
//transition
always @ (posedge clk or negedge rst_n) begin
if (!rst_n)
current_state <= SLEEP ; //give starter
else
current_state <= next_state ;
end
3.下个状态判断(产哼下一状态的组合逻辑)
always @ (current_state or input_singnals) begin //senstive list are high and low voltage
case (current_state)
SLEEP: begin
if (clock_alarm)
next_state = STUDY ;
else
next_state = SLEEP ;
end
STUDY: begin
if (lunch_time)
next_state = EAT ;
else
next_state = STUDY ;
end
EAT: ... ;
AMUSE: ... ;
default: ... ;
//if与else配对,case要有default ,是为了避免产生锁存器(latch) ——电平触发,只在组合逻辑中产生
// 触发器 ——边沿触发
endcase
end
4.各个状态下的动作(产生输出的组合逻辑)
//action
第一种写法,状态较为简单时
wire read_book;
assign read_book = (current_state == STUDY ? 1'b1 : 1'b0)
第二种写法,状态较为复杂时
always @ (current_state) begin
if(curent_book == STUDY)
read_book = 1;
else
read_book = 0;
end
由上述步骤所组合称为三段式状态机
一个三段式状态机例子(分频器)
moudle divider7_fsm (
//input ports
input sys_clk ,
input sys_rst_n ,
//output ports
output reg clk_divide_7
);
//reg define
reg [6:0] curr_st ;
reg [6:0] next_st ;
//wire define
//parameter define
parameter WIDTH = 1;
//one hot code design
parameter S0 = 7'b0000000;
parameter S1 = 7'b0000001;
parameter S2 = 7'b0000010;
parameter S3 = 7'b0000100;
parameter S4 = 7'b0001000;
parameter S5 = 7'b0010000;
parameter S6 = 7'b0100000;
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
curr_st <= 7'b0;
else
curr_st <= next_st;
end
//FSM state logic
always @ (*) begin
case (curr_st)
S0: begin
next_st = S1;
end
S1: begin
next_st = S2;
end
S2: begin
next_st = S3;
end
S3: begin
next_st = S4;
end
S4: begin
next_st = S5;
end
S5: begin
next_st = S6;
end
S6: begin
next_st = S0;
end
default: next_st = S0;
endcase
end
//control divide clock offset
always @ (posedeg sys_clk or negedge sys_rst_n) begin
if(sys_rst_n = 1'b0) begin
clk_divide_7 <= 1'b0;
end else if ((curr_st == S0) | curr_st == S1) | curr_st == S2) | curr_st == S3)) begin
clk_divide_7 <= 1'b0;
end else if ((curr_st == S4) | curr_st == S5) | curr_st == S6)) begin
clk_divide_7 <= 1'b1;
end else ;
end
三段式可以在组合逻辑后再增加一级寄存器来实现时序逻辑输出;
1.可以有效地过滤去组合逻辑输出的毛刺(锁存器等);
2.可以有效地进行时序计算与约束;
3.另外对于总线形式的输出信号(8_bits)来说,容易使总线数据对齐,从而减少总线数据间的偏移,
所以就减少了接收端数据采样出错的频率。