[X]关闭

24 FPGA知识_认识FPGA中的状态机

文档创建者:FPGA课程
浏览次数:322
最后更新:2024-08-15
FPGA基础知识
FPGA基础: FPGA编程语言 » Verilog编程入门
软件版本:无

操作系统:WIN10 64bit

硬件平台:适用所有系列FPGA

板卡获取平台:https://milianke.tmall.com/

登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!

1概述
让FPGA电路,有序执行任务,我们需要状态机电路。所有的时序电路都是随着时间的流逝发生各种状态,在FPGA中,基于时序编写状态机,可以完成几乎所有的逻辑控制任务。状态机就是用来管理电路的逻辑状态。如果你学习过C语言,你可能主要用switch case进行条件判断,但是学习了FPGA的状态机后,你可以考虑下改进下你的C语言设计,利用C语言的switch case来实现状态机,对于很多基于时间的逻辑类控制,状态机是非常好的管理方案,适合于一切的编程。

状态机的描述通常有三种方:一段式状态机、二段式状态机、三段式状态机,当然你可以写出四段式,五段式,但是一般来说,常用的不超过三段式。如果选用是一段、二段还是三段根据实际情况,一般原则,很简单的状态机一段式搞定,稍微复杂的用二段式,很复杂的用三段式。大部分情况我们都是面对的简单的状态机。

2一段式状态机
  1. module detect_1(
  2.     input clk_i,
  3.     input rst_n_i,
  4.     output out_o
  5.     );

  6. reg out_r;
  7. //状态声明和状态编码
  8. reg [1:0] state;
  9. parameter [1:0] S0=2'b00;
  10. parameter [1:0] S1=2'b01;
  11. parameter [1:0] S2=2'b10;
  12. parameter [1:0] S3=2'b11;

  13. always@(posedge clk_i)
  14. begin
  15.     if(!rst_n_i)begin
  16.         state<=0;
  17.        out_r<=1'b0;
  18.     end
  19.     else
  20.         case(state)
  21.             S0 :
  22.             begin
  23.                out_r<=1'b0;
  24.                state<= S1;
  25.             end
  26.             S1 :
  27.             begin
  28.                 out_r<=1'b1;
  29.                 state<= S2;
  30.             end
  31.             S2 :
  32.             begin
  33.                  out_r<=1'b0;
  34.                  state<= S3;
  35.             end
  36.             S3 :
  37.             begin
  38.                  out_r<=1'b1;
  39.             end
  40.         endcase
  41. end
  42. assign out_o=out_r;
  43. endmodule
复制代码

通常来说一段式状态机是不推荐使用的,但是实际情况是对于简单的代码没必要严格去比较采用一段式或者二段式状态机,而且一段式的状态机,写起来比较顺手,所以规模不大的简单状态机放心用吧。
image.jpg



3两段式状态机
  1. module detect_2(
  2.      input clk_i,
  3.      input rst_n_i,
  4.      output out_o
  5. );
  6.     reg out_r;
  7.     //状态声明和状态编码
  8.     reg [1:0] Current_state;
  9.     reg [1:0] Next_state;
  10.     parameter [1:0] S0=2'b00;
  11.     parameter [1:0] S1=2'b01;
  12.     parameter [1:0] S2=2'b10;
  13.     parameter [1:0] S3=2'b11;
  14.    
  15.     //时序逻辑:描述状态转换
  16.     always@(posedge clk_i)
  17.     begin
  18.         if(!rst_n_i)
  19.            Current_state<=0;
  20.         else
  21.             Current_state<=Next_state;
  22.     end
  23.    
  24.     //组合逻辑:描述下一状态和输出
  25.     always@(*)
  26.     begin
  27.         case(Current_state)
  28.             S0 :
  29.                 begin
  30.                  out_r=1'b0;
  31.                  Next_state= S1;
  32.                 end
  33.             S1 :
  34.                 begin
  35.                  out_r=1'b1;
  36.                  Next_state= S2;
  37.                 end
  38.             S2 :
  39.                 begin
  40.                  out_r=1'b0;
  41.                  Next_state= S3;
  42.                 end
  43.             S3 :
  44.                  begin
  45.                  out_r=1'b1;
  46.                  Next_state=Next_state;
  47.                  end
  48.             endcase
  49.     end
  50.     assign out_o=out_r;   
  51. endmodule
复制代码


两段式状态机采用两个always模块实现状态机的功能,其中一个always采用同步时序逻辑描述状态转移,另一个always采用组合逻辑来判断状态条件转移。虽然对于简单的代码我们没必要去比较一段式好还是两段式好,但是如果推荐肯定还是使用两段式的状态机,不过很多时候笔者也偷懒,使用一段式的状态机。但是如果对于时序要求和状态机机有一定的规模的电路,还是用两段式的吧。

代码翻译的电路原理图:
image.jpg

总之两段式状态机是推荐的状态机设计方法。

4三段式状态机
  1. module detect_3(
  2.         input clk_i,
  3.         input rst_n_i,
  4.         output out_o
  5.         );
  6.     reg out_r;
  7.     //状态声明和状态编码
  8.     reg [1:0] Current_state;
  9.     reg [1:0] Next_state;
  10.     parameter [1:0] S0=2'b00;
  11.     parameter [1:0] S1=2'b01;
  12.     parameter [1:0] S2=2'b10;
  13.     parameter [1:0] S3=2'b11;
  14.    
  15.     //时序逻辑:描述状态转换
  16.     always@(posedge clk_i)
  17.     begin
  18.         if(!rst_n_i)
  19.             Current_state<=0;
  20.         else
  21.             Current_state<=Next_state;
  22.     end
  23.    
  24.     //组合逻辑:描述下一状态
  25.     always@(*)
  26.     begin
  27.         case(Current_state)
  28.             S0:
  29.                 Next_state = S1;
  30.             S1:
  31.                 Next_state = S2;
  32.             S2:
  33.                 Next_state = S3;
  34.             S3:
  35.                 Next_state = Next_state;
  36.          default :
  37.             Next_state = S0;
  38.           endcase
  39.     end
  40.     //输出逻辑:让输出out,经过寄存器out_r锁存后输出,消除毛刺
  41.     always@(*)
  42.     begin
  43.         case(Current_state)
  44.                S0,S2:
  45.                    out_r<=1'b0;
  46.                S1,S3:
  47.                    out_r<=1'b1;
  48.            default :
  49.               out_r<=out_r;
  50.             endcase
  51.     end    assign out_o=out_r;
复制代码


三段式状态机在第一个always模块采用同步时序逻辑方式描述状态转移,第二个always模块采用组合逻辑方式描述状态转移规律,第三个always描述电路的输出。通常让输出信号经过寄存器缓存之后再输出,消除电路毛刺。这种状态机也是比较推崇的,主要是由于维护方便,组合逻辑与时序逻辑完全独立。

代码翻译的电路原理图:
image.jpg


5总结
通过对比三种状态机的写法,可以发现,三段式的状态机翻译出来的原理图是最简洁最高效的编写方式,两段式也是很简洁的,但是比三段式差了一点点,而一段式是最差的表现。所以推荐是使用两段式以上的状态机。


image.jpg
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则