开发环境

1.Vivado 2019.2
2.仿真:Vivado Simulater

半精度浮点数介绍

IEEE754-2008包含一种“半精度”格式,只有16位宽。故它又被称之为binary16,这种类型的浮点数只适合用于存储那些对精度要求不高的数字,不适合用于进行计算。与单精度浮点数相比,它的优点是只需要一半的存储空间和带宽,但是缺点是精度较低。
半精度的格式与单精度的格式类似,最左边的一位仍是符号位,指数有5位宽且以余-16(excess-16)的形式存储,尾数有10位宽,但具有隐含1。

具体半精度浮点数转换方法有兴趣的读者可以参考:半精度浮点数详解
本文不再赘述

半精度浮点数乘法器实现

半精度浮点数乘法器的实现主要包括对符号位的处理,指数借位,乘法计算,超范围小数等内容,均在下文的代码注释中有较为详细的介绍
Verilog代码如下:

module floatMuilt
(input wire [15:0] floatA,input wire [15:0] floatB,output reg [15:0] product
);reg sign; // 输出的正负标志位
reg signed [5:0] exponent; // 输出数据的指数,因为有正负所以选择有符号数
reg [9:0] mantissa; // 输出数据的小数
reg [10:0] fractionA, fractionB;    //fraction = {1,mantissa} // 计算二进制数据最高位补1
reg [21:0] fraction; // 相乘结果参数always @ (floatA or floatB)
beginif (floatA == 0 || floatB == 0)  // 处理乘数有一个或者两个均为0的情况product = 0;             //  输出为0else beginsign = floatA[15] ^ floatB[15]; // 异或门判断输出的计算正负exponent = floatA[14:10] + floatB[14:10] - 5'd15 + 5'd2; // 由于借位给fractionA和fractionB需要先补齐两位指数fractionA = {1'b1,floatA[9:0]}; //借位给fractionAfractionB = {1'b1,floatB[9:0]}; //借位给fractionBfraction = fractionA * fractionB; //计算二进制乘法// 找到第一个不为0的数字并对指数进行匹配处理if (fraction[21] == 1'b1) beginfraction = fraction << 1;exponent = exponent - 1; end else if (fraction[20] == 1'b1) beginfraction = fraction << 2;exponent = exponent - 2;end else if (fraction[19] == 1'b1) beginfraction = fraction << 3;exponent = exponent - 3;end else if (fraction[18] == 1'b1) beginfraction = fraction << 4;exponent = exponent - 4;end else if (fraction[17] == 1'b1) beginfraction = fraction << 5;exponent = exponent - 5;end else if (fraction[16] == 1'b1) beginfraction = fraction << 6;exponent = exponent - 6;end else if (fraction[15] == 1'b1) beginfraction = fraction << 7;exponent = exponent - 7;end else if (fraction[14] == 1'b1) beginfraction = fraction << 8;exponent = exponent - 8;end else if (fraction[13] == 1'b1) beginfraction = fraction << 9;exponent = exponent - 9;end else if (fraction[12] == 1'b0) beginfraction = fraction << 10;exponent = exponent - 10;end // 按照半精度浮点数的格式输出mantissa = fraction[21:12];if(exponent[5]==1'b1) begin //太小了输出全0(精度问题)product=16'b0000000000000000;endelse beginproduct = {sign,exponent[4:0],mantissa}; //拼接输出数据endend
end

测试文件

module tb_floatMuilt (); /* this is automatically generated */reg [15:0] floatA;reg [15:0] floatB;wire [15:0] product;floatMuilt inst_floatMuilt (   .floatA(floatA), .floatB(floatB), .product(product));initial beginfloatA = 16'b0000000000000000; //0floatB = 16'b0000000000000000; //0#40;floatA = 16'b0100000000000000; //2floatB = 16'b0011100110011010; //0.7#40;floatA = 16'b0011010110011010; //0.35floatB = 16'b0011100011110110; //0.62#40;floatA = 16'b0011000001111011; //0.14floatB = 16'b0011101010100100; //0.83#40;$stop;endendmodule

在Vivado的仿真软件中可以看出

笔者在此处给出基于python的二进制数和半精度浮点数的转化脚本,读者可以通过此脚本自行添加验证本tb文件的测试用例子进行验证。本文采用的四个测试用例均成功输出正确的数值。

import numpy as np
import structdef float2bin_half(F):  #F是浮点数return '{:016b}'.format(struct.unpack('<H', np.float16(F).tobytes())[0])def bin_half2float(B):  #B是二进制字符串return np.frombuffer(struct.pack('<H',int(B,2)), dtype='<f2')[0]if __name__ == '__main__':# print("%X" %float2bin_half(0.12))print(float2bin_half(0.14))print(float2bin_half(0.83))print(bin_half2float("0010111101110000"))

半精度浮点数加法器实现

