在计算机中浮点数 表示通常采用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. linux入门系列

    Linux基础入门 常用Linux命令 linux学习笔记-1.man_page linux学习笔记-2.常用命令 linux学习笔记-3.文件相关命令 linux学习笔记-4.系统命令 linux学 ...

  2. java中的stream的Map收集器操作

    package test9; import java.util.Collections; import java.util.HashSet; import java.util.Map; import ...

  3. normalizr实践使用(个人总结,仅供参考)

    # normalizr实践使用 原数据 (自编数据,本数据仅供参考) var aaaObj ={ "id" : "0000000000000000000000000000 ...

  4. [BZOJ3585]mex(莫队+分块)

    显然可以离线主席树,这里用莫队+分块做.分块的一个重要思想是实现修改与查询时间复杂度的均衡,这里莫队和分块互相弥补. 考虑暴力的分块做法,首先显然大于n的数直接忽略,于是将值域分成sqrt(n)份,每 ...

  5. java集合之Link的比较

    概要 前面,我们学完了List的全部内容(ArrayList, LinkedList, Vector, Stack). 现在,我们再回头看看总结一下List.内容包括:第1部分 List概括第2部分 ...

  6. MikroTik RouterOS安装后初始化配置(PPPOE拨号上网)

    1.修改登入密码 路由器默认登入账号为admin,密码为空,强烈建议修改登入密码保证安全: 2.修改接口名称 选择Interface,切换到Ethernet标签,找到状态是R(run)的两个端口. 给 ...

  7. 使用ptrace向已运行进程中注入.so并执行相关函数(转)

    1. 简介 使用ptrace向已运行进程中注入.so并执行相关函数,其中的“注入”二字的真正含义为:此.so被link到已运行进程(以下简称为:目标进程)空间中,从而.so中的函数在目标进程空间中有对 ...

  8. mongodb chunk 大小设置

    默认是64MB,取值范围是1 MB 到 1024 MB. 那改动会造成什么?下表简单总结: chunk size 调节 splitting次数(碎片数) 数据跨shard数目 数据均匀 网络传输次数 ...

  9. jquery-chosen设置默认值

    <span style="font-size:18px;"> <select id="select1" class="select1 ...

  10. 8张图理解Java---importnew---programcreek

    http://www.importnew.com/11725.html https://www.programcreek.com/2013/09/top-8-diagrams-for-understa ...