• 牛客刷题<21>三段式状态机


    题目:根据状态转移表实现时序电路_牛客题霸_牛客网

    FSM有限状态机序列检测,涉及到:;

    (1)摩尔型与米利型状态机;

    (2)一段式、两段式、三段式状态机;

    (3)状态编码(二进制、格雷码、独热码);

    摩尔型和米利型状态机

    摩尔型:输出只与当前状态有关;

    米利型:输出不仅与当前状态有关,还与当前输入有关

    1. // one step 第一段
    2. always@(posedge clk or negedge rst_n)begin
    3. if(!rst_n) 时序逻辑
    4. curr_state <=2'b00;
    5. else 次态赋给现态
    6. curr_state <= next_state; cs <= ns
    7. end
    1. //two step
    2. always@(*)begin 第二段
    3. case(curr_state)
    4. 2'b00: next_state = A?2'b11:2'b01; 组合逻辑
    5. 2'b01: next_state = A?2'b00:2'b10;
    6. 2'b10: next_state = A?2'b01:2'b11; 现态和输入决定次态
    7. 2'b11: next_state = A?2'b10:2'b00;
    8. default : next_state = 2'b00;
    9. endcase case(cs)
    10. end ....
    11. endcase

    三段式寄存器输出,不产生毛刺,有利于时序约束

    (1)一段式:一个always块,既描述状态转移,又描述状态的输入输出当前状态用寄存器输出

    (2)二段式:两个always块,时序逻辑与组合逻辑分开,一个always块采用同步时序描述状态转移另一个always块采用组合逻辑判断状态转移条件,描述状态转移规律以及输出,当前状态用组合逻辑输出,可能出现竞争冒险产生毛刺,而且不利于约束,不利于综合器和布局布线器实现高性能的设计;

    (当然,第二个always里的状态跳转和输出可以拆分用组合逻辑描述,也可能有三个always块,但是这并不是三段式,和三段式的区别在于输出到底是组合逻辑还是时序逻辑)

    (3)三段式:三个always块,一个always模块采用同步时序描述状态转移;一个always采用组合逻辑判断状态转移条件,描述状态转移规律;第三个always块使用同步时序描述状态输出,寄存器输出

    三段式与二段式相比,关键在于根据状态转移规律,在上一状态根据输入条件判断出当前状态的输出,从而在不插入额外时钟节拍的前提下,实现了寄存器输出。

    二进制码Binary Code和格雷码Gray Code占用的位宽少,相应的使用的触发器资源少,但是状态对比时需要比较多个bit,消耗的组合逻辑比较多,适用于组合电路资源丰富的情况(CPLD);

    独热码One-Hot Code的状态比较时只比较1 bit,节省逻辑资源,使用的触发器资源比较多,适用于触发器资源丰富的情况(FPGA);

    总体来讲,状态较少时(4-24个状态)用独热码效果好,状态多时格雷码(状态数大于24)效果好。

    对四个状态编码:

    二进制码:

    S0 = 2’b00;

    S1 = 2’b01;

    S2 = 2’b10;

    S3 = 2’b11;

    格雷码相邻码元之间有且只有一位不同:

    S0 = 2’b00;

    S1 = 2’b01;

    S2 = 2’b11;

    S3 = 2’b10;

    独热码只有一位是“1”:

    S0 = 4’b0001;

    S1 = 4’b0010;

    S2 = 4’b0100;

    S3 = 4’b1000;

    有时候也是用连续编码,状态值连续:

    S0 = 2’d0;

    S1 = 2’d1;

    S2 = 2’d2;

    S3 = 2’d3;

    解法一

    1. `timescale 1ns/1ns
    2. module seq_circuit(
    3. input A,
    4. input clk,
    5. input rst_n,
    6. output wire Y
    7. );
    8. reg [1:0] curr_state;
    9. reg [1:0] next_state;
    10. // one step
    11. always@(posedge clk or negedge rst_n)begin
    12. if(!rst_n)
    13. curr_state <=2'b00;
    14. else
    15. curr_state <= next_state;
    16. end
    17. //two step
    18. always@(*)begin
    19. case(curr_state)
    20. 2'b00: next_state = A?2'b11:2'b01;
    21. 2'b01: next_state = A?2'b00:2'b10;
    22. 2'b10: next_state = A?2'b01:2'b11;
    23. 2'b11: next_state = A?2'b10:2'b00;
    24. endcase
    25. end
    26. assign Y = (curr_state==2'b11)?1:0;
    27. endmodule

    解法二

    基础的时序电路设计,可采用列激励方程、输出方程,进而用D触发器和组合逻辑电路实现的方案。

    由状态表可得出,电路共4个状态,所以使用2个寄存器来实现状态的寄存。两个寄存器的输出为Q1和Q0。

    由状态转换表可列出激励方程如下:

    1. `timescale 1ns/1ns
    2. module seq_circuit(
    3. input A ,
    4. input clk ,
    5. input rst_n,
    6. output wire Y
    7. );
    8. reg Q1 ;
    9. reg Q0 ;
    10. always @(posedge clk or negedge rst_n)begin
    11. if(!rst_n)
    12. Q1 <= 1'b0;
    13. else
    14. Q1 <= Q1 ^ Q0 ^A;
    15. end
    16. always @(posedge clk or negedge rst_n)begin
    17. if(!rst_n)
    18. Q0 <= 1'b0;
    19. else
    20. Q0 <= ~Q0;
    21. end
    22. assign Y = Q1 & Q0;
    23. endmodule

     解法三:三段式状态机

    1. `timescale 1ns/1ns
    2. module seq_circuit(
    3. input A,
    4. input clk,
    5. input rst_n,
    6. output wire Y
    7. );
    8. localparam ZERO = 2'b00;
    9. localparam ONE = 2'b01;
    10. localparam TWO = 2'b10;
    11. localparam THREE = 2'b11;
    12. reg Y_temp;
    13. assign Y = Y_temp;
    14. reg [1:0] curr_state;
    15. reg [1:0] next_state;
    16. //状态转移
    17. always@(posedge clk or negedge rst_n)begin
    18. if(!rst_n)
    19. curr_state <= ZERO;
    20. else
    21. curr_state <= next_state;
    22. end
    23. //状态判断逻辑
    24. always@(*)begin
    25. case(curr_state)
    26. ZERO : next_state = A ? THREE : ONE;
    27. ONE : next_state = A ? ZERO : TWO;
    28. TWO : next_state = A ? ONE : THREE;
    29. THREE : next_state = A ? TWO : ZERO;
    30. default: next_state = ONE;
    31. endcase
    32. end
    33. //输出
    34. always@(posedge clk or negedge rst_n)begin
    35. if(!rst_n)
    36. Y_temp <= 1'b0;
    37. else begin
    38. case(next_state)
    39. ZERO : Y_temp <= 1'b0;
    40. ONE : Y_temp <= 1'b0;
    41. TWO : Y_temp <= 1'b0;
    42. THREE : Y_temp <= 1'b1;
    43. endcase
    44. end
    45. end
    46. endmodule

    解法四:容易理解 都是curr_state 没有next_state

    1. `timescale 1ns/1ns
    2. module seq_circuit(
    3. input A,
    4. input clk,
    5. input rst_n,
    6. output wire Y
    7. );
    8. reg [1:0] curr_state;
    9. parameter IDLE = 2'b00;
    10. parameter ONE = 2'b01;
    11. parameter TWO = 2'b10;
    12. parameter THREE = 2'b11;
    13. always@(posedge clk or negedge rst_n)begin
    14. if(!rst_n)
    15. curr_state <= IDLE;
    16. else
    17. case(curr_state)
    18. IDLE:
    19. if(A== 1'b0)
    20. curr_state <= ONE;
    21. else if(A == 1'b1)
    22. curr_state <= THREE;
    23. else
    24. curr_state <= curr_state;
    25. ONE:
    26. if(A== 1'b0)
    27. curr_state <= TWO;
    28. else if(A == 1'b1)
    29. curr_state <= IDLE;
    30. else
    31. curr_state <= curr_state;
    32. TWO:
    33. if(A== 1'b0)
    34. curr_state <= THREE;
    35. else if(A == 1'b1)
    36. curr_state <= ONE;
    37. else
    38. curr_state <= curr_state;
    39. THREE:
    40. if(A== 1'b0)
    41. curr_state <= IDLE;
    42. else if(A == 1'b1)
    43. curr_state <= TWO;
    44. else
    45. curr_state <= curr_state;
    46. endcase
    47. end
    48. assign Y = (curr_state==THREE) ? 1 : 0;
    49. endmodule

    解法五:不太容易想到

    1. `timescale 1ns/1ns
    2. module seq_circuit(
    3. input A,
    4. input clk,
    5. input rst_n,
    6. output wire Y
    7. );
    8. reg [1:0] q = 2'b00;
    9. always@(posedge clk or negedge rst_n)begin
    10. if(!rst_n)begin
    11. q <= 2'b00;
    12. end
    13. else begin
    14. q <= A ? (q-1'b1):(q+1'b1);
    15. end
    16. end
    17. assign Y = q[0] & q[1];
    18. endmodule

  • 相关阅读:
    mysql中函数
    简易线程池实现
    【命令式编程和声明式编程】
    js将后端返回的blob请求下载
    8.10模拟赛总结
    【微信测试号实战——02】编写你独有的微信消息模板
    初识-软件测试
    mongo中的or查询如何使用
    Java中常见包装类型Integer、BigDecimal等特点说明
    CCF CSP认证 历年题目自练Day24
  • 原文地址:https://blog.csdn.net/mxh3600/article/details/126586804