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

2011-9-22 15:44 6434 6 16 分类: FPGA/CPLD

首先声明一下本人在FPGA这条道路上走了还不到一个星期,对于很多FPGA硬件软件方面的知识理解还很不到位,所以下文必然会有很多漏洞,还希望大家多多指正,共同学习。


本文所用代码基于特权乘法器设计实验一节,代码见下面链接:http://group.ednchina.com/1375/21236.aspx



在看特权大哥16位乘法器视频的时候,一直没有弄明白最关键的乘法操作的两句话,红色标记如下:

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

begin

if(areg[i-1]) yout_r = {1'b0,yout[30:15]+breg,yout_r[14:1]}; //累加并移位

else yout_r <= yout_r>>1; //移位不累加

end

else if(i == 5'd16 && areg[15]) yout_r[31:16] <= yout_r[31:16]+breg; //累加不移位

刚开始是对乘法以为的原理不太懂,后来在草稿纸上退到之后基本明白了,先以两个4位二进制数为例,将推导思路解释一下:

20110922152218691.png

根据这个竖式,可以总结出这样一个规律:

4位二进制乘数的最位乘以被乘数时,得出的结果最高只可能出现在第7位上(从广义上说就是结果的次高位上),所以第八位(广义上说就是最高位)只是用来准备存放进位的。

如果读者能够明白这样一个规律的话,那么我们接着就以特权的代码进行分析:

首先要搞清楚在代码{1'b0,yout[30:15]+breg,yout_r[14:1]}[14:1][30:15]指的是原来数的这些位 而它们对应的 现在这个数的位数又分别是[13:0][29:14],所以这里其实就实现了右移操作。

对于第31位刚开始始终不用,每次都把结果存放在第[29:14]位之中,15个右移后,最终将真正个位数移到了最低位(0位)。

这里有个问题需要说明一下:

细心的读者估计已经发现{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;

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

所以我认为这一句应该是需要这么写的:

else if(i == 5'd16 && areg[15]) yout_r[31:15] <= yout_r[30:15]+breg; 

呵呵,在我写此文的时候,发现特权的博客上已经有前辈这么提出来了,果然论坛上还是有高手的,这里只是思路相同,没有抄袭之想法还请高手看到此文章后别误会。

下面是通过Modelsim仿真出来的结果:


(图一,为特权代码的仿真结果)

20110922152258147.png



(图二,为修改后代码的仿真结果)

20110922152309167.png



(图三为正确答案)

20110922152318100.png


后记

在笔者写这篇文章的时候同时还看到了有人这样修改了代码:

else if(i > 5'd0 && i < 5'd16) begin
    if(areg[i-1]) yout_r = {1'b0,yout[31:15]+{1'b0,breg},yout_r[14:1]}; 
     else yout_r <= yout_r>>1; 
    end
   else 

if(i == 5'd16 && areg[15]) yout_r[31:15] <= yout_r[31:15]+{1'b0,breg};  

应该说思路是一样的,这位网友强制加了一位作为进位位,纠正了进位位的丢失。对于这个代码我也随即抽了几个数做了一下仿真,结果完全正确。

结果如下:

20110922152329848.png

20110922152336325.png

20110922152342496.png



最后

特别鸣谢:特权大哥还有论坛上的那些提供意见和代码的高手们。

PARTNER CONTENT

文章评论10条评论)

登录后参与讨论

用户1838426 2015-5-22 09:33

还有数码管实验,我在买开发板回来时,在做实验想修改数码管的数字变动的时间,但在修改 else if(cnt == 24'hffffff) num <= num+1'b1; // 不起作用,我也想了半天,原来,这里cnt == 24'hffffff时倒无所谓,如果(cnt == 24'heeeeee,并没有归0,而是一直累加下去直到cnt == 24'hffffff,并且归0,再到cnt == 24'hffffff,num <= num+1'b1; 后来我把以下两个语句合二为一,(如果不合一,cnt编译出错,上网查了一下,好像是说cnt不能在两个always 语句赋值,只能同一always 语句,而且是用非阻塞语句,) always @ (posedge clk or negedge rst_n) if(!rst_n) cnt <= 25'd0; //如果系统复位了,25位的寄存器初始值是0 else cnt <= cnt+1'b1; //如果不是复位,计数器自加1 reg[3:0] num; //定一个4位的寄存器 always @ (posedge clk or negedge rst_n) if(!rst_n) num <= 4'd0; //如果系统复位了,4位的寄存器初始值是0 else if(cnt == 24'hffffff) num <= num+1'b1; //否则,如果CNT计数器到24'hffffff,4位寄存器自加1

用户1838426 2015-5-22 09:21

if(areg[i-1]) yout_r = {1'b0,yout[31:15]+{1'b0,breg},yout_r[14:1]}; else yout_r <= yout_r>>1; 这里面的yout[31:15]+breg ,应是yout_r[31:15]吧!每累加一次,都会有数据输出在输出口吗?而不是存在寄存器里面,到最后才输出在输出口引脚吗?

用户1838426 2015-5-22 09:09

if(areg[i-1]) yout_r = {1'b0,yout[31:15]+{1'b0,breg},yout_r[14:1]}; else yout_r <= yout_r>>1; 加进位之后,位拼里面的1'b0,好像可以不要了吧! 为了这个问题,我也想了很久

用户377235 2013-7-24 11:00

你好,请问乘法中不是左移么,为什么我看都是右移呢,而且为什么移动的是作为输出的y?还有breg为什么加在14——29位上?望各位给菜鸟级的我回答一下

用户377235 2013-7-24 11:00

你好,请问乘法中不是左移么,为什么我看都是右移呢,而且为什么移动的是作为输出的y?还有breg为什么加在14——29位上?望各位给菜鸟级的我回答一下

用户1408266 2012-10-7 22:07

如果把ain=60000,bin=60000,计算结果不正确,为什么呢?

用户295512 2012-4-9 12:58

谢谢楼主的分享 我菜鸟一名。我也仿真了一下,发下楼主您所说的 else if(i == 5'd16 && areg[15]) yout_r[31:15] <= yout_r[30:15]+breg; 这样写还是会有算漏进位的情况发生(如果用乘数和被乘数都是65535来仿真会发现,结果应该是不对的吧,我仿真结果是2147483649,实际应该是4294836225。当然,不排除我自己还有其他错误) 而用您介绍其他大神的方法 if(areg[i-1]) yout_r = {1'b0,yout[31:15]+{1'b0,breg},yout_r[14:1]}; else yout_r <= yout_r>>1; end else if(i == 5'd16 && areg[15]) yout_r[31:15] <= yout_r[31:15]+{1'b0,breg}; 这个来运算仿真的话,就是完美的

用户1647523 2012-2-17 16:59

Arduino使用方法学习,详细,谢谢!

用户380725 2011-9-25 10:55

围观达人

用户1696769 2011-9-23 16:39

已经把楼主加入博客名人堂了。。。哈哈
相关推荐阅读
用户378040 2011-10-18 00:30
关于上下拉电阻的探究
笔者在网上找了很多关于上下拉电阻的资料,可是感觉说的还是很乱,依然很难理解。经过笔者的认真研究,现将自己所得所感写下来希望这只是个讨论的开始而绝非终结。 首先,想说上拉电阻几乎都是应运三极管电路而...
用户378040 2011-09-25 11:35
9.25总结
这两天一口气做了串口通信实验,PS2键盘实验 和 VGA视频接口实验,这些只能算初步的调试,代码几乎都是直接照搬《Verilog那些事儿》的,通过调试这些实验,自己对FPGA有了新的认识,将这几天的思...
用户378040 2011-09-21 16:31
成功的ModelSim 仿真,简单的TestBench代码学习
今天终于搞定了ModelSim的仿真,呵呵昨天没有出波形是因为自己居然不知道TestBench是要自己编写代码的,有点2了。。。看在今天心情比较好,就把word文档慢慢弄上来吧 代码及文档见我的CSD...
用户378040 2011-09-21 16:28
键盘程序测试
按键(低电平为按下):K1 I/O144K2 I/O145K3 I/O146K4 I/O147LED(0为亮):LED1 I/O113LED2 I/O114LED3 I/O115LED4 I/O116...
用户378040 2011-09-21 12:49
进入实验室两年以来的总结
——写给自己,也写给实验室大二硬件组本文基于自己在社区上8篇总结, 和7篇培训纪要总结如下:在最初进入实验室的时候我目光的仅仅关注于单片机各项模块当中,当时我觉得只要我模块比别人调的好 调的多就会比别...
EE直播间
更多
我要评论
10
6
关闭 站长推荐上一条 /3 下一条