Verilog 组合逻辑 FP32加法器

您所在的位置:网站首页 verilog书写数字怎么相加减 Verilog 组合逻辑 FP32加法器

Verilog 组合逻辑 FP32加法器

2024-02-08 12:40| 来源: 网络整理| 查看: 265

单精度浮点数 根据 IEEE 754 标准,单精度浮点数(float)为32位,其存储格式为: 单精度浮点数格式 sign:符号位,1bit,S exponent:指数,8 bits,原码,E = (exponent)10-12710 fraction:尾数,23 bits,原码。在浮点数中隐去了小数点前的1,因此 M = 1+(fraction)10/223 该浮点数表示的10进制数为:(-1)S×M×2E

一般情况下,浮点数加法的处理步骤为:

对阶(align) 通过exponent将计算数对齐到相同指数,尾数只有在指数相同时才可以做加减运算。对齐方式为向高阶对齐,即将阶数低的尾数右移,这样不会损失高位数据的精度。尾数求和规格化(normalization) 将计算后的数据规格化。对于产生溢出位的结果右移;对于操作数符号位不同,产生结果多个高位为0时,需要左移,直到1出现在最高位。舍入(round) 因为计算过程中需要扩展位数保证精度,因此在输出浮点数结果前需要截断扩展的尾数。

但浮点数表示的数据范围有限,处理时会遇到正溢出、负溢出、数值无效的特殊情况,就需要对这些情况进行特殊处理: Special Number 处理: 当exp=8’hff 且man=23’h0时,输入为inf,表示溢出,根据sign,可以为+inf/ -inf。 当exp=8’hff 且man!=23’h0时,表示NaN。

计算过程中可产生inf的情况:

input为存在+inf或-infrounding前的exp=8’hfe,且rounding产生了进位

计算过程中可产生NaN的情况:

input为NaNinput两操作数分别为+inf与-inf

Round 处理 就近舍入: 即十进制下的四舍五入。保留23位尾数,当需要舍去的数大于2-24,进一;小于2-24,舍去;当等于2-24时,舍向最近的偶数。

例如:

多余数字是 (1001)2,它大于 (0.5)10,故最低位进 12。多余数字是 (0111)2,它小于 (0.5)10,则直接舍掉多余数字。多余数字是 (1000)2,正好是等于 (0.5)10 的特殊情况;那么此时最低位为 02 则舍掉多余位,最低位为 12 则进位 12。

对于浮点数加法实现方式的学习,可参考的代码大多数是通过时序逻辑实现的,其条理清晰,也容易理解,但大多用到循环语句,并不高效,在此不再进行赘述。以下是参考了Howeng98在GitHub上的组合逻辑实现的浮点数加法器。 链接: 参考github代码 用优先编码器修改了代码的normalization部分,使其可综合(原代码用while循环,不知道是怎么跑通的=_=); 添加了sepcial处理:针对输入为inf和NaN的情况,并对inf与NaN区分输出。

