乘法器的verilog HDL设计汇总
1、移位相加乘法器的设计:
其大致原理如下:
从被乘数的最低位开始判断,若为1,则乘数左移i(i=0,1...(WIDTH-1))位后,与上一次和相加;若为0,则乘数左移i位后,以0相加。直至被乘数的最高位。
优点:占用的资源较少,在低速信号处理中有广泛的应用 。
缺点:串行乘法器的速度比较慢,一个结果输出需要花费多个时钟周期,在高位宽乘法运算中尤为明显。Verilog HDL代码如下:
1. //移位相加乘法器的verilog HDL代码
2. module multi_Mov_Add(a,b,outcome);
3. parameter size = 8;
4. input [size - 1 : 0] a, b; //a,b为乘法器的两个输入
5. output [2*size - 1 : 0] outcome;
6. reg [2*size - 1 : 0] outcome;
7. integer i;
8.
9. always @ (a or b)
10. begin
11. outcome = 4'b0;
12. for(i = 0; i < size; i = i + 1) //用于移位
13. begin
14. if(b[i] == 1) //如果被乘数为1,则移位相加
15. begin
16. outcome = outcome + (a<<i);
17. end
18. end
19. end
20. endmodule
2、串行乘法器设计:
其状态图如下:
设计verilog HDL 代码如下:
1. module multi_CX(clk, x, y, result);
2.
3. input clk; //时钟信号
4. input [7:0] x, y; //x为乘数,y为被乘数
5. output [15:0] result; //运算结果
6.
7. reg [15:0] result;
8.
9. parameter s0 = 0, s1 = 1, s2 = 2; //状态
10. reg [2:0] count = 0;
11. reg [1:0] state = 0; //状态变量赋初值
12. reg [15:0] P, T; //P为运算结果的中间变量,T为乘数的中间变量
13. reg [7:0] y_reg; //y_reg为被乘数的中间变量
14.
15. always @(posedge clk) begin //时钟上升沿到达时,运行下面的语句
16. case (state) //状态S0为初始状态,从初始状态开始
17. s0: begin
18. count <= 0; //计算变量初值
19. P <= 0; //结果变量清零
20. y_reg <= y; //被乘数赋初值
21. T <= { {8{1'b0}}, x}; //乘数赋初值
22. state <= s1; //进入下一个状态
23. end
24. s1: begin //S1状态
25. if(count == 3'b111) //计数为3'b111,即7时,进入结束状态
26. state <= s2;
27. else begin //未进入结束状态
28. if(y_reg[0] == 1'b1) //被乘数末尾位为1时
29. P <= P + T; //中间结果加一次乘数
30. else //否则中间结果不变
31. P <= P;
32. y_reg <= y_reg >> 1; //被乘数右移一位,倒数第二位移到末尾
33. T <= T << 1; //乘加一次后,被乘数左移一位,这里从运算过程中可以看出
34. count <= count + 1; //count是为了统计运行一次乘法需要多少个时钟周期
35. state <= s1;
36. end
37. end
38. s2: begin
39. result <= P; //结束状态时,中间结果赋值给最终结果
40. state <= s0; //为下一次运算准备
41. end
42. default: ;
43. endcase
44. end
45.
46. endmodule
缺点:计算一次乘法需要8个周期,因此可以看出串行乘法器速度比较慢,时延大。
优点:该乘法器所占用的资源是所有类型乘法器中最少的,在低速的信号处理中有广泛的使用。
3、流水线乘法器
乘法器采用多级流水线的形式,将相邻的两个部分乘积结果再加到最终的输出乘积上,即排成一个二叉树形式的结构。(死磕下面的代码)
其verilog HDL设计如下:
1. module multi_4bits_pipelining(mul_a, mul_b, clk, rst_n, mul_out);
2.
3. input [3:0] mul_a, mul_b; //乘数与被乘数
4. input clk; //时钟信号
5. input rst_n; //复位信号
6. output [7:0] mul_out; //结果变量
7. reg [7:0] mul_out;
8. reg [7:0] stored0; //stored0,...stored3用来存逐位相乘的中间结果
9. reg [7:0] stored1;
10. reg [7:0] stored2;
11. reg [7:0] stored3;
12. reg [7:0] add01; //中间结果变量
13. reg [7:0] add23;
14. always @(posedge clk or negedge rst_n) begin
15. if(!rst_n) begin //复位信号有效
16. mul_out <= 0;
17. stored0 <= 0;
18. stored1 <= 0;
19. stored2 <= 0;
20. stored3 <= 0;
21. add01 <= 0;
22. add23 <= 0;
23. end
24. else begin
25. stored0 <= mul_b[0] ? {4'b0, mul_a} : 8'b0; //如果被乘数倒数第一位不为零,则与乘数相乘结果为{4'b0,mul_a}
26. stored1 <= mul_b[1] ? {3'b0, mul_a, 1'b0} : 8'b0; //如果被乘数倒数第二位不为零,则与乘数相乘结果为{3'b0,mul_a,1'b0}
27. stored2 <= mul_b[2] ? {2'b0, mul_a, 2'b0} : 8'b0; //同上
28. stored3 <= mul_b[3] ? {1'b0, mul_a, 3'b0} : 8'b0; //同上
29. add01 <= stored1 + stored0;
30. add23 <= stored3 + stored2;
31. mul_out <= add01 + add23; //最终结果
32. end
33. end
34. endmodule
Verilog HDL代码我都加上了注释,增加了可读性,我认为这是代码起码的尊严,也是对阅读者起码的尊重。原理就不多赘述,很简单,读懂代码即可了解。
4、Wallace树乘法器(重磅呈现)
在乘法器的设计中采用树形乘法器,可以减少关键路径和所需的加法器单元数目,Wallace树乘法器就是其中的一种。下面以一个4*4位乘法器为例介绍Wallace