当前位置:   article > 正文

数字IC手撕代码50题(1-10)_华为数字ic手撕代码

华为数字ic手撕代码

一、序列检测器

        可以说是最经典的题目了,数电课本上的题目,涉及到状态机的设计,出现频率非常高,这里分别采用两种方式实现:

        1.状态机

        2.移位寄存器

1.1 题目描述与分析

        使用verilog代码,设计电路,检测序列为1001,检测到的时候输出1,没检测到的时候输出0

        分析:检测四位,那么就会有五个状态。分别为 0   1    10   100  1001。显然是一个摩尔型状态机。当到达第五个状态时,输出1.对五个状态进行状态编码,IDLE = 3'b000 , s1 = 3'b001 , s2 = 3'b011 ,s3 = 3'b010, s4 = 3'b110;可以使用格雷码编码,并画出状态转移图。

       

         至此,我们可以根据这个状态转移图去写两段式状态机了。

        两段式要点:parameter 状态声明 ; 第一段 当前状态转移成下一状态 ;第二段 组合逻辑 根据输入,对当前状态进行case变换;第三段 组合逻辑 检测是否到最后一个输出状态。?:

1.2 状态机实现序列检测

  1. module moduleName1 (
  2. input clk,
  3. input rst_n,
  4. input seq,
  5. output wire detect
  6. );
  7. parameter IDLE = 3'b000 , s1 = 3'b001 , s2 = 3'b011 ,s3 = 3'b010, s4 = 3'b110;
  8. reg [2:0] cstate,nstate;
  9. always @(posedge clk or negedge rst_n) begin
  10. if(!rst_n)
  11. cstate <= IDLE;
  12. else
  13. cstate <= nstate;
  14. end
  15. always @(*) begin
  16. case (cstate)
  17. IDLE : nstate = seq ? s1 : IDLE;
  18. s1 : nstate = seq ? s1 : s2 ;
  19. s2 : nstate = seq ? s1 : s3 ;
  20. s3 : nstate = seq ? s4 : IDLE;
  21. s4 : nstate = seq ? s1 : IDLE;
  22. default: nstate = IDLE;
  23. endcase
  24. end
  25. assign detect = nstate == s4 ? 1 : 0 ;
  26. endmodule

 1.3 移位寄存器实现序列检测

        用移位寄存器的方法比状态机的方法代码要轻简很多,先说一下原理:

        ①先定义一个4位的变量用来移位——shift = 4’b0000;

        ②然后每输入一位x,移位放至shift中——shift <= {shift[2:0], x};

        ③检测shift是否等于1001.

        至于为什么移位是这样的表达,大家可以看下面的这个图。

        

         这样代码就简单了不少,如下所示:

  1. module moduleName2 (
  2. input clk,
  3. input rst_n,
  4. input seq,
  5. output wire detect
  6. );
  7. reg [3:0] shift;
  8. always @(posedge clk or negedge rst_n) begin
  9. if(!rst_n)
  10. shift <= 4'b0000;
  11. else
  12. shift <= {shift[2:0],seq};
  13. end
  14. assign detect = shift == 4'b1001 ? 1 : 0;
  15. endmodule

二、 序列发生器

2.1 题目描述与分析  

         编写一个模块,实现循环输出序列001011。

        分析:这里需要循环输出序列001011,显然定义一个reg[5:0] 去存储001011,然后按照时钟一拍一拍的把他的最高位读出即可。由于这里需要循环输出,所以当读到100000的时候,需要重新写入reg的值。

2.1 移位实现序列发生器

  1. module moduleName (
  2. input clk,
  3. input rst_n,
  4. output reg data
  5. );
  6. reg [5:0]data_r;
  7. always @(posedge clk or negedge rst_n) begin
  8. if(!rst_n)
  9. data_r <= 6'b001011;
  10. else if (data_r == 6'b100000) // 加括号
  11. data_r <= 6'b001011;
  12. else
  13. data_r <= (data_r << 1 ); // 加括号
  14. end
  15. always @(posedge clk or negedge rst_n) begin
  16. if(!rst_n)
  17. data <= 1'b0;
  18. else
  19. data <= data_r[5];
  20. end
  21. endmodule

2.2 用状态机实现序列发生器

        用状态机的思路也比较简单,可以设计 s0 = 0 , s1 = 00 ,s2 = 001, s3= 0010,s4 =00101,s5= 001011 这六个状态,并进行状态编码,每个状态都可以对应一个输出,而且状态机的转换与输入没有关系,case当前是s1,那么无条件跳到s2,并且可以对应data输出,s0对应输出0,s1对应输出0,s2对应输出1,s3对应0,等等。

  1. module moduleName2 (
  2. input wire clk;
  3. input wire rst_n;
  4. output reg data
  5. );
  6. reg [2:0] cstate,nstate;
  7. parameter s0 = 3'b000, s1 = 3'b001 , s2 = 3'b011 ,s3 = 3'b010, s4 = 3'b110, s5= 3'b111;
  8. always @(posedge clk or negedge rst_n) begin
  9. if(!rst_n)
  10. cstate <= s0;
  11. else
  12. cstate <= nstate;
  13. end
  14. always @(*) begin
  15. case (cstate)
  16. s0 : begin nstate = s1; data <= 1'b0;end
  17. s1 : begin nstate = s2; data <= 1'b0;end
  18. s2 : begin nstate = s3; data <= 1'b1;end
  19. s3 : begin nstate = s4; data <= 1'b0;end
  20. s4 : begin nstate = s5; data <= 1'b1;end
  21. s5 : begin nstate = s0; data <= 1'b1;end
  22. default: begin nstate = s0; data <= 1'b0;end
  23. endcase
  24. end
  25. endmodule

三、模三检测器

3.1 题目描述与分析

        使用verilog代码,设计电路,判断输入序列能否被三整除,能的时候输出1,不能的时候输出0。

        思路:首先,一个数去除以3,其余数只有0 1 2 三种状态,我们再加一个IDLE状态,对这四个状态进行编码。IDLE = 2‘b00,s0 = 2‘b01,s1 = 2‘b11,s2= 2'b10。分别对应余0,余1,余2三种状态。

              这个题目是判断输入序列能不能被三整除,所以我们要推断出,输入与状态转换之间的关系。每输入一位,就相当于现在的序列左移一位,在加上输入的数。

                所以,当输入为0时,序列值变成前一刻的值x的二倍 2x 。当输入序列为1时,序列值变成 2x + 1。这样我们可以推断出余数的状态转移图。

                

                对于s0,可以看做是3x。

                来一个1时,变成2*(3x)+ 1,则余1,转到s1态。

                来一个0时,变成2*(3x) ,则余0,转到s0态。

                对于s1,可以看做是3x+1。

                来一个1时,变成2*(3x+1)+ 1,则余0,转到s0态。

                来一个0时,变成2*(3x+1) ,则余2,转到s2态。

                对于s2,可以看做是3x+2。

                来一个1时,变成2*(3x+2)+ 1,则余2,转到s2态。

                来一个0时,变成2*(3x+2) ,则余1,转到s1态。

                最后判断是否为s0态,输出检测信号高电平。

3.2 状态机实现模三检测器

  1. module moduleName (
  2. input clk,
  3. input rst_n,
  4. input data,
  5. output wire mod0
  6. );
  7. parameter IDLE = 2'b00,s0 = 2'b01,s1 = 2'b11,s2 = 2'b10;
  8. reg[1:0] cstate,nstate;
  9. always @(posedge clk or negedge rst_n) begin
  10. if(!rst_n)
  11. cstate <= IDLE;
  12. else
  13. cstate <= nstate;
  14. end
  15. always @(*) begin
  16. case (cstate)
  17. IDLE : nstate = data ? s1 : s0 ;
  18. s0 : nstate = data ? s1 : s0 ;
  19. s1 : nstate = data ? s0 : s2 ;
  20. s2 : nstate = data ? s2 : s1 ;
  21. default: nstate = IDLE;
  22. endcase
  23. end
  24. assign mod0 = (cstate == s0) ? 1 : 0;
  25. endmodule

  四、自动售卖机(一)

    4.1 题目描述与分析

        使用Verilog设计电路,完成以下功能:每瓶饮料1.5元,一次只能投入一个硬币,可投入0.5与1.0两种硬币,具有找零功能。

        分析:首先就要进行 状态的划分。状态数值为售卖机里面的钱,一共有IDLE,0.5,1,1.5,2五个状态。

        具体描述一下:(只会找零0.5元)

  1. IDLE:复位状态,表示饮料机中的余额为0
  2. s1:饮料机的余额为0.5
  3. s2:饮料机中的余额为1
  4. s3:饮料机中的余额为1.5元(输出饮料,不找零)
  5. s4:饮料集中的余额为2元(输出饮料,找零0.5元)
  6. 这个设计不会找零1

        这个题目的不同点在于,有两个输入信号,决定状态机的转换,所以第二段的组合逻辑,状态转换时需要先考虑第一个输入,再考虑第二个输入。才决定状态转换。

        那么对于这个状态机的输入和输出来说
        输入:两位input代表投入的硬币,input[1]拉高意味着投入1元,input[0]拉高意味着投入0.5 元,默认一次只能投入一枚硬币
        输出:drink代表输出饮料,coin代表输出硬币。

        先判断是否有input[1],再去判断input[2].

        画出状态转移图,红色代表input[1],蓝色代表input[0],

        

        s3,s4 收到0的时候,返回IDLE。

 4.2 状态机实现自助售卖机

  1. module moduleName (
  2. input clk,
  3. input rst_n,
  4. input [1:0] money,
  5. output wire drink,
  6. output wire coin
  7. );
  8. parameter IDLE = 3'b000,s1 = 3'b001,s2 =3'b010,s3 = 3'b011,s4 = 3'b100;
  9. reg[2:0] cstate,nstate;
  10. always @(posedge clk or negedge rst_n) begin
  11. if(!rst_n)
  12. cstate <= IDLE;
  13. else
  14. cstate <= nstate;
  15. end
  16. always @(*) begin
  17. case (cstate)
  18. IDLE : nstate = money[1] ? s2 : (money[0] ? s1 : IDLE) ;
  19. s1 : nstate = money[1] ? s3 : (money[0] ? s2 : s1 ) ;
  20. s2 : nstate = money[1] ? s4 : (money[0] ? s3 : s2 ) ;
  21. s3 : nstate = money[1] ? s2 : (money[0] ? s1 : IDLE) ;
  22. s4 : nstate = money[1] ? s2 : (money[0] ? s1 : IDLE) ;
  23. default: nstate = IDLE ;
  24. endcase
  25. end
  26. assign drink = (cstate == s3) || (cstate == s4) ;
  27. assign cion = (cstate == s4) ? 1 : 0 ;
  28. endmodule

五、自动售卖机(二)

5.1 题目描述与分析 

        题目描述:   

设计一个自动贩售机,输入货币有两种,为0.5/1元,饮料价格是1.5/2.5元,要求进行找零,找零只会支付0.5元。

ps:

1、投入的货币会自动经过边沿检测并输出一个在时钟上升沿到1,在下降沿到0的脉冲信号

2、此题忽略出饮料后才能切换饮料的问题

注意rst为低电平复位

信号示意图:

d1 0.5   d2 1  sel  选择饮料 out1 饮料1 out2 饮料2 out3 零钱

        题目分析:

        与上题不同的是。多了一个选择信号,这个选择信号可以选择购买不同的饮料。

        首先,我们确定状态个数。 

        IDLE : 贩卖机里累计0元。

        s1     : 贩卖机里累计0.5元。

        s2     : 贩卖机里累计1元。

        s3     : 贩卖机里累计1.5元。

        s4     : 贩卖机里累计2元。

        s5     : 贩卖机里累计2.5元。

        s6     : 贩卖机里累计3元。

       第一种思路: 当贩售机内金额大于1.5时,也就是S3及以后的状态,还应根据饮料种类做判断。如果选择的是饮料1,sel=0,则返回S0状态;如果选择的是饮料2,sel=1,则根据投入的货币继续向下转移状态。即s3以后的状态,三目运算符会多一点点。

        第二种思路:分别两个状态机,由sel信号一开始就决定进入哪个状态机。

5.2 状态机实现自动贩卖机(二)

        第一种思路:

        

  1. module moduleName (
  2. input wire clk ,
  3. input wire rst_n ,
  4. input wire d1 ,
  5. input wire d2 ,
  6. input wire sel ,
  7. output reg out1,
  8. output reg out2,
  9. output reg out3
  10. );
  11. parameter IDLE = 3'b000, s0_5 = 3'b001,s1 =3'b010,s1_5 = 3'b011,s_2 = 3'b100;
  12. parameter s2_5 = 3'b101, s3 = 3'b110;
  13. reg[2:0] cstate,nstate;
  14. always @(posedge clk or negedge rst_n) begin
  15. if(!rst_n)
  16. cstate <= IDLE;
  17. else
  18. cstate <= nstate;
  19. end
  20. always @(*) begin
  21. case (cstate)
  22. IDLE : nstate = d1 ? s0_5 : (d2 ? s1 : IDLE) ;
  23. s0_5 : nstate = d1 ? s1 : (d2 ? s1_5 : s1) ;
  24. s1 : nstate = d1 ? s1_5 : (d2 ? s_2 : s1) ;
  25. s1_5 : nstate = !sel ? IDLE : d1 ? s_2 : (d2 ? s2_5 : s1_5);
  26. s_2 : nstate = !sel ? IDLE : d1 ? s2_5 : (d2 ? s3 : s_2);
  27. s2_5 : nstate = IDLE ;
  28. s3 : nstate = IDLE ;
  29. default: nstate = IDLE ;
  30. endcase
  31. end
  32. always@(posedge clk or negedge rst_n)begin
  33. if(rst_n == 1'b0)begin
  34. out1 <= 1'b0;
  35. out2 <= 1'b0;
  36. out3 <= 1'b0;
  37. end
  38. else begin
  39. if(!sel)begin
  40. case (nstate)
  41. s1_5: begin out1 <= 1'b1;out2 <= 1'b0;out3 <= 1'b0;end
  42. s_2: begin out1 <= 1'b1;out2 <= 1'b0;out3 <= 1'b1;end
  43. default:begin out1 <= 1'b0;out2 <= 1'b0;out3 <= 1'b0;end
  44. endcase
  45. end
  46. else begin
  47. case (nstate)
  48. s1_5: begin out1 <= 1'b0;out2 <= 1'b1;out3 <= 1'b0;end
  49. s_2: begin out1 <= 1'b0;out2 <= 1'b1;out3 <= 1'b1;end
  50. default:begin out1 <= 1'b0;out2 <= 1'b0;out3 <= 1'b0;end
  51. endcase
  52. end
  53. end
  54. end
  55. endmodule

        第二种思路:

  1. module seller2(
  2. input wire clk ,
  3. input wire rst ,
  4. input wire d1 ,
  5. input wire d2 ,
  6. input wire sel ,
  7. output reg out1,
  8. output reg out2,
  9. output reg out3
  10. );
  11. parameter S0 = 'd0, S1 = 'd1, S2 = 'd2, S3 = 'd3 , S4 = 'd4, S5 = 'd5, S6 = 'd6;
  12. reg [2:0] current_state;
  13. reg [2:0] next_state;
  14. wire [1:0] input_state;
  15. assign input_state = {d1,d2};
  16. always@(posedge clk or negedge rst)begin
  17. if(rst == 1'b0)begin
  18. current_state <= S0;
  19. end
  20. else begin
  21. current_state <= next_state;
  22. end
  23. end
  24. always@(*)begin
  25. if (!sel) begin
  26. case(current_state)
  27. S0:begin
  28. case(input_state)
  29. 2'b10 :next_state = S1 ;
  30. 2'b01 :next_state = S2 ;
  31. default:next_state = next_state;
  32. endcase
  33. end
  34. S1:begin
  35. case(input_state)
  36. 2'b10 :next_state = S2 ;
  37. 2'b01 :next_state = S3 ;
  38. default:next_state = next_state;
  39. endcase
  40. end
  41. S2:begin
  42. case(input_state)
  43. 2'b10 :next_state = S3 ;
  44. 2'b01 :next_state = S4 ;
  45. default:next_state = next_state;
  46. endcase
  47. end
  48. default: next_state = S0;
  49. endcase
  50. end
  51. else begin
  52. case(current_state)
  53. S0:begin
  54. case(input_state)
  55. 2'b10 :next_state = S1 ;
  56. 2'b01 :next_state = S2 ;
  57. default:next_state = next_state;
  58. endcase
  59. end
  60. S1:begin
  61. case(input_state)
  62. 2'b10 :next_state = S2 ;
  63. 2'b01 :next_state = S3 ;
  64. default:next_state = next_state;
  65. endcase
  66. end
  67. S2:begin
  68. case(input_state)
  69. 2'b10 :next_state = S3 ;
  70. 2'b01 :next_state = S4 ;
  71. default:next_state = next_state;
  72. endcase
  73. end
  74. S3:begin
  75. case(input_state)
  76. 2'b10 :next_state = S4 ;
  77. 2'b01 :next_state = S5 ;
  78. default:next_state = next_state;
  79. endcase
  80. end
  81. S4:begin
  82. case(input_state)
  83. 2'b10 :next_state = S5 ;
  84. 2'b01 :next_state = S6 ;
  85. default:next_state = next_state;
  86. endcase
  87. end
  88. default: next_state = S0;
  89. endcase
  90. end
  91. end
  92. always@(posedge clk or negedge rst)begin
  93. if(rst == 1'b0)begin
  94. out1 <= 1'b0;
  95. out2 <= 1'b0;
  96. out3 <= 1'b0;
  97. end
  98. else begin
  99. if(!sel)begin
  100. case (next_state)
  101. S3: begin out1 <= 1'b1;out2 <= 1'b0;out3 <= 1'b0;end
  102. S4: begin out1 <= 1'b1;out2 <= 1'b0;out3 <= 1'b1;end
  103. default:begin out1 <= 1'b0;out2 <= 1'b0;out3 <= 1'b0;end
  104. endcase
  105. end
  106. else begin
  107. case (next_state)
  108. S5: begin out1 <= 1'b0;out2 <= 1'b1;out3 <= 1'b0;end
  109. S6: begin out1 <= 1'b0;out2 <= 1'b1;out3 <= 1'b1;end
  110. default:begin out1 <= 1'b0;out2 <= 1'b0;out3 <= 1'b0;end
  111. endcase
  112. end
  113. end
  114. end
  115. endmodule

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

闽ICP备14008679号