• 并行乘法器,也就是用乘法运算符实现,下面的代码实现8bit无符号数的乘法。

代码:

 1 module mult_parrell(rst_n,
 2                             clk,
 3                             a,
 4                             b,
 5                             p
 6                                  );
 7 parameter DATA_SIZE = 8;
 8
 9 input rst_n;
10 input clk;
11 input [DATA_SIZE - 1 : 0] a;
12 input [DATA_SIZE - 1 : 0] b;
13
14 output [2*DATA_SIZE - 1 : 0] p;
15
16 reg [DATA_SIZE - 1 : 0] a_r;
17 reg [DATA_SIZE - 1 : 0] b_r;
18
19 wire [2*DATA_SIZE - 1 : 0] p_tmp;
20 reg [2*DATA_SIZE - 1 : 0] p;
21
22 //输入数据打一拍
23 always@(posedge clk)
24     if(!rst_n)
25         begin
26             a_r <= 8'd0;
27             b_r <= 8'd0;
28         end
29     else
30         begin
31             a_r <= a;
32             b_r <= b;
33         end
34
35 assign p_tmp = a*b;  //只能做无符号数的相乘,若要做有符号数乘法,需将数据声明为signed类型
36
37 //输出数据打一拍
38 always@(posedge clk)
39     if(!rst_n)
40         begin
41             p <= 16'd0;
42         end
43     else
44         begin
45             p <= p_tmp;
46         end
47
48 endmodule


  • 移位相加乘法器,下面的代码可实现8bit有符号数的相乘,注意符号扩展以及MSB位的处理:

//输入数据取反  
assign a_r_inv = ~a_r + 1;

