Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
sdp_subband_equalizer.vhd 7.76 KiB
-------------------------------------------------------------------------------
--
-- Copyright 2020
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
--
-- Author: R. van der Walle
-- Purpose: 
-- . Implements the functionality of the subband equalizer in the subband 
--   filterbank (Fsub) of the LOFAR2 SDPFW design.
-- Description:
-- . The sdp_subband_equalizer.vhd consists of mms_dp_gain_serial_arr.vhd and
--   some address counter logic to select the address of the subband weight
--   and a dp_requantize.vhd component.
-- . Subband widths:
--   - raw_sosi   : g_raw_dat_w bits
--   - quant_sosi : c_quant_dat_w = g_raw_dat_w - g_raw_fraction_w bits
-- Remark:
--
-------------------------------------------------------------------------------

LIBRARY IEEE, common_lib, dp_lib;
USE IEEE.STD_LOGIC_1164.ALL;
USE common_lib.common_pkg.ALL;
USE common_lib.common_mem_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
USE work.sdp_pkg.ALL;

ENTITY sdp_subband_equalizer IS
  GENERIC (
    g_gains_file_name    : STRING := "UNUSED";
    g_nof_streams        : NATURAL := c_sdp_P_pfb;
    g_raw_dat_w          : NATURAL := c_sdp_W_subband;
    g_raw_fraction_w     : NATURAL := 0
  );
  PORT (
    dp_clk       : IN  STD_LOGIC;
    dp_rst       : IN  STD_LOGIC;

    in_raw_sosi_arr    : IN  t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
    out_raw_sosi_arr   : OUT t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
    out_quant_sosi_arr : OUT t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);

    mm_rst       : IN  STD_LOGIC;
    mm_clk       : IN  STD_LOGIC;

    ram_gains_mosi : IN  t_mem_mosi := c_mem_mosi_rst; 
    ram_gains_miso : OUT t_mem_miso
  );
END sdp_subband_equalizer;

ARCHITECTURE str OF sdp_subband_equalizer IS

  CONSTANT c_gain_addr_w : NATURAL := ceil_log2(c_sdp_Q_fft * c_sdp_N_sub);

  -- Product width, do -1 to skip double sign bit in product
  CONSTANT c_gain_out_dat_w : NATURAL := c_sdp_W_sub_weight + g_raw_dat_w - 1;

  CONSTANT c_quant_dat_w : NATURAL := g_raw_dat_w - g_raw_fraction_w;
  
  -- Pipeline requantization to easy timing closure
  CONSTANT c_pipeline_remove_lsb : NATURAL := 1;
  CONSTANT c_pipeline_remove_msb : NATURAL := 1;

  SIGNAL in_sosi : t_dp_sosi;
  SIGNAL cnt : NATURAL RANGE 0 TO c_sdp_Q_fft * c_sdp_N_sub-1;
  SIGNAL gains_rd_address : STD_LOGIC_VECTOR(c_gain_addr_w-1 DOWNTO 0);
  SIGNAL weighted_raw_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);

