在计算机中浮点数 表示通常采用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. 子类 父类强转 HttpServlet service实现

    相当于 走父类 临时走了一趟 HttpServletRequest ->ServletRequets -> HttpServeltRequest /* */ public void ser ...

  2. 使用Synchronized块同步变量

    我们可以通过synchronized块来同步特定的静态或非静态方法.要想实现这种需求必须为这些特定的方法定义一个类变量,然后将这些方法的代码用synchronized块括起来,并将这个类变量作为参数传 ...

  3. UEditor 的使用

    UEditor 的使用 一.UEditor 的使用 官方网站:http://ueditor.baidu.com/website/ 下载地址:http://ueditor.baidu.com/websi ...

  4. 群晖NAS的Docker容器使用中国镜像加速

    vi /var/packages/Docker/etc/dockerd.json 添加如下内容: { "registry-mirrors": ["https://regi ...

  5. Overclock STM32F4 device up to 250MHz

    http://stm32f4-discovery.com/2014/11/overclock-stm32f4-device-up-to-250mhz/ Let’s test what STM32F4x ...

  6. ubuntu下smokeping安装配置

    0.参考文件 http://wenku.baidu.com/view/950fbb0a79563c1ec5da71b1 http://aaaxiang000.blog.163.com/blog/sta ...

  7. Hadoop: the definitive guide 第三版 拾遗 第四章

    第四章中提到了通过CompressionCodec对streams进行压缩和解压缩,并提供了示例程序: 输入:标准输入流 输出:压缩后的标准输出流 // cc StreamCompressor A p ...

  8. asp.net core读取appsettings.json,如何读取多环境开发配置

    摘要 在读取appsettings.json文件中配置的时候,觉得最简单的方式就是使用asp.net core注入的方式进行读取了. 步骤 首先根据配置项的结构定义一个配置类,比如叫AppSettin ...

  9. 由pushViewController说起可能出线的各种死法

    做苹果开发或者果粉对导航条这个东西应该都不陌生,这咚咚在小小的屏幕上通过一个简单的View的队列管理来做到手机界面的有条理管理,但是开发过程程序员可能碰到各种死法,下面分享一二.            ...

  10. C#编程(三十五)----------foreach和yield

    枚举 在foreach语句中使用枚举,可以迭代集合中的元素,且无需知道集合中的元素个数. 数组或集合实现带GetEumerator()方法的IEumerable接口.GetEumerator()方法返 ...