zoukankan      html  css  js  c++  java
  • [转载]采用加法器数乘法器实现17位有符号数相乘(Verilog)

    http://www.cnblogs.com/maqingbiao/archive/2010/07/27/1786187.html

    本例程采用加法器数乘法器实现17位有符号数相乘。参考《基于Verilog HDL 的数字系统应用设计》,王钿 ,桌兴旺 编著

    1 module signed_mult17b_addtree (
    2 mul_a,
    3 mul_b,
    4 mul_out,
    5 clk,
    6 rst_n,
    7 );
    8
    9  parameter MUL_WIDTH =17;
    10  parameter MUL_RESULT =33;
    11
    12  input [MUL_WIDTH-1:0] mul_a;
    13  input [MUL_WIDTH-1:0] mul_b;
    14  input clk;
    15  input rst_n;
    16
    17  output [MUL_RESULT-1:0] mul_out;
    18
    19  reg [MUL_RESULT-1:0] mul_out;
    20  reg [MUL_RESULT-1:0] mul_out_reg;
    21  reg msb;
    22  reg msb_reg_0;
    23  reg msb_reg_1;
    24  reg msb_reg_2;
    25  reg msb_reg_3;
    26  reg [MUL_WIDTH-1:0] mul_a_reg;
    27  reg [MUL_WIDTH-1:0] mul_b_reg;
    28
    29  reg [MUL_RESULT-2:0] stored0;
    30  reg [MUL_RESULT-2:0] stored1;
    31  reg [MUL_RESULT-2:0] stored2;
    32  reg [MUL_RESULT-2:0] stored3;
    33  reg [MUL_RESULT-2:0] stored4;
    34  reg [MUL_RESULT-2:0] stored5;
    35  reg [MUL_RESULT-2:0] stored6;
    36  reg [MUL_RESULT-2:0] stored7;
    37  reg [MUL_RESULT-2:0] stored8;
    38  reg [MUL_RESULT-2:0] stored9;
    39  reg [MUL_RESULT-2:0] stored10;
    40  reg [MUL_RESULT-2:0] stored11;
    41 reg [MUL_RESULT-2:0] stored12;
    42 reg [MUL_RESULT-2:0] stored13;
    43 reg [MUL_RESULT-2:0] stored14;
    44 reg [MUL_RESULT-2:0] stored15;
    45
    46 reg [MUL_RESULT-2:0] add0_0;
    47 reg [MUL_RESULT-2:0] add0_1;
    48 reg [MUL_RESULT-2:0] add0_2;
    49 reg [MUL_RESULT-2:0] add0_3;
    50 reg [MUL_RESULT-2:0] add0_4;
    51 reg [MUL_RESULT-2:0] add0_5;
    52 reg [MUL_RESULT-2:0] add0_6;
    53 reg [MUL_RESULT-2:0] add0_7;
    54
    55 reg [MUL_RESULT-2:0] add1_0;
    56 reg [MUL_RESULT-2:0] add1_1;
    57 reg [MUL_RESULT-2:0] add1_2;
    58 reg [MUL_RESULT-2:0] add1_3;
    59
    60 reg [MUL_RESULT-2:0] add2_0;
    61 reg [MUL_RESULT-2:0] add2_1;
    62
    63 reg [MUL_RESULT-1:0] add3_0;
    64
    65 always @ ( posedge clk ornegedge rst_n )
    66 begin
    67 if ( !rst_n )
    68 begin
    69 mul_a_reg <=17'b0;
    70 mul_b_reg <=17'b0;
    71
    72 stored0 <=32'b0;
    73 stored1 <=32'b0;
    74 stored2 <=32'b0;
    75 stored3 <=32'b0;
    76 stored4 <=32'b0;
    77 stored5 <=32'b0;
    78 stored6 <=32'b0;
    79 stored7 <=32'b0;
    80 stored8 <=32'b0;
    81 stored9 <=32'b0;
    82 stored10 <=32'b0;
    83 stored11 <=32'b0;
    84 stored12 <=32'b0;
    85 stored13 <=32'b0;
    86 stored14 <=32'b0;
    87 stored15 <=32'b0;
    88
    89 add0_0 <=32'b0;
    90 add0_1 <=32'b0;
    91 add0_2 <=32'b0;
    92 add0_3 <=32'b0;
    93 add0_4 <=32'b0;
    94 add0_5 <=32'b0;
    95 add0_6 <=32'b0;
    96 add0_7 <=32'b0;
    97
    98
    99 add1_0 <=32'b0;
    100 add1_1 <=32'b0;
    101 add1_2 <=32'b0;
    102 add1_3 <=32'b0;
    103
    104 add2_0 <=32'b0;
    105 add2_1 <=32'b0;
    106
    107 add3_0 <=32'b0;
    108
    109 msb <=1'b0;
    110 msb_reg_0 <=1'b0;
    111 msb_reg_1 <=1'b0;
    112 msb_reg_2 <=1'b0;
    113 msb_reg_3 <=1'b0;
    114
    115 mul_out_reg <=33'b0;
    116 mul_out <=33'b0;
    117
    118 end
    119 else
    120 begin
    121 mul_a_reg <= (mul_a[16]==0)? mul_a : {mul_a[16],~mul_a[15:0]+1'b1};
    122 mul_b_reg <= (mul_b[16]==0)? mul_b : {mul_b[16],~mul_b[15:0]+1'b1};
    123
    124 msb_reg_0 <= mul_a_reg[16] ^ mul_b_reg[16];
    125 msb_reg_1 <= msb_reg_0;
    126 msb_reg_2 <= msb_reg_1;
    127 msb_reg_3 <= msb_reg_2;
    128 msb <= msb_reg_3;
    129
    130 stored0 <= mul_b_reg[0] ? {16'b0,mul_a_reg[15:0]} : 32'b0;
    131 stored1 <= mul_b_reg[1] ? {15'b0,mul_a_reg[15:0],1'b0} : 32'b0;
    132 stored2 <= mul_b_reg[2] ? {14'b0,mul_a_reg[15:0],2'b0} : 32'b0;
    133 stored3 <= mul_b_reg[3] ? {13'b0,mul_a_reg[15:0],3'b0} : 32'b0;
    134 stored4 <= mul_b_reg[4] ? {12'b0,mul_a_reg[15:0],4'b0} : 32'b0;
    135 stored5 <= mul_b_reg[5] ? {11'b0,mul_a_reg[15:0],5'b0} : 32'b0;
    136 stored6 <= mul_b_reg[6] ? {10'b0,mul_a_reg[15:0],6'b0} : 32'b0;
    137 stored7 <= mul_b_reg[7] ? {9'b0,mul_a_reg[15:0],7'b0} : 32'b0;
    138 stored8 <= mul_b_reg[8] ? {8'b0,mul_a_reg[15:0],8'b0} : 32'b0;
    139 stored9 <= mul_b_reg[9] ? {7'b0,mul_a_reg[15:0],9'b0} : 32'b0;
    140 stored10 <= mul_b_reg[10] ? {6'b0,mul_a_reg[15:0],10'b0} : 32'b0;
    141 stored11 <= mul_b_reg[11] ? {5'b0,mul_a_reg[15:0],11'b0} : 32'b0;
    142 stored12 <= mul_b_reg[12] ? {4'b0,mul_a_reg[15:0],12'b0} : 32'b0;
    143 stored13 <= mul_b_reg[13] ? {3'b0,mul_a_reg[15:0],13'b0} : 32'b0;
    144 stored14 <= mul_b_reg[14] ? {2'b0,mul_a_reg[15:0],14'b0} : 32'b0;
    145 stored15 <= mul_b_reg[15] ? {1'b0,mul_a_reg[15:0],15'b0} : 32'b0;
    146
    147 add0_0 <= stored0 + stored1;
    148 add0_1 <= stored2 + stored3;
    149 add0_2 <= stored4 + stored5;
    150 add0_3 <= stored6 + stored7;
    151 add0_4 <= stored8 + stored9;
    152 add0_5 <= stored10 + stored11;
    153 add0_6 <= stored12 + stored13;
    154 add0_7 <= stored14 + stored15;
    155
    156 add1_0 <= add0_0 + add0_1;
    157 add1_1 <= add0_2 + add0_3;
    158 add1_2 <= add0_4 + add0_5;
    159 add1_3 <= add0_6 + add0_7;
    160
    161 add2_0 <= add1_0 + add1_1;
    162 add2_1 <= add1_2 + add1_3;
    163
    164 add3_0 <= add2_0 + add2_1;
    165
    166 mul_out_reg <= {msb,add3_0[31:0]};
    167 mul_out <= (mul_out_reg[32]==0)? mul_out_reg : {mul_out_reg[32],~mul_out_reg[31:0]+1'b1};
    168
    169 end
    170 end
    171
    172 endmodule
    173
    174

    调试小结:本例程采用了5级流水线技术,以至于能在一个时钟周期内完成一次乘法运算输出。参考的范例为4位无符号输入,采用2级流水线技术。

                  由于是有符号运算,符号位要单独处理,也就是把两个数的最高位相异或,即可得到乘积的符号位。如:

    1 msb_reg_0 <= mul_a_reg[16] ^ mul_b_reg[16];

                  有符号数是以补码形式存放在内存的,所以必须要将补码转换为原码后再进行运算,运算后的结果再根据乘积符号位判断最终结果是正还是负,若为负,还需将运算后的结果还原为补码,之后加入一位符号位,便可得到33位的有符号最终结果。(无论是整数还是小数都适用)

    1 mul_a_reg <= (mul_a[16]==0)? mul_a : {mul_a[16],~mul_a[15:0]+1'b1};
    2 mul_b_reg <= (mul_b[16]==0)? mul_b : {mul_b[16],~mul_b[15:0]+1'b1};
    3 mul_out <= (mul_out_reg[32]==0)? mul_out_reg : {mul_out_reg[32],~mul_out_reg[31:0]+1'b1};

                  由于采用流水线技术,所以有可能会出现时序不一致,该例程出现的问题就是符号位的运算和数据位的运算时序不一致,所以添增了几层赋值运算,确保二则时序一致,不然将会运算出错。

    1 msb_reg_1 <= msb_reg_0;
    2 msb_reg_2 <= msb_reg_1;
    3 msb_reg_3 <= msb_reg_2;
    4 msb <= msb_reg_3;

                  本例程只用了一个always,里面有很多的运算,最初,我心里想,我在一个always里面进行那么多的运算,一个时钟周期怎么能处理完呢,如果一个时钟周期处理不完,那么不是有些变量的值会丢失吗,最初没有调试成功,我一直都怀疑是这个原因,所以我就把always里的每一个运算都单独拿出来,放到一个always里面,也就是每个always里只有一个运算,一共写了好几十个always,程序写得相当的长,但问题还是没有解决,然后再一次仔细研究,才发现是符号位运算的时序跟数据位运算不一致,所以就想办法延时符号位运算结果送至最终乘积结果的时间,现在想出的办法是多加几层的赋值,来拖延符号运算结果送至最终乘积结果的时间。这时才发现,原来我一直没有搞明白always是怎样一步一步执行的,现在明白了,时钟触发always语句里面一般都用非阻塞赋值,非阻塞赋值就是第二个赋值语句,不需要等待第一个赋值语句完成后才进行,这样的结果是,第二个赋值语句不能以第一个语句的最新结果参与运算,而是以前一状态的值参与运算。他们几乎是同时进行的,也就是在每个时钟内,always里面的语句都将执行一次,不存在一个时钟内,有些语句还未执行到。最初,我学Verilog的时候就把非阻塞语句和阻塞语句区别开了的,但似乎并没有真正理解并会应用。我为这个,付出了很多很多,现在终于解决了!

     改正一处:

    原来:

    1 mul_out_reg <= {msb,add3_0[31:0]};
    2 mul_out <= (mul_out_reg[32]==0)? mul_out_reg :
    3 {mul_out_reg[32],~mul_out_reg[31:0]+1'b1};

    更改为: 

    1 mul_out_reg <= (add3_0==0)? 33'b0 : {msb,add3_0[31:0]};
    2 mul_out <= (mul_out_reg==0)? 33'b0 : (mul_out_reg[32]==0)? mul_out_reg :
    3 {mul_out_reg[32],~mul_out_reg[31:0]+1'b1};
    4

    更改原因:当输入的两个数,一个为0,另一个为负数时,按原来的代码运算乘积并不是0,而是-1,所以需要改正,改正后不会出现这样的错误。

    0
    0
    (请您对文章做出评价)
    « 上一篇:(转帖)写verilog代码的一些经验和小结(Verilog)
    » 下一篇:(原创)用MATLAB完成二进制,十进制,十六进制之间的转换,对滤波器的抽头系数处理非常有效(MATLAB)

    posted on 2010-07-27 17:17 小麻同学 阅读(363) 评论(3) 编辑 收藏 所属分类: Verilog

    评论

    小麻同学你好,你在文中说“本例程采用了5级流水线技术,以至于能在一个时钟周期内完成一次乘法运算输出。”但是我用modeisim仿了你这个程序,乘法运算结果相对于输入貌似是延迟了7个时钟啊。可否告诉我你的仿真条件呢,我是在ISE中自动生成的tb文件,时钟周期25ns,每隔200ns给一对输入乘数与被乘数。

    我觉得第121行mul_a_reg <= (mul_a[16]==0)? mul_a : {mul_a[16],~mul_a[15:0]+1'b1};和122行是不是用连续赋值代替可以减少延迟?

    另外请教你一点问题,参考你这个程序,写了一个8位×8位的有符号乘法器,对于负数的处理,我是先把负数当做正数参与乘法运算。最后,如果两个数符号不同,就将准结果'取反+1'转换成负数的二进制表示,并作为最终的结果.仿真来看,至少计算结果是正确的,结果相对于输入延迟4个时钟周期。
    两个问题:1、我的做法(把负数先当成正数进行运算)是否妥当?
    2、运算结果延迟的时钟个数是不是会随着乘法器位数的增加而增加的?

    希望能得到你的回复,谢谢!
     

    回复 引用 查看   

    #2楼[楼主] 2010-09-09 20:14 小麻同学      

    @我不是劫匪
    现在正在进行广西区电子竞赛 忙碌中,赛后在给你回复
     回复 引用 查看   

    #3楼[楼主] 2010-09-17 21:41 小麻同学      

    @我不是劫匪
    “我用modeisim仿了你这个程序,乘法运算结果相对于输入貌似是延迟了7个时钟啊。”这个延迟是肯定会有的,但这只是延迟而已,每个时钟周期还是可以完成一个运算的,也就是每个时钟周期都会有运算结果输出。
    “1、我的做法(把负数先当成正数进行运算)是否妥当?”这个我倒也试过,但没有成功,仿真出来的结果不正确,你可以输入多几个仿真数据,看一下是不是每种情况都能正确输出,感觉我现在那样处理时绕了一圈才回到原点的。
    “2,运算结果延迟的时钟个数是不是会随着乘法器位数的增加而增加的?” 这个肯定会这样的 肯定会增加延时,但也是能做到每个周期出一个数据,这种延时对于大多数的处理时没有多大影响的
     回复 引用 查看   

    #1楼 2010-09-09 20:11 我不是劫匪      

  • 相关阅读:
    软件测试 Lab1 实验报告
    软件测试 Homework2
    谈谈最近的一个让我印象深刻的错误
    Bill Manager Problem Statement
    C#学习记录(九)Windows Phone开发中的Binding
    C#学习记录(八) XML Serializer尝试
    C#学习记录(七)LINQ语句及LAMDA表达式
    C#学习记录(六)
    软件测试之作业三
    软件测试之实验一
  • 原文地址:https://www.cnblogs.com/zlh840/p/1917555.html
Copyright © 2011-2022 走看看