半精度浮点数的加法器不同于乘法器,需要配平待相加的两个数据的阶数后再根据正负情况进行加减运算操作。
Verilog代码如下:

module floatAdd (input   wire [15:0] floatA,input    wire [15:0] floatB,output   reg  [15:0] sum
);reg sign; // 输出结果的正负标志位
reg signed [5:0] exponent; //输出数据的指数,因为有正负所以选择有符号数
reg [9:0] mantissa; // 输出数据的尾数
reg [4:0] exponentA, exponentB; //输入数据的阶数
reg [10:0] fractionA, fractionB, fraction;  // 计算暂存位
reg [7:0] shiftAmount;  // 移位寄存器,为了计算加法时配平阶数
reg cout;always @ (floatA or floatB)
beginexponentA = floatA[14:10];exponentB = floatB[14:10];fractionA = {1'b1,floatA[9:0]};fractionB = {1'b1,floatB[9:0]}; exponent = exponentA;if (floatA == 0)      // 特殊情况A为0begin                     sum = floatB;end else if (floatB == 0)  // 特殊情况B为0begin                  sum = floatA;end else if (floatA[14:0] == floatB[14:0] && floatA[15]^floatB[15]==1'b1) //特殊情况互为相反数beginsum=0;end else beginif (exponentB > exponentA)  // 配平阶数使得相加两数在同一阶数上beginshiftAmount = exponentB - exponentA;fractionA = fractionA >> (shiftAmount);exponent = exponentB;end else if (exponentA > exponentB) begin shiftAmount = exponentA - exponentB;fractionB = fractionB >> (shiftAmount);exponent = exponentA;endif (floatA[15] == floatB[15])  // 两数同号begin                            {cout,fraction} = fractionA + fractionB;if (cout == 1'b1) begin{cout,fraction} = {cout,fraction} >> 1;exponent = exponent + 1;endsign = floatA[15];end else begin                        //两数异号if (floatA[15] == 1'b1) // A 为负数begin{cout,fraction} = fractionB - fractionA; // B-Aend else begin{cout,fraction} = fractionA - fractionB;   // A-Bendsign = cout;if (cout == 1'b1) fraction = -fraction; // 0-负数可求出此数的绝对值// 对franction进行阶数配平求出尾数if (fraction [10] == 0) beginif (fraction[9] == 1'b1) beginfraction = fraction << 1;exponent = exponent - 1;end else if (fraction[8] == 1'b1) beginfraction = fraction << 2;exponent = exponent - 2;end else if (fraction[7] == 1'b1) beginfraction = fraction << 3;exponent = exponent - 3;end else if (fraction[6] == 1'b1) beginfraction = fraction << 4;exponent = exponent - 4;end else if (fraction[5] == 1'b1) beginfraction = fraction << 5;exponent = exponent - 5;end else if (fraction[4] == 1'b1) beginfraction = fraction << 6;exponent = exponent - 6;end else if (fraction[3] == 1'b1) beginfraction = fraction << 7;exponent = exponent - 7;end else if (fraction[2] == 1'b1) beginfraction = fraction << 8;exponent = exponent - 8;end else if (fraction[1] == 1'b1) beginfraction = fraction << 9;exponent = exponent - 9;end else if (fraction[0] == 1'b1) beginfraction = fraction << 10;exponent = exponent - 10;end endendmantissa = fraction[9:0];if(exponent[5]==1'b1) begin //太小了输出全0太小了sum = 16'b0000000000000000;endelse beginsum = {sign,exponent[4:0],mantissa}; // 组合数据end        end
endendmodule

仿真文件如下图所示:

