二段式FPGA的状态机

数字系统有两大类有限状态机(Finite State Machine,FSM):Moore状态机和Mealy状态机。

Moore状态机

  其最大特点是输出只由当前状态确定,与输入无关。Moore状态机的状态图中的每一个状态都包含一个输出信号。这是一个典型的Moore状态机的状态跳转图,x、y、z是输入,a、b、c是输出。

    

Mealy状态机

  它的输出不仅与当前状态有关系,而且与它的输入也有关系,因而在状态图中每条转移边需要包含输入和输出的信息。

 

状态编码

  数字逻辑系统状态机设计中常见的编码方式有:二进制码(Binary码)、格雷码(Gray码)、独热码(One-hot码)以及二一十进制码(BCD码)。

  格雷码的特点:相邻的两个码组之间仅有一位不同。

普通二进制码与格雷码之间可以相互转换。

  二进制码转换为格雷码:从最右边一位起,一次与左边一位“异或”,作为对应格雷码该位的值,最左边的一位不变(相当于最左边是0)。

  格雷码转换为二进制码:从左边第二位起,将每一位与左边一位解码后的值“异或”,作为该解码后的值(最左边的一位依然不变)。

  独热码又分为独热1码和独热0码,是一种特殊的二进制编码方式。当任何一种状态有且仅有一个1时,就是独热1码,相反任何一种状态有且仅有一个0时,就是独热0码。

状态机的描述

  状态机有三种描述方式:一段式状态机、两段式状态机、三段式状态机。下面就用一个小例子来看看三种方式是如何实现的。

  (各种图片,各种坑爹啊 - -!)

 

一段式状态机

  当把整个状态机卸载一个always模块中,并且这个模块既包含状态转移,又含有组合逻辑输入/输出时,称为一段式状态机。不推荐采用这种状态机,因为从代码风格方面来讲,一般都会要求把组合逻辑和时序逻辑分开;从代码维护和升级来说,组合逻辑和书序逻辑混合在一起不利于代码维护和修改,也不利于约束。

     

复制代码
 1 //一段式状态机来实现:在异步复位信号的控制下,一段式状态机进入IDLE
2 //状态,q_sig4被复位,一旦sig1或者sig2有效,状态机进入WAIT状态,如果
3 //sig1和sig2同时有效,那么状态机进入DONE状态,
4 //如果sig4还有效,那么q_sig4置位,同时状态机进入IDLE状态。
5
6 module one_seg_fsm(clk,reset,sig1,sig2,sig3,q_sig4,q_sm_state);
7 //数据声明部分
8 input clk,reset,sig1,sig2,sig3;
9
10 output reg q_sig4;
11 output reg [1:0] q_sm_state;
12
13 //参数声明
14 parameter IDLE = 2'b00;
15 parameter WAIT = 2'b01;
16 parameter DONE = 2'b10;
17
18 //状态跳转逻辑程序设计
19 always @(posedge clk or posedge reset)
20 begin
21 if(reset)
22 begin
23 q_sig4 <= 0;
24 q_sm_state <= IDLE;
25 end
26 else
27 begin
28 case(q_sm_state)
29 IDLE: begin
30 if(sig1 || sig2)
31 begin
32 q_sm_state <= WAIT;
33 q_sig4 <= 1'b0;
34 end
35 else
36 begin
37 q_sm_state <= IDLE;
38 q_sig4 <= 1'b0;
39 end
40 end
41 WAIT: begin
42 if(sig2 && sig3)
43 begin
44 q_sm_state <= DONE;
45 q_sig4 <= 1'b0;
46 end
47 else
48 begin
49 q_sm_state <= WAIT;
50 q_sig4 <= 1'b0;
51 end
52 end
53
54 DONE:begin
55 if(sig3)
56 begin
57 q_sm_state <= IDLE;
58 q_sig4 <= 1'b1;
59 end
60 else
61 begin
62 q_sm_state <= DONE;
63 q_sig4 <= 1'b0;
64 end
65 end
66
67 default: begin
68 q_sm_state <= IDLE;
69 q_sig4 <= 0;
70 end
71 endcase
72 end
73 end
74 endmodule
复制代码

   

两段式状态机

  所谓的两段式状态机就是采用一个always语句来实现时序逻辑,另外一个always语句来实现组合逻辑,提高了代码的可读性,易于维护。不同于一段式状态机的是,它需要定义两个状态----现态和次态,然后通过现态和次态的转换来实现时序逻辑。

   

复制代码
 1 //本例主要采用两段式状态机:在异步复位信号的控制下,一段式状态机进入IDLE
