cnn - 半精度浮点数加法器

508 阅读7分钟

功能是实现两个数的求和。

1 对阶

2 尾数相减

3 规格化

4 舍入

5 判断溢出

(-1)^sign×2^(指数位的值)×(1+0.尾数位)

半精度浮点数

符号位 五位指数位 10位尾数

尾数包含隐藏的1,需要考虑进去。

有符号数的加法运算:

单符号数溢出检测判断方法二:最高位和符号位有且仅由一个进位时溢出,即当最高位有进位,而符号位无进位时,产生正溢;当最高位无进位,而符号位有进位时,产生负溢。

双符号位溢出判断:两个符号位相异时,表示溢出;相同时,表示未溢出。

表示一个浮点数时需要给出指数,这个指数用整数形式表示,这个整数叫做阶码,阶码指明了小数点在数据中的位置。

浮点加减法运算

对阶、尾数运算、规格化、舍入、溢出判断

假设浮点数的阶码和尾数均用补码表示,在浮点加减运算时,为便于浮点数尾数的规格化处理和浮点数的溢出判断,阶码和尾数均采用双符号位表示。

加法器

对阶,小阶向大阶对齐

尾数进行加法或减法运算

结果规格化并进行舍入处理

结果规格化并进行舍入处理

根据规格化浮点数的定义,当尾数用二进制补码表示时,规格化浮点数的尾数形式为00.1××…××或11.0××…××。若浮点数的尾数不是这两种形式,则称之为非规格化浮点数,需进行浮点数的规格化。

若浮点数的尾数形式为00.0××…××或11.1××…××,应利用向左规格化使其变为规格化浮点数,尾数每算术左移1位,阶码减1,直到浮点数的尾数变成规格化形式。

若浮点数的尾数形式为01.××…××或10.××…××,表示尾数求和的结果发生溢出,应利用向右规格化使其变为规格化浮点数,尾数算术右移1位,阶码加1,此时浮点数的尾数就变成了规格化形式。

在对阶或向右规格化时,尾数都要进行算术右移操作,为了保证运算结果的精度,运算过程中需保留右移中移出的若干位数据,称为保护位。在运算结果进行规格化后再按照某种规则进行舍入处理以去除这些数据。舍入处理就是消除保护位数据并按照某种规则调整剩下的部分,舍入处理总要影响到数据的精度。舍入处理的方法通常选用“0舍1入”法。

判断溢出 浮点数尾数的溢出可通过规格化进行处理,而浮点数运算结果的溢出则根据运算结果中浮点数的阶码来确定。若阶码未发生溢出,则表示运算结果未发生溢出;若阶码溢出,则需进行溢出处理。


module floatAdd16 (floatA,floatB,sum);
	
input [15:0] floatA, floatB;  //定义16位的输入数
output reg [15:0] sum;      // 定义16位的输出

reg sign;        // 定义fp16的符号位
reg signed [5:0] exponent; //有符号数,第五位是标志位 。 判断指数是否溢出
reg [9:0] mantissa; // 有效精度 -- 尾数。无符号数
reg [4:0] exponentA, exponentB;  //指数位
reg [10:0] fractionA, fractionB, fraction;	//fraction = {1,mantissa}  变为11位
reg [7:0] shiftAmount;  //移位寄存器
reg cout;