`timescale 1ns/1psmodule tb_floatAdd (); /* this is automatically generated */// (*NOTE*) replace reset, clock, othersreg [15:0] floatA;reg [15:0] floatB;wire [15:0] sum;floatAdd inst_floatAdd (  .floatA(floatA), .floatB(floatB), .sum(sum));initial beginfloatA = 16'b0000000000000000;floatB = 16'b0000000000000000;#20;floatA = 16'b0011110000000000;  // 1.0floatB = 16'b1100010100000000;  // -5.0#20;floatA = 16'b0011010011001101;  //0.2floatB = 16'b0011001001100110;  //0.3#20;floatA = 16'b0101011000010000;  //97floatB = 16'b0011010011001101;  //0.3#20;$stop;endendmodule

在Vivado Simulater中仿真波形入下图所示:

出现的问题:有些情况下加法器会出现精度相加不准的情况。不知道为什么会出现此类现象。希望有大佬能够给予指正。

FPGA学习笔记(2):半精度浮点数乘法器和半精度浮点数加法器的Verilog实现相关推荐

  1. FPGA学习笔记(1)简单的时序逻辑电路——流水灯

    FPGA学习笔记(1)简单的时序逻辑电路--流水灯 编程语言为Verilog HDL 原理 (1)设计一个计数器,使开发板上的4个LED状态每500ms翻转一次.开发板上的晶振输出时钟频率为50MHz ...

  2. FPGA学习笔记_UART串口协议_串口接收端设计

    FPGA学习笔记 1. UART串口协议以及串口接收端设计 1 原理图 2 Verilog 代码 3 Modelsim仿真 4. FPGA板级验证 1.1 串口协议接收端设计 目标:FPGA接收其他设 ...

  3. FPGA学习笔记(七): DSB调制解调的仿真

    笔记七是DSB调制解调的仿真实现. DSB调制解调的实现原理:首先使用DDS产生低频正弦波信号作为调制信号,再用DDS产生高频信号作为载波信号,然后使用乘法器将两者相乘产生DSB信号,DSB信号与载波 ...

  4. FPGA学习笔记(十二)IP核之FIFO的学习总结

    系列文章目录 一.FPGA学习笔记(一)入门背景.软件及时钟约束 二.FPGA学习笔记(二)Verilog语法初步学习(语法篇1) 三.FPGA学习笔记(三) 流水灯入门FPGA设计流程 四.FPGA ...

  5. FPGA学习笔记(五)Testbench(测试平台)文件编写进行Modelsim仿真

    系列文章目录 一.FPGA学习笔记(一)入门背景.软件及时钟约束 二.FPGA学习笔记(二)Verilog语法初步学习(语法篇1) 三.FPGA学习笔记(三) 流水灯入门FPGA设计流程 四.FPGA ...

  6. FPGA学习笔记(八):ASK调制解调的仿真

    笔记八是ASK调制解调的仿真实现. ASK调制解调的实现原理:首先使用MATLAB产生存储基带波形的coe文件,再让ROM读取coe文件输出基带波形,然后DDS产生正弦波信号作为载波信号,接下来使用乘 ...

  7. FPGA学习笔记之Altera FPGA使用JIC文件配置固化教程

    FPGA学习笔记之Altera FPGA使用JIC文件配置固化教程 很多做过单片机的朋友都知 道,我们在对MCU烧写完程序固件后,那么该程序固件就存储在了该MCU内部.即使MCU断电了再重新上电,程序 ...

  8. FPGA学习笔记(八)同步/异步信号的打拍分析处理及亚稳态分析

    系列文章目录 一.FPGA学习笔记(一)入门背景.软件及时钟约束 二.FPGA学习笔记(二)Verilog语法初步学习(语法篇1) 三.FPGA学习笔记(三) 流水灯入门FPGA设计流程 四.FPGA ...

  9. FPGA学习笔记_ROM核调用与调试

    FPGA学习笔记 ROM核调用与调试 1. ROM存储器IP核的使用 2. 创建.mif文件 3. In system memory content editor内存查看工具的使用 4. Signal ...

最新文章

  1. 兑换量子计算机,阅读 | 【量子计算机】构造置换量子门
  2. hdu 1325poj 1308 并查集(未解决)(掌握率50%)
  3. python输入输出-python 输入输出 - 刘江的python教程
  4. 读书笔记--对象、实例、原型、继承
  5. POJ1007 UVA612 UVALive5414 ZOJ1188 HDU1379 Bailian4086 DNA Sorting【排序+逆序数】
  6. [USACO18DEC]Cowpatibility(容斥 or bitset优化暴力)
  7. maven缺失ojdbc6解决方法(手动安装ojdbc6)
  8. vcf通讯录转excel
  9. 对数log、lg、ln
  10. Java-面试-逻辑题
  11. 金融计量模型(十一):对波动率和相关性建模
  12. 华为是怎样研发的(10)——知识管理
  13. 使用telnet和ssh登录linux
  14. jquery插件封装
  15. JavaFX教程资源
  16. m基于FPGA的GPS收发系统开发,包括码同步,载波同步,早迟门跟踪环,其中L1采用QPSK,L2采用BPSK
  17. iOS - 接入 Live2D
  18. PHP自动排班系统 源码+说明
  19. 嫁人就要嫁程序员,钱多话少死得早!
  20. 本地搭建xxl-job服务及连接验证

热门文章

  1. 单口双线PC连接转换器 手机电脑耳机转接线
  2. unity实现多个屏幕和扩展屏幕
  3. 重刷leedcode(1-10)
  4. 博约新媒体大数据中心_聚焦媒体深度融合与大数据 想成主流数据中心不可少...
  5. python程序设计搜题软件下载_智慧职教云课堂2020Python程序设计期末考试搜题公众号答案...
  6. java asm jndi_JNDI-Injection-Exploit JNDI注入利用工具
  7. 6款实惠好用的Windows Wi-Fi工具
  8. 江苏省计算机二级在线报名,2020年秋季江苏省计算机等级考试报名通知
  9. 亿级流量网站架构核心技术。(PDF版)
  10. Vue项目如何打包并部署(nginx)