Verilog实现32位乘法器

  实现乘法器有多种思路,本次作业了解了Wallace Tree算法和移位相加的方式。最终采取移位相加的方式实现。下面是对两种方式的介绍。

Wallace Tree算法

  Wallace Tree 主要思想是:将三行变成2行,实际相当于3位到2位的压缩器,简称3-2压缩器。通过合理的分配处理乘法中出现的大量部分积。因为有很多运算是可以并行计算的,所以能够极大提高运算速度。

  具体讲解参照以下两篇博客(8位乘法):

  乘法器——Wallace树型乘法器

  Wallace Tree 图解

全加器

  全加器是Wallace Tree算法中需要用到的一个部件。

全加器

Ci-1 A B S Ci
0 0 0 0 0
0 0 1 1 0
0 1 0 1 0
0 1 1 0 1
1 0 0 1 0
1 0 1 0 1
1 1 0 0 1
1 1 1 1 1

Verilog 实现:

module FA(A, B, Cin, Sum, Count);
    input A;
    input B;
    input Cin;
    output Sum;

    output Count;
    wire S1, T1, T2, T3;
    // -- statements -- //
    xor x1 (S1, A, B);
    xor x2 (Sum, S1, Cin);
    and A1 (T3, A, B );
    and A2 (T2, B, Cin);
    and A3 (T1, A, Cin);
    or O1 (Count, T1, T2, T3 );
endmodule

Verilog实现

  因为是32位乘法,分为16级全加器。由于实现代码的冗长,32位×32位会导致每一级需要有1~6个全加器,而每一级也有32个分支,需要手写的部分非常多。故没有采取这种方式来实现。

移位相加算法

  两个二进制数 a 和 b 相乘,可以认为是 a 和 b 的每一位相乘后移位后的结果相加。

  关于 a 与 b 的每一位相乘产生的中间结果,如果 b 那位是 0,那么中间结果就是 0;如果是 1,那么中间结果就是在 a 前后补上相应位数的零通过字符拼接的方式表示。然后将这些中间乘积相加就是最后的结果。

  无符号运算 Verilog 代码如下:

