This repository has been archived on 2024-01-14. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
vivado-202401/projects/duifei/duifei_online_acq_par/rtl/freq_comp.v
T
josh c32d684223 change online acq pn code length, change 814 online acq to the same
修改了在线捕获程序的PN码长和频偏搜索步进,修改了地检发送程序的PN码长,使用对飞相控阵进行了测试,得到正确结果;将程序移植到814平台,同样能够正常工作;对地检程序(20230512),对飞程序(20230512)和814程序(20230415)进行归档
2023-05-14 12:51:10 +08:00

787 lines
30 KiB
Verilog

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 05/06/2023 02:33:07 PM
// Design Name:
// Module Name: freq_comp
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module freq_comp
#(
parameter DATA_I_WIDTH = 12,
parameter DATA_O_WIDTH = 18,
parameter FREQ_WORD_WIDTH = 32,
parameter FREQ_WORD_LOWER = -1048576,
parameter FREQ_WORD_UPPER = 1048575,
parameter FREQ_WORD_STEP = 1024,
parameter MAX_DMF_NUM = 64,
parameter CHANNEL_NUM = 4,
// length of pseudorandom bit sequence, need to be a power of 2
parameter PRBS_LEN = 1024,
// interpolation of input signal, need to be a power of 2
parameter INTERP_RATE = 32,
// signal processing interpolation, need to be a power of 2
parameter PROCESS_INTERP = 2,
// possible position of pn code
parameter PRBS_POS = PRBS_LEN*PROCESS_INTERP
)
(
// clock & reset
input clk ,
input clk_4x ,
input rst ,
// module enable switch
input freq_comp_start ,
output freq_comp_busy ,
// input data
input rx_data_valid ,
input [DATA_I_WIDTH-1 : 0] rx_ch1_i ,
input [DATA_I_WIDTH-1 : 0] rx_ch1_q ,
input [DATA_I_WIDTH-1 : 0] rx_ch2_i ,
input [DATA_I_WIDTH-1 : 0] rx_ch2_q ,
input [DATA_I_WIDTH-1 : 0] rx_ch3_i ,
input [DATA_I_WIDTH-1 : 0] rx_ch3_q ,
input [DATA_I_WIDTH-1 : 0] rx_ch4_i ,
input [DATA_I_WIDTH-1 : 0] rx_ch4_q ,
// configuration
input [$clog2(MAX_DMF_NUM)-1 : 0] dmf_num_per_ch ,
input dmf_continuous ,
input [FREQ_WORD_WIDTH-1 : 0] freq_manual ,
input freq_manual_en ,
// output frequency result
output [FREQ_WORD_WIDTH-1 : 0] freq_target ,
output freq_target_valid ,
// output dmf result
output ch_peak_valid ,
output [DATA_O_WIDTH-1 : 0] ch1_peak_value_abs ,
output [DATA_O_WIDTH-1 : 0] ch1_peak_value_i ,
output [DATA_O_WIDTH-1 : 0] ch1_peak_value_q ,
output [$clog2(PRBS_POS)-1 : 0] ch1_peak_index ,
output [DATA_O_WIDTH-1 : 0] ch2_peak_value_abs ,
output [DATA_O_WIDTH-1 : 0] ch2_peak_value_i ,
output [DATA_O_WIDTH-1 : 0] ch2_peak_value_q ,
output [$clog2(PRBS_POS)-1 : 0] ch2_peak_index ,
output [DATA_O_WIDTH-1 : 0] ch3_peak_value_abs ,
output [DATA_O_WIDTH-1 : 0] ch3_peak_value_i ,
output [DATA_O_WIDTH-1 : 0] ch3_peak_value_q ,
output [$clog2(PRBS_POS)-1 : 0] ch3_peak_index ,
output [DATA_O_WIDTH-1 : 0] ch4_peak_value_abs ,
output [DATA_O_WIDTH-1 : 0] ch4_peak_value_i ,
output [DATA_O_WIDTH-1 : 0] ch4_peak_value_q ,
output [$clog2(PRBS_POS)-1 : 0] ch4_peak_index
);
localparam STATE_NUM = 5;
localparam [$clog2(STATE_NUM)-1:0]
STATE_IDLE = 0,
STATE_FREQ_SW = 1,
STATE_FREQ_DMF = 2,
STATE_CH_SW = 3,
STATE_CH_DMF = 4;
localparam FREQ_WORD_LOWER_WIDTH = $clog2(FREQ_WORD_LOWER);
localparam FREQ_WORD_UPPER_WIDTH = $clog2(FREQ_WORD_UPPER);
localparam FREQ_WORD_STEP_WIDTH = $clog2(FREQ_WORD_STEP );
localparam DDS_DATA_WIDTH = 8;
localparam STABLE_COUNT_MOD = 16;
localparam CMPY_A_WIDTH = DATA_I_WIDTH;
localparam CMPY_B_WIDTH = DDS_DATA_WIDTH;
localparam CMPY_P_WIDTH = CMPY_A_WIDTH+CMPY_B_WIDTH;
localparam CMPY_P_FULL_WIDTH = CMPY_P_WIDTH+1;
localparam CMPY_OUTPUT_WIDTH = DATA_I_WIDTH;
genvar m;
// input data clock domain crossing
wire [DATA_I_WIDTH*CHANNEL_NUM*2-1 : 0] fifo_din;
wire [DATA_I_WIDTH*CHANNEL_NUM*2-1 : 0] fifo_dout;
reg [1:0] fifo_rd_cnt = 'b0;
reg fifo_rd_en = 'b0;
wire [DATA_I_WIDTH-1 : 0] rx_cdc_ch1_i;
wire [DATA_I_WIDTH-1 : 0] rx_cdc_ch1_q;
wire [DATA_I_WIDTH-1 : 0] rx_cdc_ch2_i;
wire [DATA_I_WIDTH-1 : 0] rx_cdc_ch2_q;
wire [DATA_I_WIDTH-1 : 0] rx_cdc_ch3_i;
wire [DATA_I_WIDTH-1 : 0] rx_cdc_ch3_q;
wire [DATA_I_WIDTH-1 : 0] rx_cdc_ch4_i;
wire [DATA_I_WIDTH-1 : 0] rx_cdc_ch4_q;
assign fifo_din = {
rx_ch1_i,
rx_ch1_q,
rx_ch2_i,
rx_ch2_q,
rx_ch3_i,
rx_ch3_q,
rx_ch4_i,
rx_ch4_q};
assign {
rx_cdc_ch1_i,
rx_cdc_ch1_q,
rx_cdc_ch2_i,
rx_cdc_ch2_q,
rx_cdc_ch3_i,
rx_cdc_ch3_q,
rx_cdc_ch4_i,
rx_cdc_ch4_q
} = fifo_dout;
always @(posedge clk_4x) begin
if (rst) begin
fifo_rd_cnt <= 'b0;
end
else begin
fifo_rd_cnt <= fifo_rd_cnt + 1'b1;
end
end
always @(posedge clk_4x) begin
if (rst) begin
fifo_rd_en <= 'b0;
end
else begin
fifo_rd_en <= (fifo_rd_cnt == 2'd3) ? 1'b1 : 'b0;
end
end
fifo_rx_data u_fifo_rx_data
(
.rst (rst ), // input wire rst
.wr_clk (clk ), // input wire wr_clk
.rd_clk (clk_4x ), // input wire rd_clk
.din (fifo_din ), // input wire [95 : 0] din
.wr_en (1'b1 ), // input wire wr_en
.rd_en (fifo_rd_en ), // input wire rd_en
.dout (fifo_dout ), // output wire [95 : 0] dout
.full ( ), // output wire full
.empty ( ) // output wire empty
);
////////////////////////////////////////////////////////////////////////////////
///////////////////////////// Center State Control /////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// current and next state
reg [$clog2(STATE_NUM)-1 : 0] state_curr = STATE_IDLE;
reg [$clog2(STATE_NUM)-1 : 0] state_next = STATE_IDLE;
// edge detection
reg freq_comp_start_d1 = 'b0;
reg freq_comp_start_d2 = 'b0;
// stable counter, for dds frequency and complex multiplier to be ready
reg [$clog2(STABLE_COUNT_MOD)-1 : 0] cnt_stable = 'b0;
// dmf finish indicator
wire dmf_freq_last_peak_valid;
wire dmf_ch_last_peak_valid [0 : CHANNEL_NUM-1];
// current frequency word
reg signed [FREQ_WORD_WIDTH-1 : 0] freq_word = 'b0;
// frequency scan finish indicator
reg freq_end = 'b0;
// -----------------------------------------------------------------------------
// 1st always block, sequential state transition
// -----------------------------------------------------------------------------
always @(posedge clk_4x) begin
if (rst) begin
state_curr <= STATE_IDLE;
end
else begin
state_curr <= state_next;
end
end
// -----------------------------------------------------------------------------
// 2nd always block, combinational condition judgment
// -----------------------------------------------------------------------------
always @(*) begin
case (state_curr)
STATE_IDLE: begin
if (rx_data_valid && (freq_comp_start_d2 != freq_comp_start_d1)) begin
// when input data valid & either edge of start signal is detected
state_next = STATE_FREQ_SW;
end
else begin
state_next = STATE_IDLE;
end
end
STATE_FREQ_SW: begin
if (cnt_stable == STABLE_COUNT_MOD-1) begin
// wait util dds frequency and complex multiplier is ready
state_next = STATE_FREQ_DMF;
end
else begin
state_next = STATE_FREQ_SW;
end
end
STATE_FREQ_DMF: begin
if (dmf_freq_last_peak_valid) begin
// when dmf is done, check if frequency compensation is over
state_next = freq_end ? STATE_CH_SW : STATE_FREQ_SW;
end
else begin
state_next = STATE_FREQ_DMF;
end
end
STATE_CH_SW : begin
if (cnt_stable == STABLE_COUNT_MOD-1) begin
// wait util dds frequency and complex multiplier is ready
state_next = STATE_CH_DMF;
end
else begin
state_next = STATE_CH_SW;
end
end
STATE_CH_DMF : begin
if (dmf_ch_last_peak_valid[0]) begin
// wait until dmf is done
state_next = STATE_IDLE;
end
else begin
state_next = STATE_CH_DMF;
end
end
default: begin
// hold
state_next = state_next;
end
endcase
end
// -----------------------------------------------------------------------------
// 3rd always block, the sequential FSM output
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// edge detection
// -----------------------------------------------------------------------------
always @(posedge clk_4x) begin
freq_comp_start_d1 <= freq_comp_start;
freq_comp_start_d2 <= freq_comp_start_d1;
end
// -----------------------------------------------------------------------------
// busy indicator
// -----------------------------------------------------------------------------
reg freq_comp_busy_buf = 'b0;
assign freq_comp_busy = freq_comp_busy_buf;
always @(posedge clk_4x) begin
if (rst) begin
freq_comp_busy_buf <= 'b0;
end
else begin
case (state_next)
// change between states
STATE_IDLE : freq_comp_busy_buf <= 1'b0;
STATE_FREQ_SW : freq_comp_busy_buf <= 1'b1;
STATE_FREQ_DMF: freq_comp_busy_buf <= 1'b1;
STATE_CH_SW : freq_comp_busy_buf <= 1'b1;
STATE_CH_DMF : freq_comp_busy_buf <= 1'b1;
default : freq_comp_busy_buf <= freq_comp_busy_buf;
endcase
end
end
// -----------------------------------------------------------------------------
// stable counter, for dds frequency and complex multiplier to be ready
// -----------------------------------------------------------------------------
always @(posedge clk_4x) begin
if (rst) begin
cnt_stable <= 'b0;
end
else case (state_curr)
// change within one state
STATE_FREQ_SW: cnt_stable <= cnt_stable + 1'b1;
STATE_CH_SW : cnt_stable <= cnt_stable + 1'b1;
default : cnt_stable <= 'b0;
endcase
end
// -----------------------------------------------------------------------------
// frequency word control
// -----------------------------------------------------------------------------
// record the frequency word generating the maximum peak
reg [FREQ_WORD_WIDTH-1 : 0] max_freq_peak_freq = 'b0;
always @(posedge clk_4x) begin
if (rst) begin
freq_word <= FREQ_WORD_LOWER;
end
else case (state_next)
// change between states
STATE_FREQ_SW: begin
if (state_curr == STATE_IDLE) begin
// initialization
freq_word <= FREQ_WORD_LOWER;
end
else if (state_curr == STATE_FREQ_DMF) begin
// switch frequency
freq_word <= freq_word + FREQ_WORD_STEP;
end
end
STATE_CH_SW: begin
freq_word <= (freq_manual_en) ? freq_manual : max_freq_peak_freq;
end
default: begin
freq_word <= freq_word;
end
endcase
end
// -----------------------------------------------------------------------------
// frequency scan finish indicator
// -----------------------------------------------------------------------------
always @(posedge clk_4x) begin
if (rst) begin
freq_end <= 'b0;
end
else if (freq_word > FREQ_WORD_UPPER) begin
freq_end <= 1'b1;
end
else begin
freq_end <= 'b0;
end
end
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// DDS //////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
localparam AXIS_FREQ_WORD_WIDTH = 8*((FREQ_WORD_WIDTH-1)/8+1);
localparam AXIS_DDS_DATA_WIDTH = 8*((DDS_DATA_WIDTH-1)/8+1);
wire [DDS_DATA_WIDTH-1:0] sin_dds, cos_dds;
wire dds_valid;
wire dds_s_axis_config_tvalid;
wire [AXIS_FREQ_WORD_WIDTH-1 : 0] dds_s_axis_config_ttdata;
wire dds_m_axis_data_tvalid ;
wire [2*AXIS_DDS_DATA_WIDTH-1 : 0] dds_m_axis_data_ttdata ;
assign dds_s_axis_config_tvalid = freq_comp_busy;
assign dds_s_axis_config_ttdata = freq_word;
assign dds_valid = dds_m_axis_data_tvalid;
assign {sin_dds,cos_dds} = dds_m_axis_data_ttdata;
dds_32b_8b u_dds_bb_shift
(
.aclk (clk_4x ), // input wire aclk
.s_axis_config_tvalid (dds_s_axis_config_tvalid ), // input wire s_axis_config_tvalid
.s_axis_config_tdata (dds_s_axis_config_ttdata ), // input wire [31 : 0] s_axis_config_tdata
.m_axis_data_tvalid (dds_m_axis_data_tvalid ), // output wire m_axis_data_tvalid
.m_axis_data_tdata (dds_m_axis_data_ttdata ) // output wire [15 : 0] m_axis_data_tdata
);
////////////////////////////////////////////////////////////////////////////////
///////////// Complex Multiplier for Frequency Shift Compensation //////////////
////////////////////////////////////////////////////////////////////////////////
localparam AXIS_CMPY_A_WIDTH = 8*((CMPY_A_WIDTH-1)/8+1);
localparam AXIS_CMPY_B_WIDTH = 8*((CMPY_B_WIDTH-1)/8+1);
localparam AXIS_CMPY_P_WIDTH = 8*((CMPY_P_FULL_WIDTH-1)/8+1);
// input data
wire [DATA_I_WIDTH-1 : 0] din_freq_real;
wire [DATA_I_WIDTH-1 : 0] din_freq_imag;
assign din_freq_real = rx_cdc_ch2_i;
assign din_freq_imag = rx_cdc_ch2_q;
// cmpy
wire [CMPY_OUTPUT_WIDTH-1 : 0] din_freq_cxr_real;
wire [CMPY_OUTPUT_WIDTH-1 : 0] din_freq_cxr_imag;
wire din_freq_cxr_valid; // declared ahead
wire cmpy_a_valid;
wire [2*AXIS_CMPY_A_WIDTH-1 : 0] cmpy_a ;
wire cmpy_b_valid;
wire [2*AXIS_CMPY_B_WIDTH-1 : 0] cmpy_b ;
wire cmpy_p_valid;
wire [2*AXIS_CMPY_P_WIDTH-1 : 0] cmpy_p ;
assign cmpy_a_valid = freq_comp_busy;
assign cmpy_b_valid = dds_valid;
assign din_freq_cxr_valid = cmpy_p_valid;
// sign bit extension to fit axis 8-bit data format
assign cmpy_a = {{(AXIS_CMPY_A_WIDTH-CMPY_A_WIDTH){din_freq_imag[DATA_I_WIDTH-1]}},din_freq_imag,
{(AXIS_CMPY_A_WIDTH-CMPY_A_WIDTH){din_freq_real[DATA_I_WIDTH-1]}},din_freq_real};
assign cmpy_b = {{(AXIS_CMPY_B_WIDTH-CMPY_B_WIDTH){sin_dds[DDS_DATA_WIDTH-1]}},sin_dds,
{(AXIS_CMPY_B_WIDTH-CMPY_B_WIDTH){cos_dds[DDS_DATA_WIDTH-1]}},cos_dds};
if (CMPY_OUTPUT_WIDTH > CMPY_P_WIDTH) begin
// append zeros
assign din_freq_cxr_real = {cmpy_p[0 +: CMPY_P_WIDTH],{(CMPY_OUTPUT_WIDTH-CMPY_P_WIDTH){1'b0}}};
assign din_freq_cxr_imag = {cmpy_p[AXIS_CMPY_P_WIDTH +: CMPY_P_WIDTH],{(CMPY_OUTPUT_WIDTH-CMPY_P_WIDTH){1'b0}}};
end
else begin
// truncate valid msb
assign din_freq_cxr_real = cmpy_p[CMPY_P_WIDTH-1 -: CMPY_OUTPUT_WIDTH];
assign din_freq_cxr_imag = cmpy_p[AXIS_CMPY_P_WIDTH+CMPY_P_WIDTH-1 -: CMPY_OUTPUT_WIDTH];
end
cmpy_12x8 u_cmpy_12x8_freq
(
.aclk (clk_4x ), // input wire aclk
.s_axis_a_tvalid (cmpy_a_valid ), // input wire s_axis_a_tvalid
.s_axis_a_tdata (cmpy_a ), // input wire [31 : 0] s_axis_a_tdata
.s_axis_b_tvalid (cmpy_b_valid ), // input wire s_axis_b_tvalid
.s_axis_b_tdata (cmpy_b ), // input wire [15 : 0] s_axis_b_tdata
.m_axis_dout_tvalid (cmpy_p_valid ), // output wire m_axis_dout_tvalid
.m_axis_dout_tdata (cmpy_p ) // output wire [47 : 0] m_axis_dout_tdata
);
////////////////////////////////////////////////////////////////////////////////
/////////// Digital Matched Filter for Frequency Shift Compensation ////////////
////////////////////////////////////////////////////////////////////////////////
reg dmf_freq_start = 'b0;
wire dmf_freq_busy;
wire dmf_freq_din_valid;
wire [DATA_I_WIDTH-1 : 0] dmf_freq_din_real;
wire [DATA_I_WIDTH-1 : 0] dmf_freq_din_imag;
wire dmf_freq_peak_valid;
wire [DATA_O_WIDTH-1 : 0] dmf_freq_peak_value_abs;
wire [DATA_O_WIDTH-1 : 0] dmf_freq_peak_value_i;
wire [DATA_O_WIDTH-1 : 0] dmf_freq_peak_value_q;
wire [$clog2(PRBS_POS)-1 : 0] dmf_freq_peak_index;
wire [DATA_O_WIDTH-1 : 0] dmf_freq_moduli_abs;
assign dmf_freq_din_valid = din_freq_cxr_valid;
if (DATA_I_WIDTH > CMPY_OUTPUT_WIDTH) begin
// append zeros
assign dmf_freq_din_real = {din_freq_cxr_real,{(DATA_I_WIDTH-CMPY_OUTPUT_WIDTH){1'b0}}};
assign dmf_freq_din_imag = {din_freq_cxr_imag,{(DATA_I_WIDTH-CMPY_OUTPUT_WIDTH){1'b0}}};
end
else begin
// truncate msb
assign dmf_freq_din_real = din_freq_cxr_real[CMPY_OUTPUT_WIDTH-1 -: DATA_I_WIDTH];
assign dmf_freq_din_imag = din_freq_cxr_imag[CMPY_OUTPUT_WIDTH-1 -: DATA_I_WIDTH];
end
// -----------------------------------------------------------------------------
// dmf start control
// -----------------------------------------------------------------------------
always @(posedge clk_4x) begin
if (rst) begin
dmf_freq_start <= 'b0;
end
else case (state_next)
STATE_FREQ_DMF: dmf_freq_start <= (state_curr == STATE_FREQ_SW) ? ~dmf_freq_start : dmf_freq_start;
default: dmf_freq_start <= dmf_freq_start;
endcase
end
// dmf instantiation
rx_dmf #(
.PRBS_LEN (PRBS_LEN ),
.INTERP_RATE (INTERP_RATE ),
.PROCESS_INTERP (PROCESS_INTERP ),
.DATA_I_WIDTH (DATA_I_WIDTH ),
.DATA_O_WIDTH (DATA_O_WIDTH )
) u_rx_dmf_freq
(
.clk (clk_4x ),
.rst (rst ),
.dmf_start (dmf_freq_start ),
.dmf_busy (dmf_freq_busy ),
.dmf_num (1 ),
.dmf_continuous (1'b0 ),
.din_valid (dmf_freq_din_valid ),
.din_real (dmf_freq_din_real ),
.din_imag (dmf_freq_din_imag ),
.peak_valid (dmf_freq_peak_valid ),
.last_peak_valid(dmf_freq_last_peak_valid ),
.peak_value_abs (dmf_freq_peak_value_abs ),
.peak_value_i (dmf_freq_peak_value_i ),
.peak_value_q (dmf_freq_peak_value_q ),
.peak_index (dmf_freq_peak_index )
);
assign dmf_freq_moduli_abs = u_rx_dmf_freq.moduli_abs;
// -----------------------------------------------------------------------------
// peak finding at different frequencies
// -----------------------------------------------------------------------------
reg max_freq_peak_valid = 'b0;
reg [DATA_O_WIDTH-1 : 0] max_freq_peak_value_abs = 'b0;
reg [DATA_O_WIDTH-1 : 0] max_freq_peak_value_i = 'b0;
reg [DATA_O_WIDTH-1 : 0] max_freq_peak_value_q = 'b0;
reg [$clog2(PRBS_POS)-1 : 0] max_freq_peak_index = 'b0;
// output result to port
assign freq_target_valid = max_freq_peak_valid;
assign freq_target = max_freq_peak_freq;
always @(posedge clk_4x) begin
if (rst) begin
max_freq_peak_valid <= 'b0;
max_freq_peak_value_abs <= 'b0;
max_freq_peak_value_i <= 'b0;
max_freq_peak_value_q <= 'b0;
max_freq_peak_index <= 'b0;
max_freq_peak_freq <= 'b0;
end
else case (state_next)
STATE_IDLE: begin
max_freq_peak_valid <= 'b0;
max_freq_peak_value_abs <= 'b0;
max_freq_peak_value_i <= 'b0;
max_freq_peak_value_q <= 'b0;
max_freq_peak_index <= 'b0;
max_freq_peak_freq <= 'b0;
end
STATE_FREQ_SW: begin
if ((state_curr == STATE_FREQ_DMF) && (dmf_freq_peak_value_abs > max_freq_peak_value_abs)) begin
// at the end of [STATE_FREQ_DMF] state, check if peak is valid
max_freq_peak_value_abs <= dmf_freq_peak_value_abs;
max_freq_peak_value_i <= dmf_freq_peak_value_i ;
max_freq_peak_value_q <= dmf_freq_peak_value_q ;
max_freq_peak_index <= dmf_freq_peak_index ;
max_freq_peak_freq <= freq_word ;
end
else begin
// hold otherwise
max_freq_peak_value_abs <= max_freq_peak_value_abs;
max_freq_peak_value_i <= max_freq_peak_value_i ;
max_freq_peak_value_q <= max_freq_peak_value_q ;
max_freq_peak_index <= max_freq_peak_index ;
max_freq_peak_freq <= max_freq_peak_freq ;
end
end
STATE_CH_SW: begin
if (state_curr == STATE_FREQ_DMF) begin
// indicate the target frequency word is found
max_freq_peak_valid <= 1'b1;
end
else begin
max_freq_peak_valid <= 'b0;
end
end
default: begin
max_freq_peak_valid <= 'b0;
max_freq_peak_value_abs <= max_freq_peak_value_abs;
max_freq_peak_value_i <= max_freq_peak_value_i ;
max_freq_peak_value_q <= max_freq_peak_value_q ;
max_freq_peak_index <= max_freq_peak_index ;
max_freq_peak_freq <= max_freq_peak_freq ;
end
endcase
end
////////////////////////////////////////////////////////////////////////////////
//////////////////// Complex Multiplier for Signal Channels ////////////////////
////////////////////////////////////////////////////////////////////////////////
// cmpy input
wire [CMPY_OUTPUT_WIDTH-1 : 0] din_ch_real [0 : CHANNEL_NUM-1];
wire [CMPY_OUTPUT_WIDTH-1 : 0] din_ch_imag [0 : CHANNEL_NUM-1];
assign din_ch_real[0] = rx_cdc_ch1_i;
assign din_ch_real[1] = rx_cdc_ch2_i;
assign din_ch_real[2] = rx_cdc_ch3_i;
assign din_ch_real[3] = rx_cdc_ch4_i;
assign din_ch_imag[0] = rx_cdc_ch1_q;
assign din_ch_imag[1] = rx_cdc_ch2_q;
assign din_ch_imag[2] = rx_cdc_ch3_q;
assign din_ch_imag[3] = rx_cdc_ch4_q;
// cmpy output
wire [CMPY_OUTPUT_WIDTH-1 : 0] din_ch_cxr_real [0 : CHANNEL_NUM-1];
wire [CMPY_OUTPUT_WIDTH-1 : 0] din_ch_cxr_imag [0 : CHANNEL_NUM-1];
wire din_ch_cxr_valid [0 : CHANNEL_NUM-1];
generate
for (m = 0; m < CHANNEL_NUM; m = m + 1) begin: cmpy_ch
wire cmpy_a_valid;
wire [2*AXIS_CMPY_A_WIDTH-1 : 0] cmpy_a ;
wire cmpy_b_valid;
wire [2*AXIS_CMPY_B_WIDTH-1 : 0] cmpy_b ;
wire cmpy_p_valid;
wire [2*AXIS_CMPY_P_WIDTH-1 : 0] cmpy_p ;
assign cmpy_a_valid = freq_comp_busy;
assign cmpy_b_valid = dds_valid;
assign din_ch_cxr_valid[m] = cmpy_p_valid;
// sign bit extension to fit axis 8-bit data format
assign cmpy_a = {{(AXIS_CMPY_A_WIDTH-CMPY_A_WIDTH){din_ch_imag[m][DATA_I_WIDTH-1]}},din_ch_imag[m],
{(AXIS_CMPY_A_WIDTH-CMPY_A_WIDTH){din_ch_real[m][DATA_I_WIDTH-1]}},din_ch_real[m]};
assign cmpy_b = {{(AXIS_CMPY_B_WIDTH-CMPY_B_WIDTH){sin_dds[DDS_DATA_WIDTH-1]}},sin_dds,
{(AXIS_CMPY_B_WIDTH-CMPY_B_WIDTH){cos_dds[DDS_DATA_WIDTH-1]}},cos_dds};
if (CMPY_OUTPUT_WIDTH > CMPY_P_WIDTH) begin
// append zeros
assign din_ch_cxr_real[m] = {cmpy_p[0 +: CMPY_P_WIDTH],{(CMPY_OUTPUT_WIDTH-CMPY_P_WIDTH){1'b0}}};
assign din_ch_cxr_imag[m] = {cmpy_p[AXIS_CMPY_P_WIDTH +: CMPY_P_WIDTH],{(CMPY_OUTPUT_WIDTH-CMPY_P_WIDTH){1'b0}}};
end
else begin
// truncate valid msb
assign din_ch_cxr_real[m] = cmpy_p[CMPY_P_WIDTH-1 -: CMPY_OUTPUT_WIDTH];
assign din_ch_cxr_imag[m] = cmpy_p[AXIS_CMPY_P_WIDTH+CMPY_P_WIDTH-1 -: CMPY_OUTPUT_WIDTH];
end
cmpy_12x8 u_cmpy_12x8_ch
(
.aclk (clk_4x ), // input wire aclk
.s_axis_a_tvalid (cmpy_a_valid ), // input wire s_axis_a_tvalid
.s_axis_a_tdata (cmpy_a ), // input wire [31 : 0] s_axis_a_tdata
.s_axis_b_tvalid (cmpy_b_valid ), // input wire s_axis_b_tvalid
.s_axis_b_tdata (cmpy_b ), // input wire [15 : 0] s_axis_b_tdata
.m_axis_dout_tvalid (cmpy_p_valid ), // output wire m_axis_dout_tvalid
.m_axis_dout_tdata (cmpy_p ) // output wire [47 : 0] m_axis_dout_tdata
);
end
endgenerate
////////////////////////////////////////////////////////////////////////////////
////////////////// Digital Matched Filter for Signal Channels //////////////////
////////////////////////////////////////////////////////////////////////////////
reg dmf_ch_start = 'b0;
wire dmf_ch_busy [0 : CHANNEL_NUM-1];
wire dmf_ch_din_valid [0 : CHANNEL_NUM-1];
wire [DATA_I_WIDTH-1 : 0] dmf_ch_din_real [0 : CHANNEL_NUM-1];
wire [DATA_I_WIDTH-1 : 0] dmf_ch_din_imag [0 : CHANNEL_NUM-1];
wire dmf_ch_peak_valid [0 : CHANNEL_NUM-1];
wire [DATA_O_WIDTH-1 : 0] dmf_ch_peak_value_abs [0 : CHANNEL_NUM-1];
wire [DATA_O_WIDTH-1 : 0] dmf_ch_peak_value_i [0 : CHANNEL_NUM-1];
wire [DATA_O_WIDTH-1 : 0] dmf_ch_peak_value_q [0 : CHANNEL_NUM-1];
wire [$clog2(PRBS_POS)-1 : 0] dmf_ch_peak_index [0 : CHANNEL_NUM-1];
wire [DATA_O_WIDTH-1 : 0] dmf_ch_moduli_abs [0 : CHANNEL_NUM-1];
// -----------------------------------------------------------------------------
// dmf start control
// -----------------------------------------------------------------------------
always @(posedge clk_4x) begin
if (rst) begin
dmf_ch_start <= 'b0;
end
else case (state_next)
STATE_CH_DMF: dmf_ch_start <= (state_curr == STATE_CH_SW) ? ~dmf_ch_start : dmf_ch_start;
default: dmf_ch_start <= dmf_ch_start;
endcase
end
generate
for (m = 0; m < CHANNEL_NUM; m = m + 1) begin: dmf_ch
assign dmf_ch_din_valid[m] = din_ch_cxr_valid[m];
if (DATA_I_WIDTH > CMPY_OUTPUT_WIDTH) begin
// append zeros
assign dmf_ch_din_real[m] = {din_ch_cxr_real[m],{(DATA_I_WIDTH-CMPY_OUTPUT_WIDTH){1'b0}}};
assign dmf_ch_din_imag[m] = {din_ch_cxr_imag[m],{(DATA_I_WIDTH-CMPY_OUTPUT_WIDTH){1'b0}}};
end
else begin
// truncate msb
assign dmf_ch_din_real[m] = din_ch_cxr_real[m][CMPY_OUTPUT_WIDTH-1 -: DATA_I_WIDTH];
assign dmf_ch_din_imag[m] = din_ch_cxr_imag[m][CMPY_OUTPUT_WIDTH-1 -: DATA_I_WIDTH];
end
// dmf instantiation
rx_dmf #(
.PRBS_LEN (PRBS_LEN ),
.INTERP_RATE (INTERP_RATE ),
.PROCESS_INTERP (PROCESS_INTERP ),
.DATA_I_WIDTH (DATA_I_WIDTH ),
.DATA_O_WIDTH (DATA_O_WIDTH )
) u_rx_dmf_ch
(
.clk (clk_4x ),
.rst (rst ),
.dmf_start (dmf_ch_start ),
.dmf_busy (dmf_ch_busy[m] ),
.dmf_num (dmf_num_per_ch ),
.dmf_continuous (dmf_continuous ),
.din_valid (dmf_ch_din_valid[m] ),
.din_real (dmf_ch_din_real[m] ),
.din_imag (dmf_ch_din_imag[m] ),
.peak_valid (dmf_ch_peak_valid[m] ),
.last_peak_valid(dmf_ch_last_peak_valid[m] ),
.peak_value_abs (dmf_ch_peak_value_abs[m] ),
.peak_value_i (dmf_ch_peak_value_i[m] ),
.peak_value_q (dmf_ch_peak_value_q[m] ),
.peak_index (dmf_ch_peak_index[m] )
);
assign dmf_ch_moduli_abs[m] = u_rx_dmf_ch.moduli_abs;
end
endgenerate
assign ch_peak_valid = dmf_ch_peak_valid[0];
assign ch1_peak_value_abs = dmf_ch_peak_value_abs[0];
assign ch1_peak_value_i = dmf_ch_peak_value_i[0] ;
assign ch1_peak_value_q = dmf_ch_peak_value_q [0] ;
assign ch1_peak_index = dmf_ch_peak_index[0] ;
assign ch2_peak_value_abs = dmf_ch_peak_value_abs[1];
assign ch2_peak_value_i = dmf_ch_peak_value_i[1] ;
assign ch2_peak_value_q = dmf_ch_peak_value_q [1] ;
assign ch2_peak_index = dmf_ch_peak_index[1] ;
assign ch3_peak_value_abs = dmf_ch_peak_value_abs[2];
assign ch3_peak_value_i = dmf_ch_peak_value_i[2] ;
assign ch3_peak_value_q = dmf_ch_peak_value_q [2] ;
assign ch3_peak_index = dmf_ch_peak_index[2] ;
assign ch4_peak_value_abs = dmf_ch_peak_value_abs[3];
assign ch4_peak_value_i = dmf_ch_peak_value_i[3] ;
assign ch4_peak_value_q = dmf_ch_peak_value_q [3] ;
assign ch4_peak_index = dmf_ch_peak_index[3] ;
endmodule