原创 对特权同学的16位乘法器代码的理解与修正

2014-8-10 10:44 2220 24 29 分类: FPGA/CPLD

        一直很想学FPGA,去年11月份买了一套FPGA的开发板,玩了没两天,换了新的工作,那套开发板也束之高阁了。最近公司做了一个《时间管理》的培训,发现自己这一年总是在浪费时间没有什么进步,很后悔。然后决定好好学习一下特权同学的《深入浅出玩转FPGA》那套视频,因为还有些基础在,就直接跳到lesson12—乘法器设计实验。

 

看特权同学的视频,一直没有弄明白最关键的乘法操作的两句话(红色字体)。

else if (i > 5'd0 && i < 5'd16)

begin

if(areg[i-1])   yout_r <= {1'b0,yout_r[30:15]+breg,yout_r[14:1]};

else               yout_r <= yout_r >> 1;

end

else if (i == 5'd16 && areg[15])  yout_r = yout_r[31:16] + 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[15:0] ain;

input[15:0] bin;

output done;

output[31:0]yout;

reg[15:0]areg;

reg[15:0]breg;

reg[31:0]yout_r;

reg done_r;

reg[4:0]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[i-1]) yout_r = {1'b0,yout[31:16]+breg,yout_r[15:1]};  

                                               else yout_r <= yout_r>>1;       

                                     end

                   end

end

assign yout = yout_r;

endmodule

 

testbench:

module ex_tb;

reg clk;

reg rst_n;        

reg start;

reg[15:0] ain;

reg[15:0] bin;

 

wire[31:0] 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跑出来的结果:

qq图片20140810102649.jpg

计算器所得的结果

qq图片20140810102636.jpg

说明我的代码应该完全正确。

特权同学代码仿真出来的结果:

qq图片20140810104303.jpg

发现是错误的。

特权同学的代码错在哪儿?以下是网友的分析:

细心的读者估计已经发现{1'b0,yout[30:15]+breg,yout_r[14:1]}这条语句中位数怎么算都是31位啊,明明应该是32位的嘛(视频里也说是32位的啊)为什么会出现这个bug呢?

这里,有些网友是这样解释的yout[30:15]+breg这两个16位数相加如果足够大,肯定是会产生进位的,所以就成了17位。呵呵,现在刚好17+14+1=32位了吧。

但是这个解释有一个很明显的bug:那要是没有进位呢?不还是16位的吗?

笔者认真考虑了一个晚上想了很多解释最终觉得以下两个解释,虽然自己也不是很有信心,但勉强可以支撑一下这个算法:

1,对于verilog语言“+”会产生一个一个加法器,而加法器都是会带进位位的,所以yout[30:15]+breg会自动产生一个进位位,变成17位。

2,即使上面一个说法不成立,那么当{...}中不足32位时应该会在最高位自动补0或者X吧,这样最终依然是32位。并且不影响后面的计算结果。

对于这样两种猜想,由于本人能力有限,且刚刚接触FPGA所以不敢保证不是谬论,还希望高手们要多多指教。

上面啰嗦了这么多,其实只是对特权大哥代码的一个解读,真正有问题的是下一句:

根据上面总结出的那个规律,最高位只是用来进位用的那么这句代码:

yout_r[31:16]<=yout_r[31:16]+breg;

就明显有问题了,如果两个加数相加产生进位该怎么办呢?

 

 

暂时就写这么多,有什么不对的地方欢迎大家批评指正!!!

文章评论5条评论)

登录后参与讨论

用户1840013 2015-10-8 20:47

你好 ,我还有一点疑问 比如说两个四位数1100*1101按照你所说的最低位为1右移累加 得 0110 0000此低位为0右移 得 0011 0000第三位为1右移累加 得 0100 1000最高位相加 得 1000 0100而正确的答案是 1001 1100是什么原因,求大神解惑

wiliamzhou_446210705 2014-8-27 22:42

谢谢你给我的启发。^-^

用户1774260 2014-8-20 14:18

矮油,我就是那个你文章里的的网友,好开心啊。

ilove314_323192455 2014-8-13 19:22

是的,最新的代码工程已经勘误了。

用户1711475 2014-8-13 11:15

矮油,跟风云博主叫板;对特权指指点点的人,想必也不是无名之辈。关注一下!
相关推荐阅读
wiliamzhou_446210705 2015-04-10 14:57
【博客大赛】Odyssey Max 10双配置闪存
 MAX10的非易失性是因为它把FPGA配置的Flsah做到了芯片里面,增加了安全性,减小了电路板面积,降低成本与功耗,而且逻辑单元在4000以上的Max10内部都含有两个配置闪存,今天我们就对这...
wiliamzhou_446210705 2015-04-08 20:47
【博客大赛】Odyssey Max 10 overview
    Odyssey Max 10 IOT Evaluation Kit是来自世界著名分销商品牌Macnica的一款开发套件,我从同事手上拿到了这个开发套件,终于见识到传说中的MAX 10,这是Al...
wiliamzhou_446210705 2014-11-21 20:46
如何计算射频串联器件的噪声指数
如何计算射频串联器件的噪声指数噪声指数是用来衡量某一电子器件的噪声性能,它定义为信号在进入这一器件前和从该器件输出后的载噪比变化的倍数。射频电子元器件在信号处理过程中会将其本身所具有的热噪声附加到信号...
wiliamzhou_446210705 2014-09-22 22:58
串口通信之发送模块
上篇博文介绍了一下UART接收模块,这篇我们谈一谈发送模块。 发送模块将需要传输的8位数据以字符帧格式发送出去。那我们就开门见山,发送模块由哪些模块组成? 由上图可知,波特率定时模块...
wiliamzhou_446210705 2014-09-20 00:19
串口通信之接收模块
    好久没有写博客了,这次我们谈一谈串口通信,记得以前看过特权同学的uart收发模块的代码,当时没能很好的弄明白,主要原因可能特权同学的代码即包含接收模块,又包含发射模块,代码量很大一时难以理...
wiliamzhou_446210705 2014-09-01 23:37
浅谈有限状态机FSM——以序列检测为例
什么是状态机?简单来说,就是通过不同的状态迁移来完成一些特定的顺序逻辑。硬件的并行性决定了用Verilog描述的硬件实现(譬如不同的always语句)都是并行执行的,那么如果希望分多个时间完成一个任务...
我要评论
5
24
关闭 站长推荐上一条 /2 下一条