• 二叉树乘法器


          对于两个N位数相乘 P=AB,之前的移位累加乘法器是先将B装载于一个2N位的寄存器中,然后B逐次移位,再根据A的各位情况累加。

          现在我们将A按权展开:                               

          以两个8位数相乘为例:

               

           首先我们可以写一个函数实现1位数和8位数的相乘,以得到上面的八个相加的数;

           然后我们可以将这八个数分组两两相加,第一次相加后得到4个中间结果,再将4个数分组两两相加,得到2个中间结果,最后再将这两个数相加得到最终结果。这样增加了芯片资源的耗用,但是可以提升速度。

          在《数字系统设计与Verilog HDL》中对于8位二叉树(加法树)乘法器有如下代码:

    module add_tree(out,a,b,clk);
    output [15:0] out;
    input [7:0] a,b;
    input clk;
    wire [15:0] out;
    wire [14:0] out1,c1;
    wire [12:0] out2;
    wire [10:0] out3,c2;
    wire [8:0] out4;
    reg [14:0] temp0;
    reg [13:0] temp1;
    reg [12:0] temp2;
    reg [11:0] temp3;
    reg [10:0] temp4;
    reg [9:0] temp5;
    reg [8:0] temp6;
    reg [7:0] temp7;
    //该函数实现8x1乘法
    function [7:0] mult8x1;
    input [7:0] operand;
    input sel;
    begin
    mult8x1=(sel)?(operand):8'b00000000;
    end
    endfunction
    //调用函数实现b各位与a相乘
    always @ ( posedge clk )
    begin
    temp7<=mult8x1(a,b[0]);
    temp6<=(mult8x1(a,b[1])<<1);
    temp5<=(mult8x1(a,b[2])<<2);
    temp4<=(mult8x1(a,b[3])<<3);
    temp3<=(mult8x1(a,b[4])<<4);
    temp2<=(mult8x1(a,b[5])<<5);
    temp1<=(mult8x1(a,b[6])<<6);
    temp0<=(mult8x1(a,b[7])<<7);
    end

    assign out1=temp0+temp1;
    assign out2=temp2+temp3;
    assign out3=temp4+temp5;
    assign out4=temp6+temp7;
    assign c1=out1+out2;
    assign c2=out3+out4;
    assign out=c1+c2;

    endmodule

         上面代码在调用函数的时候,左移k位是为了实现公式中2的k次方这个权系数。

          其实该代码其实是有错的,以temp6+temp7为例,temp6为9位,temp7为8位,相加的结果out4它定义为9位,如果两数相加结果为9位,则不会出现问题;

    如果两数相加产生进位,则进位将丢失,得不到正确结果。该代码的前仿真结果如下:

         由此可以看到,255×255时结果错误,就是因为有进位丢失。

         现在我们修改上述中间变量的位宽。由于两个8位数相乘结果最多为16位,因此如果我们将所有中间变量都改为16位的,结果肯定不会出问题,但是这样比较浪费资源。

         所以这里我们将temp6(9b)+temp7(8b)的结果out4设为10位,temp4(11b)+temp5(10b)的结果out3设为12位,temp2(13b)+temp3(12b)的结果out2设为14位,temp0(15b)+temp1(14b)的结果out1设为16位。

         然后将out3(12b)+out4(10b)的结果c2设为13位,out1(16b)+out2(14b)的结果c1设为16位,这里就不用考虑进位丢失了,因此最终结果最多为16位。

         修改的这部分代码如下: 

    wire  [15:0] out;
    wire [15:0] out1,c1;
    wire [13:0] out2;
    wire [11:0] out3;
    wire [12:0] c2;
    wire [9:0] out4;

        现在再仿真的结果如下:(可以看到结果正确了)

        该乘法器能在一个时钟周期内完成乘法运算。但是它不能插入流水线,因为后面的分组加法运算是组合逻辑实现的。我们可以看一下用XST综合的时序报告:

       (位宽有问题的代码的综合结果)

       Minimum input arrival time before clock: 3.687ns

       Maximum output required time after clock: 16.068ns

       现在我们将加法运算也放入always块内,在此需要先将wire型变量改为reg型,assign语句删除。always块如下:(位宽没改)

    always @ ( posedge clk )
    begin
    temp7<=mult8x1(a,b[0]);
    temp6<=(mult8x1(a,b[1])<<1);
    temp5<=(mult8x1(a,b[2])<<2);
    temp4<=(mult8x1(a,b[3])<<3);
    temp3<=(mult8x1(a,b[4])<<4);
    temp2<=(mult8x1(a,b[5])<<5);
    temp1<=(mult8x1(a,b[6])<<6);
    temp0<=(mult8x1(a,b[7])<<7);
    out1<=temp0+temp1;
    out2<=temp2+temp3;
    out3<=temp4+temp5;
    out4<=temp6+temp7;
    c1<=out1+out2;
    c2<=out3+out4;
    out<=c1+c2;
    end

        由代码分析可知道从第一个数据输入到第一个数据输出有3个时钟周期延迟,仿真如下:

        

        但是我们再看一下综合报告:

        Minimum input arrival time before clock: 3.687ns

        Maximum output required time after clock: 6.216ns

        与之前的对比可知,建立时间一样,但是保持时间小多了,因此时钟周期也小多了。并且,该实现方式可以在加法器之间插入寄存器以实现流水线,从而再次提高时钟频率。



  • 相关阅读:
    C语言的数组
    C语言的组成 以及预编译
    python实战——网络爬虫之request
    python实战——网络爬虫
    web渗透-sqli-labs-master 下载与安装
    PHP之旅4 php 超全局变量
    PHP之旅9 MySQL数据库
    PHP之旅8 URL与表单
    mysql数据库事务隔离级别与设置
    xsell 过期后的处理方法
  • 原文地址:https://www.cnblogs.com/haigege/p/2218158.html
Copyright © 2020-2023  润新知