FPGA学习篇之状态机
前言
相信学过数电的同学一定不会对状态机陌生,状态机的英文名称为Finite State Machine,通常简写为FSM。FPGA擅长做并行计算,当然芯片中少不了一些需要串行执行的控制过程,这时就需要用状态机来实现。在数字电路中状态机的应用十分广泛,状态机本质上是输入与输出之间的函数关系,我们生活中的绝大多数问题都可以用状态机来描述。
一、状态机的分类
状态机可以分为Moore型状态机和Mealy型状态机,Moore型状态机的输出只与当前状态机所处的状态有关,与当前输入无关。 Mealy型状态机的输出不仅与当前状态机所处的状态有关,也与当前输入有关。由于Mealy型状态机的输出与输入有关,输出信号中很容易出现毛刺,所以在日常设计中一般采用Moore型状态机。
二、状态机的写法
FSM有多种描述风格,常用的有一段式描述、二段式描述和三段式描述。每种描述都有各自的优缺点和应用场合。
- 一段式状态机是把状态译码、状态寄存、状态输出都放在一个always块中,这种描述方式是代码编写简单,缺点是对代码的修改和维护比较困难。
......//省略状态编码
always @ (posedge or negedeg rst_n)
if(!rst_n) begin
state <= state0;
out <= 1'b0;
end
else begin
case(state)
state0: begin
if(in1) begin
state <= state1;
out1 <= 1'b1;
end
else begin
state <= state0;
out1 <= 1'b0;
eng
end
state1: begin
if(in2) begin
state <= state2;
out2 <= 1'b1;
end
else begin
state <= state1;
out2 <= 1'b0;
eng
end
....
default: ....
endcase
end
- 二段式状态机是把状态译码、状态输出都放在一个always块中(通常用组合逻辑描述),状态寄存放在另外一个always块中(通常用时序逻辑描述)。
......//省略状态编码
// 组合逻辑状态跳转
always @ (*) begin
case(state)
state0: begin
if(in1) begin
next_state = state1;
out1 = 1'b1;
end
else begin
next_state = state0;
out1 = 1'b0;
eng
end
state1: begin
if(in2) begin
next_state = state2;
out2 = 1'b1;
end
else begin
next_state = state1;
out2 = 1'b0;
end
end
....
default: ....
endcase
end
// 时序逻辑状态寄存
always @ (posedge or negedeg rst_n)
if(!rst_n)
state <= state0;
else
state <= next_state;
- 三段式状态机是把状态译码、状态输出和状态缓存分别放在三个always块中,相对于二段式状态机层次逻辑更清晰,同时便于修改和维护。
......//省略状态编码
// 组合逻辑状态跳转
always @ (*) begin
case(state)
state0: begin
if(in1)
next_state = state1;
else
next_state = state0;
end
state1: begin
if(in2)
next_state = state2;
else
next_state = state1;
end
....
default: ....
endcase
end
// 时序逻辑状态寄存
always @ (posedge or negedeg rst_n)
if(!rst_n)
state <= state0;
else
state <= next_state;
// 组合逻辑输出结果
always @ (*) begin
case(state)
state0: out0 = 1'b1;
state1: out1 = 1'b1;
state2: out2 = 1'b1;
....
default:...
endcase
end
三、总结
介绍了状态机的分类以及常见的状态机代码,在代码编写中应尽量采用三段式状态机,便于后期修改和维护。同时在状态编码时应注意,根据状态机状态数目采用独热码或格雷码编码,在逻辑资源占用和最高运行速度上会有些许区别。