assign a_shift0 = b_r[0] ? {{8{a_r[7]}},a_r} : 0;
assign a_shift1 = b_r[1] ? {{7{a_r[7]}},a_r,1'b0} : 0;
assign a_shift2 = b_r[2] ? {{6{a_r[7]}},a_r,2'b0} : 0;
assign a_shift3 = b_r[3] ? {{5{a_r[7]}},a_r,3'b0} : 0;
assign a_shift4 = b_r[4] ? {{4{a_r[7]}},a_r,4'b0} : 0;
assign a_shift5 = b_r[5] ? {{3{a_r[7]}},a_r,5'b0} : 0;
assign a_shift6 = b_r[6] ? {{2{a_r[7]}},a_r,6'b0} : 0;
assign a_shift7 = b_r[7] ? {{1{a_r_inv[7]}},a_r_inv,7'b0} : 0;  //被乘数为无符号数时,特别处理

代码:

 1 module mult_shift_add(rst_n,
 2                                 clk,
 3                                 a,
 4                                 b,
 5                                 p
 6                                      );
 7 parameter DATA_SIZE = 8;
 8
 9 input rst_n;
10 input clk;
11 input [DATA_SIZE - 1 : 0] a;
12 input [DATA_SIZE - 1 : 0] b;
13
14 output [2*DATA_SIZE - 2 : 0] p;
15
16 //输入数据打一个时钟节拍
17 reg [DATA_SIZE - 1 : 0] a_r;
18 reg [DATA_SIZE - 1 : 0] b_r;
19
20 //输入数据取反
21 wire [DATA_SIZE - 1 : 0] a_r_inv;
22
23 //输入数据移位
24 wire [2*DATA_SIZE - 1 : 0] a_shift0;
25 wire [2*DATA_SIZE - 1 : 0] a_shift1;
26 wire [2*DATA_SIZE - 1 : 0] a_shift2;
27 wire [2*DATA_SIZE - 1 : 0] a_shift3;
28 wire [2*DATA_SIZE - 1 : 0] a_shift4;
29 wire [2*DATA_SIZE - 1 : 0] a_shift5;
30 wire [2*DATA_SIZE - 1 : 0] a_shift6;
31 wire [2*DATA_SIZE - 1 : 0] a_shift7;
32
33 //输出数据打一个时钟节拍
34 wire [2*DATA_SIZE - 1 : 0] p_tmp;
35 reg [2*DATA_SIZE - 1 : 0] p;
36
37 //输入数据打一个时钟节拍
38 always@(posedge clk)
39     if(!rst_n)
40         begin
41             a_r <= 8'd0;
42             b_r <= 8'd0;
43         end
44     else
45         begin
46             a_r <= a;
47             b_r <= b;
48         end
49 //输入数据取反
50 assign a_r_inv = ~a_r + 1;
51
52 //输入数据移位,注意符号扩展,不仅仅是最高位扩展
53 //对每一个bit都需扩展
54 assign a_shift0 = b_r[0] ? {{8{a_r[7]}},a_r} : 0;
55 assign a_shift1 = b_r[1] ? {{7{a_r[7]}},a_r,1'b0} : 0;
56 assign a_shift2 = b_r[2] ? {{6{a_r[7]}},a_r,2'b0} : 0;
57 assign a_shift3 = b_r[3] ? {{5{a_r[7]}},a_r,3'b0} : 0;
58 assign a_shift4 = b_r[4] ? {{4{a_r[7]}},a_r,4'b0} : 0;
59 assign a_shift5 = b_r[5] ? {{3{a_r[7]}},a_r,5'b0} : 0;
60 assign a_shift6 = b_r[6] ? {{2{a_r[7]}},a_r,6'b0} : 0;
61 assign a_shift7 = b_r[7] ? {{1{a_r_inv[7]}},a_r_inv,7'b0} : 0;  //被乘数为无符号数时,特别处理
62
63 assign p_tmp = a_shift0 + a_shift1 + a_shift2 + a_shift3 + a_shift4
64                     + a_shift5 + a_shift6 + a_shift7;
65
66 always@(posedge clk)
67     if(!rst_n)
68         begin
69             //p <= 16'd0;
70             p <= 15'd0;
71         end
72     else
73         begin
74             //p <= p_tmp[15:0];
75             p <= p_tmp[14:0];
76         end
77
78 endmodule

testbench:

 1 module mult_shift_add_tb;
 2
 3     // Inputs
 4     reg rst_n;
 5     reg clk;
 6     reg [7:0] a;
 7     reg [7:0] b;
 8
 9     // Outputs
10     wire [14:0] p;
11
12     // Instantiate the Unit Under Test (UUT)
13     mult_shift_add uut (
14         .rst_n(rst_n),
15         .clk(clk),
16         .a(a),
17         .b(b),
18         .p(p)
19     );
20
21     parameter CLK_PERIOD = 10;
22
23     initial begin
24         rst_n = 0;
25         clk = 0;
26
27         #100;
28         rst_n = 1;
29     end
30
31     always #(CLK_PERIOD/2) clk = ~clk;
32
33     always@(posedge clk)
34     if(!rst_n)
35         begin
36             a = 8'd0;
37             b = 8'd0;
38         end
39     else
40         begin
41             a = a + 1;
42             b = b - 1;
43         end
44
45 endmodule

ISIM仿真结果:


  • 移位相加乘法器树:

assign p_tmp = a_shift0 + a_shift1 + a_shift2 + a_shift3 + a_shift4 + a_shift5 + a_shift6 + a_shift7;

换为:

assign sum_01 = a_shift0 + a_shift1;
assign sum_23 = a_shift2 + a_shift3;
assign sum_45 = a_shift4 + a_shift5;
assign sum_67 = a_shift6 + a_shift7;

assign sum_0123 = sum_01 + sum_23;
assign sum_4567 = sum_45 + sum_67;

assign p_tmp = sum_0123 + sum_4567;

就成为乘法器树。

原理是通过切断关键路径,提高电路的运行频率。


  • LUT乘法,下面的代码利用2bit的LUT实现4bit无符号数的乘法。

代码:

 1 module mult_lut(rst_n,
 2                         clk,
 3                         a,
 4                         b,
 5                         p
 6                              );
 7
 8 parameter DATA_SIZE = 4;
 9
10 input rst_n;
11 input clk;
12 input [DATA_SIZE - 1 : 0] a;
13 input [DATA_SIZE - 1 : 0] b;
14
15 output [2*DATA_SIZE - 1 : 0] p;
16
17 //输入数据打一个时钟节拍
18 reg [DATA_SIZE - 1 : 0] a_r;
19 reg [DATA_SIZE - 1 : 0] b_r;
20
21 //输入数据拆半的乘积
22
23 wire [DATA_SIZE - 1 : 0] p_tmp00;
24 wire [DATA_SIZE - 1 : 0] p_tmp01;
25
26 wire [DATA_SIZE - 1 : 0] p_tmp10;
27 wire [DATA_SIZE - 1 : 0] p_tmp11;
28
29 //reg [2*DATA_SIZE - 1 : 0] sum01;
30 //reg [2*DATA_SIZE - 1 : 0] sum23;
31
32 wire [2*DATA_SIZE - 1 : 0] p_tmp;
33 reg [2*DATA_SIZE - 1 : 0] p;
34
35 //输入数据打一个时钟节拍
36 always@(posedge clk)
37     if(!rst_n)
38         begin
39             a_r <= 4'd0;
40             b_r <= 4'd0;
41         end
42     else
43         begin
44             a_r <= a;
45             b_r <= b;
46         end
47
48 mult_lut_2bit u0_mult_lut_2bit (
49     .rst_n(rst_n),
50     .clk(clk),
51     .a(a_r[1:0]),
52     .b(b_r[1:0]),
53     .p(p_tmp00)
54     );
55
56 mult_lut_2bit u1_mult_lut_2bit (
57     .rst_n(rst_n),
58     .clk(clk),
59     .a(a_r[1:0]),
60     .b(b_r[3:2]),
61     .p(p_tmp01)
62     );
63
64 mult_lut_2bit u2_mult_lut_2bit (
65     .rst_n(rst_n),
66     .clk(clk),
67     .a(a_r[3:2]),
68     .b(b_r[1:0]),
69     .p(p_tmp10)
70     );
71
72 mult_lut_2bit u3_mult_lut_2bit (
73     .rst_n(rst_n),
74     .clk(clk),
75     .a(a_r[3:2]),
76     .b(b_r[3:2]),
77     .p(p_tmp11)
78     );
79
80 //assign p_tmp = p_tmp00 + p_tmp01<<2 + p_tmp10<<2 + p_tmp11<<4; //不能直接用移位操作符实现移位
81 assign p_tmp = p_tmp00 + {p_tmp01,2'b00} + {p_tmp10,2'b00} + {p_tmp11,4'b00};
82 //assign sum01 = p_tmp00 + p_tmp01<<2;
83 //assign sum23 = p_tmp10<<2 + p_tmp11<<4;
84
85 //assign p_tmp = sum01 + sum23;
86
87 always@(posedge clk)
88     if(!rst_n)
89         begin
90             p <= 8'd0;
91         end
92     else
93         begin
94             p <= p_tmp;
95         end
96
97 endmodule

2bitLUT乘法器:

 1 module mult_lut_2bit(rst_n,
 2                             clk,
 3                             a,
 4                             b,
 5                             p
 6                                  );
 7
 8 parameter DATA_SIZE = 2;
 9
10 input rst_n;
11 input clk;
12 input [DATA_SIZE - 1 : 0] a;
13 input [DATA_SIZE - 1 : 0] b;
14
15 output [2*DATA_SIZE - 1 : 0] p;
16
17 //输入数据打一个时钟节拍
18 reg [DATA_SIZE - 1 : 0] a_r;
19 reg [DATA_SIZE - 1 : 0] b_r;
20
21 //输出数据打一个时钟节拍
22 reg [2*DATA_SIZE - 1 : 0] p_tmp;
23 reg [2*DATA_SIZE - 1 : 0] p;
24
25 //输入数据打一个时钟节拍
26 always@(posedge clk)
27     if(!rst_n)
28         begin
29             a_r <= 8'd0;
30             b_r <= 8'd0;
31         end
32     else
33         begin
34             a_r <= a;
35             b_r <= b;
36         end
37
38 always@(*)
39     begin
40         case({a_r,b_r})
41             4'b0000 : p_tmp = 4'b0000;
42             4'b0001 : p_tmp = 4'b0000;
43             4'b0010 : p_tmp = 4'b0000;
44             4'b0011 : p_tmp = 4'b0000;
45             4'b0100 : p_tmp = 4'b0000;
46             4'b0101 : p_tmp = 4'b0001;
47             4'b0110 : p_tmp = 4'b0010;
48             4'b0111 : p_tmp = 4'b0011;
49
50             4'b1000 : p_tmp = 4'b0000;
51             4'b1001 : p_tmp = 4'b0010;
52             4'b1010 : p_tmp = 4'b0100;
53             4'b1011 : p_tmp = 4'b0110;
54             4'b1100 : p_tmp = 4'b0000;
55             4'b1101 : p_tmp = 4'b0011;
56             4'b1110 : p_tmp = 4'b0110;
57             4'b1111 : p_tmp = 4'b1001;
58         endcase
59     end
60
61 always@(posedge clk)
62     if(!rst_n)
63         begin
64             p <= 4'd0;
65         end
66     else
67         begin
68             p <= p_tmp[3:0];
69         end
70
71 endmodule

仿真结果与并行乘法一致。

上面的LUT乘法器求p_tmp的组合逻辑时延比较大,可以通过加入寄存器的方法进行拆分,将

assign p_tmp = p_tmp00 + {p_tmp01,2'b00} + {p_tmp10,2'b00} + {p_tmp11,4'b00};

替换为:

always@(posedge clk)
 if(!rst_n)
  begin
   sum01 <= 8'd0;
   sum23 <= 8'd0;
  end
 else
  begin  
   sum01 <= p_tmp00 + {p_tmp01,2'b00};
   sum23 <= {p_tmp10,2'b00} + {p_tmp11,4'b00};
  end
  
assign p_tmp = sum01 + sum23;

这样就分割了组合逻辑,切断关键路径,从而提高电路的运行速度。虽然加入寄存器,对中间结果缓存,使得乘法器的输出对于输入的延时增加,但是提高了电路的整体运行频率,这是更重要的。

如下:

  1 module mult_lut_reg(rst_n,
  2                         clk,
  3                         a,
  4                         b,
  5                         p
  6                              );
  7
  8 parameter DATA_SIZE = 4;
  9
 10 input rst_n;
 11 input clk;
 12 input [DATA_SIZE - 1 : 0] a;
 13 input [DATA_SIZE - 1 : 0] b;
 14
 15 output [2*DATA_SIZE - 1 : 0] p;
 16
 17 //输入数据打一个时钟节拍
 18 reg [DATA_SIZE - 1 : 0] a_r;
 19 reg [DATA_SIZE - 1 : 0] b_r;
 20
 21 //输入数据拆半的乘积
 22
 23 wire [DATA_SIZE - 1 : 0] p_tmp00;
 24 wire [DATA_SIZE - 1 : 0] p_tmp01;
 25
 26 wire [DATA_SIZE - 1 : 0] p_tmp10;
 27 wire [DATA_SIZE - 1 : 0] p_tmp11;
 28
 29 reg [2*DATA_SIZE - 1 : 0] sum01;
 30 reg [2*DATA_SIZE - 1 : 0] sum23;
 31
 32 wire [2*DATA_SIZE - 1 : 0] p_tmp;
 33 reg [2*DATA_SIZE - 1 : 0] p;
 34
 35 //输入数据打一个时钟节拍
 36 always@(posedge clk)
 37     if(!rst_n)
 38         begin
 39             a_r <= 4'd0;
 40             b_r <= 4'd0;
 41         end
 42     else
 43         begin
 44             a_r <= a;
 45             b_r <= b;
 46         end
 47
 48 mult_lut_2bit u0_mult_lut_2bit (
 49     .rst_n(rst_n),
 50     .clk(clk),
 51     .a(a_r[1:0]),
 52     .b(b_r[1:0]),
 53     .p(p_tmp00)
 54     );
 55
 56 mult_lut_2bit u1_mult_lut_2bit (
 57     .rst_n(rst_n),
 58     .clk(clk),
 59     .a(a_r[1:0]),
 60     .b(b_r[3:2]),
 61     .p(p_tmp01)
 62     );
 63
 64 mult_lut_2bit u2_mult_lut_2bit (
 65     .rst_n(rst_n),
 66     .clk(clk),
 67     .a(a_r[3:2]),
 68     .b(b_r[1:0]),
 69     .p(p_tmp10)
 70     );
 71
 72 mult_lut_2bit u3_mult_lut_2bit (
 73     .rst_n(rst_n),
 74     .clk(clk),
 75     .a(a_r[3:2]),
 76     .b(b_r[3:2]),
 77     .p(p_tmp11)
 78     );
 79
 80 always@(posedge clk)
 81     if(!rst_n)
 82         begin
 83             sum01 <= 8'd0;
 84             sum23 <= 8'd0;
 85         end
 86     else
 87         begin
 88             sum01 <= p_tmp00 + {p_tmp01,2'b00};
 89             sum23 <= {p_tmp10,2'b00} + {p_tmp11,4'b00};
 90         end
 91
 92 assign p_tmp = sum01 + sum23;
 93
 94 always@(posedge clk)
 95     if(!rst_n)
 96         begin
 97             p <= 8'd0;
 98         end
 99     else
100         begin
101             p <= p_tmp;
102         end
103
104 endmodule

乘法器的verilog实现(并行、移位相加、查找表)相关推荐

  1. 数字电路基础知识——组合逻辑电路之乘法器的设计(一)—— 并行、移位相加、加法树、查找表乘法器

    数字电路基础知识--乘法器的设计(一)-- 并行.移位相加.加法树.查找表 乘法器的设计主要应用在数字信号处理和数字通信,本节主要介绍乘法器的四种实现方法.使用并行乘法器.移位相加乘法器.查找表乘法器 ...

  2. 8位移位相加乘法器-Verilog

    Verilog 前言 一.移位相加乘法器如何实现? 二.使用步骤 前言 用verilog编写8位乘法器,采用移位相加的办法,最后输出16位结果 写的时候去掉了注释,现在自己也看不懂了,哈哈哈 一.移位 ...

  3. (88)FPGA乘法器设计(移位相加乘法器)

    (88)FPGA乘法器设计(移位相加乘法器) 1 文章目录 1)文章目录 2)FPGA入门与提升课程介绍 3)FPGA简介 4)FPGA乘法器设计(移位相加乘法器) 5)技术交流 6)参考资料 2 F ...

  4. (147)FPGA面试题-Verilog移位相加实现乘法(二)

    1.1 FPGA面试题-Verilog移位相加实现乘法(二) 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA面试题-Verilog移位相加实现乘法(二): 5) ...

  5. FPGA学习之路—应用程序—原码二位乘法器及Verilog代码分析

    FPGA学习之路--原码二位乘法器及Verilog代码分析 原理 原码乘法可以分为原码一位乘和原码二位乘,两者在实现规则上大同小异.原码一位乘每次判断乘数的最低位,对被乘数和部分积进行相应操作.而原码 ...

  6. (20)Verilog HDL并行块:fork-join

    (20)Verilog HDL并行块:fork-join 1.1 目录 1)目录 2)FPGA简介 3)Verilog HDL简介 4)Verilog HDL并行块:fork-join 5)结语 1. ...

  7. Quarter square 查找表乘法器,手动建立rom

    建立一个C的范围为0~255,内容是(C)2/4的查表 占用256个存储空间,但可以计算出+-127的两个数之积.传统算法需要至少127×127个存储空间. 查找表模块的建立: module lut_ ...

  8. sin查找表 matlab,利用Xilinx中的ROM构造查找表来计算sin和cos的方法探讨

    1.使用matlab制作.coe文件 查找表的构造 构造256点的正余弦表 exp(-j*2*pi*(0:255)/256),分别得到 cos和sin的查找表 matlab代码: 求sin fid = ...

  9. 基于查找表的正弦波生成的研究

    本文原文为:<A Study on Look-up TableBased Sine Wave Generation> Abstract 正弦波发生器广泛应用于通信.控制.生物医学电子和音乐 ...

最新文章

  1. OpenCV | OpenCV将图像转换成黑白图像(二进制)
  2. 【unity3d study ---- 麦子学院】---------- unity3d常用组件及分析 ---------- 组件的使用...
  3. ireport怎么套打_阴阳师:当前版本道馆突破怎么打?九套阵容让你成为道馆小能手...
  4. leetcode算法题--最长的斐波那契子序列的长度
  5. Matlab图像处理创新实践-实验3【图像锐化】
  6. maven工程如何引用css和js文件
  7. nginx连接uwsgi使用web.py框架构造pythonweb项目
  8. 刷排名优优软件_QQ群拉人了,排名后置了?申诉案例
  9. django-用户文件的上传-后台上传
  10. 如何设置打印的时候不加上页面链接_电子面单史上最全打印问题集合--【拼点管家软件】...
  11. First-chance exception in KERNEL32.DLL 0xE06D7363 Microsoft C++ Exception
  12. 密码学---攻击类型
  13. app播放无声音乐实现app后台运行
  14. php查询mysql显示在html表格中_php – 在网页上的HTML表格中显示MySQL数据库表中的值...
  15. 如何用记事本写Java程序
  16. 窗口------菜单条 菜单 菜单项
  17. redhat linux 7.2系统安装详细过程
  18. 扫盲加扯淡——网友随笔画之云计算
  19. 微信小程序【网易云音乐实战】(第五篇 转发分享、每日推荐、音乐播放、页面通信npm包、进度条、全局数据)
  20. linux 网卡 mac 配置文件,Linux下更改网卡的MAC物理地址

热门文章

  1. python3.7.4+Django2.2.6一直提示path404报错问题:“Using the URLconf defined in XXX.urls, Django tried this...”
  2. 【CV实战】年轻人的第一个GAN项目应该是什么样的(Pytorch框架)?
  3. 速卖通2022新开店入驻流程及费用
  4. 全球及中国纳米材料行业竞争格局及发展规模预测报告2021年版
  5. 中国工业节能减排产业项目盈利模式及投资风险预警报告2021-2027年
  6. linux面试题中的简答题,Linux面试题(简答题部分)
  7. PHP复习第二天-变量
  8. 20144303 20145239 实验三 实时系统的移植
  9. 20145324 20145325 《信息安全系统设计基础》实验三
  10. mac os系统使用Visual Studio Code打开浏览器查看HTML文件