2 //状态,q_sig4被复位,一旦sig1或者sig2有效,状态机进入WAIT状态,如果sig1和sig2同时有效,那么
3 //状态机进入DONE状态,如果sig4还有效,那么q_sig4置位,同时状态机进入IDLE状态。
4
5 module two_seg_fsm(clk,reset,sig1,sig2,sig3,q_sig4);
6 //数据声明部分
7 input clk,reset,sig1,sig2,sig3;
8
9 output reg q_sig4;
10
11 reg [1:0] current_state, next_state;
12
13 //参数声明
14 parameter IDLE = 2'b00;
15 parameter WAIT = 2'b01;
16 parameter DONE = 2'b10;
17
18 //状态跳转程序设计
19 always @(posedge clk or posedge reset)
20 if(reset)
21 current_state <= IDLE;
22 else
23 current_state <= next_state;
24
25 //状态逻辑输出
26 always @(current_state or sig1 or sig2 or sig3)
27 begin
28 case(current_state)
29 IDLE: begin
30 if(sig1 || sig2)
31 begin
32 next_state = WAIT;
33 q_sig4 = 1'b0;
34 end
35 else
36 begin
37 next_state = IDLE;
38 q_sig4 = 1'b0;
39 end
40 end
41 WAIT: begin
42 if(sig2 && sig3)
43 begin
44 next_state = DONE;
45 q_sig4 = 1'b0;
46 end
47 else
48 begin
49 next_state = WAIT;
50 q_sig4 = 1'b0;
51 end
52 end
53
54 DONE:begin
55 if(sig3)
56 begin
57 next_state = IDLE;
58 q_sig4 = 1'b1;
59 end
60 else
61 begin
62 next_state = DONE;
63 q_sig4 = 1'b0;
64 end
65 end
66
67 default: begin
68 next_state = IDLE;
69 q_sig4 = 0;
70 end
71 endcase
72
73 end
74 endmodule
复制代码

     

三段式状态机

  三段式状态机与两段式状态机的区别:两段式直接采用组合逻辑输出,而三段式则通过在组合逻辑后再增加一级寄存器来实现时序逻辑输出。这样做的好处是可以有效地滤去租个逻辑输出的毛刺,同时可以有效地进行时序计算与约束,另外对于总线形式的输出信号来说,容易使总线数据对其,从而减小总线数据间的偏移,减小接收端数据采样出错的频率。

  三段式状态机的基本格式是:第一个always语句实现同步状态跳转;第二个always语句实现组合逻辑;第三个always语句实现同步输出。

    

复制代码
 1 //本例主要采用三段式状态机:在异步复位信号的控制下,一段式状态机进入IDLE
2 //状态,q_sig4被复位,一旦sig1或者sig2有效,状态机进入WAIT状态,如果sig1和sig2同时有效,那么
3 //状态机进入DONE状态,如果sig4还有效,那么q_sig4置位,同时状态机进入IDLE状态。
4
5 module three_seg_fsm(clk,reset,sig1,sig2,sig3,q_sig4);
6 //数据声明部分
7 input clk,reset,sig1,sig2,sig3;
8
9 output reg q_sig4;
10
11 reg [1:0] current_state, next_state;
12
13 //参数声明
14 parameter IDLE = 2'b00;
15 parameter WAIT = 2'b01;
16 parameter DONE = 2'b10;
17
18 //状态跳转程序设计
19 always @(posedge clk or posedge reset)
20 if(reset)
21 current_state <= IDLE;
22 else
23 current_state <= next_state;
24
25 //状态跳转输出
26 always @(current_state or sig1 or sig2 or sig3)
27 begin
28 case(current_state)
29 IDLE: begin
30 if(sig1 || sig2)
31 begin
32 next_state = WAIT;
33 end
34 else
35 begin
36 next_state = IDLE;
37 end
38 end
39 WAIT: begin
40 if(sig2 && sig3)
41 begin
42 next_state = DONE;
43 end
44 else
45 begin
46 next_state = WAIT;
47 end
48 end
49
50 DONE:begin
51 if(sig3)
52 begin
53 next_state = IDLE;
54 end
55 else
56 begin
57 next_state = DONE;
58 end
59 end
60
61 default: begin
62 next_state = IDLE;
63 end
64 endcase
65 end
66
67 //逻辑输出
68 always @(posedge clk or posedge reset)
69 if(reset)
70 q_sig4 <= 1'b0;
71 else
72 begin
73 case(next_state)
74 IDLE,
75 WAIT: q_sig4 <= 1'b0;
76 DONE: q_sig4 <= 1'b1;
77 default: q_sig4 <= 1'b0;
78 endcase
79 end
80
81 endmodule
复制代码

      

