详细介绍FPGA状态机的设计和应用

时间:2025-04-28  作者:Diven  阅读:0

FPGA的特点是并行执行,但如果需要处理一些具有前后顺序的事件,就需要使用状态机。状态机是用于处理具有前后顺序的事件的计算机模型,包含现态、条件、动作和次态四个要素,可以将一个复杂的控制流程分解成多个互相独立的状态,从而简化设计过程并提高了系统的可靠性和性能。本文将对FPGA状态机进行详细介绍,帮助大家了解状态机的设计和应用。

详细介绍FPGA状态机的设计和应用

一、FPGA状态机基础

1、基础概念

FPGA状态机是能够描述对象在运行周期内的所有状态,以及从一个状态到另一个状态转换的过程的抽象模型。状态机可归纳为4个要素,即现态、条件、动作、次态。

①现态:当前所处的状态。

②条件:当一个条件被满足,将会触发一个动作,或者执行一次运行状态的变化。

③动作:条件满足后执行的动作。动作不是必需的,也可以直接迁移到新状态而不进行任何动作。

④次态:条件满足后要跳转到的新状态。其中,“次态”是相对于“现态”而言的,一旦被跳转后,“次态”就转变成新的“现态”了。

2、状态机分类

通常情况下,FPGA状态机一般有两种类型: 

  • Moore型状态机:下一状态只由当前状态决定 。
  • Mealy 型状态机:下一状态不但与当前状态有关,还与当前输入值有关 。

由于Mealy型状态机的输出与输入有关,输出信号很容易出现毛刺,所以一般采用Moore型状态机。

(1)Mealy状态机

输出逻辑不但取决于当前“状态”还取决于“输入”,如图所示。

(2)Moore状态机

输出逻辑仅仅取决于当前状态,且与当前时刻的输入无关,如图所示。

二、FPGA状态机实现方式

FPGA状态机的描述方式主要分为3种,分别是一段式、两段式、三段式。

1、一段式状态机

一段式状态机使用1个always块,把状态跳转和寄存器输出逻辑都写在一起,其输出是寄存器输出,无毛刺,但是这种方式代码较混乱,逻辑不清晰,难于修改和调试,应该尽量避免使用。

下面给出一个一段式的Mealy状态机示例:

