• 牛客刷题<四>移位运算与乘法


    题目:移位运算与乘法_牛客题霸_牛客网

    思路:在FPGA中进行乘除法运算是比较耗费资源的一种方法,想要在不影响延迟并尽量减少资源损耗,必须从硬件的特点上进行设计。根据寄存器的原理,由于是二进制,所以左移或右移一位相当于×2或÷2,同样×3相当于左移一位再加原数据,×7相当于左移两位加上左移一位再加上原数据,×8正好相当于左移三位。也就是解法一的原理。

    解法一:此方法是最容易想到的

    1. `timescale 1ns/1ns
    2. module multi_sel(
    3. input [7:0]d ,
    4. input clk,
    5. input rst,
    6. output reg input_grant,
    7. output reg [10:0]out
    8. );
    9. //*************code***********//
    10. reg [1:0] cnt;
    11. reg [7:0] d_r;
    12. always @(posedge clk or negedge rst) begin
    13. if(!rst) begin
    14. cnt <= 2'b0;
    15. end
    16. else if(cnt == 2'd3)begin
    17. cnt <= 2'd0;
    18. end
    19. else begin
    20. cnt <= cnt + 2'd1;
    21. end
    22. end
    23. always @(posedge clk or negedge rst) begin
    24. if(!rst) begin
    25. out <= 0;
    26. input_grant <= 0;
    27. d_r <= 0;
    28. end
    29. else begin
    30. case (cnt)
    31. 2'd0 : begin
    32. out <= d;
    33. d_r <= d;
    34. input_grant <= 1'b1;
    35. end
    36. 2'd1 : begin
    37. out <= d_r + (d_r << 1);
    38. input_grant <= 1'b0;
    39. end
    40. 2'd2 : begin
    41. out <= d_r + (d_r << 1) + (d_r << 2);
    42. end
    43. 2'd3 : begin
    44. out <=(d_r << 3);
    45. end
    46. default : begin
    47. out <= 0;
    48. input_grant <= 0;
    49. end
    50. endcase
    51. end
    52. end
    53. always @(posedge clk or negedge rst) begin
    54. if(!rst) begin
    55. end
    56. end
    57. //*************code***********//
    58. endmodule

    解法二:

    根据题意分析,可以得到状态转换:

    设输入为d,计数器为cnt

    移位运算逻辑:

    位运算
    1d
    3(din<<2)-din
    7(din<<3)-din
    8(din<<3)

    状态机逻辑

    cntoutinout_grant
    0直接输出d,并寄存d的值为din1
    1(din<<2)-din0
    2(din<<3)-din0
    3(din<<3)0
    1. `timescale 1ns/1ns
    2. module multi_sel(
    3. input [7:0]d ,
    4. input clk,
    5. input rst,
    6. output reg input_grant,
    7. output reg [10:0]out
    8. );
    9. //*************code***********//
    10. reg [1:0] cnt;
    11. reg [7:0] din;
    12. always@(posedge clk or negedge rst)
    13. begin
    14. if(!rst)
    15. begin
    16. cnt <= 0;
    17. din <= 0;
    18. out <= 0;
    19. input_grant <= 0;
    20. end
    21. else begin
    22. cnt <= cnt + 2'd1;
    23. case(cnt)
    24. 2'd0:begin
    25. input_grant <= 1;
    26. din <= d;
    27. out <= d;
    28. end
    29. 2'd1:begin
    30. input_grant <= 0;
    31. out <= (din << 2) - din;
    32. end
    33. 2'd2:begin
    34. input_grant <= 0;
    35. out <= (din << 3) - din;
    36. end
    37. 2'd3:begin
    38. input_grant <= 0;
    39. out <= (din << 3);
    40. end
    41. endcase
    42. end
    43. end
    44. //*************code***********//
    45. endmodule

     或者

    1. `timescale 1ns/1ns
    2. module multi_sel
    3. (
    4. input [7:0] d,
    5. input clk,
    6. input rst,
    7. output reg input_grant,
    8. output reg [10:0] out
    9. );
    10. reg [1:0] cnt;
    11. reg [7:0] din;
    12. always@(posedge clk or negedge rst)
    13. begin
    14. if(!rst)
    15. cnt <= 2'd0;
    16. else if(cnt == 2'd3)
    17. cnt <= 2'd0;
    18. else
    19. cnt <= cnt + 2'd1;
    20. end
    21. always@(posedge clk or negedge rst)
    22. begin
    23. if(!rst)begin
    24. input_grant <= 0;
    25. din <= 8'd0;
    26. end
    27. else if(cnt == 2'd0)begin
    28. din <= d;
    29. input_grant <= 1;
    30. end
    31. else begin
    32. din <= din;
    33. input_grant <= 0;
    34. end
    35. end
    36. always@(posedge clk or negedge rst)
    37. begin
    38. if(!rst)
    39. out <= 11'd0;
    40. else
    41. case(cnt)
    42. 2'd0:out <= d;
    43. 2'd1:out <= (din << 2) - din;
    44. 2'd2:out <= (din << 3) - din;
    45. 2'd3:out <= (din << 3);
    46. default: out <= 11'd0;
    47. endcase
    48. end
    49. endmodule

     解法三:利用乘法器,虽然浪费资源

    1. `timescale 1ns/1ns
    2. module multi_sel
    3. (
    4. input [7:0] d,
    5. input clk,
    6. input rst,
    7. output reg input_grant,
    8. output reg [10:0] out
    9. );
    10. reg [1:0] cnt;
    11. reg [7:0] din;
    12. always@(posedge clk or negedge rst)
    13. begin
    14. if(!rst)
    15. cnt <= 2'd0;
    16. else if(cnt == 2'd3)
    17. cnt <= 2'd0;
    18. else
    19. cnt <= cnt + 2'd1;
    20. end
    21. always@(posedge clk or negedge rst)
    22. begin
    23. if(!rst)begin
    24. input_grant <= 0;
    25. din <= 8'd0;
    26. end
    27. else if(cnt == 2'd0)begin
    28. din <= d;
    29. input_grant <= 1;
    30. end
    31. else begin
    32. din <= din;
    33. input_grant <= 0;
    34. end
    35. end
    36. always@(posedge clk or negedge rst)
    37. begin
    38. if(!rst)
    39. out <= 11'd0;
    40. else
    41. case(cnt)
    42. 2'd0:out <= d;
    43. 2'd1:out <= din * 3;
    44. 2'd2:out <= din * 7;
    45. 2'd3:out <= din * 8;
    46. default: out <= 11'd0;
    47. endcase
    48. end
    49. endmodule

    解法四:状态机,注意每次状态跳转之间的联系,out保存的是上一状态的值

    1. `timescale 1ns/1ns
    2. module multi_sel(
    3. input [7:0]d ,
    4. input clk,
    5. input rst,
    6. output reg input_grant,
    7. output reg [10:0]out
    8. );
    9. //*************code***********//
    10. reg [1:0]state;
    11. reg [7:0]d_temp;
    12. always@(posedge clk,negedge rst) begin
    13. if(!rst) begin
    14. out <= 0;
    15. input_grant <= 0;
    16. state <= 2'b00;
    17. end
    18. else begin
    19. case(state)
    20. 2'b00:begin
    21. d_temp <=d;
    22. out <= d;
    23. state <= 2'b01;
    24. input_grant <= 1;
    25. end
    26. 2'b01:begin
    27. d_temp <=d_temp;
    28. out <= d_temp + (out<<1);//用的是上一状态的Out
    29. state <= 2'b11;
    30. input_grant <= 0;
    31. end
    32. 2'b11:begin
    33. d_temp <=d_temp;
    34. out <= d_temp + (out<<1);//用的是上一状态的Out
    35. state <= 2'b10;
    36. input_grant <= 0;
    37. end
    38. 2'b10:begin
    39. d_temp <=d_temp;
    40. out <= d_temp + out;//用的是上一状态的Out
    41. state <= 2'b00;
    42. input_grant <= 0;
    43. end
    44. default:begin
    45. out <=0;
    46. state <= 2'b00;
    47. input_grant <= 0;
    48. end
    49. endcase
    50. end
    51. end
    52. //*************code***********//
    53. endmodule

    解法五:状态机

    1. `timescale 1ns/1ns
    2. module multi_sel(
    3. input [7:0]d ,
    4. input clk,
    5. input rst,
    6. output reg input_grant,
    7. output reg [10:0]out
    8. );
    9. //*************code***********//
    10. parameter TIMES1=0, TIMES3=1, TIMES7=2, TIMES8=3;
    11. reg [1:0] state;
    12. reg [7:0] d_r;
    13. always @(posedge clk or negedge rst) begin
    14. if(~rst) begin
    15. input_grant <= 1'b0;
    16. out <= 11'b0;
    17. state <= TIMES1;
    18. end
    19. else begin
    20. case(state)
    21. TIMES1: begin
    22. input_grant <= 1'b1;
    23. out <= d;
    24. state <= TIMES3;
    25. d_r <= d;
    26. end
    27. TIMES3: begin
    28. input_grant <= 1'b0;
    29. out <= (d_r<<1) + d_r;
    30. state <= TIMES7;
    31. d_r <= d_r;
    32. end
    33. TIMES7: begin
    34. input_grant <= 1'b0;
    35. out <= (d_r<<3) - d_r;
    36. state <= TIMES8;
    37. d_r <= d_r;
    38. end
    39. TIMES8: begin
    40. input_grant <= 1'b0;
    41. out <= d_r<<3;
    42. state <= TIMES1;
    43. d_r <= d_r;
    44. end
    45. default: begin
    46. input_grant <= 1'b0;
    47. out <= 11'b0;
    48. state <= TIMES1;
    49. d_r <= 8'b0;
    50. end
    51. endcase
    52. end
    53. end
    54. //*************code***********//
    55. endmodule

    疑惑:解法四和五中后面三个状态d_temp和d_r为什么不能赋值为d?

    Testbench

    1. `timescale 1ns/1ns
    2. module testbench();
    3. reg clk=0;
    4. always #1 clk = ~clk; // Create clock with period=10
    5. // parameter daclare
    6. parameter T = 2;
    7. // reg declare
    8. reg rst ;
    9. reg [7:0] d;
    10. wire [10:0] out;
    11. wire input_grant;
    12. initial begin
    13. rst = 1'b0;
    14. d = 8'd143;
    15. #T rst = 1'b1;
    16. #(3*T) d = 8'd7;
    17. #(5*T) d = 8'd6;
    18. #T d = 8'd6;
    19. #T d = 8'd128;
    20. #T d = 8'd129;
    21. #(5*T) $finish;
    22. end
    23. // instantiate
    24. multi_sel u_multi_sel(
    25. .d(d),
    26. .clk(clk),
    27. .rst(rst),
    28. .input_grant(input_grant),
    29. .out(out)
    30. );
    31. //end
    32. initial begin
    33. $dumpfile("out.vcd");
    34. // This will dump all signal, which may not be useful
    35. //$dumpvars;
    36. // dumping only this module
    37. //$dumpvars(1, testbench);
    38. // dumping only these variable
    39. // the first number (level) is actually useless
    40. $dumpvars(0, testbench);
    41. end
    42. endmodule

     

  • 相关阅读:
    自学(网络安全)黑客——高效学习2024
    Python 算法高级篇:归并排序的优化与外部排序
    【二分查找】Leetcode 33. 搜索旋转排序数组【中等】
    小学生Python编程 ----- 打鸭子
    HTTP状态码及其描述
    懵了?一夜之间,Rust 审核团队突然集体辞职
    Python生成器
    Allegro阻抗分析指导书
    MySQL 8.0中查询缓存的废弃与原因分析
    DeepLab V2学习笔记
  • 原文地址:https://blog.csdn.net/mxh3600/article/details/126393963