<think>嗯,用户想了解FPGA三段式状态机的设计与实现,我得先理清楚三段式状态机的基本概念和结构。根据引用里的内容,三段式状态机分为三个always块:时序逻辑处理状态转移,组合逻辑计算次态,第三个时序或组合逻辑处理输出。需要区分Moore和Mealy型,引用中提到Moore型的输出仅依赖当前状态,而Mealy还依赖输入。用户可能需要知道为什么用三段式而不是两段式,比如避免组合逻辑输出导致的毛刺,或者结构更清晰。引用4和5提到三段式的结构,其中第三个always块用时序逻辑,这样输出更稳定。同时要注意状态编码,比如独热码或二进制,引用5提到了参数化状态定义。还要注意设计中的常见问题,比如状态转移条件命名规范,避免锁存器,引用4提到转移条件用xx2xx_start的形式,这样代码更易读。另外,在组合逻辑中,如果没有覆盖所有情况会产生锁存器,所以default情况很重要。可能用户的实际应用场景是什么?比如通信协议处理、控制流程等,引用1和2提到状态机在数字系统中的重要性,应用广泛。需要给出一个实例,比如UART接收的状态,分空闲、起始位、数据位、停止位等状态,这样用户更容易理解。另外,性能优化方面,比如状态编码方式的选择,独热码适合FPGA因为触发器多,组合逻辑简单。引用3提到状态机的三个要素:状态、输入、输出,设计时要明确这些。总结下来,回答的结构应该先介绍三段式的组成,每部分的作用,然后比较Moore和Mealy的区别,给出设计步骤和实例,最后注意事项和常见问题。这样用户能逐步理解如何设计和实现三段式状态机,并应用到实际项目中。</think>### FPGA三段式状态机设计与实现详解 #### 一、三段式状态机基本结构 三段式状态机通过分离**状态转移**、**次态计算**和**输出逻辑**,实现代码清晰且易于维护的设计。其核心结构如下: 1. **时序逻辑块**:管理当前状态寄存器的更新,仅在时钟边沿触发 ```verilog always @(posedge clk or negedge rst_n) begin if (!rst_n) current_state <= IDLE; else current_state <= next_state; end ``` 2. **组合逻辑块**:根据当前状态和输入条件计算次态 ```verilog always @(*) begin case (current_state) IDLE: next_state = (start_signal) ? STATE1 : IDLE; STATE1: next_state = (condition_met) ? STATE2 : STATE1; default: next_state = IDLE; endcase end ``` 3. **输出逻辑块**(建议用时序逻辑):根据当前状态生成输出 ```verilog always @(posedge clk) begin if (current_state == STATE2) output <= 1'b1; else output <= 1'b0; end ``` #### 二、Moore型与Mealy型对比 | 类型 | 输出依赖 | 代码实现差异 | 应用场景 | |---------|--------------------|---------------------------|-------------------| | Moore型 | 仅当前状态 | 输出逻辑与输入无关 | 稳定输出控制[^3] | | Mealy型 | 当前状态+输入信号 | 输出逻辑需包含输入条件判断 | 响应式系统[^2] | #### 三、设计步骤与实例(以UART接收为例) 1. **状态定义** ```verilog parameter IDLE = 3'b001, START_BIT = 3'b010, DATA_BITS = 3'b100; ``` 2. **状态转移逻辑** ```verilog always @(*) begin case (current_state) IDLE: next_state = (rx_start) ? START_BIT : IDLE; START_BIT: next_state = (sample_done) ? DATA_BITS : START_BIT; DATA_BITS: next_state = (bit_cnt == 8) ? IDLE : DATA_BITS; endcase end ``` 3. **输出控制** ```verilog always @(posedge clk) begin if (current_state == DATA_BITS) shift_reg <= {sample_data, shift_reg[7:1]}; end ``` #### 四、关键设计要点 1. **状态编码优化** - 独热码(One-Hot):占用更多触发器但简化组合逻辑,适合FPGA架构[^5] - 二进制编码:资源利用率高,但状态切换延迟较大 2. **避免锁存器** 组合逻辑中必须覆盖所有分支,例如: ```verilog always @(*) begin case (current_state) // 必须包含default分支 endcase end ``` 3. **时序约束** 通过添加时序例外(false path)约束状态机路径,提升时序收敛性。 #### 五、典型应用场景 1. 通信协议解析(SPI/I2C/UART) 2. 数据流控制(FIFO状态管理) 3. 复杂控制流程(工业自动化时序控制)[^1]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值