Archived
472 lines
16 KiB
Verilog
472 lines
16 KiB
Verilog
`timescale 1ns / 1ps
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// Company:
|
|
// Engineer:
|
|
// _ _ ____
|
|
// | | ___ ___| |__ / ___| __ _ ___
|
|
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
|
|
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
|
|
// \___/ \___/|___/_| |_| \____|\__,_|\___/
|
|
//
|
|
// Create Date: 04/25/2023 05:53:44 PM
|
|
// Design Name:
|
|
// Module Name: rx_dmf
|
|
// Project Name:
|
|
// Target Devices:
|
|
// Tool Versions:
|
|
// Description:
|
|
//
|
|
// Dependencies:
|
|
//
|
|
// Revision:
|
|
// Revision 0.01 - File Created
|
|
// Additional Comments:
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
module rx_dmf
|
|
#(
|
|
// length of pseudorandom bit sequence, need to be a power of 2
|
|
parameter PRBS_LEN = 128,
|
|
// interpolation of input signal, need to be a power of 2
|
|
parameter INTERP_RATE = 8,
|
|
// 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,
|
|
parameter MAX_DMF_NUM = 64,
|
|
parameter DATA_I_WIDTH = 12,
|
|
parameter DATA_O_WIDTH = 18
|
|
)
|
|
(
|
|
input clk ,
|
|
input rst ,
|
|
|
|
input dmf_start ,
|
|
output dmf_busy ,
|
|
|
|
input din_valid ,
|
|
input [DATA_I_WIDTH-1 : 0] din_real ,
|
|
input [DATA_I_WIDTH-1 : 0] din_imag ,
|
|
|
|
input [$clog2(MAX_DMF_NUM+1)-1 : 0] dmf_num ,
|
|
|
|
output peak_valid ,
|
|
output last_peak_valid ,
|
|
output [DATA_O_WIDTH-1 : 0] peak_value_abs ,
|
|
output [DATA_O_WIDTH-1 : 0] peak_value_i ,
|
|
output [DATA_O_WIDTH-1 : 0] peak_value_q ,
|
|
output [$clog2(PRBS_POS)-1 : 0] peak_index
|
|
);
|
|
|
|
localparam CMPLX_DIM = 2;
|
|
localparam APPROX_ABS_WIDTH = 29;
|
|
localparam ABS_WIDTH = 18;
|
|
|
|
localparam DMF_I_WIDTH = 12;
|
|
localparam DMF_O_WIDTH = DMF_I_WIDTH+$clog2(PRBS_POS);
|
|
|
|
localparam AXIS_DMF_I_WIDTH = 8*((DMF_I_WIDTH-1)/8+1);
|
|
localparam AXIS_DMF_O_WIDTH = 8*((DMF_O_WIDTH-1)/8+1);
|
|
|
|
genvar m;
|
|
integer i;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////// Center State Control /////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
reg dmf_busy_buf = 'b0;
|
|
reg dmf_start_d1 = 'b0;
|
|
reg dmf_start_d2 = 'b0;
|
|
reg [$clog2(MAX_DMF_NUM)-1 : 0] cnt_dmf_num = 'b0;
|
|
|
|
reg moduli_max_valid = 'b0;
|
|
|
|
assign dmf_busy = dmf_busy_buf;
|
|
|
|
always @(posedge clk) begin
|
|
dmf_start_d1 <= dmf_start;
|
|
dmf_start_d2 <= dmf_start_d1;
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
cnt_dmf_num <= 'b0;
|
|
end
|
|
else if (dmf_busy) begin
|
|
cnt_dmf_num <= (moduli_max_valid) ? cnt_dmf_num + 1'b1 : cnt_dmf_num;
|
|
end
|
|
else begin
|
|
cnt_dmf_num <= 'b0;
|
|
end
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
dmf_busy_buf <= 'b0;
|
|
end
|
|
else if (cnt_dmf_num == dmf_num+1) begin
|
|
// clear when output is valid
|
|
dmf_busy_buf <= 'b0;
|
|
end
|
|
else if (din_valid && (dmf_start_d2 != dmf_start_d1) && (dmf_num != 'b0)) begin
|
|
// set when either edge is detected
|
|
dmf_busy_buf <= 1'b1;
|
|
end
|
|
else begin
|
|
// otherwise keep
|
|
dmf_busy_buf <= dmf_busy_buf;
|
|
end
|
|
end
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////// Decimation Counter //////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
reg [$clog2(INTERP_RATE/PROCESS_INTERP)-1 : 0] cnt_deci = 'b0;
|
|
reg din_deci_valid = 'b0;
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
cnt_deci <= 'b0;
|
|
end
|
|
else if (dmf_busy && din_valid) begin
|
|
cnt_deci <= cnt_deci + 1'b1;
|
|
end
|
|
else begin
|
|
cnt_deci <= 'b0;
|
|
end
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
din_deci_valid <= 'b0;
|
|
end
|
|
else begin
|
|
din_deci_valid <= (cnt_deci == INTERP_RATE/PROCESS_INTERP-1) ? 1'b1 : 'b0;
|
|
end
|
|
end
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////// Digital Matched Filter ////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// input & output signals
|
|
wire [AXIS_DMF_I_WIDTH-1 : 0] dmf_axis_i_real;
|
|
wire [AXIS_DMF_I_WIDTH-1 : 0] dmf_axis_i_imag;
|
|
wire signed [AXIS_DMF_O_WIDTH-1 : 0] dmf_axis_o_real;
|
|
wire signed [AXIS_DMF_O_WIDTH-1 : 0] dmf_axis_o_imag;
|
|
wire signed [DMF_O_WIDTH-1 : 0] dmf_o_real;
|
|
wire signed [DMF_O_WIDTH-1 : 0] dmf_o_imag;
|
|
wire dmf_o_valid;
|
|
|
|
// dmf input data formatting
|
|
if (AXIS_DMF_I_WIDTH > DATA_I_WIDTH) begin
|
|
// sign extension to fit 8-bit axis data format
|
|
assign dmf_axis_i_real = {{(AXIS_DMF_I_WIDTH-DATA_I_WIDTH){din_real[DATA_I_WIDTH-1]}},din_real};
|
|
assign dmf_axis_i_imag = {{(AXIS_DMF_I_WIDTH-DATA_I_WIDTH){din_imag[DATA_I_WIDTH-1]}},din_imag};
|
|
end
|
|
else begin
|
|
// truncate msb
|
|
assign dmf_axis_i_real = din_real[DATA_I_WIDTH-1 -: AXIS_DMF_I_WIDTH];
|
|
assign dmf_axis_i_imag = din_imag[DATA_I_WIDTH-1 -: AXIS_DMF_I_WIDTH];
|
|
end
|
|
|
|
// dmf output data formatting, truncate valid bits
|
|
assign dmf_o_real = dmf_axis_o_real[DMF_O_WIDTH-1 -: DMF_O_WIDTH];
|
|
assign dmf_o_imag = dmf_axis_o_imag[DMF_O_WIDTH-1 -: DMF_O_WIDTH];
|
|
|
|
// fir port definition
|
|
wire s_axis_data_tvalid_real;
|
|
wire s_axis_data_tready_real;
|
|
wire [AXIS_DMF_I_WIDTH-1 : 0] s_axis_data_ttdata_real;
|
|
wire m_axis_data_tvalid_real;
|
|
wire [AXIS_DMF_O_WIDTH-1 : 0] m_axis_data_ttdata_real;
|
|
|
|
wire s_axis_data_tvalid_imag;
|
|
wire s_axis_data_tready_imag;
|
|
wire [AXIS_DMF_I_WIDTH-1 : 0] s_axis_data_ttdata_imag;
|
|
wire m_axis_data_tvalid_imag;
|
|
wire [AXIS_DMF_O_WIDTH-1 : 0] m_axis_data_ttdata_imag;
|
|
|
|
// fir port connection
|
|
assign s_axis_data_tvalid_real = din_deci_valid;
|
|
assign s_axis_data_ttdata_real = dmf_axis_i_real;
|
|
assign dmf_axis_o_real = m_axis_data_ttdata_real;
|
|
|
|
assign s_axis_data_tvalid_imag = din_deci_valid;
|
|
assign s_axis_data_ttdata_imag = dmf_axis_i_imag;
|
|
assign dmf_axis_o_imag = m_axis_data_ttdata_imag;
|
|
|
|
assign dmf_o_valid = m_axis_data_tvalid_real;
|
|
|
|
// fir ip core instantiation
|
|
fir_prbs7_invert_rep2 u_dmf_real
|
|
(
|
|
.aclk (clk ), // input wire aclk
|
|
.aresetn (dmf_busy ), // input aresetn
|
|
.s_axis_data_tvalid (s_axis_data_tvalid_real), // input wire s_axis_data_tvalid
|
|
.s_axis_data_tready (s_axis_data_tready_real), // output wire s_axis_data_tready
|
|
.s_axis_data_tdata (s_axis_data_ttdata_real), // input wire [15 : 0] s_axis_data_tdata
|
|
.m_axis_data_tvalid (m_axis_data_tvalid_real), // output wire m_axis_data_tvalid
|
|
.m_axis_data_tdata (m_axis_data_ttdata_real) // output wire [23 : 0] m_axis_data_tdata
|
|
);
|
|
|
|
fir_prbs7_invert_rep2 u_dmf_imag
|
|
(
|
|
.aclk (clk ), // input wire aclk
|
|
.aresetn (dmf_busy ), // input aresetn
|
|
.s_axis_data_tvalid (s_axis_data_tvalid_imag), // input wire s_axis_data_tvalid
|
|
.s_axis_data_tready (s_axis_data_tready_imag), // output wire s_axis_data_tready
|
|
.s_axis_data_tdata (s_axis_data_ttdata_imag), // input wire [15 : 0] s_axis_data_tdata
|
|
.m_axis_data_tvalid (m_axis_data_tvalid_imag), // output wire m_axis_data_tvalid
|
|
.m_axis_data_tdata (m_axis_data_ttdata_imag) // output wire [23 : 0] m_axis_data_tdata
|
|
);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////// Chip Counter /////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
localparam PEAK_ABS_DELAY = 6; // 5 for multiplier, 1 for adder
|
|
|
|
reg [$clog2(PRBS_POS)-1 : 0] cnt_chip = 'b0;
|
|
reg [$clog2(PRBS_POS)-1 : 0] cnt_chip_delay [0 : PEAK_ABS_DELAY-1];
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
cnt_chip <= 'b0;
|
|
end
|
|
else if (dmf_busy) begin
|
|
cnt_chip <= (dmf_o_valid) ? cnt_chip + 1'b1 : cnt_chip;
|
|
end
|
|
else begin
|
|
cnt_chip <= 'b0;
|
|
end
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
|
|
for (i = 1; i < PEAK_ABS_DELAY; i = i + 1) begin
|
|
cnt_chip_delay[i] <= cnt_chip_delay[i-1];
|
|
end
|
|
|
|
cnt_chip_delay[0] <= cnt_chip;
|
|
end
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////// Accumulation & Peak Search //////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// moduli
|
|
wire moduli_valid;
|
|
reg moduli_valid_delay [0 : PEAK_ABS_DELAY-1];
|
|
wire [ABS_WIDTH-1 : 0] moduli_real;
|
|
wire [ABS_WIDTH-1 : 0] moduli_imag;
|
|
reg [ABS_WIDTH-1 : 0] moduli_real_delay [0 : PEAK_ABS_DELAY-1];
|
|
reg [ABS_WIDTH-1 : 0] moduli_imag_delay [0 : PEAK_ABS_DELAY-1];
|
|
|
|
assign moduli_valid = dmf_o_valid;
|
|
|
|
if (ABS_WIDTH > DMF_O_WIDTH) begin
|
|
// append zeros
|
|
assign moduli_real = {dmf_o_real,{(ABS_WIDTH-DMF_O_WIDTH){1'b0}}};
|
|
assign moduli_imag = {dmf_o_imag,{(ABS_WIDTH-DMF_O_WIDTH){1'b0}}};
|
|
end
|
|
else begin
|
|
// truncate msb
|
|
assign moduli_real = dmf_o_real[DMF_O_WIDTH-1 -: ABS_WIDTH];
|
|
assign moduli_imag = dmf_o_imag[DMF_O_WIDTH-1 -: ABS_WIDTH];
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
|
|
for (i = 1; i < PEAK_ABS_DELAY; i = i + 1) begin
|
|
moduli_valid_delay[i] <= moduli_valid_delay[i-1];
|
|
moduli_real_delay[i] <= moduli_real_delay[i-1];
|
|
moduli_imag_delay[i] <= moduli_imag_delay[i-1];
|
|
end
|
|
|
|
moduli_valid_delay[0] <= moduli_valid;
|
|
moduli_real_delay[0] <= moduli_real;
|
|
moduli_imag_delay[0] <= moduli_imag;
|
|
end
|
|
|
|
wire [2*ABS_WIDTH-1 : 0] moduli_real_square;
|
|
wire [2*ABS_WIDTH-1 : 0] moduli_imag_square;
|
|
reg [ABS_WIDTH-1 : 0] moduli_abs_square = 'b0;
|
|
wire [DATA_O_WIDTH-1 : 0] moduli_abs;
|
|
wire moduli_abs_valid;
|
|
|
|
assign moduli_abs_valid = moduli_valid_delay[PEAK_ABS_DELAY-1];
|
|
|
|
if (DATA_O_WIDTH > ABS_WIDTH) begin
|
|
// append zeros
|
|
assign moduli_abs = {moduli_abs_square,{(DATA_O_WIDTH-ABS_WIDTH){1'b0}}};
|
|
end
|
|
else begin
|
|
// truncate msb
|
|
assign moduli_abs = moduli_abs_square[ABS_WIDTH-1 -: DATA_O_WIDTH];
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
moduli_abs_square <= 'b0;
|
|
end
|
|
else begin
|
|
moduli_abs_square <= moduli_real_square[(2*ABS_WIDTH-1) -: (ABS_WIDTH-1)] + moduli_imag_square[(2*ABS_WIDTH-1) -: (ABS_WIDTH-1)];
|
|
end
|
|
end
|
|
|
|
mult_18x18 u_mult_real
|
|
(
|
|
.CLK(clk ), // input wire CLK
|
|
.A (moduli_real ), // input wire [17 : 0] A
|
|
.B (moduli_real ), // input wire [17 : 0] B
|
|
.P (moduli_real_square ) // output wire [17 : 0] P
|
|
);
|
|
|
|
mult_18x18 u_mult_imag
|
|
(
|
|
.CLK(clk ), // input wire CLK
|
|
.A (moduli_imag ), // input wire [17 : 0] A
|
|
.B (moduli_imag ), // input wire [17 : 0] B
|
|
.P (moduli_imag_square ) // output wire [17 : 0] P
|
|
);
|
|
|
|
// wire accum_current_valid;
|
|
|
|
// assign accum_current_valid = dmf_o_valid;
|
|
|
|
// wire [APPROX_ABS_WIDTH-2 : 0] accum_moduli_real;
|
|
// wire [APPROX_ABS_WIDTH-2 : 0] accum_moduli_imag;
|
|
// wire [APPROX_ABS_WIDTH-1 : 0] accum_moduli_abs ;
|
|
// wire accum_current_abs_valid;
|
|
// wire [DATA_O_WIDTH-1 : 0] accum_current_abs;
|
|
|
|
// if (APPROX_ABS_WIDTH-1 > DMF_O_WIDTH) begin
|
|
// // append zeros
|
|
// assign accum_moduli_real = {dmf_o_real,{(APPROX_ABS_WIDTH-1-DMF_O_WIDTH){1'b0}}};
|
|
// assign accum_moduli_imag = {dmf_o_imag,{(APPROX_ABS_WIDTH-1-DMF_O_WIDTH){1'b0}}};
|
|
// end
|
|
// else begin
|
|
// // truncate msb
|
|
// assign accum_moduli_real = dmf_o_real[DMF_O_WIDTH-1 -: (APPROX_ABS_WIDTH-1)];
|
|
// assign accum_moduli_imag = dmf_o_imag[DMF_O_WIDTH-1 -: (APPROX_ABS_WIDTH-1)];
|
|
// end
|
|
|
|
// if (DATA_O_WIDTH > APPROX_ABS_WIDTH) begin
|
|
// // append zeros
|
|
// assign accum_current_abs = {accum_moduli_abs,{(DATA_O_WIDTH-APPROX_ABS_WIDTH){1'b0}}};
|
|
// end
|
|
// else begin
|
|
// // truncate msb
|
|
// assign accum_current_abs = accum_moduli_abs[APPROX_ABS_WIDTH-1 -: DATA_O_WIDTH];
|
|
// end
|
|
|
|
// ApproxAbs u_accum_abs
|
|
// (
|
|
// .clk (clk ),
|
|
// .Nd (accum_current_valid ),
|
|
// .Dini (accum_moduli_real ),
|
|
// .Dinq (accum_moduli_imag ),
|
|
// .Abs_Rdy (accum_current_abs_valid),
|
|
// .Abs_Dout (accum_moduli_abs )
|
|
// );
|
|
|
|
// peak record
|
|
reg [DATA_O_WIDTH-1 : 0] moduli_max_abs = 'b0;
|
|
reg [DATA_O_WIDTH-1 : 0] moduli_max_real = 'b0;
|
|
reg [DATA_O_WIDTH-1 : 0] moduli_max_imag = 'b0;
|
|
reg [$clog2(PRBS_POS)-1 : 0] moduli_max_index = 'b0;
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
moduli_max_valid <= 'b0;
|
|
moduli_max_abs <= 'b0;
|
|
moduli_max_real <= 'b0;
|
|
moduli_max_imag <= 'b0;
|
|
moduli_max_index <= 'b0;
|
|
end
|
|
else if (dmf_busy) begin
|
|
if (moduli_abs_valid) begin
|
|
if ((cnt_chip_delay[PEAK_ABS_DELAY-1] == 0) || (moduli_abs > moduli_max_abs)) begin
|
|
// reset when chip counter reaches zero or record peak
|
|
moduli_max_abs <= moduli_abs ;
|
|
moduli_max_real <= moduli_real_delay[PEAK_ABS_DELAY-1];
|
|
moduli_max_imag <= moduli_imag_delay[PEAK_ABS_DELAY-1];
|
|
moduli_max_index <= cnt_chip_delay[PEAK_ABS_DELAY-1] ;
|
|
end
|
|
else begin
|
|
moduli_max_abs <= moduli_max_abs;
|
|
moduli_max_real <= moduli_max_real;
|
|
moduli_max_imag <= moduli_max_imag;
|
|
moduli_max_index <= moduli_max_index;
|
|
end
|
|
|
|
if (cnt_chip_delay[PEAK_ABS_DELAY-1] == PRBS_POS-1) begin
|
|
// peak record valid when chip counter reaches maximum value
|
|
moduli_max_valid <= 1'b1;
|
|
end
|
|
else begin
|
|
moduli_max_valid <= 'b0;
|
|
end
|
|
end
|
|
else begin
|
|
moduli_max_valid <= 'b0;
|
|
moduli_max_abs <= moduli_max_abs;
|
|
moduli_max_real <= moduli_max_real;
|
|
moduli_max_imag <= moduli_max_imag;
|
|
moduli_max_index <= moduli_max_index;
|
|
end
|
|
end
|
|
else begin
|
|
moduli_max_valid <= 'b0;
|
|
moduli_max_abs <= 'b0;
|
|
moduli_max_real <= 'b0;
|
|
moduli_max_imag <= 'b0;
|
|
moduli_max_index <= 'b0;
|
|
end
|
|
end
|
|
|
|
// register output
|
|
reg peak_valid_buf = 1'b0;
|
|
reg last_peak_valid_buf = 1'b0;
|
|
reg [DATA_O_WIDTH-1 : 0] peak_value_abs_buf = 'b0;
|
|
reg [DATA_O_WIDTH-1 : 0] peak_value_i_buf = 'b0;
|
|
reg [DATA_O_WIDTH-1 : 0] peak_value_q_buf = 'b0;
|
|
reg [$clog2(PRBS_POS)-1 : 0] peak_index_buf = 'b0;
|
|
|
|
assign peak_valid = peak_valid_buf ;
|
|
assign last_peak_valid = last_peak_valid_buf;
|
|
assign peak_value_abs = peak_value_abs_buf ;
|
|
assign peak_value_i = peak_value_i_buf ;
|
|
assign peak_value_q = peak_value_q_buf ;
|
|
assign peak_index = peak_index_buf ;
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
peak_valid_buf <= 'b0;
|
|
last_peak_valid_buf <= 'b0;
|
|
peak_value_abs_buf <= 'b0;
|
|
peak_value_i_buf <= 'b0;
|
|
peak_value_q_buf <= 'b0;
|
|
peak_index_buf <= 'b0;
|
|
end
|
|
else if (moduli_max_valid && (cnt_dmf_num != 'b0)) begin
|
|
peak_valid_buf <= 1'b1;
|
|
peak_value_abs_buf <= moduli_max_abs ;
|
|
peak_value_i_buf <= moduli_max_real ;
|
|
peak_value_q_buf <= moduli_max_imag ;
|
|
peak_index_buf <= moduli_max_index;
|
|
|
|
last_peak_valid_buf<= (cnt_dmf_num == dmf_num) ? 1'b1 : 'b0;
|
|
end
|
|
else begin
|
|
peak_valid_buf <= 1'b0;
|
|
last_peak_valid_buf <= 1'b0;
|
|
peak_value_abs_buf <= peak_value_abs_buf;
|
|
peak_value_i_buf <= peak_value_i_buf ;
|
|
peak_value_q_buf <= peak_value_q_buf ;
|
|
peak_index_buf <= peak_index_buf ;
|
|
end
|
|
end
|
|
|
|
endmodule
|