在计算机中浮点数 表示通常采用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