always @ (floatA or floatB) begin
        //取指数位
	exponentA = floatA[14:10];
	exponentB = floatB[14:10];
        //取尾数,并加入1。
	fractionA = {1'b1,floatA[9:0]};
	fractionB = {1'b1,floatB[9:0]}; 
	
	exponent = exponentA;

        
        //特殊情况
	if (floatA == 0) begin	
        // 如果floatA = 0,总和为floatB
        //special case (floatA = 0)
		sum = floatB;
	end else if (floatB == 0) begin
        // 如果floatB = 0,总和为floatA
        //special case (floatB = 0)
		sum = floatA;
        // floatA与floatB 大小相等,符号相反。符号位相反
	end else if (floatA[14:0] == floatB[14:0] && floatA[15]^floatB[15]==1'b1) begin
		sum=0;
	end else begin
                // 对阶,使两个数的阶码,小阶向大阶看齐,尾数每右移一位,阶码加1。 使指数位相同
                // 需要移位的数目
		if (exponentB > exponentA) begin
                        // fraction 尾数 进行移位。 对浮点数的尾数进行算术左移或者算术右移来改变阶码,使两个浮点数的阶码相等。
			shiftAmount = exponentB - exponentA;
			fractionA = fractionA >> (shiftAmount);         // 指数位等于大的
			exponent = exponentB;
		end else if (exponentA > exponentB) begin 
			shiftAmount = exponentA - exponentB;
			fractionB = fractionB >> (shiftAmount);
			exponent = exponentA;
		end
                
                
                //尾数运算。 尾数相加减和规格化
                //符号位相同
		if (floatA[15] == floatB[15]) begin			//same sign
                        
			{cout,fraction} = fractionA + fractionB;
                        //判断相加后进位
                        //右移一位,阶码加一。指数位加1
			if (cout == 1'b1) begin
				{cout,fraction} = {cout,fraction} >> 1;
				exponent = exponent + 1;
			end
                        
                        //符号位相同
			sign = floatA[15];
		end else begin						//different signs
                
                
                        //符号位不同时候 floatA的符号位为1,为负数。
			if (floatA[15] == 1'b1) begin
				{cout,fraction} = fractionB - fractionA;
			end else begin
				{cout,fraction} = fractionA - fractionB;
			end
			sign = cout;
			if (cout == 1'b1) begin
				fraction = -fraction;
			end else begin
			end
                        //根据规格化浮点数的定义,当尾数用二进制补码表示时,规格化浮点数的尾数形式为**00.1××…××**或**11.0××…××**。若浮点数的尾数不是这两种形式,则称之为非规格化浮点数,需进行浮点数的规格化。
                        // 规格化,如果最高位为0
			if (fraction [10] == 0) begin
                                //第10位为1.  左移一位。
				if (fraction[9] == 1'b1) begin
					fraction = fraction << 1;
                                        //指数减1
					exponent = exponent - 1;
                                        
                                   //第10位无1,第9位有1,进行左移两位。
				end else if (fraction[8] == 1'b1) begin
					fraction = fraction << 2;
					exponent = exponent - 2;
				end else if (fraction[7] == 1'b1) begin
					fraction = fraction << 3;
					exponent = exponent - 3;
				end else if (fraction[6] == 1'b1) begin
					fraction = fraction << 4;
					exponent = exponent - 4;
				end else if (fraction[5] == 1'b1) begin
					fraction = fraction << 5;
					exponent = exponent - 5;
				end else if (fraction[4] == 1'b1) begin
					fraction = fraction << 6;
					exponent = exponent - 6;
				end else if (fraction[3] == 1'b1) begin
					fraction = fraction << 7;
					exponent = exponent - 7;
				end else if (fraction[2] == 1'b1) begin
					fraction = fraction << 8;
					exponent = exponent - 8;
				end else if (fraction[1] == 1'b1) begin
					fraction = fraction << 9;
					exponent = exponent - 9;
				end else if (fraction[0] == 1'b1) begin
					fraction = fraction << 10;
					exponent = exponent - 10;
				end 
			end
		end
                
                
                
                // 进行规格化后,将fraction的0:9 位取出,因为最高位为1.
		mantissa = fraction[9:0];
                //判断指数位 最高位表示符号位。 若指数位为1表示负的。 表示溢出。  溢出要置为0.
		if(exponent[5]==1'b1) begin //exponent is negative
			sum = 16'b0000000000000000;
		end
		else begin
                        // 否则就组成fp16的数。
			sum = {sign,exponent[4:0],mantissa};
		end		
	end		
end

endmodule

首先为特殊情况的处理,两个数中的一个数为0,或者两个数符号位不同,其余位相同。

1 对阶,小阶向大阶对齐

如果阶码相同,直接对尾数进行加减运算。

如果阶码不同,对阶码进行对齐。 对阶。

求出阶码之差,通过浮点数对尾数进行逻辑左移或者逻辑右移来改变阶码。使两个浮点数的阶码相等。 通过小阶的算术右移来改变阶码,使阶码相等。

2 尾数进行加减运算

对阶结束,进行尾数加法或减法运算。

3 规格化并进行舍入

当尾数用二进制补码表示时,规格化浮点数的尾数形式为00.1××…××11.0××…××。若浮点数的尾数不是这两种形式,则称之为非规格化浮点数,需进行浮点数的规格化。

判断最高位,如果尾数最高位为0,次高位为1,左移一位。次次高位为1,左移两位,阶码减2. 以此类推,完成规格化。

4 判断溢出

浮点数尾数的溢出通过规格化进行处理,若阶码未发生溢出,则表明结果未发生溢出。

阶码最高位为1, 表示溢出。置为0.

否则进行拼接。