赞
踩
在硬件设计中,乘法器是非常重要的一个器件,乘法器的种类繁多,常见的有并行乘法器、移位相加乘法器和查找表乘法器,并行乘法器的实现非常简单,在Verilog中只需要通过assign dout=a*b实现即可,若要进行有符号的乘法,只需在变量前加上$signed。查找表乘法器实际上是先将乘法的计算结果提前算好,这样就可以在计算时通过查表的方式直接得到结果,一般用于位宽较小的情况。移位相加乘法器是一种耗费较少资源的算法,其思想是将乘法转化为加法和移位运算,不足之处是计算过程的延时较长,一般用于对性能要求不高的场合。
移位相加乘法器的原理:
以a=1011和b=1001相乘为例(均为无符号数)
1.b的第0位为1,所以
result=result+a<<0;
2.b的第二位为0,result保持不变
3.b的第三位也为0,保持不变
4.b的第四位为1,则
result=result+a<<3,得到最终的计算结果
可以看到,W位宽的无符号乘法器,需要W个周期才能计算完成。
下面是无符号乘法的Verilog实现:
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2022/03/18 21:37:17 // Design Name: // Module Name: demo // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module demo ( input logic clk, input logic rst_n, input logic vld, input logic [7:0] dina, input logic [7:0] dinb, output logic [15:0] dout, output logic ovld ); logic [7:0] reg_a; //被乘数 logic [7:0] reg_b; //乘数 logic [15:0] psum; logic [15:0] T; logic busy; logic one_bit; logic [3:0] cnt; // always_ff@(posedge clk,negedge rst_n) if(~rst_n) begin reg_a<=0; end else if(vld) begin reg_a<=dina; end always_ff@(posedge clk) if(vld) psum<=0; else if(busy&&one_bit) // psum<=psum+T; else psum<=psum; //T always_ff@(posedge clk) if(vld) T<=dina; else if(busy) T<=(T<<1); //reg_b always_ff@(posedge clk) if(vld) reg_b<=dinb; else if(busy) reg_b<={1'b0,reg_b[7:1]}; //one_bit assign one_bit=reg_b[0]; //busy always_ff@(posedge clk) if(vld) busy<=1; else if(busy&&cnt==7) busy<=0; //cnt always_ff@(posedge clk) if(vld) cnt<=0; else if(busy) cnt<=cnt+1; //dout assign dout=psum; //ovld always_ff@(posedge clk,negedge rst_n) if(~rst_n) ovld<=0; else if(busy&&cnt==7) ovld<=1; else ovld<=0; endmodule
经过仿真,发现上述代码功能正确。
我们通过调用无符号乘法器,来实现有符号乘法。具体方法为
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2022/03/23 13:08:23 // Design Name: // Module Name: signed_mult // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module signed_mult( input logic clk, input logic rst_n, input logic vld, input logic [7:0] dina, input logic [7:0] dinb, output logic [15:0] dout, output logic ovld ); logic sign_a; logic sign_b; logic sign_o; logic [7:0] unsigned_a; logic [7:0] unsigned_b; logic [15:0] unsigned_o; assign sign_a=dina[7]; assign sign_b=dinb[7]; assign sign_o=sign_a^sign_b; //1为负,0为正 assign unsigned_a=(sign_a==1'b1)?~dina+1:dina; assign unsigned_b=(sign_b==1'b1)?~dinb+1:dinb; assign dout=(sign_o==1'b1)?~unsigned_o+1:unsigned_o; // demo unsigned_mult ( .clk(clk), .rst_n(rst_n), .vld(vld), .dina(unsigned_a), .dinb(unsigned_b), .dout(unsigned_o), .ovld(ovld) ); endmodule
以下是仿真波形,测试了a,b均为正,均为负数,一正一负四种情况,结果均正确:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。