在计算机中浮点数 表示通常采用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)的更多相关文章

  1. Verilog 加法器和减法器(8)-串行加法器

    如果对速度要求不高,我们也可以使用串行加法器.下面通过状态机来实现串行加法器的功能. 设A=an-1an-2-a0, B=bn-1bn-2-b0,是要相加的两个无符号数,相加的和为:sum=sn-1s ...

  2. Verilog 加法器和减法器(4)

    类似于行波进位加法器,用串联的方法也能够实现多位二进制数的减法操作.  比如下图是4位二进制减法逻辑电路图. 8位二进制减法的verilog代码如下: module subn(x, y, d,cin) ...

  3. Verilog 加法器和减法器(6)

    为了减小行波进位加法器中进位传播延迟的影响,可以尝试在每一级中快速计算进位,如果能在较短时间完成计算,则可以提高加法器性能. 我们可以进行如下的推导: 设 gi=xi&yi, pi = xi ...

  4. Verilog 加法器和减法器(3)

    手工加法运算时候,我们都是从最低位的数字开始,逐位相加,直到最高位.如果第i位产生进位,就把该位作为第i+1位输入.同样的,在逻辑电路中,我们可以把一位全加器串联起来,实现多位加法,比如下面的四位加法 ...

  5. Verilog 加法器和减法器(2)

    类似半加器和全加器,也有半减器和全减器. 半减器只考虑当前两位二进制数相减,输出为差以及是否向高位借位,而全减器还要考虑当前位的低位是否曾有借位.它们的真值表如下: 对半减器,diff = x ^y, ...

  6. Verilog 加法器和减法器(1)

    两个一位的二进制数x,y相加,假设和为s,进位为cout,其真值表为: 从真值表中,我们可以得到:s = x^y, cout = x&y,实现两个一位数相加的逻辑电路称为半加器. 实现该电路的 ...

  7. Verilog 加法器和减法器(5)

    前面二进制加法运算,我们并没有提操作数是有符号数,还是无符号数.其实前面的二进制加法对于有符号数和无符号数都成立.比如前面的8位二进制加法运算,第一张图我们选radix是unsigned,表示无符号加 ...

  8. 基于Xilinx的Synthesize

    所谓综合.就是讲HDL语言.原理图等设计输入翻译成由与.或.非们和RAM.触发器登记本逻辑单元的逻辑连接(即网表).并依据目标和要求(约束条件)优化生成的逻辑连接. ISE-XST XST是Xilin ...

  9. FPGA综合工具--Synplify Pro的常用选项及命令

    最近要用到Synplify,但以前没使用过,无基础,找到一篇帖子,隧保存下来. 本文转自:http://blog.sina.com.cn/s/blog_65fe490d0100v8ax.html Sy ...

随机推荐

  1. 026.Zabbix简单调优

    一 调优相关对应项 Zabbix busy trapper processes, in % StartTrappers=5 Zabbix busy poller processes, in % Sta ...

  2. Python - 列表与字符串的互相转换

    题目:请将text字符串中的数字取出,并输出成一个新的字符串 text = "aAsmr3 idd4bgs7Dlsf 9eAF" b = list(text) new_list = ...

  3. 谈 JavaScript 中的强制类型转换 (2. 应用篇)

    这一部分内容是承接上一篇的, 建议先阅读谈 JavaScript 中的强制类型转换 (1. 基础篇) 前两章讨论了基本数据类型和基本包装类型的关系, 以及两个在类型转换中十分重要的方法: valueO ...

  4. Windows上Nginx的安装教程详解

    一 背景 为了方便本地的开发和验证,于是整理了这一篇Windows上安装Nginx的博文,建议一般学习还是使用Linux,一般正规公司都是在Linux上安装Nginx服务! 本篇内容相对比较简单,如果 ...

  5. ServletContextListener 详解

    1.首先来看一看源码 该类的源码 public interface ServletContextListener extends EventListener { /** * Receives noti ...

  6. BZOJ4175 : 小G的电话本

    用后缀树统计出出现了x次的本质不同的子串的个数,最后再乘以x,得到一个多项式. 这个多项式常数项为0,但是一次项不为0. 于是把整个多项式除以一次项,通过多项式求ln和多项式求exp求出它的幂. 最后 ...

  7. Codeforces Round #369 (Div. 2) C. Coloring Trees 动态规划

    C. Coloring Trees 题目连接: http://www.codeforces.com/contest/711/problem/C Description ZS the Coder and ...

  8. spring-boot 速成(10) -【个人邮箱/企业邮箱】发送邮件

    发邮件是一个很常见的功能,代码本身并不复杂,有坑的地方主要在于各家邮件厂家的设置,下面以qq个人邮箱以及腾讯企业邮箱为例,讲解如何用spring-boot发送邮件: 一.添加依赖项 compile ' ...

  9. LPC43xx Asymmetric Dual Core : Cortex-M0 and Cortex-M4

  10. AVR Programming Methods

    AVR Programming Methods  There are many ways to program AVR microcontrollers. Since many people ask ...