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核计算结果:

相关推荐
952364 小时前
计算机组成原理 - 主存储器
单片机·嵌入式硬件·学习·fpga开发
简简单单做算法6 小时前
【第2章>第1节】基于FPGA的图像放大和插值处理概述
计算机视觉·fpga开发·双线性插值·线性插值·图像放大·均值插值·最邻近插值
木心术17 小时前
OpenClaw FPGA资源利用率优化深度指南
人工智能·fpga开发
发光的沙子7 小时前
FPGA----zynq 7000与zynqMP内存区域保留方法
fpga开发
minglie17 小时前
c和hdl对偶关系
fpga开发
verse_armour9 小时前
【FPGA】在PYNQ开发板上搭建卷积神经网络实现交通标志识别
fpga开发
Aaron15881 天前
RFSOC+VU13P/VU9P+GPU通用一体化硬件平台
人工智能·算法·fpga开发·硬件架构·硬件工程·信息与通信·基带工程
XINVRY-FPGA1 天前
XC7VX485T-2FFG1157I Xilinx Virtex-7 FPGA
arm开发·嵌入式硬件·fpga开发·硬件工程·fpga
鄙人菜鸡1 天前
Xilinx IP Aurora 8B/10B 多级光纤串联复位时序
fpga开发
是大强1 天前
数字 IC 设计
fpga开发