`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 = -4194304, parameter FREQ_WORD_UPPER = 4194303, parameter FREQ_WORD_STEP = 1024, parameter MAX_DMF_NUM = 64, // 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 = 4, // possible position of pn code parameter PRBS_POS = 2*PRBS_LEN*PROCESS_INTERP ) ( // clock & reset input clk , 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 [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 reg [DATA_O_WIDTH-1 : 0] ch1_peak_value_abs , output reg [DATA_O_WIDTH-1 : 0] ch1_peak_value_i , output reg [DATA_O_WIDTH-1 : 0] ch1_peak_value_q , output reg [$clog2(PRBS_POS-1) : 0] ch1_peak_index , output reg [DATA_O_WIDTH-1 : 0] ch2_peak_value_abs , output reg [DATA_O_WIDTH-1 : 0] ch2_peak_value_i , output reg [DATA_O_WIDTH-1 : 0] ch2_peak_value_q , output reg [$clog2(PRBS_POS-1) : 0] ch2_peak_index , output reg [DATA_O_WIDTH-1 : 0] ch3_peak_value_abs , output reg [DATA_O_WIDTH-1 : 0] ch3_peak_value_i , output reg [DATA_O_WIDTH-1 : 0] ch3_peak_value_q , output reg [$clog2(PRBS_POS-1) : 0] ch3_peak_index , output reg [DATA_O_WIDTH-1 : 0] ch4_peak_value_abs , output reg [DATA_O_WIDTH-1 : 0] ch4_peak_value_i , output reg [DATA_O_WIDTH-1 : 0] ch4_peak_value_q , output reg [$clog2(PRBS_POS-1) : 0] ch4_peak_index ); localparam STATE_NUM = 8; localparam [$clog2(STATE_NUM)-1:0] STATE_IDLE = 0, STATE_FREQ_SW = 1, STATE_FREQ_DMF = 2, STATE_CH_SW = 3, STATE_CH1 = 4, STATE_CH2 = 5, STATE_CH3 = 6, STATE_CH4 = 7; 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; //////////////////////////////////////////////////////////////////////////////// ///////////////////////////// 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; // count the number of times dmf has been executed on each channel reg [$clog2(MAX_DMF_NUM)-1 : 0] cnt_dmf_ch = 'b0; // cmpy output data valid indicator wire din_cxr_valid; // dmf finish indicator wire dmf_peak_valid; // current frequency word reg signed [FREQ_WORD_WIDTH-1 : 0] freq_word = 'b0; // frequency scan finish indicator reg freq_end = 'b0; // dmf finish indicator for each channel reg ch1_peak_valid = 'b0; reg ch2_peak_valid = 'b0; reg ch3_peak_valid = 'b0; reg ch4_peak_valid = 'b0; // ----------------------------------------------------------------------------- // 1st always block, sequential state transition // ----------------------------------------------------------------------------- always @(posedge clk) 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_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 // go through each channel if (!ch1_peak_valid) begin state_next <= STATE_CH1; end else if (!ch2_peak_valid) begin state_next <= STATE_CH2; end else if (!ch3_peak_valid) begin state_next <= STATE_CH3; end else if (!ch4_peak_valid) begin state_next <= STATE_CH4; end end else begin state_next <= STATE_CH_SW; end end STATE_CH1 : begin if (ch1_peak_valid) begin // wait until dmf is done state_next <= STATE_CH_SW; end else begin state_next <= STATE_CH1; end end STATE_CH2 : begin if (ch2_peak_valid) begin // wait until dmf is done state_next <= STATE_CH_SW; end else begin state_next <= STATE_CH2; end end STATE_CH3 : begin if (ch3_peak_valid) begin state_next <= STATE_CH_SW; // wait until dmf is done end else begin state_next <= STATE_CH3; end end STATE_CH4 : begin if (ch4_peak_valid) begin // wait until dmf is done, check if the number of dmf is enough state_next <= (cnt_dmf_ch == dmf_num_per_ch-1) ? STATE_IDLE : STATE_CH_SW; end else begin state_next <= STATE_CH4; end end default: begin // hold state_next = state_next; end endcase end // ----------------------------------------------------------------------------- // 3rd always block, the sequential FSM output // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // edge detection // ----------------------------------------------------------------------------- always @(posedge clk) 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) 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_CH1 : freq_comp_busy_buf <= 1'b1; STATE_CH2 : freq_comp_busy_buf <= 1'b1; STATE_CH3 : freq_comp_busy_buf <= 1'b1; STATE_CH4 : 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) 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 // ----------------------------------------------------------------------------- // count the number of times dmf has been executed on each channel // ----------------------------------------------------------------------------- always @(posedge clk) begin if (rst) begin cnt_dmf_ch <= 'b0; end else if (state_next == STATE_IDLE) begin cnt_dmf_ch <= 'b0; end else begin cnt_dmf_ch <= (ch_peak_valid) ? cnt_dmf_ch + 1'b1 : cnt_dmf_ch; end end // ----------------------------------------------------------------------------- // frequency word control // ----------------------------------------------------------------------------- // record the frequency word generating the maximum peak reg [FREQ_WORD_WIDTH-1 : 0] max_peak_freq = 'b0; always @(posedge clk) 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_peak_freq; end default: begin freq_word <= freq_word; end endcase end // ----------------------------------------------------------------------------- // frequency scan finish indicator // ----------------------------------------------------------------------------- always @(posedge clk) 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 // ----------------------------------------------------------------------------- // complex multiplier input data control // ----------------------------------------------------------------------------- reg [DATA_I_WIDTH-1 : 0] din_real = 'b0; reg [DATA_I_WIDTH-1 : 0] din_imag = 'b0; always @(posedge clk) begin if (rst) begin din_real <= 'b0; din_imag <= 'b0; end else case (state_next) // reset when idle; using ch2 data for frequency scan STATE_IDLE : begin din_real <= 'b0 ; din_imag <= 'b0 ; end STATE_FREQ_SW : begin din_real <= rx_ch2_i; din_imag <= rx_ch2_q; end STATE_FREQ_DMF : begin din_real <= rx_ch2_i; din_imag <= rx_ch2_q; end STATE_CH_SW : case (state_curr) STATE_FREQ_DMF: begin din_real <= rx_ch1_i; din_imag <= rx_ch1_q; end STATE_CH1 : begin din_real <= rx_ch2_i; din_imag <= rx_ch2_q; end STATE_CH2 : begin din_real <= rx_ch3_i; din_imag <= rx_ch3_q; end STATE_CH3 : begin din_real <= rx_ch4_i; din_imag <= rx_ch4_q; end STATE_CH4 : begin din_real <= rx_ch1_i; din_imag <= rx_ch1_q; end default : begin din_real <= rx_ch1_i; din_imag <= rx_ch1_q; end endcase STATE_CH1 : begin din_real <= rx_ch1_i; din_imag <= rx_ch1_q; end STATE_CH2 : begin din_real <= rx_ch2_i; din_imag <= rx_ch2_q; end STATE_CH3 : begin din_real <= rx_ch3_i; din_imag <= rx_ch3_q; end STATE_CH4 : begin din_real <= rx_ch4_i; din_imag <= rx_ch4_q; end default : begin din_real <= rx_ch2_i; din_imag <= rx_ch2_q; end endcase 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 ), // 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 ////////////////////////////// //////////////////////////////////////////////////////////////////////////////// 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); // cmpy wire [CMPY_OUTPUT_WIDTH-1 : 0] din_cxr_real; wire [CMPY_OUTPUT_WIDTH-1 : 0] din_cxr_imag; // wire din_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_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_imag[DATA_I_WIDTH-1]}},din_imag, {(AXIS_CMPY_A_WIDTH-CMPY_A_WIDTH){din_real[DATA_I_WIDTH-1]}},din_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_cxr_real = {cmpy_p[0 +: CMPY_P_WIDTH],{(CMPY_OUTPUT_WIDTH-CMPY_P_WIDTH){1'b0}}}; assign din_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_cxr_real = cmpy_p[CMPY_P_WIDTH-1 -: CMPY_OUTPUT_WIDTH]; assign din_cxr_imag = cmpy_p[AXIS_CMPY_P_WIDTH+CMPY_P_WIDTH-1 -: CMPY_OUTPUT_WIDTH]; end cmpy_12x8 u_cmpy_12x8 ( .aclk (clk ), // 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 //////////////////////////// //////////////////////////////////////////////////////////////////////////////// reg dmf_start = 'b0; wire dmf_busy; wire dmf_din_valid; wire [DATA_I_WIDTH-1 : 0] dmf_din_real; wire [DATA_I_WIDTH-1 : 0] dmf_din_imag; wire [DATA_O_WIDTH-1 : 0] dmf_peak_value_abs; wire [DATA_O_WIDTH-1 : 0] dmf_peak_value_i; wire [DATA_O_WIDTH-1 : 0] dmf_peak_value_q; wire [$clog2(PRBS_POS-1) : 0] dmf_peak_index; assign dmf_din_valid = din_cxr_valid; if (DATA_I_WIDTH > CMPY_OUTPUT_WIDTH) begin // append zerod assign dmf_din_real = {din_cxr_real,{(DATA_I_WIDTH-CMPY_OUTPUT_WIDTH){1'b0}}}; assign dmf_din_imag = {din_cxr_imag,{(DATA_I_WIDTH-CMPY_OUTPUT_WIDTH){1'b0}}}; end else begin // truncate msb assign dmf_din_real = din_cxr_real[CMPY_OUTPUT_WIDTH-1 -: DATA_I_WIDTH]; assign dmf_din_imag = din_cxr_imag[CMPY_OUTPUT_WIDTH-1 -: DATA_I_WIDTH]; end // ----------------------------------------------------------------------------- // dmf start control // ----------------------------------------------------------------------------- always @(posedge clk) begin if (rst) begin dmf_start <= 'b0; end else case (state_next) STATE_FREQ_DMF: dmf_start <= (state_curr == STATE_FREQ_SW) ? ~dmf_start : dmf_start; STATE_CH1 : dmf_start <= (state_curr == STATE_CH_SW ) ? ~dmf_start : dmf_start; STATE_CH2 : dmf_start <= (state_curr == STATE_CH_SW ) ? ~dmf_start : dmf_start; STATE_CH3 : dmf_start <= (state_curr == STATE_CH_SW ) ? ~dmf_start : dmf_start; STATE_CH4 : dmf_start <= (state_curr == STATE_CH_SW ) ? ~dmf_start : dmf_start; default: dmf_start <= dmf_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 ( .clk (clk ), .rst (rst ), .dmf_start (dmf_start ), .dmf_busy (dmf_busy ), .din_valid (dmf_din_valid ), .din_real (dmf_din_real ), .din_imag (dmf_din_imag ), .peak_valid (dmf_peak_valid ), .peak_value_abs (dmf_peak_value_abs ), .peak_value_i (dmf_peak_value_i ), .peak_value_q (dmf_peak_value_q ), .peak_index (dmf_peak_index ) ); // ----------------------------------------------------------------------------- // peak finding at different frequencies // ----------------------------------------------------------------------------- reg max_peak_valid = 'b0; reg [DATA_O_WIDTH-1 : 0] max_peak_value_abs = 'b0; reg [DATA_O_WIDTH-1 : 0] max_peak_value_i = 'b0; reg [DATA_O_WIDTH-1 : 0] max_peak_value_q = 'b0; reg [$clog2(PRBS_POS-1) : 0] max_peak_index = 'b0; // output result to port assign freq_target_valid = max_peak_valid; assign freq_target = max_peak_freq; always @(posedge clk) begin if (rst) begin max_peak_valid <= 'b0; max_peak_value_abs <= 'b0; max_peak_value_i <= 'b0; max_peak_value_q <= 'b0; max_peak_index <= 'b0; max_peak_freq <= 'b0; end else case (state_next) STATE_IDLE: begin max_peak_valid <= 'b0; max_peak_value_abs <= 'b0; max_peak_value_i <= 'b0; max_peak_value_q <= 'b0; max_peak_index <= 'b0; max_peak_freq <= 'b0; end STATE_FREQ_SW: begin if ((state_curr == STATE_FREQ_DMF) && (dmf_peak_value_abs > max_peak_value_abs)) begin // at the end of [STATE_FREQ_DMF] state, check if peak is valid max_peak_value_abs <= dmf_peak_value_abs; max_peak_value_i <= dmf_peak_value_i ; max_peak_value_q <= dmf_peak_value_q ; max_peak_index <= dmf_peak_index ; max_peak_freq <= freq_word ; end else begin // hold otherwise max_peak_value_abs <= max_peak_value_abs; max_peak_value_i <= max_peak_value_i ; max_peak_value_q <= max_peak_value_q ; max_peak_index <= max_peak_index ; max_peak_freq <= max_peak_freq ; end end STATE_CH_SW: begin if (state_curr == STATE_FREQ_DMF) begin // indicate the target frequency word is found max_peak_valid <= 1'b1; end else begin max_peak_valid <= 'b0; end end default: begin max_peak_valid <= 'b0; max_peak_value_abs <= max_peak_value_abs; max_peak_value_i <= max_peak_value_i ; max_peak_value_q <= max_peak_value_q ; max_peak_index <= max_peak_index ; max_peak_freq <= max_peak_freq ; end endcase end // ----------------------------------------------------------------------------- // peak record for each channel // ----------------------------------------------------------------------------- // reg [DATA_O_WIDTH-1 : 0] ch1_peak_value_abs = 'b0; // reg [DATA_O_WIDTH-1 : 0] ch1_peak_value_i = 'b0; // reg [DATA_O_WIDTH-1 : 0] ch1_peak_value_q = 'b0; // reg [$clog2(PRBS_POS-1) : 0] ch1_peak_index = 'b0; // reg [DATA_O_WIDTH-1 : 0] ch2_peak_value_abs = 'b0; // reg [DATA_O_WIDTH-1 : 0] ch2_peak_value_i = 'b0; // reg [DATA_O_WIDTH-1 : 0] ch2_peak_value_q = 'b0; // reg [$clog2(PRBS_POS-1) : 0] ch2_peak_index = 'b0; // reg [DATA_O_WIDTH-1 : 0] ch3_peak_value_abs = 'b0; // reg [DATA_O_WIDTH-1 : 0] ch3_peak_value_i = 'b0; // reg [DATA_O_WIDTH-1 : 0] ch3_peak_value_q = 'b0; // reg [$clog2(PRBS_POS-1) : 0] ch3_peak_index = 'b0; // reg [DATA_O_WIDTH-1 : 0] ch4_peak_value_abs = 'b0; // reg [DATA_O_WIDTH-1 : 0] ch4_peak_value_i = 'b0; // reg [DATA_O_WIDTH-1 : 0] ch4_peak_value_q = 'b0; // reg [$clog2(PRBS_POS-1) : 0] ch4_peak_index = 'b0; always @(posedge clk) begin if (rst) begin ch1_peak_valid <= 'b0; ch1_peak_value_abs <= 'b0; ch1_peak_value_i <= 'b0; ch1_peak_value_q <= 'b0; ch1_peak_index <= 'b0; ch2_peak_valid <= 'b0; ch2_peak_value_abs <= 'b0; ch2_peak_value_i <= 'b0; ch2_peak_value_q <= 'b0; ch2_peak_index <= 'b0; ch3_peak_valid <= 'b0; ch3_peak_value_abs <= 'b0; ch3_peak_value_i <= 'b0; ch3_peak_value_q <= 'b0; ch3_peak_index <= 'b0; ch4_peak_valid <= 'b0; ch4_peak_value_abs <= 'b0; ch4_peak_value_i <= 'b0; ch4_peak_value_q <= 'b0; ch4_peak_index <= 'b0; end else case (state_curr) STATE_CH_SW : begin ch1_peak_valid <= ch1_peak_valid; ch2_peak_valid <= ch2_peak_valid; ch3_peak_valid <= ch3_peak_valid; ch4_peak_valid <= ch4_peak_valid; end STATE_CH1 : begin ch1_peak_valid <= (dmf_peak_valid) ? 1'b1 : ch1_peak_valid; ch1_peak_value_abs <= (dmf_peak_valid) ? dmf_peak_value_abs : ch1_peak_value_abs; ch1_peak_value_i <= (dmf_peak_valid) ? dmf_peak_value_i : ch1_peak_value_i ; ch1_peak_value_q <= (dmf_peak_valid) ? dmf_peak_value_q : ch1_peak_value_q ; ch1_peak_index <= (dmf_peak_valid) ? dmf_peak_index : ch1_peak_index ; end STATE_CH2 : begin ch2_peak_valid <= (dmf_peak_valid) ? 1'b1 : ch2_peak_valid; ch2_peak_value_abs <= (dmf_peak_valid) ? dmf_peak_value_abs : ch2_peak_value_abs; ch2_peak_value_i <= (dmf_peak_valid) ? dmf_peak_value_i : ch2_peak_value_i ; ch2_peak_value_q <= (dmf_peak_valid) ? dmf_peak_value_q : ch2_peak_value_q ; ch2_peak_index <= (dmf_peak_valid) ? dmf_peak_index : ch2_peak_index ; end STATE_CH3 : begin ch3_peak_valid <= (dmf_peak_valid) ? 1'b1 : ch3_peak_valid; ch3_peak_value_abs <= (dmf_peak_valid) ? dmf_peak_value_abs : ch3_peak_value_abs; ch3_peak_value_i <= (dmf_peak_valid) ? dmf_peak_value_i : ch3_peak_value_i ; ch3_peak_value_q <= (dmf_peak_valid) ? dmf_peak_value_q : ch3_peak_value_q ; ch3_peak_index <= (dmf_peak_valid) ? dmf_peak_index : ch3_peak_index ; end STATE_CH4 : begin if ((state_next == STATE_CH_SW) || (state_next == STATE_IDLE)) begin // when another dmf is needed, clear valid indicator ch1_peak_valid <= 'b0; ch2_peak_valid <= 'b0; ch3_peak_valid <= 'b0; ch4_peak_valid <= 'b0; end else begin ch4_peak_valid <= (dmf_peak_valid) ? 1'b1 : ch4_peak_valid; ch4_peak_value_abs <= (dmf_peak_valid) ? dmf_peak_value_abs : ch4_peak_value_abs; ch4_peak_value_i <= (dmf_peak_valid) ? dmf_peak_value_i : ch4_peak_value_i ; ch4_peak_value_q <= (dmf_peak_valid) ? dmf_peak_value_q : ch4_peak_value_q ; ch4_peak_index <= (dmf_peak_valid) ? dmf_peak_index : ch4_peak_index ; end end default : begin ch1_peak_valid <= 'b0 ; ch1_peak_value_abs <= ch1_peak_value_abs; ch1_peak_value_i <= ch1_peak_value_i ; ch1_peak_value_q <= ch1_peak_value_q ; ch1_peak_index <= ch1_peak_index ; ch2_peak_valid <= 'b0 ; ch2_peak_value_abs <= ch2_peak_value_abs; ch2_peak_value_i <= ch2_peak_value_i ; ch2_peak_value_q <= ch2_peak_value_q ; ch2_peak_index <= ch2_peak_index ; ch3_peak_valid <= 'b0 ; ch3_peak_value_abs <= ch3_peak_value_abs; ch3_peak_value_i <= ch3_peak_value_i ; ch3_peak_value_q <= ch3_peak_value_q ; ch3_peak_index <= ch3_peak_index ; ch4_peak_valid <= 'b0 ; ch4_peak_value_abs <= ch4_peak_value_abs; ch4_peak_value_i <= ch4_peak_value_i ; ch4_peak_value_q <= ch4_peak_value_q ; ch4_peak_index <= ch4_peak_index ; end endcase end // ----------------------------------------------------------------------------- // indicate dmf on all 4 channels are finished // ----------------------------------------------------------------------------- reg ch_peak_valid_buf = 'b0; assign ch_peak_valid = ch_peak_valid_buf; always @(posedge clk) begin if (rst) begin ch_peak_valid_buf <= 'b0; end else if ((state_curr == STATE_CH4) && dmf_peak_valid) begin ch_peak_valid_buf <= 1'b1; end else begin ch_peak_valid_buf <= 'b0; end end endmodule