image.png :::info 【分析】

  1. 根据要求,在sel = 0的时候输入才是有效的,其他时刻的输入是没用的,因此必须声明一个reg类型来对输入进行暂存(与移位运算和乘法题目相同);
  2. 位分割; :::

    1. Verilog代码实现

    ``verilogtimescale 1ns/1ns module data_cal( input clk, input rst, input [15:0] d, input [1:0] sel, output [4:0] out, output validout ); //**code*// reg [15:0] d_reg; reg [4:0] out_reg; reg validout_reg; always@(posedge clk or negedge rst) begin if(!rst) begin out_reg <= 5’b0; validout_reg <= 1’b0; end else begin case(sel)
    1. 2'b00 : begin
    2. validout_reg <= 1'b0;
    3. d_reg <= d;
    4. out_reg <= 5'b0;
    5. end
    6. 2'b01 : begin
    7. validout_reg <= 1'b1;
    8. out_reg <= d_reg[3:0] + d_reg[7:4];
    9. end
    10. 2'b10 : begin
    11. validout_reg <= 1'b1;
    12. out_reg <= d_reg[3:0] + d_reg[11:8];
    13. end
    14. 2'b11 : begin
    15. validout_reg <= 1'b1;
    16. out_reg <= d_reg[3:0] + d_reg[15:12];
    17. end
    18. default : begin
    19. validout_reg <= 1'b0;
    20. out_reg <= 5'b0;
    21. end
    endcase end end assign validout = validout_reg; assign out = out_reg; //**code*// endmodule // Method2 reg [15:0] d_reg; wire [3:0] d0; wire [3:0] d1; wire [3:0] d2; wire [3:0] d3; assign d0 = d_reg[3:0]; assign d1 = d_reg[7:4]; assign d2 = d_reg[11:8]; assign d3 = d_reg[15:12]; reg [4:0] out_reg; //**code*// endmodule
  1. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/22348254/1655277874651-b31fbd09-635b-4452-8308-1af949934459.png#clientId=u82c5e2b5-7e45-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=376&id=uccc8482c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=470&originWidth=1271&originalType=binary&ratio=1&rotation=0&showTitle=false&size=25190&status=done&style=none&taskId=uba2f744a-a35a-4ccf-b3e5-c612120378a&title=&width=1016.8)
  2. > 过程中遇到的问题:
  3. > 1. 复位的时候是只对output信号进行复位;
  4. > 1. always块中必须使用reg类型,因此必须声明reg类型的变量来进行存放并在之后使用assign连接;
  5. > 1. 使用第二种方法对寄存器提前进行位拆分,在以后的大型逻辑电路中可以更方便对照。
  6. <a name="yUE7Z"></a>
  7. # 2. Testbench自测模式
  8. :::info
  9. `timescale 1ns/1ns:<br />前面的1ns指的是时间的间隔:比如 #5就是5ns;<br />后面的1ns指的是时间的精度,设置的越小仿真就越慢。
  10. :::
  11. ```verilog
  12. `timescale 1ns/1ns
  13. module data_cal_tb;
  14. bit clk;
  15. bit rst;
  16. reg [15:0] d;
  17. reg [1:0] sel;
  18. wire [4:0] out;
  19. wire validout;
  20. data_cal dut(
  21. .clk(clk),
  22. .rst(rst),
  23. .d(d),
  24. .sel(sel),
  25. .out(out),
  26. .validout(validout)
  27. );
  28. initial begin : gen_clk
  29. forever #5 clk <= !clk;
  30. end
  31. initial begin
  32. clk = 0;
  33. rst = 0;
  34. d = 16'd0;
  35. sel = 2'b00;
  36. #30;
  37. rst = 1;
  38. sel = 2'b00;
  39. d = 16'b1000_0100_0010_0001;
  40. #10;
  41. sel = 2'b01;
  42. d = 16'b1111_1111_1111_1111;
  43. #10;
  44. sel = 2'b10;
  45. d = 16'b1000_0000_0000_0000;
  46. #10;
  47. sel = 2'b11;
  48. d = 16'b1000_0000_0000_0000;
  49. #10;
  50. sel = 2'b00;
  51. d = 16'b1000_0100_0010_0001;
  52. #30;
  53. $finish();
  54. end
  55. endmodule

image.png

将data_cal.v和tb.sv文件放在Questasim中编译并仿真,观察tb中信号的波形,结果如上:

  • 在SEL为0的时候输入有效,输入的值是十六进制的8421并保存在寄存器中;
  • 在SEL为1的时候输出低8位相加,相加以后的结果就是3。

在写tb的时候需要注意:

  1. 功能方面需要和设计文件保持一致,从复位以后的值开始。
  2. 在rst拉高以后其他信号有效,此时观察序列运算后的结果。