因为算法需要降低难度,所以对算法进行了调整,调整过后需要使用arccos,arcsin,三次开平方根操作,所以查找资料编写了一下IP,用于使用,希望能帮到大家,如果对你有帮助请点赞,关注加收藏啊。
原理:就是对输入数据进行指数和对数变换,将开方根操作改成指数,对数和乘法运算,有因为ln是有输入范围的,所以需要先对输入数据进行sign判断。公式如下
module cubicroot #(
yinzi = 32'h3EAAAAAB //开根号因子,对于三次开方根 = 1/3 ;
)
(
/*
模块功能: root
任意幂次开方根备注:
1.纯浮点计算
2.流水线计算
*/
// System
input clk,
input rst_n,
// Input
input din_en,
input [31:0] din,
input din_last, // 略
// Output
output dout_en,
output [31:0] dout,
output dout_last //略
);
//--------------- Step0 判断正负值----------------
reg din_en_r0 = 0;
reg [31:0] din_r0 = 0;
always @ (posedge clk)
begin
din_en_r0 <= din_en;
din_r0 <= din;
end
reg [1:0] result=0;// 0:表示输入为0; 1:表示输入为正数; 2:表示输入为负数
always @ (posedge clk)
begin
if(din_en)
begin
if(din == 0)
begin
result <= 0;
end
else if(din[31] == 0)
begin
result <= 1;
end
else
begin
result <= 2;
end
end
end
//----------------Step1 取log|x|-------------------
wire dout_log_en;
wire [31:0] dout_log;
reg [1:0] result_r1 [22:0];
integer i;
always @ (posedge clk)
begin
for (i=0;i<22;i=i+1)
begin
result_r1[i+1] <=result_r1[i];
end
result_r1[0] <= result;
end
//23延迟
floating_log log (
.aclk(clk), // input wire aclk
.s_axis_a_tvalid(din_en_r0), // input wire s_axis_a_tvalid
.s_axis_a_tready(), // output wire s_axis_a_tready
.s_axis_a_tdata({1'b0,din_r0[30:0]}), // input wire [31 : 0] s_axis_a_tdata
.m_axis_result_tvalid(dout_log_en), // output wire m_axis_result_tvalid
.m_axis_result_tready(1'b1), // input wire m_axis_result_tready
.m_axis_result_tdata(dout_log) // output wire [31 : 0] m_axis_result_tdata
);
wire [1:0] result_log = result_r1[22];
//---------------Step 取1/3*log|x|----------------
wire dout_mul_en;
wire [31:0] dout_mul;
reg [1:0] result_r3 [6:0];
integer k;
always @ (posedge clk)
begin
for (k=0;k<6;k=k+1)
begin
result_r3[k+1] <=result_r3[k];
end
result_r3[0] <= result_log;
end
floating_mul your_instance_name (
.aclk(clk), // input wire aclk
.s_axis_a_tvalid(dout_log_en), // input wire s_axis_a_tvalid
.s_axis_a_tready(), // output wire s_axis_a_tready
.s_axis_a_tdata(dout_log), // input wire [31 : 0] s_axis_a_tdata
.s_axis_b_tvalid(dout_log_en), // input wire s_axis_b_tvalid
.s_axis_b_tready(), // output wire s_axis_b_tready
.s_axis_b_tdata(yinzi), // input wire [31 : 0] s_axis_b_tdata // 1/3
.m_axis_result_tvalid(dout_mul_en), // output wire m_axis_result_tvalid
.m_axis_result_tready(1'b1), // input wire m_axis_result_tready
.m_axis_result_tdata(dout_mul) // output wire [31 : 0] m_axis_result_tdata
);
wire [1:0] result_mul = result_r3[6];
//----------------Step3 取e.^(1/3*log|x|)---------------
wire dout_en_e;
wire [31:0] dout_e;
reg [1:0] result_r2 [20:0];
integer j;
always @ (posedge clk)
begin
for (j=0;j<20;j=j+1)
begin
result_r2[j+1] <=result_r2[j];
end
result_r2[0] <= result_mul;
end
//21 延迟
floating_exponential exponeetial(
.aclk(clk), // input wire aclk
.s_axis_a_tvalid(dout_mul_en), // input wire s_axis_a_tvalid
.s_axis_a_tready(), // output wire s_axis_a_tready
.s_axis_a_tdata(dout_mul), // input wire [31 : 0] s_axis_a_tdata
.m_axis_result_tvalid(dout_en_e), // output wire m_axis_result_tvalid
.m_axis_result_tready(1'b1), // input wire m_axis_result_tready
.m_axis_result_tdata(dout_e) // output wire [31 : 0] m_axis_result_tdata
);
wire [1:0] result_e = result_r2[20];
//---------Step 选择输出------------------
assign dout_en = dout_en_e;
assign dout = result_e==0?0:(result_e==1?dout_e:({1'b1,dout_e[30:0]}));
endmodule
单浮点精度,流水线操作,已经验证过结果了,没有问题,采用vivado写的,
yinzi = 32’h3EAAAAAB //开根号因子,对于三次开方根 = 1/3 ;
如果需要开N次根,只需要给yinzi = 1/N(浮点表示就可以) ,关于如何表示可以使用浮点数转换小工具
原理:采用毕达哥拉斯和三角比,需要用到的IP有cordic (其中的sqrt和arctan)
module arccos_atan(
/*
模块功能: acos 也可以用于求asin
原理:毕达哥拉斯定理和三角比
1.纯定点计算
2.流水线计算
*/
// System
input clk,
input rst_n,
// Input
input din_en,
input signed [15:0] din, //fix16_15
input din_last, // 略
// Output
output dout_en,
output [17:0] dout, //fix18_15
output dout_last //略
);
//------------------ Step0 x^2--------------- 定点
reg signed [30:0] X2 = 0;
reg dout_en_X2 = 0; //fix31_30
reg [15:0] din_r1;
always @ (posedge clk)
begin
dout_en_X2 <= din_en;
din_r1 <= din;
end
always @ (posedge clk)
begin
if(din_en)
begin
X2 <= din * din;
end
else
begin
X2 <= 0;
end
end
//---------------- Step1 1-x^2----------- 定点
reg signed [30:0] X2_1 = 0; //fix31_30
reg [15:0] din_r2;
reg signed [30:0] One = {1'b0,30'h3fffffff};
reg dout_en_X2_1 = 0;
always @ (posedge clk)
begin
dout_en_X2_1 <= dout_en_X2;
din_r2 <= din_r1;
end
always @ (posedge clk)
begin
X2_1 <= One - X2;
end
//--------------- Step 2 root2(1-x^2)---------- 定点
wire dout_en_root2;
wire [15:0]dout_root_2;
reg [15:0] din_x [15:0];
integer i;
always @ (posedge clk)
begin
for (i=0;i<15;i=i+1)
begin
din_x[i+1] <=din_x[i];
end
din_x[0] <= din_r2;
end
wire [15:0] dout_xx = din_x[15];
//16 延迟
cordic_root2 root2(
.aclk(clk), // input wire aclk
.s_axis_cartesian_tvalid(dout_en_X2_1 ), // input wire s_axis_cartesian_tvalid
.s_axis_cartesian_tdata({1'b0,X2_1}), // input wire [31 : 0] s_axis_cartesian_tdata
.m_axis_dout_tvalid(dout_en_root2), // output wire m_axis_dout_tvalid
.m_axis_dout_tdata(dout_root_2) // output wire [31 : 0] m_axis_dout_tdata
);
//----------------- 四象限正切 , 因为y一定是大于0,则输入定会在第一象限与第二象限,其输出也一定会是0-pi之间
wire dout_en_atan4;
wire [17:0] dout_atan4; //FIX 18_15
// 22 延迟
cordic_atan4 S4 (
.aclk(clk), // input wire aclk
.s_axis_cartesian_tvalid(dout_en_root2), // input wire s_axis_cartesian_tvalid
.s_axis_cartesian_tdata({7'd0,dout_root_2[15],dout_root_2,7'd0,dout_xx[15],dout_xx}), // input wire [47 : 0] s_axis_cartesian_tdata
.m_axis_dout_tvalid(dout_en_atan4), // output wire m_axis_dout_tvalid
.m_axis_dout_tdata(dout_atan4) // output wire [23 : 0] m_axis_dout_tdata
);
assign dout_en = dout_en_atan4;
assign dout = dout_atan4;
endmodule
定点,流水线操作,已经验证过结果了,没有问题,采用vivado写的,不同位宽延迟略有不同,你需要根据实际生成IP延迟进行修改,以上是求arccos,求arcsin需要添加判断,因为四象限正切的值一定会是正值,而arcsin是-pi/2 到 pi/2之间,所以最后需要修改下,很简单。