Module one_state_machine (
input clk,
input rst_n,
input [1:0] inp,
output reg outp
);
// 定义状态
localparam STATE_0 = 0,
STATE_1 = 1,
STATE_2 = 2,
STATE_3 = 3;
// 定义状态寄存器和初始状态
reg [1:0] state_r;
// 初始化状态寄存器
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
state_r<= STATE_0;
end else begin
case (state_reg)
STATE_0: begin
if (inp == 2'b00) begin
state_r <= STATE_0;
outp <= 0;
end else if (inp == 2'b01) begin
state_r <= STATE_1;
outp <= 1;
end else if (inp == 2'b10) begin
state_r <= STATE_2;
outp <= 0;
end else begin
state_r <= STATE_3;
outp <= 1;
end
end
STATE_1: begin
if (inp == 2'b00) begin
state_r <= STATE_1;
outp <= 1;
end else if (inp == 2'b01) begin
state_r <= STATE_2;
outp <= 0;
end else if (inp == 2'b10) begin
state_r <= STATE_3;
outp <= 1;
end else begin
state_r <= STATE_0;
outp <= 0;
end
end
STATE_2: begin
if (inp == 2'b00) begin
state_r <= STATE_2;
outp <= 0;
end else if (inp == 2'b01) begin
state_r <= STATE_3;
outp <= 1;
end else if (inp == 2'b10) begin
state_r <= STATE_0;
outp <= 0;
end else begin
state_r <= STATE_1;
outp <= 1;
end
end
STATE_3: begin
if (inp == 2'b00) begin
state_r <= STATE_3;
outp <= 1;
end else if (inp == 2'b01) begin
state_r <= STATE_0;
outp <= 0;
end else if (inp == 2'b10) begin
state_r <= STATE_1;
outp <= 1;
end else begin
state_reg <= STATE_2;
outp <= 0;
end
end
endcase
end
end
endModule

2、二段式状态机

二段式状态机使用2个always块,都是时序逻辑,其中一个always块用于写状态机的状态跳转逻辑,另一个always块用于写当前状态下的寄存器输出逻辑。这种方式逻辑代码清晰,易于调试和理解,是比较推荐的一个方式。

下面给出一个二段式的Moore状态机示例:

module state_machine (
input clk,
input rst_n,
output reg out_reg
);
// 状态寄存器和下一个状态寄存器
reg [1:0] state_r;
// 状态定义
parameter IDLE = 2'b00;
parameter STATE1 = 2'b01;
parameter STATE2 = 2'b10;
parameter STATE3 = 2'b11;
// always @(posedge clk or negedge rst_n) 时序逻辑代码块,实现状态跳转逻辑
always@(posedge clk or negedge rst_n) begin
if(~rst_n) begin
state_r <= IDLE;
end else begin
case(state_r)
IDLE: begin
state_r <= STATE1;
end
STATE1: begin
state_r <= STATE2;
end
STATE2: begin
state_r <= STATE3;
end
STATE3: begin
state_r <= IDLE;
end
endcase
end
end
// always @(*) 时序逻辑代码块,实现状态输出逻辑
always@(posedge clk or negedge rst_n) begin
if(~rst_n) begin
out_reg <= 1'b0;
end else begin
case(state_r)
IDLE: begin
out_reg <= 1'b0;
end
STATE1: begin
out_reg <= 1'b1;
end
STATE2: begin
out_reg <= 1'b1;
end
STATE3: begin
out_reg <= 1'b0;
end
endcase
end
end
endmodule

3、三段式状态机

三段式状态机使用3个always块,其中一个组合always块用于写状态机的状态跳转逻辑,一个时序always块用于缓存状态寄存器,另一个always块用于写当前状态下的寄存器输出逻辑。这种方式逻辑代码清晰,易于调试和理解,也是比较推荐的一个方式。

module state_machine (
input clk,
input rst_n,
input [1:0] inp,
output reg outp
);
// 定义状态
localparam STATE_0 = 0,
STATE_1 = 1,
STATE_2 = 2,
STATE_3 = 3;
// 定义状态寄存器和初始状态
reg [1:0] state_r, next_state ;
// 定义状态寄存器
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
state_r <= STATE_0;
end else begin
state_r <= next_state;
end
end
// 定义状态转移逻辑
always @(*) begin
case (state_r)
STATE_0: begin
if (inp == 2'b00) begin
next_state = STATE_0;
end else if (inp == 2'b01) begin
next_state = STATE_1;
end else if (inp == 2'b10) begin
next_state = STATE_2;
end else begin
next_state = STATE_3;
end
end
STATE_1: begin
if (inp == 2'b00) begin
next_state = STATE_1;
end else if (inp == 2'b01) begin
next_state = STATE_2;
end else if (inp == 2'b10) begin
next_state = STATE_3;
end else begin
next_state = STATE_0;
end
end
STATE_2: begin
if (inp == 2'b00) begin
next_state = STATE_2;
end else if (inp == 2'b01) begin
next_state = STATE_3;
end else if (inp == 2'b10) begin
next_state = STATE_0;
end else begin
next_state = STATE_1;
end
end
STATE_3: begin
if (inp == 2'b00) begin
next_state = STATE_3;
end else if (inp == 2'b01) begin
next_state = STATE_0;
end else if (inp == 2'b10) begin
next_state = STATE_1;
end else begin
next_state = STATE_2;
end
end
endcase
end
// 定义输出逻辑
always @(*) begin
case (state_r)
STATE_0: outp = 0;
STATE_1: outp = 1;
STATE_2: outp = 0;
STATE_3: outp = 1;
endcase
end
endmodule

注意:组合逻辑代码中,if语句和case语句必须写满,否则容易形成latch,导致实际运行出问题。

三、状态机的编码方式

1、独热码

独热码(One-hot)是状态编码方式,其特点是对于任意给定的状态,状态寄存器中只有1位为1,其余位都为0。使用独热码可以简化译码逻辑电路,因为状态机只需对寄存器中的一位进行译码,同时可用省下的面积抵消额外触发器占用的面积。相比于其类型的有限状态机,加入更多的状态时,独热码的译码逻辑并不会变得更加复杂,速度仅取决于到某特定状态的转移数量。

独热码还具有诸如设计简单、修改灵活、易于综合和调试等优点。但值得注意的是,相对于二进制码,独热码速度更快但占用面积较大。

module state_machine(
input clk,
output reg [3:0] state_out
);
localparam STATE_A = 4'b0001;
localparam STATE_B = 4'b0010;
localparam STATE_C = 4'b0100;
localparam STATE_D = 4'b1000;
reg [3:0] current_state, next_state;
always @(posedge clk) begin
current_state <= next_state; // 当时钟上升沿到来时更新状态
end
always @(*) begin
case (current_state)
STATE_A: next_state = STATE_B;
STATE_B: next_state = STATE_C;
STATE_C: next_state = STATE_D;
STATE_D: next_state = STATE_A;
default: next_state = STATE_A; // 默认情况下返回初始状态
endcase
end
assign state_out = current_state; // 将当前状态作为输出
endmodule

2、格雷码

格雷码是相邻的两个码组之间仅有一位不同的编码方式。在格雷码中,相邻的两个码组之间仅有一位不同,这种编码方式可以用于实现相邻的两个状态之间只有一位不同的状态机;

FPGA 中的状态机通常需要高速运行,因此使用格雷码可以减少状态转换的开销,并提高时序性能。

module gray_code_state_machine(
input clk,
output reg [3:0] state_out
);
localparam G0 = 4'b0000;
localparam G1 = 4'b0001;
localparam G2 = 4'b0011;
localparam G3 = 4'b0010;
reg [3:0] current_state, next_state;
always @(posedge clk) begin
current_state <= next_state; // 当时钟上升沿到来时更新状态
end
always @(*) begin
case (current_state)
G0: next_state = G1;
G1: next_state = G3;
G2: next_state = G0;
G3: next_state = G2;
default: next_state = G0; // 默认情况下返回初始状态
endcase
end
assign state_out = current_state; // 将当前状态作为输出
endmodule

3、普通二进制码

FPGA状态机可以用普通二进制码表示,不同状态按照二进制数累加表示,是常用的方式,仿真调试时,状态显示清晰,易于理解代码。

module binary_state_machine(
input clk,
output reg [1:0] state_out
);
localparam STATE_A = 2'b00;
localparam STATE_B = 2'b01;
localparam STATE_C = 2'b10;
reg [1:0] current_state, next_state;
always @(posedge clk) begin
current_state <= next_state; // 当时钟上升沿到来时更新状态
end
always @(*) begin
case (current_state)
STATE_A: next_state = STATE_B;
STATE_B: next_state = STATE_C;
STATE_C: next_state = STATE_A;
default: next_state = STATE_A; // 默认情况下返回初始状态
endcase
end
assign state_out = current_state; // 将当前状态作为输出
endmodule

4、格雷码与普通二进制码互转

  • 二进制码:一个n位的二进制码可以表示2^n种状态,有2^(n-1)个相邻状态之间只有一个位不同。
  • 格雷码:一个n位的格雷码可以表示2^n种状态,有2^(n-1)个相邻状态之间只有一位变化。

(1)二进制码转换成格雷码

假设当前的状态用二进制码表示为B,那么所对应的格雷码G可以按照以下方式计算得出:

G = B xor (B >> 1)

其中,">>"表示右移操作,"xor"表示异或操作。具体来说,我们先将B右移一位,再与原来的B进行异或运算,就可以得到对应的格雷码G。

(2)格雷码转换成二进制码

假设当前的状态用格雷码表示为G,那么所对应的二进制码B可以按照以下方式计算得出:

B = G xor (G >> 1)

与二进制码转换成格雷码的方法类似,我们先将G右移一位,再与原来的G进行异或运算,就可以得到对应的二进制码B。

个,下面给出“4位格雷码与4位二进制码转换”的示例代码:

module bin2gray (
input [3:0] bin,
output reg [3:0] gray
);
always @* begin
gray[0] = bin[0];
gray[1] = bin[1] ^ bin[0];
gray[2] = bin[2] ^ bin[1];
gray[3] = bin[3] ^ bin[2];
end
endmodule

注意用来转换格雷码时,如果输入的格雷码不是有效的格雷码,输出的结果将会是无意义的。

四、

以上了FPGA状态机中有关的知识点,大家可以参考下,建议状态机的写法一般用二段式或三段式,代码逻辑清晰,易于理解和调试,同时需要注意always@(*)块中的组合逻辑,使用if和case语句都要写满,否则综合后容易形成latch,导致上板与仿真结果不一致。

猜您喜欢

LED 照明因其节能环保的特点,近年来在家庭和商业场所都得到了应用。然而,与任何电子设备一样,LED 灯及其电源驱动器也可能出现故障。LED 电源驱动器负责将交...
2024-06-22 00:00:00

取样器和采样器在许多领域中被使用,但功能和应用存在一定的区别。取样器通常指的是设备或工具,用于从特定的环境或物质中提取样本,常见于实验室或工业检测中。取样器的设...
2025-08-22 00:00:00

在高度发展的现代工业中,现代测试技术向数字化、信息化方向发展已成必然发展趋势,而测试系统的最前端是传感器,它是整个测试系统的灵魂,被世界各国列为尖端技术,特别是...
2023-10-19 08:07:00

电子电路中,二极管是一个非常重要的元件,主要功能是允许电流在一个方向上流动,而阻止在相反方向上流动。在某些情况下,二极管的工作状态可能会受到影响,导致出现“死区...
2025-04-01 06:31:07

高频/RF继电器是专为高频信号传输设计的电气开关设备。能够在高频率范围内(通常为几十兆赫兹到几千兆赫兹)稳定地开关电路,应用于无线通信、射频识别(RFID)、卫...
2016-05-18 00:00:00

安规测试仪是用于检测电气设备安全性的专业仪器。通过模拟设备在实际使用中的各种工作状态,评估其是否符合相关安全标准和法规。主要功能包括电绝缘测试、接地测试、漏电流...
2014-07-10 00:00:00

近日,珠海芯森电子科技有限公司在第十三届中国创新创业大赛(广东·珠海赛区)暨2024年珠海市“科创杯”创新创业大赛中荣获优胜奖。此次大赛汇聚了众多创新企业,经过...
2024-12-04 08:13:00

扫描仪作为重要的办公设备,应用于多个领域。在教育行业,扫描仪帮助教师和学生将纸质资料数字化,方便资料的存储与分享,提高学习效率。在医疗领域,扫描仪用于将病历、检...
2015-07-22 00:00:00

对于FPGA调试,主要以Intel FPGA为例,在win10 Quartus ii 17.0环境下进行仿真和调试,开发板类型EP4CE15F17。主要包括一下...
2020-03-29 11:37:00

接触调压器是电力系统中重要的设备,主要用于调节电压,以确保电力的稳定供应。不同类型的接触调压器在结构和功能上存在一些显著的区别。机械调压器与电子调压器在工作原理...
2009-08-23 00:00:00