Verilog 加法器和减法器(7)
在计算机中浮点数 表示通常采用IEEE754规定的格式,具体参考以下文章。
https://www.cnblogs.com/mikewolf2002/p/10095995.html
下面我们在Verilog中用状态机实现单精度浮点数的加减法功能。这个实现是多周期的单精度浮点加法。
浮点加法分为以下几个步骤:
1.初始化阶段,分离指数和尾数以及符号位。判断加数和被加数是否是规约浮点数,不是话,直接置overflow=0x11,重新进入初始化阶段,进行下一组数的加法
2.判断加数和被加数中是否有0,有零的话,可以直接得到结果。
3.对接操作,小阶向大阶对齐。
4.对接后,进行尾数相加。
5.规格化尾数,进行左规和右规处理。
6.判断是否溢出,设置overflow标志。
下面是verilog代码:


- module floatadd(clk, rst_n, x, y, z,overflow);
- input clk;
- input rst_n;
- input [31:0] x;
- input [31:0] y;
- output [31:0] z;
- output [1:0] overflow;//0,没有溢出,1,上溢,10,下溢,11 输入不是规格化数
- reg [31:0] z; // z=x+y
- reg[24:0] xm, ym, zm; //尾数部分, 0+ 1+[22:0],
- reg[7:0] xe, ye, ze; //阶码部分
- reg[2:0] state, nextstate; //状态机
- reg zsign; //z的符号位
- reg [1:0] overflow;
- parameter start=3'b000,zerock=3'b001,exequal=3'b010,addm=3'b011,infifl=3'b100,over =3'b110;
- always @(posedge clk) begin
- if(!rst_n)
- state <= start;
- else
- state <= nextstate;
- end
- //状态机进行浮点加法处理
- always@(state,nextstate,xe,ye,xm,ym,ze,zm) begin
- case(state)
- start: //初始化,分离尾数和指数,调整符号位
- begin
- xe <= x[30:23];
- xm <= {1'b0,1'b1,x[22:0]};
- ye <= y[30:23];
- ym <= {1'b0,1'b1,y[22:0]};
- //判断是否溢出,大于最大浮点数,小于最小浮点数
- if((xe==8'd255)||(ye==8'd255)||((xe==8'd0)&&(xm[22:0]!=23'b0))||((ye==8'd0)&&(ym[22:0]!=23'b0)) )
- begin
- overflow <= 2'b11;
- nextstate <= start; //直接到初始化
- z <= 32'b1; //直接赋值最小非规约数,
- end
- else
- nextstate <= zerock;
- end
- zerock://检测x,y如果有一个为0,则跳转到over state
- begin
- if((x[22:0]==23'b0)&&(xe==8'b0))
- begin
- {zsign, ze,zm} <= {y[31],ye, ym};
- nextstate <= over;
- end
- else
- begin
- if((y[22:0]==23'b0)&&(ye==8'b0))
- begin
- {zsign,ze,zm} <= {x[31],xe, xm};
- nextstate <= over;
- end
- else
- nextstate <= exequal;
- end
- end
- exequal:
- begin
- if(xe == ye)
- nextstate <= addm;
- else
- begin
- if(xe > ye)
- begin
- ye <= ye + 1'b1;//阶码加1
- ym[23:0] <= {1'b0, ym[23:1]};
- if(ym==8'b0)
- begin
- zm <= xm;
- ze <= xe;
- zsign<=x[31];
- nextstate <= over;
- end
- else
- nextstate <= exequal;
- end
- else
- begin
- xe <= xe + 1'b1;//阶码加1
- xm[23:0] <= {1'b0, xm[23:1]};
- if(xm==8'b0)
- begin
- zm <= ym;
- ze <= ye;
- zsign <= y[31];
- nextstate <= over;
- end
- else
- nextstate <= exequal;
- end
- end
- end
- addm://尾数相加
- begin
- ze <= xe;
- if((x[31]^y[31])==1'b0) //同符号
- begin
- zsign = x[31];
- zm <= xm + ym;
- end
- else
- begin
- if(xm>ym)
- begin
- zsign = x[31];
- zm <= xm - ym;
- end
- else
- begin
- zsign = y[31];
- zm <= ym - xm;
- end
- end
- if(zm[23:0]==24'b0)
- nextstate <= over;
- else
- nextstate <=infifl;
- end
- infifl://规格化处理
- begin
- if(zm[24]==1'b1)//有进位,或借位
- begin
- zm <= {1'b0,zm[24:1]};
- ze <= ze + 1'b1;
- nextstate <= over;
- end
- else
- begin
- if(zm[23]==1'b0)
- begin
- zm <= {zm[23:0],1'b0};
- ze <= ze - 1'b1;
- nextstate <= infifl;
- end
- else
- begin
- nextstate <= over;
- end
- end
- end
- over:
- begin
- z <= {zsign, ze[7:0], zm[22:0]};
- //判断是否溢出,大于最大浮点数,小于最小浮点数
- if(ze==8'd255 )
- begin
- overflow <= 2'b01;
- end
- else if((ze==8'd0)&&(zm[22:0]!=23'b0)) //不处理非规约数
- begin
- overflow <= 2'b10;
- end
- else
- overflow <= 2'b00;
- nextstate <= start;
- end
- default:
- begin
- nextstate <= start;
- end
- endcase
- end
- endmodule
下面是testbench代码:
代码中仅有两组加法操作,以后会写出更完备的testbench代码,用c语言产生更多的测试数据,在testbench中读入。to do…
- `timescale 1ns/1ns
- `define clock_period 20
- module floatadd_tb;
- reg [31:0] x,y;
- wire [31:0] z;
- reg clk;
- reg rst_n;
- wire [1:0] overflow;
- floatadd floatadd_0(
- .clk(clk),
- .rst_n(rst_n),
- .x(x),
- .y(y),
- .add(add),
- .z(z),
- .overflow(overflow)
- );
- initial clk = 0;
- always #(`clock_period/2) clk = ~clk;
- initial begin
- x = 0;
- rst_n = 1'b0;
- #20 rst_n = 1'b1;
- #(`clock_period) x = 32'b01000000011011101001011110001101; //3.456
- #(`clock_period*7) x = 32'hc2b5999a; //-90.8
- end
- initial begin
- y = 0;
- #20
- #(`clock_period) y = 32'b01000000010011001100110011001101;//2.4
- #(`clock_period*7) y = 32'h41a3c28f;//20.47
- end
- initial begin
- #(`clock_period*100)
- $stop;
- end
- endmodule
浮点数减法很简单,只要把减数的符号位取反就可以了。
下面是浮点加减法代码。如果add为1,执行加法操作,如果add为0,执行减法操作。
- module floataddsub(clk, rst_n, x, y, add, z,overflow);
- input clk;
- input rst_n;
- input [31:0] x;
- input [31:0] y;
- input add;
- output [31:0] z;
- output [1:0] overflow;
- wire [31:0] y1;
- floatadd floatadd_0(
- .clk(clk),
- .rst_n(rst_n),
- .x(x),
- .y(y1),
- .z(z),
- .overflow(overflow)
- );
- assign y1 = add ? y:{~y[31],y[30:0]};
- endmodule
用下面的testbench代码,实现加减法操作。
- `timescale 1ns/1ns
- `define clock_period 20
- module floataddsub_tb;
- reg [31:0] x,y;
- reg add;
- wire [31:0] z;
- reg clk;
- reg rst_n;
- wire [1:0] overflow;
- floataddsub floataddsub_0(
- .clk(clk),
- .rst_n(rst_n),
- .x(x),
- .y(y),
- .add(add),
- .z(z),
- .overflow(overflow)
- );
- initial
- begin
- clk = 1'b0;
- add = 1'b0;
- #(`clock_period*9)
- add = 1'b1;
- end
- always #(`clock_period/2) clk = ~clk;
- initial begin
- x = 0;
- rst_n = 1'b0;
- #20 rst_n = 1'b1;
- #(`clock_period) x = 32'b01000000011011101001011110001101; //3.456
- #(`clock_period*7) x = 32'hc2b5999a; //-90.8
- end
- initial begin
- y = 0;
- #20
- #(`clock_period) y = 32'b01000000010011001100110011001101;//2.4
- #(`clock_period*7) y = 32'h41a3c28f;//20.47
- end
- initial begin
- #(`clock_period*100)
- $stop;
- end
- endmodule
功能仿真的波形如下:
Verilog 加法器和减法器(7)的更多相关文章
- Verilog 加法器和减法器(8)-串行加法器
如果对速度要求不高,我们也可以使用串行加法器.下面通过状态机来实现串行加法器的功能. 设A=an-1an-2-a0, B=bn-1bn-2-b0,是要相加的两个无符号数,相加的和为:sum=sn-1s ...
- Verilog 加法器和减法器(4)
类似于行波进位加法器,用串联的方法也能够实现多位二进制数的减法操作. 比如下图是4位二进制减法逻辑电路图. 8位二进制减法的verilog代码如下: module subn(x, y, d,cin) ...
- Verilog 加法器和减法器(6)
为了减小行波进位加法器中进位传播延迟的影响,可以尝试在每一级中快速计算进位,如果能在较短时间完成计算,则可以提高加法器性能. 我们可以进行如下的推导: 设 gi=xi&yi, pi = xi ...
- Verilog 加法器和减法器(3)
手工加法运算时候,我们都是从最低位的数字开始,逐位相加,直到最高位.如果第i位产生进位,就把该位作为第i+1位输入.同样的,在逻辑电路中,我们可以把一位全加器串联起来,实现多位加法,比如下面的四位加法 ...
- Verilog 加法器和减法器(2)
类似半加器和全加器,也有半减器和全减器. 半减器只考虑当前两位二进制数相减,输出为差以及是否向高位借位,而全减器还要考虑当前位的低位是否曾有借位.它们的真值表如下: 对半减器,diff = x ^y, ...
- Verilog 加法器和减法器(1)
两个一位的二进制数x,y相加,假设和为s,进位为cout,其真值表为: 从真值表中,我们可以得到:s = x^y, cout = x&y,实现两个一位数相加的逻辑电路称为半加器. 实现该电路的 ...
- Verilog 加法器和减法器(5)
前面二进制加法运算,我们并没有提操作数是有符号数,还是无符号数.其实前面的二进制加法对于有符号数和无符号数都成立.比如前面的8位二进制加法运算,第一张图我们选radix是unsigned,表示无符号加 ...
- 基于Xilinx的Synthesize
所谓综合.就是讲HDL语言.原理图等设计输入翻译成由与.或.非们和RAM.触发器登记本逻辑单元的逻辑连接(即网表).并依据目标和要求(约束条件)优化生成的逻辑连接. ISE-XST XST是Xilin ...
- FPGA综合工具--Synplify Pro的常用选项及命令
最近要用到Synplify,但以前没使用过,无基础,找到一篇帖子,隧保存下来. 本文转自:http://blog.sina.com.cn/s/blog_65fe490d0100v8ax.html Sy ...
随机推荐
- 转载-解决ORACLE 在控制台进行exp,导出时,空表不能导出
一.问题原因: 11G中有个新特性,当表无数据时,不分配segment,以节省空间 1.insert一行,再rollback就产生segment了. 该方法是在在空表中插入数据,再删除,则产生segm ...
- Cause: java.sql.SQLException: Could not retrieve transation read-only status server
背景 最近在部署一套完整的项目,部署过程中遇到很多的问题,在来总结一些如标题的这个错误! 环境说明: 使用分布式数据库,使用的是mysql! ### Cause: java.sql.SQLExcept ...
- JedisConnectionException: java.net.ConnectException: Connection refused
出现问题 我遇到的一个问题,在连接redis的时候出现了错误!错误如下: JedisConnectionException: java.net.ConnectException: Connection ...
- Python异常处理回顾与总结
1 引言 在我们调试程序时,经常不可避免地出现意料之外的情况,导致程序不得不停止运行,然后提示大堆提示信息,大多是这种情况都是由异常引起的.异常的出现一方面是因为写代码时粗心导致的语法错误,这种错误在 ...
- 8.9 正睿暑期集训营 Day6
目录 2018.8.9 正睿暑期集训营 Day6 A 萌新拆塔(状压DP) B 奇迹暖暖 C 风花雪月(DP) 考试代码 A B C 2018.8.9 正睿暑期集训营 Day6 时间:2.5h(实际) ...
- 简表-Java-Echart报表介绍
Java后台报表尝试了很多,最终发现了一款,而且是开源的,简表地址:http://www.jatools.com/jor/.问题的引入:该报表支持嵌套,钻去,应对excel类似的报表,足够了.但是,报 ...
- Azure存储上传下载(断点续传)
最近有一个客户需要将文件系统(VM搭建)迁移到Azure存储上,对于Azure存储这里就不多做介绍,但是该客户由于网络原因下载文件的时候经常出现上传中断,所以想在Azure 存储上实现下载的断点续传. ...
- Chrome中使用老的标题栏界面
Chrome 69中启用了新的UI界面,看着更加秀气了. 但新UI一个不好用的地方是标签栏太高了,留给windows标题栏的空白太小,导致拖动窗口位置非常不方便,如下是一个解决方法: 在地址栏输入: ...
- the difference between an embOS interrupt and a zero latency interrupt
the difference between an embOS interrupt and a zero latency interrupt is the interrupt priority lev ...
- bitnami下webmin安装
下载 我在官方网站下载最新的安装包(webmin_1.670_all.deb):http://sourceforge.net/projects/webadmin/files/webmin 安装 单独 ...