四位booth乘法的verilog实现

最近做了一个四位的booth乘法器的实验,在这里记录一下我的实验过程,需要说明的是,我认为最好的方法是使用有限状态机的方法(做完之后才知道),我这里的方法是根据比较的结果来生成使能信号,进而控制运算模块的运算。

算法流程
先简单介绍一下在这篇文章中booth乘法的前期准备及算法流程:

首先,符号是会参与运算的,booth乘法也是计算补码的,得出的结果是补码

1、先对被乘数进行符号拓展,就是将被乘数变成双符号位。
2、部分积寄存器pi置0,乘数寄存器放入乘数,但是乘数寄存器需要在最后一位添加一位0,所以乘数寄存器是有5位的,还需要一个计数器来计数运算了多少次。
3、比较乘数寄存器的末两位,如果两位是00或者11,则部分积寄存器和乘数寄存器都右移一位,如果是01,则部分积寄存器加乘数的补码,部分积寄存器和乘数寄存器再右移一位,如果是10,则部分积寄存器减乘数的补码,部分积寄存器和乘数寄存器再右移一位。同时计数器加1。(这里的右移一位会把部分积寄存器的最后一位移入乘数寄存器,而乘数寄存器的最后一位会被舍弃)
4、重复4次(4位的乘法器是比较4次),结果的低4位是乘数寄存器的高四位,结果的高3位是部分积寄存器的低3位。(这里结果取了7位,因为取8位也只不过是多了一位的符号位)

比较结果运算
00部分积寄存器和乘数寄存器都右移一位
01则部分积寄存器加乘数的补码,部分积寄存器和乘数寄存器再右移一位
10部分积寄存器减乘数的补码,部分积寄存器和乘数寄存器再右移一位
11部分积寄存器和乘数寄存器都右移一位

使能信号表如下

乘数低两位比较结果使能信号g
0000
1100
0101
1010

得出最终实现方案的尝试
下面是我做的第一个没有用计数器的方案,这是一个存在问题的方案。

