当前位置:   article > 正文

刷完这套题,我才发现Verilog原来如此简单----HDLBits答案系列 -- Building Larger Circuits_刷完这套题,我才发现

刷完这套题,我才发现

写在前面

全部答案汇总:刷完这套题,我才发现Verilog原来如此简单----HDLBits答案汇总

今天更新Circuits章节中的Building Larger Circuits


Counter with period 1000

【题目】:

        设计一个从0-999(1000个周期)的计数器。同步复位,复位值0。

  

【个人思路】:
        经典的计数器,数字电路、FPGA的基础应用之一。计数器首先复位清零,当计数器计数到最大值999时清零,没计数到最大值则每个周期+1。

  1. module top_module (
  2. input clk ,
  3. input reset ,
  4. output [9:0] q
  5. );
  6. //计数器:0-999
  7. always @(posedge clk)begin
  8. if(reset)
  9. q <= 10'd0; //同步复位清零
  10. else if(q == 10'd999)
  11. q <= 10'd0; //计数到最大值清零
  12. else
  13. q <= q + 1'b1; //其他时候每个时钟周期+1
  14. end
  15. endmodule

4 - bit shift register and down counter 

【题目】:

        设计一个四位移位寄存器,也作为一个下行计数器。当shift_ena为1时,数据会先以最高有效位移位。当前移位寄存器中的数字在count_ena为1时递减。系统不会出现两种使能信号同时为高的情况,所以不存在优先级问题。

         

【个人思路】:

        当shift_ena有效时,数据开始循环移位,当count_ena为1时,该移位寄存器做递减器。

  1. module top_module (
  2. input clk,
  3. input shift_ena,
  4. input count_ena,
  5. input data,
  6. output [3:0] q);
  7. always@(posedge clk)begin
  8. case({shift_ena,count_ena})
  9. 2'b01: q <= q -1'b1;
  10. 2'b10: q <= {q[2:0],data};
  11. default:;
  12. endcase
  13. end
  14. endmodule

FSM:Sequence 1101 recognizer 

【题目】:

        设计一个有限状态机FSM,从输入码流中找出“1101”序列,当1101被找到后,永远的拉高start_shifting信号,直到复位才拉低。

【个人思路】

        经典的序列检测问题,笔试常见,一定要掌握。可以参考我的这篇博文:‘10010’序列检测器的两种实现方法(有限状态机、移位寄存器)

        设计的有限状态机状态转移图如下:

  • S0:初始状态,开始检测1101序列的第一个1,若检测到1,则跳转到S1,若检测到0,则保持该状态
  • S1:若检测到1,则说明可能是1101序列的第二个1,所以状态跳转到S2, 若检测到0,则状态跳转到S0,去检测1101的第一个1
  • S2:若检测到0,则说明可能是1101序列的0,所以状态跳转到S3, 若检测到1,此时接收的码流为“111”,则后面的11可以视为1101序列中的前两个11,所以继续在该状态检测
  • S3:若检测到1,则说明是1101序列的最后的1,所以状态跳转到S4, 若检测到0,此时接收的码流为“1100”,则状态跳转到S0,重新开始检测
  • S4: 保持在该状态,且在该状态拉高start_shifting信号
  1. module top_module (
  2. input clk ,
  3. input reset ,
  4. input data ,
  5. output start_shifting
  6. );
  7. parameter S0 = 5'b00001,
  8. S1 = 5'b00010,
  9. S2 = 5'b00100,
  10. S3 = 5'b01000,
  11. S4 = 5'b10000;
  12. reg [4:0] cur_state , //定义现态寄存器
  13. next_state ; //定义次态寄存器
  14. //三段式状态机第一段:同步时序描述状态转移
  15. always @(posedge clk)begin
  16. if(reset)
  17. cur_state <= S0;
  18. else
  19. cur_state <= next_state;
  20. end
  21. //三段式状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
  22. always@(*)begin
  23. next_state = S0;
  24. case(cur_state)
  25. S0:
  26. if(data) //检测到1101的第1个1
  27. next_state = S1;
  28. else
  29. next_state = S0; //没有检测到1101的第1个1
  30. S1:
  31. if(data) //检测到1101的第2个1
  32. next_state = S2;
  33. else
  34. next_state = S0; //没有检测到1101的第2个1
  35. S2:
  36. if(!data) //检测到1101的0
  37. next_state = S3;
  38. else
  39. next_state = S2; //没有检测到1101的0,此时为111,后面两个11可以视为检测到了1101的11
  40. S3:
  41. if(data) //检测到1101的最后的1,检测完成
  42. next_state = S4;
  43. else
  44. next_state = S0; //没有检测到第一个字节(1100)则跳转到S0
  45. S4:
  46. next_state = S4; //永远保持在这个状态,因为start_shifting永远为1,只检测一次
  47. default:next_state = S0;
  48. endcase
  49. end
  50. //三段式状态机第三段:时序逻辑描述输出
  51. always @(posedge clk)begin
  52. if(reset)
  53. start_shifting <= 1'b0;
  54. else
  55. case(next_state)
  56. S0,S1,S2,S3:
  57. start_shifting <= 1'b0;
  58. S4:
  59. start_shifting <= 1'b1;
  60. default:start_shifting <= 1'b0;
  61. endcase
  62. end
  63. endmodule

FSM:Enable shift register

【题目】:

        作为控制移位寄存器的FSM的一部分,我们希望能够在检测到合适的位模式时,使移位寄存器精确地为4个时钟周期。我们在Exams/review2015_fsmseq中处理序列检测,所以FSM的这部分只处理4个周期的移位寄存器启用。

        当FSM被重置时,置位shift_ena 4个周期,然后0永远(直到重置)。

【个人思路】

        这道题的意思是,如果复位信号有效,shift_ena信号就为1;当复位信号撤销以后,shift_ena信号保持4个周期高电平后变为0。

        使用一个计数器计数,reset该计数器复位到0,shift_ena高电平期间计数(在此期间计数0-3),计数到3后计数器清零。

        shift_ena在复位有效后拉高,在计数器计数到3后拉低。

        预期波形图如下:

        

  1. module top_module (
  2. input clk,
  3. input reset, // Synchronous reset
  4. output shift_ena);
  5. reg [2:0] cnt;
  6. always @(posedge clk)begin
  7. if(reset)
  8. shift_ena <= 1'b1; //复位拉高shift_ena
  9. else if(cnt == 3'd3)
  10. shift_ena <= 1'b0; //计数器到3说明维持了4个周期,shift_ena拉低
  11. else
  12. shift_ena <= shift_ena; //其他时候不变
  13. end
  14. //计数器:0-3
  15. always @(posedge clk)begin
  16. if(reset)
  17. cnt <= 3'd0; //复位清零
  18. else if(shift_ena)
  19. cnt <= cnt + 1'd1; //shift_ena有效时递增1
  20. else
  21. cnt <= cnt; //其他时候不变
  22. end
  23. endmodule

 FSM式解法:

  1. module top_module (
  2. input clk,
  3. input reset, // Synchronous reset
  4. output shift_ena);
  5. parameter S0 = 5'b00001,
  6. S1 = 5'b00010,
  7. S2 = 5'b00100,
  8. S3 = 5'b01000,
  9. S4 = 5'b10000;
  10. reg [4:0] cur_state , //定义现态寄存器
  11. next_state ; //定义次态寄存器
  12. //三段式状态机第一段:同步时序描述状态转移
  13. always @(posedge clk)begin
  14. if(reset)
  15. cur_state <= S0;
  16. else
  17. cur_state <= next_state;
  18. end
  19. //三段式状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
  20. always@(*)begin
  21. next_state = S0;
  22. case(cur_state)
  23. S0: next_state = S1; //维持第1个时钟周期
  24. S1: next_state = S2; //维持第2个时钟周期
  25. S2: next_state = S3; //维持第3个时钟周期
  26. S3: next_state = S4; //维持第4个时钟周期
  27. S4: next_state = S4; //保持在这个状态,直到下一次复位
  28. default: next_state = S0;
  29. endcase
  30. end
  31. assign shift_ena = (cur_state == S0 || cur_state == S1 || cur_state == S2 || cur_state == S3);
  32. //三段式状态机第三段:时序逻辑描述输出
  33. /*always @(posedge clk)begin
  34. if(reset)
  35. shift_ena <= 1'b0;
  36. else
  37. case(next_state)
  38. S0,S1,S2,S3:
  39. shift_ena <= 1'b1;
  40. S4:
  41. shift_ena <= 1'b0;
  42. default:shift_ena <= 1'b0;
  43. endcase
  44. end */
  45. endmodule

FSM:The complete FSM

【题目】:

        首先检测序列“1101”,检测到后停止检测,拉高shift_ena4个时钟周期,然后拉高counting直到输入done_counting为1,然后拉高done直到输入ack为1。

【个人思路】:

        这题目是前面几道题的结合,状态转移图如下:

        

  • S:初始状态,开始检测1101序列的第一个1,若检测到1,则跳转到S1,若检测到0,则保持该状态
  • S1:若检测到1,则说明可能是1101序列的第二个1,所以状态跳转到S11, 若检测到0,则状态跳转到S,去检测1101的第一个1
  • S11:若检测到0,则说明可能是1101序列的0,所以状态跳转到S110, 若检测到1,则保持在该状态
  • S110:若检测到1,则说明是1101序列的最后一个1,所以状态跳转到B0, 若检测到0,则状态跳转到S,去检测1101的第一个1
  • B0:直接跳转到B1
  • B1:直接跳转到B2
  • B2:直接跳转到B3
  • B3:直接跳转到COUNT
  • COUNT:当counting为1时跳转到状态WAIT,不然一直停留在该状态
  • WAIT:当ack为0时跳转到状态S,不然一直停留在该状态
  1. module top_module (
  2. input clk,
  3. input reset, // Synchronous reset
  4. input data,
  5. input ack,
  6. input done_counting,
  7. output shift_ena,
  8. output counting,
  9. output done
  10. );
  11. parameter S = 4'd0,
  12. S1 = 4'd1,
  13. S11 = 4'd2,
  14. S110 = 4'd3,
  15. B0 = 4'd4,
  16. B1 = 4'd5,
  17. B2 = 4'd6,
  18. B3 = 4'd7,
  19. COUNT = 4'd8,
  20. WAIT = 4'd9;
  21. reg [3:0] cur_state , //定义现态寄存器
  22. next_state ; //定义次态寄存器
  23. //三段式状态机第一段:同步时序描述状态转移
  24. always @(posedge clk)begin
  25. if(reset)
  26. cur_state <= S;
  27. else
  28. cur_state <= next_state;
  29. end
  30. //三段式状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
  31. always@(*)begin
  32. //next_state = S;
  33. case(cur_state)
  34. S :
  35. if(data)
  36. next_state = S1;
  37. else
  38. next_state = S;
  39. S1 :
  40. if(data)
  41. next_state = S11;
  42. else
  43. next_state = S;
  44. S11 :
  45. if(!data)
  46. next_state = S110;
  47. else
  48. next_state = S11;
  49. S110 :
  50. if(data)
  51. next_state = B0;
  52. else
  53. next_state = S;
  54. B0 :
  55. next_state = B1;
  56. B1 :
  57. next_state = B2;
  58. B2 :
  59. next_state = B3;
  60. B3 :
  61. next_state = COUNT;
  62. COUNT:
  63. if(done_counting)
  64. next_state = WAIT;
  65. else
  66. next_state = COUNT;
  67. WAIT :
  68. if(ack)
  69. next_state = S;
  70. else
  71. next_state = WAIT;
  72. default: next_state = S;
  73. endcase
  74. end
  75. /*
  76. assign shift_ena = (cur_state == B0 || cur_state == B1 || cur_state == B2 || cur_state == B3);
  77. assign counting = (cur_state == COUNT);
  78. assign done = (cur_state == WAIT);
  79. */
  80. //三段式状态机第三段:时序逻辑描述输出
  81. always @(posedge clk)begin
  82. if(reset)begin
  83. shift_ena <= 1'b0;
  84. counting <= 1'b0;
  85. done <= 1'b0;
  86. end
  87. else
  88. case(next_state)
  89. B0,B1,B2,B3:begin
  90. shift_ena <= 1'b1;
  91. counting <= 1'b0;
  92. done <= 1'b0;
  93. end
  94. COUNT:begin
  95. shift_ena <= 1'b0;
  96. counting <= 1'b1;
  97. done <= 1'b0;
  98. end
  99. WAIT:begin
  100. shift_ena <= 1'b0;
  101. counting <= 1'b0;
  102. done <= 1'b1;
  103. end
  104. default:begin
  105. shift_ena <= 1'b0;
  106. counting <= 1'b0;
  107. done <= 1'b0;
  108. end
  109. endcase
  110. end
  111. endmodule

The complete timer

【题目】:             

        在数据流中检测到序列 1101 后,电路需要将接下来的 4bit 数据移入移位寄存器。4bit 数据决定了计数器的计数周期,称为 delay[3:0]。首先到达的比特作为数据的高位。之后,状态机置高 counting 信号,表示其正在等待计数器完成计数。在 FSM 中增加计数器状态,计数周期为 (delay[3:0] + 1 )* 1000 个时钟周期。比如 delay = 0 时,计数值为 1000 个周期。delay = 5 代表 6000 个周期。同时输出 count 当前剩余的计数周期,输出当前剩余计数周期的千位(比如,还剩1000个周期输出 1,还剩 999 个周期时输出 0)。当计数停止后,count 的输出可以为任意数。

        当计数完成后,电路置高 done 信号通知上层应用计数器计数完成,等待 ack 信号置高后,状态机清除 done 信号,返回空闲状态等待捕获下一个 1101 序列。

        本题给出了一个期望输入输出的例子。图中的斜线代表当前信号为 'X', 表示状态机不关心该信号当前的值。比如图例中,一旦 FSM 检测到 1101 序列并读取 delay[3:0] 后,在此次计数器事件完成前,对于当前的数据流不再关心。

        在图例中,电路计数周期为 2000 ,因为 delay[3:0] 数值为 4'b0001 。在后续的第二个计数周期中,因为 delay[3:0] = 4‘b1110,所以计数周期为 15000。

【个人思路】:

         首先需要找到序列“1101”,接下来的码流输出的4个数据(高位在前)+1,再乘以1000,就是接下来要延时的时间。延时完成后,拉高done,直到ack拉高(响应了),再重新开始新一轮。count输出的是计数的千位数,比如计数器还是1999,那么输出为1。

        设计状态转移如下图:

  • S           :  初始状态,检测到1,则跳转到S1,否则保持该状态
  • S1         :  检测到1,则跳转到S11,否则跳转到S
  • S11       :  检测到0,则跳转到S110,否则保持该状态
  • S110     :  检测到1,则跳转到DELAY  ,否则跳转到S
  • DELAY  :  在次状态延时4个时钟周期(cnt_delay从0-3),用来接收输入码流上接下来的4个数据,作为延时的时间
  • COUNT :  延时状态,直到延时到指定的时间 
  • WAIT     :  在次状态等待akc响应信号

再贴几张写的仿真的仿真结果,方便理解:

  

  1. module top_module (
  2. input clk,
  3. input reset,
  4. input data,
  5. input ack,
  6. output [3:0] count,
  7. output counting,
  8. output done
  9. );
  10. parameter S = 4'd0,
  11. S1 = 4'd1,
  12. S11 = 4'd2,
  13. S110 = 4'd3,
  14. DELAY = 4'd4,
  15. COUNT = 4'd5,
  16. WAIT = 4'd6;
  17. reg [3:0] cur_state , //定义现态寄存器
  18. next_state ; //定义次态寄存器
  19. reg [1:0] cnt_delay ; //用来接收码流的计数器
  20. reg [15:0] cnt ;
  21. reg [3:0] delay ;
  22. //三段式状态机第一段:同步时序描述状态转移
  23. always @(posedge clk)begin
  24. if(reset)
  25. cur_state <= S;
  26. else
  27. cur_state <= next_state;
  28. end
  29. //三段式状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
  30. always@(*)begin
  31. //next_state = S;
  32. case(cur_state)
  33. S :
  34. if(data)
  35. next_state = S1;
  36. else
  37. next_state = S;
  38. S1 :
  39. if(data)
  40. next_state = S11;
  41. else
  42. next_state = S;
  43. S11 :
  44. if(!data)
  45. next_state = S110;
  46. else
  47. next_state = S11;
  48. S110 :
  49. if(data)
  50. next_state = DELAY;
  51. else
  52. next_state = S;
  53. DELAY:
  54. if(cnt_delay == 2'd3)
  55. next_state = COUNT;
  56. else
  57. next_state = DELAY;
  58. COUNT:
  59. if(cnt == 16'd0)
  60. next_state = WAIT;
  61. else
  62. next_state = COUNT;
  63. WAIT :
  64. if(ack)
  65. next_state = S;
  66. else
  67. next_state = WAIT;
  68. default: next_state = S;
  69. endcase
  70. end
  71. //三段式状态机第三段:描述输出
  72. assign count = cnt/1000;
  73. assign counting = (cur_state == COUNT);
  74. assign done = (cur_state == WAIT);
  75. //延时计数器,计数4个时钟,来接收delay数据
  76. always @(posedge clk)begin
  77. if(reset)
  78. cnt_delay <= 2'd0;
  79. else if(cur_state == DELAY)begin
  80. cnt_delay <= cnt_delay + 1'b1;
  81. end
  82. else
  83. cnt_delay <= cnt_delay;
  84. end
  85. //根据接收到的delay数据进行计数延时
  86. always @(posedge clk)begin
  87. if(reset)
  88. cnt <= 16'd0;
  89. else if(cur_state == DELAY)
  90. cnt <= (delay+1'b1) * 1000-1'd1;
  91. else if(cur_state == COUNT)
  92. cnt <= cnt - 1'd1;
  93. else
  94. cnt <= cnt;
  95. end
  96. //接收delay数据
  97. always@(*)begin
  98. if(cur_state == DELAY)
  99. case(cnt_delay)
  100. 2'd0: delay[3] = data;
  101. 2'd1: delay[2] = data;
  102. 2'd2: delay[1] = data;
  103. 2'd3: delay[0] = data;
  104. default:;
  105. endcase
  106. else
  107. delay = 4'b0000;
  108. end
  109. endmodule

 One-hot logic equations

【题目】:本题给出了一个具有 3 输入,3 输出以及 10 个状态的 FSM 的状态转移图。仅需要实现状态转移和输出逻辑的组合逻辑,tb 会检测是否按照要求使用了独热码。

 【个人思路】:

        使用独热码进行输出,跟之前有类似的题,就直接做了。

  1. module top_module(
  2. input d,
  3. input done_counting,
  4. input ack,
  5. input [9:0] state, // 10-bit one-hot current state
  6. output B3_next,
  7. output S_next,
  8. output S1_next,
  9. output Count_next,
  10. output Wait_next,
  11. output done,
  12. output counting,
  13. output shift_ena
  14. ); //
  15. parameter S=0, S1=1, S11=2, S110=3, B0=4, B1=5, B2=6, B3=7, Count=8, Wait=9;
  16. assign B3_next = state[B2];
  17. assign S_next = ~d & state[S] | ~d & state[S1] | ~d & state[S110] | ack & state[Wait];
  18. assign S1_next = d & state[S];
  19. assign Count_next = state[B3] | ~done_counting & state[Count];
  20. assign Wait_next = done_counting & state[Count] | ~ack & state[Wait];
  21. assign done = state[Wait];
  22. assign counting = state[Count];
  23. assign shift_ena = state[B0] | state[B1] | state[B2] |state[B3];
  24. endmodule

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/648810
推荐阅读
相关标签
  

闽ICP备14008679号