`timescale 1ns / 1ps

module MULTU(
    input           clk,    // 乘法器时钟信号
    input           reset,
    input   [31:0]  a,      // 输入 a(被乘数)
    input   [31:0]  b,      // 输入 b(乘数)
    output  [63:0]  z       // 乘积输出 z
);

    wire [63:0] temp;
    
    // 申请寄存器
    reg [63:0] stored0;
    reg [63:0] stored1;
    reg [63:0] stored2;
    reg [63:0] stored3;
    reg [63:0] stored4;
    reg [63:0] stored5;
    reg [63:0] stored6;
    reg [63:0] stored7;
    reg [63:0] stored8;
    reg [63:0] stored9;
    reg [63:0] stored10;
    reg [63:0] stored11;
    reg [63:0] stored12;
    reg [63:0] stored13;
    reg [63:0] stored14;
    reg [63:0] stored15;
    reg [63:0] stored16;
    reg [63:0] stored17;
    reg [63:0] stored18;
    reg [63:0] stored19;
    reg [63:0] stored20;
    reg [63:0] stored21;
    reg [63:0] stored22;
    reg [63:0] stored23;
    reg [63:0] stored24;
    reg [63:0] stored25;
    reg [63:0] stored26;
    reg [63:0] stored27;
    reg [63:0] stored28;
    reg [63:0] stored29;
    reg [63:0] stored30;
    reg [63:0] stored31;
    
    wire [63:0] add0_1;
    wire [63:0] add2_3;
    wire [63:0] add4_5;
    wire [63:0] add6_7;
    wire [63:0] add8_9;
    wire [63:0] add10_11;
    wire [63:0] add12_13;
    wire [63:0] add14_15;
    wire [63:0] add16_17;
    wire [63:0] add18_19;
    wire [63:0] add20_21;
    wire [63:0] add22_23;
    wire [63:0] add24_25;
    wire [63:0] add26_27;
    wire [63:0] add28_29;
    wire [63:0] add30_31;
    
    wire [63:0] add0t1_2t3;
    wire [63:0] add4t5_6t7;
    wire [63:0] add8t9_10t11;
    wire [63:0] add12t13_14t15;
    wire [63:0] add16t17_18t19;
    wire [63:0] add20t21_22t23;
    wire [63:0] add24t25_26t27;
    wire [63:0] add28t29_30t31;
    
    wire [63:0] add0t3_4t7;
    wire [63:0] add8t11_12t15;
    wire [63:0] add16t19_20t23;
    wire [63:0] add24t27_28t31;
    
    wire [63:0] add0t7_8t15;
    wire [63:0] add16t23_24t31;
    
    assign z = temp;
    assign add0_1 = stored0 + stored1;
    assign add2_3 = stored2 + stored3;
    assign add4_5 = stored4 + stored5;
    assign add6_7 = stored6 + stored7;
    assign add8_9 = stored8 + stored9;
    assign add10_11 = stored10 + stored11;
    assign add12_13 = stored12 + stored13;
    assign add14_15 = stored14 + stored15;
    assign add16_17 = stored16 + stored17;
    assign add18_19 = stored18 + stored19;
    assign add20_21 = stored20 + stored21;
    assign add22_23 = stored22 + stored23;
    assign add24_25 = stored24 + stored25;
    assign add26_27 = stored26 + stored27;
    assign add28_29 = stored28 + stored29;
    assign add30_31 = stored30 + stored31;
    
    assign add0t1_2t3 = add0_1 + add2_3;
    assign add4t5_6t7 = add4_5 + add6_7;
    assign add8t9_10t11 = add8_9 + add10_11;
    assign add12t13_14t15 = add12_13 + add14_15;
    assign add16t17_18t19 = add16_17 + add18_19;
    assign add20t21_22t23 = add20_21 + add22_23;
    assign add24t25_26t27 = add24_25 + add26_27;
    assign add28t29_30t31 = add28_29 + add30_31;
    
    assign add0t3_4t7 = add0t1_2t3 + add4t5_6t7;
    assign add8t11_12t15 = add8t9_10t11 + add12t13_14t15;
    assign add16t19_20t23 = add16t17_18t19 + add20t21_22t23;
    assign add24t27_28t31 = add24t25_26t27 + add28t29_30t31;
    
    assign add0t7_8t15 = add0t3_4t7 + add8t11_12t15;
    assign add16t23_24t31 = add16t19_20t23 + add24t27_28t31;
    
    assign temp = add0t7_8t15 + add16t23_24t31;

    always @(posedge clk or negedge reset)
    begin
        // reset 置零
        if(reset == 0) 
        begin
            stored0 <= 0;
            stored1 <= 0;
            stored2 <= 0;
            stored3 <= 0;
            stored4 <= 0;
            stored5 <= 0;
            stored6 <= 0;
            stored7 <= 0;
            stored8 <= 0;
            stored9 <= 0;
            stored10 <= 0;
            stored11 <= 0;
            stored12 <= 0;
            stored13 <= 0;
            stored14 <= 0;
            stored15 <= 0;
            stored16 <= 0;
            stored17 <= 0;
            stored18 <= 0;
            stored19 <= 0;
            stored20 <= 0;
            stored21 <= 0;
            stored22 <= 0;
            stored23 <= 0;
            stored24 <= 0;
            stored25 <= 0;
            stored26 <= 0;
            stored27 <= 0;
            stored28 <= 0;
            stored29 <= 0;
            stored30 <= 0;
            stored31 <= 0;
        end
        else 
        begin
        //通过字符拼接方式表示出中间相乘值,并相加
        stored0 <= b[0]? {32'b0, a} :64'b0;
        stored1 <= b[1]? {31'b0, a, 1'b0} :64'b0;
        stored2 <= b[2]? {30'b0, a, 2'b0} :64'b0;
        stored3 <= b[3]? {29'b0, a, 3'b0} :64'b0;
        stored4 <= b[4]? {28'b0, a, 4'b0} :64'b0;
        stored5 <= b[5]? {27'b0, a, 5'b0} :64'b0;
        stored6 <= b[6]? {26'b0, a, 6'b0} :64'b0;
        stored7 <= b[7]? {25'b0, a, 7'b0} :64'b0;
        stored8 <= b[8]? {24'b0, a, 8'b0} :64'b0;
        stored9 <= b[9]? {23'b0, a, 9'b0} :64'b0;
        stored10 <= b[10]? {22'b0, a, 10'b0} :64'b0;
        stored11 <= b[11]? {21'b0, a, 11'b0} :64'b0;
        stored12 <= b[12]? {20'b0, a, 12'b0} :64'b0;
        stored13 <= b[13]? {19'b0, a, 13'b0} :64'b0;
        stored14 <= b[14]? {18'b0, a, 14'b0} :64'b0;
        stored15 <= b[15]? {17'b0, a, 15'b0} :64'b0;
        stored16 <= b[16]? {16'b0, a, 16'b0} :64'b0;
        stored17 <= b[17]? {15'b0, a, 17'b0} :64'b0;
        stored18 <= b[18]? {14'b0, a, 18'b0} :64'b0;
        stored19 <= b[19]? {13'b0, a, 19'b0} :64'b0;
        stored20 <= b[20]? {12'b0, a, 20'b0} :64'b0;
        stored21 <= b[21]? {11'b0, a, 21'b0} :64'b0;
        stored22 <= b[22]? {10'b0, a, 22'b0} :64'b0;
        stored23 <= b[23]? {9'b0, a, 23'b0} :64'b0;
        stored24 <= b[24]? {8'b0, a, 24'b0} :64'b0;
        stored25 <= b[25]? {7'b0, a, 25'b0} :64'b0;
        stored26 <= b[26]? {6'b0, a, 26'b0} :64'b0;
        stored27 <= b[27]? {5'b0, a, 27'b0} :64'b0;
        stored28 <= b[28]? {4'b0, a, 28'b0} :64'b0;
        stored29 <= b[29]? {3'b0, a, 29'b0} :64'b0;
        stored30 <= b[30]? {2'b0, a, 30'b0} :64'b0;
        stored31 <= b[31]? {1'b0, a, 31'b0} :64'b0;
        end
    end
endmodule

  有符号运算 Verilog 代码如下:

`timescale 1ns / 1ps