module subtracter(input [3:0]X1,X2,output [6:0]Y

    );
    reg [9:0]p=0;
    reg [4:0]x_0;
    reg [4:0]x_1;
    reg z1,c1,z2,c2,z3,c3,z4,c4,c5,z5;
    reg [3:0]t;
    always @ (*) begin
        p=10'b0;
        p[4:1]=X2;  //这里是一个全加器,用来算乘数[-x]补码,因为可能是我本地软件的原因,我用+运算符算不出来,所以只能这样。
        {c1,z1}=!X1[0]+1;
        {c2,z2}=!X1[1]+c1;
        {c3,z3}=!X1[2]+c2;
        {c4,z4}=!X1[3]+c3;
        t={z4,z3,z2,z1};
        x_0={!X1[3],t};
        x_1={X1[3],X1};
        repeat (4) begin
            if(p[1]^~p[0]) begin
                p={p[9],p[9:1]};
            end
            else if(p[1]===1'b0) begin
                {c1,z1}=p[5]+x_1[0]+1'b0;
                {c2,z2}=p[6]+x_1[1]+c1;
                {c3,z3}=p[7]+x_1[2]+c2;
                {c4,z4}=p[8]+x_1[3]+c3;
                {c5,z5}=p[9]+x_1[4]+c4;
                p[9:5]={z5,z4,z3,z2,z1};
                p={p[9],p[9:1]};
            end
            else begin
                {c1,z1}=p[5]+x_0[0]+1'b0;
                {c2,z2}=p[6]+x_0[1]+c1;
                {c3,z3}=p[7]+x_0[2]+c2;
                {c4,z4}=p[8]+x_0[3]+c3;
                {c5,z5}=p[9]+x_0[4]+c4;
                p[9:5]={z5,z4,z3,z2,z1};
                p={p[9],p[9:1]};
                //p[8]=1'b1;
            end 
        end
    end
    assign Y=p[7:1];
endmodule


问题
可以发现的是,这里没有用计数器而是用了repeat来让模块重复运算4次,这样就存在着在综合的过程中加法器会出现不确定个数的情况,可能会有多个加法器,在芯片的加法器个数有限的情况下,显然是不符合实际的,因此我改用了生成使能信号来告诉运算模块进行专门运算,这样就能够解决上述的问题。但是我的这种方法还是用了两个加法器。

接下来就是最终方案

module subtracter(input [3:0]X1,X2,output [6:0]Y,input CLK

    );
    reg [9:0]p=0;//我将乘数寄存器与部分积寄存器定义为一个10位的寄存器类型的数据
    reg [4:0]x_0;//用来存拓展符号位之后的[-x]补码
    reg [4:0]x_1;//用来存拓展符号位之后的[x]补码
    reg [1:0]f; //用来存乘数寄存器低两位,其实可以不用
    reg [1:0]g;//使能信号寄存器
    reg [3:0]t;
    wire [9:0]p_1;//用来接收运算模块的结果
    reg re;//使能信号,初始化各个寄存器的值
    integer count;//计数器
    reg z1,c1,z2,c2,z3,c3,z4,c4,c5,z5;
    always @ (X1 or X2) begin 
        re=1'b1;    //当乘数或者被乘数发生变化的时候,这个信号会置1
    end
    
    always @ (posedge CLK) begin
        if (re) begin
            p=10'b0;
            p[4:1]=X2;
            {c1,z1}=!X1[0]+1;
            {c2,z2}=!X1[1]+c1;
            {c3,z3}=!X1[2]+c2;
            {c4,z4}=!X1[3]+c3;
            t={z4,z3,z2,z1};
            x_0={!X1[3],t};
            x_1={X1[3],X1};
            count=0;
            re=1'b0;
        end
        else begin
            f={p[1],p[0]};
            case(f)
                2'b00: g=2'b00;
                2'b11: g=2'b00;
                2'b01: g=2'b01;
                2'b10: g=2'b10;
                default: g=2'b11;//表示保持之前的p寄存器的结果
            endcase
            if(count==4||count>4) begin
                g=2'b11;//当运算过4次之后,运算不会进行
            end
            count=count+1;
        end
    end    
    AL ALU (x_0,x_1,g,p,p_1,CLK);
    always @ (CLK) begin
        p=p_1;
    end
    assign Y=p_1[7:1];
    
endmodule

module AL(input [4:0]x_0,x_1,input [1:0]g,input [9:0]p,output reg[9:0]p_1,input CLK

    );
    reg c1,c2,c3,c4,c5,z1,z2,z3,z4,z5;
    always @ (posedge CLK) begin
        p_1=p;
        case (g) 
            2'b00: begin 
                    p_1={p_1[9],p_1[9:1]};
                    end
            2'b01: begin
                        {c1,z1}=p[5]+x_1[0]+1'b0;
                        {c2,z2}=p[6]+x_1[1]+c1;
                        {c3,z3}=p[7]+x_1[2]+c2;
                        {c4,z4}=p[8]+x_1[3]+c3;
                        {c5,z5}=p[9]+x_1[4]+c4;
                        p_1[9:5]={z5,z4,z3,z2,z1};
                        p_1={p_1[9],p_1[9:1]};
                   end
           2'b10: begin
                       {c1,z1}=p[5]+x_0[0]+1'b0;
                       {c2,z2}=p[6]+x_0[1]+c1;
                       {c3,z3}=p[7]+x_0[2]+c2;
                       {c4,z4}=p[8]+x_0[3]+c3;
                       {c5,z5}=p[9]+x_0[4]+c4;
                       p_1[9:5]={z5,z4,z3,z2,z1};
                       p_1={p_1[9],p_1[9:1]};
            
                  end
          2'b11: p_1=p_1;
          default: p_1=p_1;
        endcase
    end
endmodule

验证
仿真能够看出模块的逻辑功能是否正确,在仿真的时候,我们的乘法器需要至少4个时钟上升沿才能够算完,如果不满足的话是会显示中间计算结果的。

module one_true_from_subtracter_bench;
reg [3:0]X1,X2;
wire [6:0]Y;
reg CLK;
initial
    begin
    CLK=0;
    end
always #10
    CLK=~CLK;
one_true_from_subtracter U0 (X1,X2,Y,CLK);
initial begin
     X1=4'b1101;X2=4'b0101;
    #200 X1=4'b1001;X2=4'b1100;
    #150 X1=4'b1111;X2=4'b1100;
    #150 X1=4'b1101;X2=4'b0101;
    #150 X1=4'b1000;X2=4'b1011;
    //#1 X1=4'b1101;X2=4'b1010;

end 
endmodule

波形图如下,可以看出我们的模块逻辑功能是正确的。经过4个时钟周期,算出来结果,而在没有新的数据输入的时候,结果是会保持的。
仿真波形图
我没有综合,无法得知综合的结果,因为我电脑的问题,综合的时候软件会闪退(哭~)。

可能存在的问题
我的方法不是一个最佳的解决方式,我用了两个加法器,并且没有综合,不知道综合的时候会不会有问题。

总结
这次的实验做下来,在编程中我其实出现了许多的问题,比如说在判断条件的小于等于,如果用 ‘<=’ 是不行的,在verilog里面这个是非阻塞赋值的符号。我一开始的第一种实现方案其实还是用了软件的思维去写硬件,仿真出来结果也确实是对的。但是硬件与软件不同,虽然说软件跟硬件用代码能够实现某种东西,但是在硬件里面,还需要考虑到的是能不能综合,实际做成电路有没有难度,会不会造成歧义,模块的是否有必要重复存在,成本会不会更高等等。

  • 8
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值