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

相关文章: