HDLBits 系列(38)值得一看的状态机设计题目

举报
李锐博恩 发表于 2021/07/15 02:32:05 2021/07/15
【摘要】 目录 背景 原题复现 我的方案 状态转移图 我的设计 更新方案 FPGA/IC群推荐   背景 这是这个系列中的一个状态机的题目,但是相比于给了你完整状态转移图之类的题目,这个题目还是稍微有点难的,我实在不知道该怎么给这个博客起个什么名字? 我在线等一个简单的方式去解决今天的问题,而如题所说,我用最无能的方式来解决这个问题,但简单的方式一定...

目录

背景

原题复现

我的方案

状态转移图

我的设计

更新方案

FPGA/IC群推荐


 


背景

这是这个系列中的一个状态机的题目,但是相比于给了你完整状态转移图之类的题目,这个题目还是稍微有点难的,我实在不知道该怎么给这个博客起个什么名字?

我在线等一个简单的方式去解决今天的问题,而如题所说,我用最无能的方式来解决这个问题,但简单的方式一定存在。

2019/12/16更新

今天一个帅兄弟给了我一个答案,很巧妙,这里十分感谢。我把它放到后面来给出。

原题复现

原题复现:

Consider a finite state machine with inputs s and w. Assume that the FSM begins in a reset state called A, as depicted below. The FSM remains in state A as long as s = 0, and it moves to state B when s = 1. Once in state B the FSM examines the value of the input w in the next three clock cycles. If w = 1 in exactly two of these clock cycles, then the FSM has to set an output z to 1 in the following clock cycle. Otherwise z has to be 0. The FSM continues checking w for the next three clock cycles, and so on. The timing diagram below illustrates the required values of z for different values of w.

Use as few states as possible. Note that the s input is used only in state A, so you need to consider just the w input.

我的方案

状态转移图

我的解决方案,有点无奈,多加了一些状态:

我的设计

根据此状态转移图给出我的设计:


  
  1. module top_module (
  2. input clk,
  3. input reset, // Synchronous reset
  4. input s,
  5. input w,
  6. output z
  7. );
  8. localparam A = 0, B = 1, S0 = 3, S1 = 4, S2 = 5, S3 = 6, S4 = 7, S5 = 8, S6 = 9, S7 = 10, S8 = 11, S9 = 12, S10 = 13, S11 = 14;
  9. reg [3:0] state, next_state;
  10. always@(*) begin
  11. case(state)
  12. A: begin
  13. if(s) next_state = B;
  14. else next_state = A;
  15. end
  16. B: begin
  17. if(w) next_state = S1;
  18. else next_state = S0;
  19. end
  20. S0: begin
  21. if(w) next_state = S2;
  22. else next_state = S4;
  23. end
  24. S1: begin
  25. if(w) next_state = S9;
  26. else next_state = S6;
  27. end
  28. S2: begin
  29. if(w) next_state = S3;
  30. else next_state = S5;
  31. end
  32. S3: begin
  33. if(w) next_state = S1;
  34. else next_state = S0;
  35. end
  36. S4: begin
  37. next_state = S5;
  38. end
  39. S5: begin
  40. if(w) next_state = S1;
  41. else next_state = S0;
  42. end
  43. S6: begin
  44. if(w) next_state = S7;
  45. else next_state = S8;
  46. end
  47. S7: begin
  48. if(w) next_state = S1;
  49. else next_state = S0;
  50. end
  51. S8: begin
  52. if(w) next_state = S1;
  53. else next_state = S0;
  54. end
  55. S9: begin
  56. if(w) next_state = S11;
  57. else next_state = S10;
  58. end
  59. S10: begin
  60. if(w) next_state = S1;
  61. else next_state = S0;
  62. end
  63. S11: begin
  64. if(w) next_state = S1;
  65. else next_state = S0;
  66. end
  67. default: begin
  68. next_state = A;
  69. end
  70. endcase
  71. end
  72. always@(posedge clk) begin
  73. if(reset) state <= 0;
  74. else state <= next_state;
  75. end
  76. assign z = (state == S10 || state == S7 || state == S3) ? 1 : 0;
  77. endmodule

测试成功。


更新方案

今天群里的大佬给了一种简单的方法,状态转移图确实简单了,但是理解起来呢?

我之前用的方案是在B之后的三个周期内,列举w的值,取值情况有8种,然后添加更多的状态去解决这个问题,不得不说状态转移图看起来复杂很多,也绝对不是推荐的方案。

我等待的确实是今天的这个方案,通过计数,不需要添加更多的状态,这也是我一开始就想用的方法,只是计数的时序当时没有搞定,今天很感谢,群里的一位兄弟。