module MULT(
    input           clk,    // 乘法器时钟信号
    input           reset,
    input   [31:0]  a,      // 输入 a(被乘数)
    input   [31:0]  b,      // 输入 b(乘数)
    output  [63:0]  z       // 乘积输出 z
);

    wire [63:0] temp;
    wire [63:0] res;
    wire [31:0] temp_a;
    wire [31:0] temp_b;
    wire sign;
    
    // 申请寄存器
    reg [63:0] stored0;
    reg [63:0] stored1;
    reg [63:0] stored2;
    reg [63:0] stored3;
    reg [63:0] stored4;
    reg [63:0] stored5;
    reg [63:0] stored6;
    reg [63:0] stored7;
    reg [63:0] stored8;
    reg [63:0] stored9;
    reg [63:0] stored10;
    reg [63:0] stored11;
    reg [63:0] stored12;
    reg [63:0] stored13;
    reg [63:0] stored14;
    reg [63:0] stored15;
    reg [63:0] stored16;
    reg [63:0] stored17;
    reg [63:0] stored18;
    reg [63:0] stored19;
    reg [63:0] stored20;
    reg [63:0] stored21;
    reg [63:0] stored22;
    reg [63:0] stored23;
    reg [63:0] stored24;
    reg [63:0] stored25;
    reg [63:0] stored26;
    reg [63:0] stored27;
    reg [63:0] stored28;
    reg [63:0] stored29;
    reg [63:0] stored30;
    reg [63:0] stored31;
    
    wire [63:0] add0_1;
    wire [63:0] add2_3;
    wire [63:0] add4_5;
    wire [63:0] add6_7;
    wire [63:0] add8_9;
    wire [63:0] add10_11;
    wire [63:0] add12_13;
    wire [63:0] add14_15;
    wire [63:0] add16_17;
    wire [63:0] add18_19;
    wire [63:0] add20_21;
    wire [63:0] add22_23;
    wire [63:0] add24_25;
    wire [63:0] add26_27;
    wire [63:0] add28_29;
    wire [63:0] add30_31;
    
    wire [63:0] add0t1_2t3;
    wire [63:0] add4t5_6t7;
    wire [63:0] add8t9_10t11;
    wire [63:0] add12t13_14t15;
    wire [63:0] add16t17_18t19;
    wire [63:0] add20t21_22t23;
    wire [63:0] add24t25_26t27;
    wire [63:0] add28t29_30t31;
    
    wire [63:0] add0t3_4t7;
    wire [63:0] add8t11_12t15;
    wire [63:0] add16t19_20t23;
    wire [63:0] add24t27_28t31;
    
    wire [63:0] add0t7_8t15;
    wire [63:0] add16t23_24t31;
    
    assign temp_a = a[31]? {~a[31:0] + 1'b1}:a;
    assign temp_b = b[31]? {~b[31:0] + 1'b1}:b;
    assign sign = a[31]^b[31];  //异或
    assign add0_1 = stored0 + stored1;
    assign add2_3 = stored2 + stored3;
    assign add4_5 = stored4 + stored5;
    assign add6_7 = stored6 + stored7;
    assign add8_9 = stored8 + stored9;
    assign add10_11 = stored10 + stored11;
    assign add12_13 = stored12 + stored13;
    assign add14_15 = stored14 + stored15;
    assign add16_17 = stored16 + stored17;
    assign add18_19 = stored18 + stored19;
    assign add20_21 = stored20 + stored21;
    assign add22_23 = stored22 + stored23;
    assign add24_25 = stored24 + stored25;
    assign add26_27 = stored26 + stored27;
    assign add28_29 = stored28 + stored29;
    assign add30_31 = stored30 + stored31;
    
    assign add0t1_2t3 = add0_1 + add2_3;
    assign add4t5_6t7 = add4_5 + add6_7;
    assign add8t9_10t11 = add8_9 + add10_11;
    assign add12t13_14t15 = add12_13 + add14_15;
    assign add16t17_18t19 = add16_17 + add18_19;
    assign add20t21_22t23 = add20_21 + add22_23;
    assign add24t25_26t27 = add24_25 + add26_27;
    assign add28t29_30t31 = add28_29 + add30_31;
    
    assign add0t3_4t7 = add0t1_2t3 + add4t5_6t7;
    assign add8t11_12t15 = add8t9_10t11 + add12t13_14t15;
    assign add16t19_20t23 = add16t17_18t19 + add20t21_22t23;
    assign add24t27_28t31 = add24t25_26t27 + add28t29_30t31;
    
    assign add0t7_8t15 = add0t3_4t7 + add8t11_12t15;
    assign add16t23_24t31 = add16t19_20t23 + add24t27_28t31;
    
    assign temp = add0t7_8t15 + add16t23_24t31;
    assign res = sign? {~temp[63:0] + 1'b1}:temp;
    assign z = res;
    
    
    always @(posedge clk or negedge reset)
    begin
        // reset 置零
        if(reset == 0) 
        begin
            stored0 <= 0;
            stored1 <= 0;
            stored2 <= 0;
            stored3 <= 0;
            stored4 <= 0;
            stored5 <= 0;
            stored6 <= 0;
            stored7 <= 0;
            stored8 <= 0;
            stored9 <= 0;
            stored10 <= 0;
            stored11 <= 0;
            stored12 <= 0;
            stored13 <= 0;
            stored14 <= 0;
            stored15 <= 0;
            stored16 <= 0;
            stored17 <= 0;
            stored18 <= 0;
            stored19 <= 0;
            stored20 <= 0;
            stored21 <= 0;
            stored22 <= 0;
            stored23 <= 0;
            stored24 <= 0;
            stored25 <= 0;
            stored26 <= 0;
            stored27 <= 0;
            stored28 <= 0;
            stored29 <= 0;
            stored30 <= 0;
            stored31 <= 0;
        end
        else 
        begin
        //通过字符拼接方式表示出中间相乘值,并相加
        assign stored0 = temp_b[0]? {32'b0, temp_a} :64'b0;
        assign stored1 = temp_b[1]? {31'b0, temp_a, 1'b0} :64'b0;
        assign stored2 = temp_b[2]? {30'b0, temp_a, 2'b0} :64'b0;
        assign stored3 = temp_b[3]? {29'b0, temp_a, 3'b0} :64'b0;
        assign stored4 = temp_b[4]? {28'b0, temp_a, 4'b0} :64'b0;
        assign stored5 = temp_b[5]? {27'b0, temp_a, 5'b0} :64'b0;
        assign stored6 = temp_b[6]? {26'b0, temp_a, 6'b0} :64'b0;
        assign stored7 = temp_b[7]? {25'b0, temp_a, 7'b0} :64'b0;
        assign stored8 = temp_b[8]? {24'b0, temp_a, 8'b0} :64'b0;
        assign stored9 = temp_b[9]? {23'b0, temp_a, 9'b0} :64'b0;
        assign stored10 = temp_b[10]? {22'b0, temp_a, 10'b0} :64'b0;
        assign stored11 = temp_b[11]? {21'b0, temp_a, 11'b0} :64'b0;
        assign stored12 = temp_b[12]? {20'b0, temp_a, 12'b0} :64'b0;
        assign stored13 = temp_b[13]? {19'b0, temp_a, 13'b0} :64'b0;
        assign stored14 = temp_b[14]? {18'b0, temp_a, 14'b0} :64'b0;
        assign stored15 = temp_b[15]? {17'b0, temp_a, 15'b0} :64'b0;
        assign stored16 = temp_b[16]? {16'b0, temp_a, 16'b0} :64'b0;
        assign stored17 = temp_b[17]? {15'b0, temp_a, 17'b0} :64'b0;
        assign stored18 = temp_b[18]? {14'b0, temp_a, 18'b0} :64'b0;
        assign stored19 = temp_b[19]? {13'b0, temp_a, 19'b0} :64'b0;
        assign stored20 = temp_b[20]? {12'b0, temp_a, 20'b0} :64'b0;
        assign stored21 = temp_b[21]? {11'b0, temp_a, 21'b0} :64'b0;
        assign stored22 = temp_b[22]? {10'b0, temp_a, 22'b0} :64'b0;
        assign stored23 = temp_b[23]? {9'b0, temp_a, 23'b0} :64'b0;
        assign stored24 = temp_b[24]? {8'b0, temp_a, 24'b0} :64'b0;
        assign stored25 = temp_b[25]? {7'b0, temp_a, 25'b0} :64'b0;
        assign stored26 = temp_b[26]? {6'b0, temp_a, 26'b0} :64'b0;
        assign stored27 = temp_b[27]? {5'b0, temp_a, 27'b0} :64'b0;
        assign stored28 = temp_b[28]? {4'b0, temp_a, 28'b0} :64'b0;
        assign stored29 = temp_b[29]? {3'b0, temp_a, 29'b0} :64'b0;
        assign stored30 = temp_b[30]? {2'b0, temp_a, 30'b0} :64'b0;
        assign stored31 = temp_b[31]? {1'b0, temp_a, 31'b0} :64'b0; 
        end
    end
endmodule