在学习openofdm过程中,看到作者进行复数乘法运算时用了专用的ip,我简单尝试了一下在vivado下进行调用(原作者是在ISE生产复数乘法器并调用),觉得vivado下的复数乘法器应该有BUG,觉得一个复数乘法器是很简单的事,没有必要调用IP,直接自己写一个就好,无非就是处理乘法时候编译器会自动例化内嵌DSP模块。考虑用在数据流处理环境下,就直接写成流水线的处理方式吧。
module complex_multiplier_rtl(
input aclk , s_axis_a_tvalid , s_axis_b_tvalid,
input signed [31:0] s_axis_a_tdata ,s_axis_b_tdata ,
output reg [63:0]m_axis_dout_tdata ,
output signed m_axis_dout_tvalid );
//(a+bi)(c+di)=(ac-bd)+(bc+ad)i。
wire valid = s_axis_a_tvalid & s_axis_b_tvalid ;
reg [3:0] do_it ; always@ (posedge aclk) do_it <= { do_it[2:0], valid } ;
assign m_axis_dout_tvalid = do_it[3] ;
reg signed [15:0] a ,b,c,d ;
always @ (posedge aclk ) a <= s_axis_a_tdata[31:16] ;
always @ (posedge aclk ) b <= s_axis_a_tdata[15:0] ; //0
always @ (posedge aclk ) c <= s_axis_b_tdata[31:16] ;
always @ (posedge aclk ) d <= s_axis_b_tdata[15:0] ;
reg signed [31:0]ac,bd,bc,ad ;
always @ (posedge aclk ) ac <= a * c ; //1
always @ (posedge aclk ) bd <= b * d ;
always @ (posedge aclk ) bc <= b * c ;
always @ (posedge aclk ) ad <= a * d ;
reg signed [31:0] ac_m_bd ,bc_p_ad ;
always @ (posedge aclk ) ac_m_bd <= ac - bd ;//2
always @ (posedge aclk ) bc_p_ad <= bc + ad ;
always @ (posedge aclk ) m_axis_dout_tdata[63:0] <={ ac_m_bd[31:0] ,bc_p_ad[31:0] } ; //3
endmodule
数据输入输出接口对应关系如下图:
两个复数 (a+bi)和(c+di)相乘得到结果是(e+fi),其中abcd都是16位的,实例化如下:
wire [15:0] a,b,c,d,e,f ;
complex_multiplier_rtl abcdef (
.aclk (aclk ),
.s_axis_a_tvalid (do_mul),
.s_axis_b_tvalid (do_mul),
.s_axis_a_tdata ({a,b}),
.s_axis_b_tdata({c,d}) ,
.m_axis_dout_tdata ({e,f}),
.m_axis_dout_tvalid(valid)
);
应用在OPENOFDM替代以前需要用XILINX IP的复数乘法器,下面是仿真波形,得到正确结果。可以看到延迟四个周期。
OK,完活。
在资源足够,时序满足的前提下,可以尝试调整减小周期数为3,甚至尝试为2,注意延迟寄存器抽头要做对应修改。
我的店 TQTT.TAOBAO.COM