/* 对于数据格式的说明: signed exp man 31 30...23 22...0 特殊情况: exponent fraction value 0 zero 0 0 non-zero +-2^(-126)*0.(man) 1~254 any +-2^(exp-127)*1.(man) 255 zero +-inf 255 non-zero NaN */ module fpadder ( input [31:0] src1, input [31:0] src2, output reg [31:0] out ); reg [66:0] fraction_1; reg [66:0] fraction_2; reg [66:0] sum; reg [66:0] fraction_Ans; reg [7:0] exponent_1; reg [7:0] exponent_2; reg [7:0] exponent_Ans; reg [4:0] norm_count; reg norm_vld; reg sign_1; reg sign_2; reg sign_Ans; reg guard_bit; reg round_bit; reg sticky_bit; reg inf_1; reg inf_2; reg nan_1; reg nan_2; / FP ADDER /// always@(*) begin //loading begin fraction_1 = {2'd0,src1[22:0],42'd0}; // 对尾数扩展。前2bit第一位为进位位,第二位为隐藏的1, fraction_2 = {2'd0,src2[22:0],42'd0}; // 此处不赋值2'b01是留在special case中处理指数全0的情况。后42bit保障精度,可适当减少 exponent_1 = src1[30:23]; exponent_2 = src2[30:23]; sign_1 = src1[31]; sign_2 = src2[31]; inf_1 = 1'b0; nan_1 = 1'b0; inf_2 = 1'b0; nan_2 = 1'b0; end //preprocessing begin if(exponent_1 == 0) begin //when exponent is zero but fraction is non-zero,set it to 1 exponent_1 = 1; fraction_1[65] = 0; //make 0.(Frac) //参考代码开头对于特殊情况的说明 end else fraction_1[65] = 1; if(exponent_2 == 0) begin exponent_2 = 1; fraction_2[65] = 0; end else fraction_2[65] = 1; //make 1.(Frac) end //special case begin if((exponent_1 == 0) && (fraction_1 == 0)) begin //if src1 is zero, then return src2 sign_Ans = sign_2; exponent_Ans = exponent_2; fraction_Ans = fraction_2; end else if (exponent_1 == 8'hff) begin if (fraction_1 == 23'h0) inf_1 = 1'b1; // 补充原代码缺失的对inf与NaN的处理 else nan_1 = 1'b1; end else begin end if((exponent_2 == 0) && (fraction_2 == 0)) begin // if src2 is zero, then return src1 sign_Ans = sign_1; exponent_Ans = exponent_1; fraction_Ans = fraction_1; end else if (exponent_2 == 8'hff) begin if (fraction_2 == 23'h0) inf_2 = 1'b1; else nan_2 = 1'b1; end else begin end end //align begin if(exponent_1 > exponent_2) begin fraction_2 = fraction_2 >> (exponent_1 - exponent_2); exponent_Ans = exponent_1; end else if(exponent_1 > (exponent_2 - exponent_1); exponent_Ans = exponent_2; end else begin exponent_Ans = exponent_1; end end //add significands begin if(sign_1 == sign_2) begin fraction_Ans = fraction_1 + fraction_2; sign_Ans = sign_1; end else begin if(fraction_1 >= fraction_2) begin fraction_Ans = fraction_1 - fraction_2; sign_Ans = sign_1; end else begin fraction_Ans = fraction_2 - fraction_1; sign_Ans = sign_2; end end end sum = fraction_Ans; //sum is for checking the addition of src1 and src2 //overflow begin if(fraction_Ans[66]) begin fraction_Ans = fraction_Ans >> 1; exponent_Ans = exponent_Ans + 1; end end //normalization begin if(fraction_Ans == 67'b0) begin fraction_Ans = 67'b0; exponent_Ans = 8'b0; end else begin if(fraction_Ans[65] == 0)begin PENC32({11'b0, fraction_Ans[64:42]}, norm_count, norm_vld); // 用优先编码器计算最高位1所在bit fraction_Ans = fraction_Ans 0))begin // fraction_Ans = fraction_Ans 0) sticky_bit = 1; else sticky_bit = 0; if(guard_bit && (fraction_Ans[42] | round_bit | sticky_bit)) begin // 对照进位的条件 fraction_Ans = fraction_Ans + 67'b0000000000000000000000001000000000000000000000000000000000000000000; end end //convert: begin out[22:0] = fraction_Ans[64:42]; out[30:23] = exponent_Ans[7:0]; out[31] = sign_Ans; //special case if(fraction_Ans == 0) //when fraction is 23'd0 out = 0; if(nan_1 || nan_2 || (inf_1 && inf_2 && (sign_1 ^ sign_2))) begin // return NaN exponent_Ans = 8'hff; fraction_Ans = 23'h1; end else if(inf_1 || inf_2 || (exponent_Ans == 8'b11111111)) begin // return inf fraction_Ans = 0; out[22:0] = 23'h0; end // if(exponent_Ans == 8'b11111111) //when exponent is 11111111 // fraction_Ans = 0; // out[22:0] = fraction_Ans[64:42]; end end // PENC TASK // 用4个PENC8拼接实现32bit优先编码 task PENC8; //port declaration input [7:0] D; output [2:0] Q; output vld; //internal node signals declaration begin vld = D[7]|D[6]|D[5]|D[4]|D[3]|D[2]|D[1]|D[0]; Q[2] = D[7]|D[6]|D[5]|D[4]; Q[1] = (D[7]|D[6]|D[5]|D[4]) ? (D[7]|D[6]) : (D[3]|D[2]); Q[0] = (D[7]|D[6]|D[5]|D[4]) ? (D[7]|((~D[6])&D[5])) : (D[3]|((~D[2])&D[1])); end endtask task PENC16; //port declaration input [15:0] D; output [3:0] Q; output vld; //internal node signals declaration reg [2:0] Q1_h, Q1_l; reg vld1_h, vld1_l; begin PENC8( D[15:8], Q1_h, vld1_h); PENC8( D[7:0], Q1_l, vld1_l); Q[3] = vld1_h; Q[2:0] = vld1_h ? Q1_h : Q1_l; vld = vld1_h | vld1_l; end endtask task PENC32; //port declaration input [31:0] D; output [4:0] Q; output vld; //internal node signals declaration reg [3:0] Q2_h, Q2_l; reg vld2_h, vld2_l; begin PENC16( D[31:16], Q2_h, vld2_h); PENC16( D[15:0], Q2_l, vld2_l); Q[4] = vld2_h; Q[3:0] = vld2_h ? Q2_h : Q2_l; vld = vld2_h | vld2_l; end endtask endmodule

这个代码应该还可以用assign的方式重写,将一些分支语句改为并行执行,然后通过mux输出,以获得更高的速度。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3