相关阅读
数字信号处理作为微处理器的核心部件,是决定着总体处理器性能的因素之一,而数字乘法器是最常见的一种数字信号处理电路。通常情况下,乘法器是数字系统中制约运算速度的关键路径。本系列将从基本的乘法器入手,再逐渐深入,探究了各种优化乘法器在体系结构,乘法算法等方面的优化策略。
作为最基本的组合逻辑乘法器,阵列乘法器(Array multiplier)虽然已不太常用,但在某些对性能要求不高的应用场景下,还能见到它的使用。
为了简便起见,本文考虑两个四位二进制数A和B相乘,其中A为被乘数,B为乘数,先产生部分积,然后使用加法器累加这些部分积,总体规划如表1所示。从乘数B的最低位B0开始,依次与被乘数A的各位A0、A1、A2、A3相与(乘)形成4组16个部分积项目,分组是根据乘数B的位而言,如所有有B0项目的是第0组部分积。然后每一组根据分组的不同,移动到乘数B每一位对应的位置,最后将部分积累加。注意,在部分积的累加过程中,可能会出现来自低位的进位,此时需要使用全加器,否则使用半加器即可。
表1 无符号4位二进制乘法规划
A3 B3 | A2 B2 | A1 B1 | A0 B0 | 被乘数 乘数 | 资源配置 | ||||
A3B1 C12 | A3B0 A2B1 C11 | A2B0 A1B1 C10 | A1B0 A0B1 | A0B0 | 部分积0 部分积1 低位进位 | 第1行加法器 | |||
C13 A3B2 C22 | S13 A2B2 C21 | S12 A1B2 C20 | S11 A0B2 | S10 | S00 | 第1行和 部分积2 低位进位 | 第2行乘法器 | ||
C23 A3B3 C32 | S23 A2B3 C31 | S22 A1B3 C30 | S21 A0B3 | S20 | 第2行和 部分积3 低位进位 | 第3行乘法器 | |||
C33 | S33 | S32 | S31 | S30 | 第3行和 | ||||
C33 | S33 | S32 | S31 | S30 | S20 | S10 | S00 | 最终结果 | |
27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 权重 |
4位乘法器的组合逻辑结构如图1所示,可以看出这种结构十分规则,大多是由加法器和与门构成的基本单元复制得到,但由红线和紫线描绘的路径可以看出其中存在较长的加法器链(即可能的关键路径),换个角度,结构中使用了3组行波进位加法器(Ripple Carry Adder)或者说串行进位加法器(Serial Carry Adder)、进位传播加法器(Carry Propagate Adder),这种乘法器的优点在于可复用性和可配置性强,非常利于集成电路制造,但缺点是进位操作的关键路径较长,控制组合电路输入输出的时钟周期需要与电路中的最长路径相适应。为了提高性能,可以在这种结构中植入流水线来获得更大的数据吞吐量,这是对组合逻辑优化的一个常见方法。具体的Verilog代码实现见附录,Modelsim软件仿真截图如图2所示。使用Synopsis的综合工具Design Compiler综合的结果如图3所示,综合使用了0.13μm工艺库。
图1 基本单元构成的阵列乘法器
图2 阵列乘法器仿真结果
图3 阵列乘法器综合结果
在Design Compiler中使用report_timing命令,可以得到关键路径的延迟,如图4所示,使用report_area命令,报告所设计电路的面积占用情况,如图5所示
图4 阵列乘法器关键路径报告
图5 阵列乘法器面积报告
阵列乘法器的Verilog代码如下所示。
module Array_multiplier(
input [3:0] A,
input [3:0] B,
output [7:0] Sum
);
wire [3:0]partial_product[3:0];
// 产生部分积
assign partial_product[0] = B[0]?A:0;
assign partial_product[1] = B[1]?A:0;
assign partial_product[2] = B[2]?A:0;
assign partial_product[3] = B[3]?A:0;
// 中间进位
wire C10, C11, C12, C13;
wire C20, C21, C22, C23;
wire C30, C31, C32, C33;
// 中间和
wire S11, S12, S13;
wire S21, S22, S23;
// 第一行加法器
assign Sum[0] = partial_product[0][0];
Adder_half Adder_half_0(partial_product[0][1], partial_product[1][0], Sum[1], C10);
Adder Adder_0(partial_product[0][2], partial_product[1][1], C10, S11, C11);
Adder Adder_1(partial_product[0][3], partial_product[1][2], C11, S12, C12);
Adder_half Adder_half_1(partial_product[1][3], C12, S13, C13);
// 第二行乘法器
Adder_half Adder_half_2(S11, partial_product[2][0], Sum[2], C20);
Adder Adder_2(S12, partial_product[2][1], C20, S21, C21);
Adder Adder_3(S13, partial_product[2][2], C21, S22, C22);
Adder Adder_4(C13, partial_product[2][3], C22, S23, C23);
// 第三行加法器
Adder_half Adder_half_3(S21, partial_product[3][0], Sum[3], C30);
Adder Adder_5(S22, partial_product[3][1], C30, Sum[4], C31);
Adder Adder_6(S23, partial_product[3][2], C31, Sum[5], C32);
Adder Adder_7(C23, partial_product[3][3], C32, Sum[6], Sum[7]);
endmodule
// 半加器
module Adder_half(
input Add1,
input Add2,
output Res,
output Carry
);
assign Res = Add1 ^ Add2;
assign Carry = Add1 & Add2;
endmodule
// 全加器
module Adder(
input Add1,
input Add2,
input I_carry,
output Res,
output Carry
);
assign Res = Add1 ^ Add2 ^ I_carry;
assign Carry = (Add1 & Add2) | ((Add1 ^ Add2) & I_carry);
endmodule