首页 / 资讯中心 / 文章详情

FP16的加法器的数字电路实现(Verilog)

FP16的加法器的数字电路实现(Verilog) ★ FEATURED ARTICLE
Github仓库含源.v文件和Tb用python文件Liat190906012/FP16_adder: FP16的加法器的数字电路实现Verilog# FP16的加法器的数字电路实现Verilog## 项目背景AI推理框架的运算量化已经成为不可避免的趋势量化牺牲了部分浮点数的精度换来了更低的成本和更高的访存效率。从FP32到FP16、BF16再到FP8和NF4此类运算单元在DSP和张量、卷积的方面应用极多而且多种不同精度的MAC的配合也成为流行。现在对目前的项目做一个简单的记录本工程的短期目标便是实现FP8的加乘器并保留一定的精度。在Vibe的帮助下无论是电路Verilog的搭建还是TB都进行得很快。目前实现的是FP16的加法器虽说乘法器还未实现不过其思路过程基本一样之后完成TB后再做记录。此加法器是6步流水线的形式可以保证一定吞吐量取决于主频**第0步和第5步的流水更像是做data buffer并接受输入和向外输出**。## 核心思路统一步长的整数幅值计算本加法器的核心思路是幅值计算将两个输入数统一缩放写成两个高位自然数然后计算得到结果后再缩回正常的级数。先把两个尾数左移相应的位数得到sig_a/b再进行指数对齐。左移的位数计算公式如下textvalue sig_a/b × 2^(Exp_a/b − 25)其中指数偏置为15位数偏置为10加起来是25sig_a是尾数加上隐藏位后得到的11位小数就是1.zzzzzzzzzz。接下来进行指数对齐。两个浮点数相加把所有数统一换算成“以2⁻²⁴为最小步长”的整数——即每个数表示成整数 × 2⁻²⁴。这样两个数一相加就是两个普通整数相加小数点天然对齐。换算方法就是除以步长2⁻²⁴textvalue / 2⁻²⁴ sig_a/b × 2^(Exp_a/b − 25) × 2²⁴ sig_a/b × 2^(Exp_a/b − 1)而Exp_a/b在[1, 30]中所以Exp_a/b − 1在[0, 29]最大的位数拓展就是29了。次正规数的情况就会更加简单次正规数不存在隐藏位所以它不需要进行左移。不过为了统一运算还是需要进行29位的位拓展。本运算器采用的流水线模式所以变量的赋值均为非堵塞幅值。## 接口text输入a[15:0], b[15:0], sub[0], valid_in[0]输出result[15:0], valid_out[0], Overflow[0], Underflow[0]## 第1步拆包、分类与尾数统一拆出符号位、指数位、尾数位Sign[15]、Exp[14:10]、Frac[9:0]。这里是直接设置的reg变量来存储。reg az0,bz0;reg [4:0] ea0,eb0; reg [9:0] fa0,fb0;……sa0a[15]; sb0b[15];ea0a[14:10]; eb0b[14:10]; fa0a[9:0]; fb0b[9:0];拆分后会对指数位ea0 [4:0], eb0[4:0] 判断输入数中是否存在非正规数NaN、Inf、Zero这些数会统一存进special_results[15:0]不参与之后的运算并随流水线自然递进直到输出。指数字段 | 类别00000 | 零或次正规数00001 ~ 11110 | 正规规格数11111 | 无穷/NaN规格数指数从 00001 开始最小规格数的真实指数是 1 − 15 −14有效数字是 1.f有隐藏位 1。次正规数指数是 00000但真实指数被特意钉死为 −14而不是按公式 0 − 15 −15同时有效数字变成 0.f去掉隐藏位 1。次正规数和正规数会单独提出尾数位[9:0]加上隐藏位后得到[10:0]正规数为1次正规数为0。然后位拓展verilogmag_a/b[39:0] { {29{1b0}}, Sig_a/b[10:0] } //Sig_a和Sig_b都要进行位拓展然后再进行指数对齐。这里拓展29位是为了容纳FP16的完整指数范围详细见前文幅值计算。拓展后进行步长对齐指数对齐左移Exp_a/b − 1这样两个数已被处理成40位宽、步长2⁻²⁴的整数幅值可以直接加减了。此步流水完成后将进入下一步。siga (ea 0) ? {1b0, fa} : {1b1, fa};sigb (eb 0) ? {1b0, fb} : {1b1, fb};shift_a (ea 0) ? 0 : ea - 1b1;shift_b (eb 0) ? 0 : eb - 1b1;ma {29b0, siga} shift_a;mb {29b0, sigb} shift_b;## 第2步幅值和符号加减第一步中我们得到了两个数的幅值和两个数的符号位Sign_a/b[0]再结合输入的操作数sub[0]可以得到最终的加/减指令。在减法中本加法器采用的是先比较幅值然后大减小并确定符号位。幅值经过计算后可以得到幅值结果mag2[40:0]注意到这里多拓展了一位是因为作加法时可能会产生一位进位。幅值结果mag2[40:0]和符号结果sign2[0]会传入下一道流水线。if (sign_a1 sign_b1) beginmag2 {1b0, mag_a1} {1b0, mag_b1};sign2 sign_a1;end else if (mag_a1 mag_b1) beginmag2 {1b0, mag_a1} - {1b0, mag_b1};sign2 sign_a1;end else beginmag2 {1b0, mag_b1} - {1b0, mag_a1};sign2 sign_b1;end## 第3步规格化、指数计算、GRS提取首先是寻找最高有效位根据这一步可以找到最终的指数值本工程采取的是前导零计数。最高位的值会被存储进msb[5:0]。if (!special2 (mag2 ! 0)) beginmsb 0;found 1b0;for (i40; i0; ii-1) beginif (!found mag2[i]) beginmsb i;found 1b1;endend此时对幅值mag3[40:0]进行左移左移一共14位存进ext[13:0]ext[13:3]是有效尾数ext[2:0]是舍入判断位。同时在得到了msb[5:0]后对指数进入计算指数公式为textexp[5:0] msb − 9msb减去步长24再加上指数偏置15得到上述结果。ext[13:0]和exp[5:0]会进入到下一步的舍入及拼数。## 第4步舍入、异常判断、FP16打包ext3: [13] [12..3] [2] [1] [0]隐藏位 尾数10位 G R Sveriloground_up G (R || S || LSB);if (ext3[2] (ext3[1] || ext3[0] || ext3[3]))rounded rounded 1b1;保留11 bit尾数rounded[11:0]GRS即为ext[13:0]的末三位。此公式的核心逻辑便是遵循FP16的舍入规则就近进位大于0.5向上进位小于0.5保留不进位恰好为0.5时将选择偶数为最终结果LSB 0。接下来是判断舍入是否产生进位如果是便右移一位、指数加一指数是否产生溢出若溢出上溢设置为Inf并记录overflow下溢则次正规数甚者则处理为带符号00/-0并记录underflow。上述完成后统一打包符号位、指数位、尾数位流入下一级输出。## 六级流水线的Dataflow上述四步是实际处理步骤寄存器变量的流动dataflow如下。text输入a[15:0] b[15:0] sub[0:0] valid_in[0:0]│▼┌───────────────────────────────────────────────┐│ Stage 0输入锁存 ││ a0[15:0] b0[15:0] ││ sub0[0:0] v0[0:0] │└───────────────────────┬───────────────────────┘▼┌───────────────────────────────────────────────┐│ Stage 1拆包、分类、尾数统一 ││ sign_a1/sign_b1 1 bit ││ ea/eb 5 bit ││ fa/fb 10 bit ││ siga/sigb 11 bit ││ mag_a1/mag_b1 40 bit ││ special1 1 bit ││ special_result1 16 bit ││ invalid1 1 bit │└───────────────────────┬───────────────────────┘▼┌───────────────────────────────────────────────┐│ Stage 2符号-幅值加减 ││ mag2 41 bit ││ sign2 1 bit ││ special2 1 bit ││ special_result2 16 bit ││ invalid2 1 bit │└───────────────────────┬───────────────────────┘▼┌───────────────────────────────────────────────┐│ Stage 3规格化、指数计算、GRS提取 ││ sign3 1 bit ││ exp3 6 bit ││ ext3 14 bit ││ exact_subnormal3 1 bit ││ special3 1 bit ││ special_result3 16 bit ││ invalid3 1 bit │└───────────────────────┬───────────────────────┘▼┌───────────────────────────────────────────────┐│ Stage 4舍入、溢出判断、FP16打包 ││ rounded 12 bit ││ result4 16 bit ││ overflow4 1 bit ││ underflow4 1 bit ││ invalid4 1 bit ││ v4 1 bit │└───────────────────────┬───────────────────────┘▼┌───────────────────────────────────────────────┐│ Stage 5最终输出寄存器 ││ result 16 bit ││ valid_out 1 bit ││ overflow 1 bit ││ underflow 1 bit ││ invalid 1 bit │└───────────────────────────────────────────────┘## 关于GRS的个人理解再说一下GRS笔者自认为就是多保留三位而已只是这恰好有个相关理论笔者也只是简单询问了AI没有做相关的理论文献查找可能会有认知偏差。在和AI的相关讨论中笔者也问了相关的问题保留两位是否就可以AI给出的答案是在实际硬件的移位器中保留两位还是三位的硬件资源成本相差不大而且本身这三位也是只保留一步流水线不占资源更不会占推理框架的访存资源所以这里也选择了这个相对折中的方法。## GRS的官方解释GRS的全称是Guard保护位Round舍入位Sticky粘位。GRS是IEEE 754 舍入机制的经典概念。GRS 位不是 IEEE 754 标准里用GRS这个词命名的但舍入时需要额外位extra bits来判断丢弃部分与 0.5 的关系这个机制是标准明确规定的。标准原文讲的是round to nearest需要知道被丢掉的尾数是否超过一半而这在实现上就对应 GRS 三位。标准文档IEEE 754-2019最新修订版替代 754-2008关键章节4.3 Rounding 和 4.3.1 Round to nearesthttps://standards.ieee.org/standard/754-2019.htmlGoldberg 论文https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
阅读完成 · 觉得有帮助?
咨询建站