分时复用的移位相加乘法器

基本算法

移位相加即是日常我们使用的手算算法,移位相加的描述如下

  • 设置积的初值为0
  • 若乘数的最低位为0,则积不变,否则累加被乘数
  • 若乘数的第一位为0,则积不变,否则累加向左移位一位的被乘数
  • ...
  • 若乘数的第n位(最高位)为0,则积不变,否则累加向左移位n位的被乘数

RTL代码

module serial_shiftadder_multipcation # (
    parameter WIDTH = 4
)(
    input clk,    // Clock
    input rst_n,  // Asynchronous reset active low

    input multiplier_valid,
    input [WIDTH - 1:0]multiplier1,
    input [WIDTH - 1:0]multiplier2,

    output reg product_valid,
    output reg [2 * WIDTH - 1:0]product
);

接口定义部分,采用参数化设计,WIDTH为乘数/被乘数的位宽,multiplier_valid拉高时表示输入有效,并开始计算。product_valid被拉高时表示计算完成,当前的输出是有效的

/*****************buffer and shift*******************/
reg [WIDTH - 1:0]min_mult;
reg [2 * WIDTH - 1:0]max_mult;
always @ (posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        {max_mult,min_mult} <= 'b0;
    end else if(multiplier_valid == 1'b1) begin
        if(multiplier1 > multiplier2) begin
            max_mult <= '{multiplier1};
            min_mult <= multiplier2;
        end else begin
            max_mult <= '{multiplier2};
            min_mult <= multiplier1;
        end
    end else if(min_mult != 'b0) begin
        max_mult <= max_mult << 1;
        min_mult <= min_mult >> 1;
    end else begin
        max_mult <= max_mult;
        min_mult <= min_mult;
    end
end

移位部分,有输入时比较两个输入的大小,使用小的数控制迭代数量,减小时间消耗。若较小的乘数不为0,则将较大的数向左移位,较小的的数向右位移。

/******************adder********************/
always @ (posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        {product_valid,product} <= 'b0;
    end else if(min_mult[0] == 1'b1) begin
        product <= product + max_mult;
        product_valid <= 1'b0;
    end else if(min_mult != 'b0) begin
        product <= product;
        product_valid <= 1'b0;
    end else if(multiplier_valid == 1'b1) begin
        product <= 'b0;
        product_valid <= 1'b0;
    end else begin
        product <= product;
        product_valid <= 1'b1;
    end
end

endmodule

累加部分,若较小的乘数最低位为0,保持积不变,否则累加当前的大乘数,当小乘数为0是,表示运算已经结束,输出有效拉高。

测试

使用自动化测试,使用高层次方法计算积,再与输出比较看是否相等

module mult_tb (
);

parameter WIDTH = 4;

logic clk,rst_n;
logic multiplier_valid;
logic [WIDTH - 1:0]multiplier1;
logic [WIDTH - 1:0]multiplier2;

logic product_valid;
logic [2 * WIDTH - 1:0]product;

serial_shiftadder_multipcation # (
    .WIDTH(WIDTH)
) dut (
    .clk(clk),    // Clock
    .rst_n(rst_n),  // Asynchronous reset active low

    .multiplier_valid(multiplier_valid),
    .multiplier1(multiplier1),
    .multiplier2(multiplier2),

    .product_valid(product_valid),
    .product(product)
);

initial begin
    clk = 1'b0;
    forever begin
        #50 clk = ~clk;
    end
end

initial begin
    rst_n = 1'b1;
    #5 rst_n = 1'b0;
    #10 rst_n = 1'b1;
end

initial begin
    {multiplier_valid,multiplier1,multiplier2} = 'b0;
    forever begin
        @(negedge clk);
        if(product_valid == 1'b1) begin
            multiplier1 = (WIDTH)'($urandom_range(0,2 ** WIDTH));
            multiplier2 = (WIDTH)'($urandom_range(0,2 ** WIDTH));
            multiplier_valid = 1'b1;
        end else begin
            multiplier_valid = 1'b0;
        end
    end
end

logic [2 * WIDTH - 1:0]exp;
initial begin
    forever begin
        @(posedge product_valid);
        exp = multiplier1 * multiplier2;
        if(exp == product) begin
            $display("successfully, mult1=%d mult2=%d product=%d",multiplier1,multiplier2,product);
        end else begin
            $display("failed,mult1=%d mult2=%d product=%d exp=%d",multiplier1,multiplier2,product,exp);
        end
    end
end

endmodule

你可能感兴趣的:(分时复用的移位相加乘法器)