直接给出设计,通过代码就应该能看出来设计的思路:


  
  1. module top_module (
  2. input clk,
  3. input reset, // Synchronous reset
  4. input s,
  5. input w,
  6. output z
  7. );
  8. parameter A = 1'b0, B = 1'b1;
  9. reg current_state;
  10. reg next_state;
  11. always@(posedge clk)begin
  12. if(reset)begin
  13. current_state <= A;
  14. end
  15. else begin
  16. current_state <= next_state;
  17. end
  18. end
  19. always@(*)begin
  20. case(current_state)
  21. A:begin
  22. next_state = s ? B : A;
  23. end
  24. B:begin
  25. next_state = B;
  26. end
  27. endcase
  28. end
  29. reg w_reg1;
  30. reg w_reg2;
  31. always@(posedge clk)begin
  32. if(reset)begin
  33. w_reg1 <= 1'b0;
  34. w_reg2 <= 1'b0;
  35. end
  36. else if(next_state == B)begin
  37. w_reg1 <= w;
  38. w_reg2 <= w_reg1;
  39. end
  40. else begin
  41. w_reg1 <= 1'b0;
  42. w_reg2 <= 1'b0;
  43. end
  44. end
  45. always@(posedge clk)begin
  46. if(reset)begin
  47. z <= 1'b0;
  48. end
  49. else if(next_state == B && counter == 2'd0)begin
  50. if(~w & w_reg1 & w_reg2 | w & ~w_reg1 & w_reg2 | w & w_reg1 & ~w_reg2)begin
  51. z <= 1'b1;
  52. end
  53. else begin
  54. z <= 1'b0;
  55. end
  56. end
  57. else begin
  58. z <= 1'b0;
  59. end
  60. end
  61. reg [1:0] counter;
  62. always@(posedge clk)begin
  63. if(reset)begin
  64. counter <= 2'd0;
  65. end
  66. else if(counter == 2'd2)begin
  67. counter <= 2'd0;
  68. end
  69. else if(next_state == B)begin
  70. counter <= counter + 1'b1;
  71. end
  72. end
  73. endmodule

巧妙之处在于将输入w延迟两拍之后进行判断,如果有两个w为1,则在下一个周期将输出z置位.

有的朋友,也许在状态机的设计中,习惯将第三段使用组合逻辑来实现,这个题目的第三段也可以使用组合逻辑,但是呢?确实也没有必要,因为状态机的第三段本身既可以使用组合逻辑,也可以使用时序逻辑,如果使用时序逻辑。

下面给出组合逻辑的方案:


  
  1. module top_module (
  2. input clk,
  3. input reset, // Synchronous reset
  4. input s,
  5. input w,
  6. output reg z
  7. );
  8. parameter A = 1'b0, B = 1'b1;
  9. reg current_state;
  10. reg next_state;
  11. always@(posedge clk)begin
  12. if(reset)begin
  13. current_state <= A;
  14. end
  15. else begin
  16. current_state <= next_state;
  17. end
  18. end
  19. always@(*)begin
  20. case(current_state)
  21. A:begin
  22. next_state = s ? B : A;
  23. end
  24. B:begin
  25. next_state = B;
  26. end
  27. endcase
  28. end
  29. reg w_reg1;
  30. reg w_reg2;
  31. always@(posedge clk)begin
  32. if(reset)begin
  33. w_reg1 <= 1'b0;
  34. w_reg2 <= 1'b0;
  35. end
  36. else if(next_state == B)begin
  37. w_reg1 <= w;
  38. w_reg2 <= w_reg1;
  39. end
  40. else begin
  41. w_reg1 <= 1'b0;
  42. w_reg2 <= 1'b0;
  43. end
  44. end
  45. reg z_mid;
  46. always@(*)begin
  47. if(reset)begin
  48. z_mid <= 1'b0;
  49. end
  50. else if(current_state == B && counter == 2'd0)begin
  51. if(~w & w_reg1 & w_reg2 | w & ~w_reg1 & w_reg2 | w & w_reg1 & ~w_reg2)begin
  52. z_mid <= 1'b1;
  53. end
  54. else begin
  55. z_mid <= 1'b0;
  56. end
  57. end
  58. else begin
  59. z_mid <= 1'b0;
  60. end
  61. end
  62. always@(posedge clk)begin
  63. if(reset)begin
  64. z <= 1'b0;
  65. end
  66. else begin
  67. z <= z_mid;
  68. end
  69. end
  70. reg [1:0] counter;
  71. always@(posedge clk)begin
  72. if(reset)begin
  73. counter <= 2'd0;
  74. end
  75. else if(counter == 2'd2)begin
  76. counter <= 2'd0;
  77. end
  78. else if(next_state == B)begin
  79. counter <= counter + 1'b1;
  80. end
  81. end
  82. endmodule

只需要将第三段改为组合逻辑,但是输出需要延迟一拍,为什么?看时序图。

FPGA/IC群推荐

IC/FPGA 技术交流

有幸在这个群里认识了诸多俊杰,让我欣慰。

 

 

 

 

 

文章来源: reborn.blog.csdn.net,作者:李锐博恩,版权归原作者所有,如需转载,请联系作者。

原文链接:reborn.blog.csdn.net/article/details/103484037

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。