tag 标签: 乘法

相关博文
  • 热度 29
    2014-8-10 10:44
    2215 次阅读|
    5 个评论
            一直很想学FPGA,去年11月份买了一套FPGA的开发板,玩了没两天,换了新的工作,那套开发板也束之高阁了。最近公司做了一个《时间管理》的培训,发现自己这一年总是在浪费时间没有什么进步,很后悔。然后决定好好学习一下特权同学的《深入浅出玩转FPGA》那套视频,因为还有些基础在,就直接跳到lesson12—乘法器设计实验。   看特权同学的视频,一直没有弄明白最关键的乘法操作的两句话(红色字体)。 else if (i 5'd0 i 5'd16) begin if(areg )   yout_r = {1'b0,yout_r +breg,yout_r }; else               yout_r = yout_r 1; end else if (i == 5'd16 areg )  yout_r = yout_r + breg; 然后自己在在草稿纸上慢慢演算,弄明白了二进制乘法是怎么相乘的。 我们以四位数乘以四位数举例:用4位二进制乘数的最高位乘以被乘数时,得出的结果最高只可能出现在第7位上(从广义上说就是结果的次高位上),所以第八位(广义上说就是最高位)只是用来准备存放进位的。 1010(被乘数) X1011(乘数) --------------------------- 乘数的最低位为1      得到0101 0000(右移累加) 乘数的次低位为1      得到0111 1000(右移累加) 乘数的第三位为0      得到0011 1100(右移) 乘数的最高位为1      得到0110 1110(右移累加) 我总结的规律就是乘数位上为1,结果先右移一位,次高位开始累加乘数。                                乘数位上为0,结果就只右移一位。 我感觉我总结的规律与特权同学的不一样,我先验证我所得到规律是否正确。 我写的乘法器的源码: module ex(               clk,rst_n,               ain,bin,start,yout,done               ); input clk,rst_n,start; input ain; input bin; output done; output yout; reg areg; reg breg; reg yout_r; reg done_r; reg i; always @(posedge clk or negedge rst_n)       if(!rst_n) i = 5'd0;            else if(start == 1 i=5'd16) i = i + 1'b1;            else if(!start) i = 5'd0;            always @(posedge clk or negedge rst_n)      if(!rst_n) done_r = 1'b0;            else if(i == 5'd16) done_r = 1'b1;            else if(i == 5'd17) done_r = 1'b0;   assign done = done_r;       always @(posedge clk or negedge rst_n) begin          if(!rst_n) begin                             areg = 16'h0000;                             breg = 16'h0000;                             yout_r = 32'h00000000;                    end          else if(start) begin                                        if(i == 5'd0) begin                                                    areg = ain;                                                breg = bin;                                      end                             else if(i 5'd0 i 5'd17) begin                                                if(areg ) yout_r = {1'b0,yout +breg,yout_r };                                                  else yout_r = yout_r1;                                             end                    end end assign yout = yout_r; endmodule   testbench: module ex_tb; reg clk; reg rst_n;         reg start; reg ain; reg bin;   wire yout; wire done;   ex i_ex (        .clk       (clk),        .rst_n     (rst_n),       .ain       (ain),       .bin       (bin),       .start      (start),       .yout      (yout),       .done      (done) );   initial begin          clk = 0;          forever          #10 clk = ~clk;  end   initial begin          rst_n = 1'b0;          start = 1'b0;          ain = 16'd0;          bin = 16'd0;          #1000;          rst_n = 1'b1;                      #1000;          ain = 16'd65535;          bin = 16'd32768;          #100;          start = 1'b1;          #4500;          start = 1'b0;          #1000_000;          $stop; end endmodule modelsim跑出来的结果: 计算器所得的结果 说明我的代码应该完全正确。 特权同学代码仿真出来的结果: 发现是错误的。 特权同学的代码错在哪儿?以下是网友的分析: 细心的读者估计已经发现{1'b0,yout +breg,yout_r }这条语句中位数怎么算都是31位啊,明明应该是32位的嘛(视频里也说是32位的啊)为什么会出现这个bug呢? 这里,有些网友是这样解释的yout +breg这两个16位数相加如果足够大,肯定是会产生进位的,所以就成了17位。呵呵,现在刚好17+14+1=32位了吧。 但是这个解释有一个很明显的bug:那要是没有进位呢?不还是16位的吗? 笔者认真考虑了一个晚上想了很多解释最终觉得以下两个解释,虽然自己也不是很有信心,但勉强可以支撑一下这个算法: 1,对于verilog语言“+”会产生一个一个加法器,而加法器都是会带进位位的,所以yout +breg会自动产生一个进位位,变成17位。 2,即使上面一个说法不成立,那么当{...}中不足32位时应该会在最高位自动补0或者X吧,这样最终依然是32位。并且不影响后面的计算结果。 对于这样两种猜想,由于本人能力有限,且刚刚接触FPGA所以不敢保证不是谬论,还希望高手们要多多指教。 上面啰嗦了这么多,其实只是对特权大哥代码的一个解读,真正有问题的是下一句: 根据上面总结出的那个规律,最高位只是用来进位用的那么这句代码: yout_r =yout_r +breg; 就明显有问题了,如果两个加数相加产生进位该怎么办呢?     暂时就写这么多,有什么不对的地方欢迎大家批评指正!!!
相关资源