BEGIN

  in_sosi <= in_raw_sosi_arr(0);  -- use ctrl from input [0]

  -----------------------------------------------------------------------------
  -- Counter
  -----------------------------------------------------------------------------
  -- The subband weigths per PN are stored as
  -- (cint16)subband_weights[S_pn/Q_fft]_[Q_fft][N_sub], but have 
  -- to be applied according the subband data order 
  -- fsub[S_pn/Q_fft]_[N_sub][Q_fft]. Therefore the counter in 
  -- sdp_subband_equalizer.vhd has to account for this difference in order.
  p_cnt : PROCESS(dp_clk, dp_rst)
    -- Use short index variables v_Q, v_SUB names in capitals, to ease
    -- recognizing them as (loop) indices.
    VARIABLE v_Q, v_SUB : NATURAL;
  BEGIN
    IF dp_rst = '1' THEN
      cnt <= 0;
      v_Q := 0;
      v_SUB := 0;
    ELSIF rising_edge(dp_clk) THEN
      IF in_sosi.valid = '1' THEN
        IF in_sosi.eop = '1' THEN
          v_Q := 0;
          v_SUB := 0;
        ELSE
          IF v_Q >= c_sdp_Q_fft-1 THEN
            v_Q := 0;
            IF v_SUB >= c_sdp_N_sub-1 THEN
              v_SUB := 0;
            ELSE
              v_SUB := v_SUB + 1;
            END IF;
          ELSE
            v_Q := v_Q + 1;
          END IF;
        END IF;
        cnt <= v_Q * c_sdp_N_sub + v_SUB;
      END IF;
    END IF;
  END PROCESS;
  gains_rd_address <= TO_UVEC(cnt, c_gain_addr_w);

  -----------------------------------------------------------------------------
  -- Gain
  -----------------------------------------------------------------------------
  u_mms_dp_gain_serial_arr : ENTITY dp_lib.mms_dp_gain_serial_arr
  GENERIC MAP (
    g_nof_streams     => g_nof_streams,
    g_nof_gains       => c_sdp_Q_fft * c_sdp_N_sub,
    g_complex_data    => TRUE,
    g_complex_gain    => TRUE,
    g_gain_w          => c_sdp_W_sub_weight,
    g_in_dat_w        => g_raw_dat_w,
    g_out_dat_w       => c_gain_out_dat_w,
    g_gains_file_name => g_gains_file_name
  )
  PORT MAP (
    -- System
    mm_rst            =>  mm_rst,              
    mm_clk            =>  mm_clk,              
    dp_rst            =>  dp_rst,              
    dp_clk            =>  dp_clk,              

    -- MM interface  
    ram_gains_mosi    =>  ram_gains_mosi,      
    ram_gains_miso    =>  ram_gains_miso,      
    
    -- ST interface 
    gains_rd_address  =>  gains_rd_address,    
                                           
    in_sosi_arr       =>  in_raw_sosi_arr,
    out_sosi_arr      =>  weighted_raw_sosi_arr
  );

  -----------------------------------------------------------------------------
  -- Requantize 
  -----------------------------------------------------------------------------

  gen_dp_requantize : FOR I IN 0 TO g_nof_streams-1 GENERATE
    -- For raw output only round the c_sdp_W_sub_weight_fraction, and keep the
    -- g_raw_fraction_w, so that the output width remains the same as the input
    -- width g_raw_dat_w.
    u_dp_requantize_out_raw : ENTITY dp_lib.dp_requantize
    GENERIC MAP (
      g_complex             => TRUE,
      g_representation      => "SIGNED",
      g_lsb_w               => c_sdp_W_sub_weight_fraction,
      g_lsb_round           => TRUE,
      g_lsb_round_clip      => FALSE,
      g_msb_clip            => TRUE,  -- clip subband overflow
      g_msb_clip_symmetric  => FALSE,
      g_pipeline_remove_lsb => c_pipeline_remove_lsb,
      g_pipeline_remove_msb => c_pipeline_remove_msb,
      g_in_dat_w            => c_gain_out_dat_w,
      g_out_dat_w           => g_raw_dat_w
    )
    PORT MAP (
      rst          => dp_rst,
      clk          => dp_clk,
      -- ST sink
      snk_in       => weighted_raw_sosi_arr(I),
      -- ST source
      src_out      => out_raw_sosi_arr(I)
    );

    -- For quant output round the entire fraction, so that the output width
    -- becomes c_quant_dat_w.
    u_dp_requantize_out_quant : ENTITY dp_lib.dp_requantize
    GENERIC MAP (               
      g_complex             => TRUE,  
      g_representation      => "SIGNED",           
      g_lsb_w               => c_sdp_W_sub_weight_fraction + g_raw_fraction_w,
      g_lsb_round           => TRUE,       
      g_lsb_round_clip      => FALSE,      
      g_msb_clip            => TRUE,  -- clip subband overflow
      g_msb_clip_symmetric  => FALSE,      
      g_pipeline_remove_lsb => c_pipeline_remove_lsb,
      g_pipeline_remove_msb => c_pipeline_remove_msb,
      g_in_dat_w            => c_gain_out_dat_w,
      g_out_dat_w           => c_quant_dat_w
    )
    PORT MAP (
      rst          => dp_rst, 
      clk          => dp_clk,
      -- ST sink
      snk_in       => weighted_raw_sosi_arr(I),
      -- ST source
      src_out      => out_quant_sosi_arr(I)
    );
  END GENERATE;
END str;