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核在有符号模式下有以下几种输出可能
- 商为0,小数部分为0,商和小数的符号位分别为2'b00
- 商为0,小数部分为正,商和小数的符号位分别为2'b00
- 商为0,小数部分为负,商和小数的符号位分别为2'b01
- 商为正,小数部分为0,商和小数的符号位分别为2'b00
- 商为正,小数部分为正,商和小数的符号位分别为2'b00
- 商为负,小数部分为0,商和小数的符号位分别为2'b10
- 商为负,小数部分为负,商和小数的符号位分别为2'b11
xilinx 除法器IP核在有符号模式下商和小数合并为定点数的方法
- 拼接合并法,拼接规则如下:
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位、整数位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
仿真验证
- 在工程中添加一个除法IP核,除数和被除数均为18位有符号数,输出小数保留11位,采用非阻塞时序。
步骤1:打开IP Catalog,找到除法IP核

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


步骤3:生成除法IP核

- 创建仿真激励文件


后面弹出的define module页面直接关闭即可。 - 在仿真激励文件中输入以下内容
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
-
运行仿真,仿真波形图如下

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

xilinx除法IP核计算结果:
