03 xilinx除法IP核的使用

xilinx除法器IP核配置

Algorithm Type:算法类型,可选High Radix、LutMult、Radix2,一般常用Radix2

Operand Sign:有符号和无符号选择

Dividend Width:被除数宽度

Divisor Width:除数宽度

Remainder Type :余数类型,可以选择小数模式或者余数模式

Fractional Width :余数模式为小数时选择小数宽度

Clocks per Division :每多少个时钟周期处理一除法运算

Flow Control:流控选择,可选Blocking和Non Blocking

Latency Configuration:输出延迟,一般选择Automatic

lmplementation Details:配置细节,如被除数位段、除数位段、商位段、小数或余数位段

除法器IP核时序

下面非阻塞模式下的时序,需要除数和被除数同时有效才进行计算(图中假设Latency为0,实际使用中一般不为0):

下面是阻塞模式下的时序,相当于在除数和被除数端口加了个FIFO,除数和被除数不要求同时有效(图中假设Latency为0,实际使用中一般不为0):

除法器IP核小数格式

xilinx 除法器IP核在将余数输出模式配置为小数模式时其输出结果分为商和小数两部分部分,如下分别是有符号模式和无符号模式下小数输出规则。

无符号模式:

FractRmd:除法器IP核的输出

IntRmd:余数

Divisor:除数

F:输出小数位宽

即除法器小数部分输出结果为真实小数放大了2^n倍取整

有符号模式:

FractRmd:除法器IP核的输出

IntRmd:余数

Divisor:除数

F:输出小数位宽

即除法器小数部分输出结果为真实小数放大了2^(F-1)倍取整(因为符号要占1位,所以放大倍数为2^(F-1))

除法器IP核在有符号模式下有以下几种输出可能

  1. 商为0,小数部分为0,商和小数的符号位分别为2'b00
  2. 商为0,小数部分为正,商和小数的符号位分别为2'b00
  3. 商为0,小数部分为负,商和小数的符号位分别为2'b01
  4. 商为正,小数部分为0,商和小数的符号位分别为2'b00
  5. 商为正,小数部分为正,商和小数的符号位分别为2'b00
  6. 商为负,小数部分为0,商和小数的符号位分别为2'b10
  7. 商为负,小数部分为负,商和小数的符号位分别为2'b11

xilinx 除法器IP核在有符号模式下商和小数合并为定点数的方法

  1. 拼接合并法,拼接规则如下:
c 复制代码
当商和小数的符号位分别为2'b00时:
	{商的符号位, 商, 小数去符号位}
当商和小数的符号位分别为2'b01时:
	{ 商取反, 小数包含符号位}
当商和小数的符号位分别为2'b10时:
	{商的符号位, 商, 小数去符号位}
当商和小数的符号位分别为2'b11时:
​ 	{商的符号位, 商-1, 小数去符号位}

如下是两个有符号相除,采用符号位1位、整数位7位、小数位10位格式进行量化:

c 复制代码
//浮点数等式
-18.625/6.325 = -2.944664031620553 
//转换为定点格式
(-18.625 * 2^10) / (6.325  * 2^10)
-19072/6476
18'b11_1011_0101_1000_0000/18'b00_0110_0100_0111_0110
//定点数相除结果
商:18'b11_1111_1111_1111_1110 = -2,小数:11'b100_0011_1001 = -967
//将商和余数合并
{1'b1, 7'b111 1110 - 1'b1, 10'b00 0011 1001} =  {1'b1, 7'b111 1101, 10'b00 0011 1001}  = 18'b11_1111_0100_0011_1001 = -3015
//将结果转换回浮点数
-3015 /2^10 = -2.9443359375
  1. 相加合并法,规则如下:
    将商按小数的保留位宽进行放大,然后再与小数部分相加(相加时两边需要用符号位扩展到相同位宽),如下是两个有符号相除,采用符号位1位、整数位7位、小数位10位格式进行量化:
c 复制代码
//浮点数等式
-18.625/6.325 = -2.944664031620553
//转换为定点格式
(-18.625 * 2^10) / (6.325  * 2^10)
-19072/6476
18'b11_1011_0101_1000_0000/18'b00_0110_0100_0111_0110
商:18'b11_1111_1111_1111_1110 = -2,小数:11'b100_0011_1001 = -967
//将商和余数合并
 (-2 << 10) + (-967) = 18'b11_1111_1000_0000_0000 + 18'b11_1111_1100_0011_1001 = 18'b11_1111_0100_0011_1001 = -3015
//将结果转换回浮点数
-3015 /2^10 = -2.9443359375

仿真验证

  1. 在工程中添加一个除法IP核,除数和被除数均为18位有符号数,输出小数保留11位,采用非阻塞时序。
    步骤1:打开IP Catalog,找到除法IP核

    步骤2:打开除法IP核配置界面,并进行配置


    步骤3:生成除法IP核
  2. 创建仿真激励文件

    后面弹出的define module页面直接关闭即可。
  3. 在仿真激励文件中输入以下内容
c 复制代码
`timescale 1ns / 1ps

module tb_div_gen_i18_i18_f11( );

//激励时钟
reg                aclk = 1'b0;

//被除数
reg                dividend_tvalid = 1'b0;
reg  signed [23:0] dividend_tdata = 'd0;

//除数
reg                divisor_tvalid = 1'b0;
reg  signed [23:0] divisor_tdata = 'd0;

//商和小数
wire signed [17:0] quotient;
wire signed [10:0] fractional;

//采用加法合并的成定点数结果
reg  signed [17:0] add_q10 = 18'h0;
//采用拼接合并的成定点数结果
reg  signed [28:0] splice_q10_temp = 29'h0;
wire signed [17:0] splice_q10;

//除法器输出,包含商和小数
wire               div_dout_tvalid;
wire        [31:0] div_dout_tdata;

//仿真结束标志
reg                sim_done_flag = 1'b0;
//仿真数据写入标志
reg                write_sim_flag = 1'b0;

//产生激励时钟
initial begin
    aclk = 1'b0;
end
always #10 aclk = ~aclk;

initial begin
	dividend_tvalid = 1'b0;
	divisor_tvalid = 1'b0;
	dividend_tdata = 0;
	divisor_tdata = 0;
	
	//商为0,小数部分为0,商和小数的符号位为2'b00           
	//0/1.5--->0/1536
	repeat(100) @(posedge aclk);
	dividend_tvalid = 1'b1;
	divisor_tvalid = 1'b1;
	dividend_tdata = 0;
	divisor_tdata = 1536;
	@(posedge aclk);
	dividend_tvalid = 1'b0;
	divisor_tvalid = 1'b0;
	
	//商为0,小数部分为正,商和小数的符号位为2'b00        
	//0.5/1.5--->512/1536
	repeat(100) @(posedge aclk);
	dividend_tvalid = 1'b1;
	divisor_tvalid = 1'b1;
	dividend_tdata = 512;
	divisor_tdata = 1536;
	@(posedge aclk);
	dividend_tvalid = 1'b0;
	divisor_tvalid = 1'b0;
	
	//商为0,小数部分为负,商和小数的符号位为2'b01       
	//-0.5/1.5--->-512/1536
	repeat(100) @(posedge aclk);
	dividend_tvalid = 1'b1;
	divisor_tvalid = 1'b1;
	dividend_tdata = -512;
	divisor_tdata = 1536;
	@(posedge aclk);
	dividend_tvalid = 1'b0;
	divisor_tvalid = 1'b0;
	
	//商为正,小数部分为0,商和小数的符号位为2'b00        
	//1.5/0.5--->1536/512
	repeat(100) @(posedge aclk);
	dividend_tvalid = 1'b1;
	divisor_tvalid = 1'b1;
	dividend_tdata = 1536;
	divisor_tdata = 512;
	@(posedge aclk);
	dividend_tvalid = 1'b0;
	divisor_tvalid = 1'b0;
	
	//商为正,小数部分为正,商和小数的符号位为2'b00       
	//1.8/0.5--->1843/512
	repeat(100) @(posedge aclk);
	dividend_tvalid = 1'b1;
	divisor_tvalid = 1'b1;
	dividend_tdata = 1843;
	divisor_tdata = 512;
	@(posedge aclk);
	dividend_tvalid = 1'b0;
	divisor_tvalid = 1'b0;
	
	//商为负,小数部分为0,商和小数的符号位为2'b10       
	//-1.5/0.5--->-1536/512
	repeat(100) @(posedge aclk);
	dividend_tvalid = 1'b1;
	divisor_tvalid = 1'b1;
	dividend_tdata = -1536;
	divisor_tdata = 512;
	@(posedge aclk);
	dividend_tvalid = 1'b0;
	divisor_tvalid = 1'b0;
	
	//商为负,小数部分为负,商和小数的符号位为2'b11      
	//-1.8/0.5--->-1843/512
	repeat(100) @(posedge aclk);
	dividend_tvalid = 1'b1;
	divisor_tvalid = 1'b1;
	dividend_tdata = -1843;
	divisor_tdata = 512;
	@(posedge aclk);
	dividend_tvalid = 1'b0;
	divisor_tvalid = 1'b0;
	
	//仿真结束
	repeat(100) @(posedge aclk);
	sim_done_flag = 1'b1;
	@(posedge aclk);
	sim_done_flag = 1'b0;
end

//商
assign quotient = div_dout_tdata[28:11];
//小数
assign fractional = div_dout_tdata[10:0];

//采用加法合并成定点数,其中符号位1位、整数位7位、小数位10位(将商按小数的保留位宽进行放大,然后再与小数部分相加,相加时需要扩位)
always @(posedge aclk) begin 
	if(div_dout_tvalid == 1'b1)
		add_q10 <= {quotient[17], quotient[6:0], 10'h000} + {{7{fractional[10]}}, fractional};
end

//采用拼接合并成定点数,其中符号位1位、整数位18位、小数位10位
always @(posedge aclk) begin 
	if(div_dout_tvalid == 1'b1) begin
		case({quotient[17], fractional[10]})
			2'b00: splice_q10_temp <= {quotient[17], quotient, fractional[9:0]};
			2'b01: splice_q10_temp <= {~quotient, fractional};
			2'b10: splice_q10_temp <= {quotient[17], quotient, fractional[9:0]};
			2'b11: splice_q10_temp <= {quotient[17], quotient-1'b1, fractional[9:0]};
		endcase
	end
end
//将符号位1位、整数位18位、小数位10位转换为符号位1位、整数位7位、小数位10位
assign splice_q10 = {splice_q10_temp[28], splice_q10_temp[16:0]};

//产生仿真数据写入文件标志
always @(posedge aclk) begin 
	write_sim_flag <= div_dout_tvalid;
end

//dout_tdata = dividend_tdata/divisor_tdata
div_gen_i18_i18_f11 tb_div_gen_i18_i18_f11_inst0 (
	.aclk(aclk),                                   	// input wire aclk
	
	.s_axis_divisor_tvalid(divisor_tvalid),    		// input wire s_axis_divisor_tvalid
	.s_axis_divisor_tdata(divisor_tdata),      		// input wire [23 : 0] s_axis_divisor_tdata
	
	.s_axis_dividend_tvalid(dividend_tvalid),  		// input wire s_axis_dividend_tvalid
	.s_axis_dividend_tdata(dividend_tdata),    		// input wire [23 : 0] s_axis_dividend_tdata
	
	.m_axis_dout_tvalid(div_dout_tvalid),         	// output wire m_axis_dout_tvalid
	.m_axis_dout_tdata(div_dout_tdata)            	// output wire [31 : 0] m_axis_dout_tdata
);

integer prtf;

//创建仿真输出文件,文件路径根据实际情况修改
initial begin
  prtf = $fopen("F:/AD9361/02-division/vivado_project/div_out.csv", "w");
  $fwrite(prtf,"divisor,dividend,quotient,fractional,add_q10,splice_q10\n");
end

//存储仿真输出数据
always @(posedge aclk) begin
	if(write_sim_flag == 1'b1)
		$fwrite(prtf,"%d,%d,%d,%d,%d,%d\n",  dividend_tdata, divisor_tdata,quotient, fractional, add_q10, splice_q10);
end

//仿真结束,关闭文件
always @(posedge aclk) begin
	if(sim_done_flag == 1'b1)
		$fclose(prtf);
end

endmodule
  1. 运行仿真,仿真波形图如下

  2. 计算结果验证,仿真结束后会得到一个div_out.csv的文件,可以通过excel表格验算结果是否正确

    excel表格计算结果:

    xilinx除法IP核计算结果:

相关推荐
智能物联网开发2 小时前
机器人电子皮肤系统开发:36通道柔性触觉阵列 + FPGA高速采集
fpga开发·计算机外设·嵌入式·fpga数据采集
沐欣工作室_lvyiyi3 小时前
基于FPGA的智能音箱设计(论文+源码)
fpga开发·毕业设计·智能音箱
我爱C编程4 小时前
【硬件片内测试】基于FPGA的4FSK扩频通信链路测试,包含帧同步,定时点,扩频伪码同步,信道,误码统计
fpga开发·帧同步·定时点·扩频通信·扩频伪码同步·4fsk
GateWorld4 小时前
Lattice FPGA开发全攻略--十余种输出文件格式及其区别
fpga开发·lattice·fpga开发工具
芯门19 小时前
基于 Xilinx K7 FPGA 的全套万兆 10G GigE Vision 商业级传输方案
计算机视觉·fpga开发·万兆gige
ehiway19 小时前
FPGA在未来产业中的应用潜力与商业机会分析
fpga开发
GateWorld20 小时前
FPGA内部模块详解之第1篇 FPGA内部结构总览
fpga开发·fpga内部模块
爱吃汽的小橘20 小时前
驱动GPIO使用GPIO中断模式
fpga开发
普密斯科技21 小时前
精准把控每一处细节——FPGA焊点高度精准检测实施方案
人工智能·深度学习·数码相机·计算机视觉·fpga开发·测量