-------------------------------------------------------------------------------
--
-- Copyright 2022
-- 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: Job van Wee
-- Purpose: when there is output this component will turn it back into a
-- sosi arr.
--
-- Description:
--  The data from the ddr memory gets resized into its original size and gets
--  back its bsn.
--
-- Remark:
--  Use VHDL coding template from:
--  https://support.astron.nl/confluence/display/SBe/VHDL+design+patterns+for+RTL+coding

LIBRARY IEEE, technology_lib, tech_ddr_lib, common_lib, dp_lib;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
USE technology_lib.technology_pkg.ALL;
USE tech_ddr_lib.tech_ddr_pkg.ALL;
USE common_lib.common_pkg.ALL;
USE common_lib.common_mem_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;


ENTITY ddrctrl_output IS
  GENERIC (
    g_technology      : NATURAL;
    g_tech_ddr        : t_c_tech_ddr;                                                               -- type of memory
    g_sim_model       : BOOLEAN                                     := TRUE;                        -- determens if this is a simulation
    g_in_data_w       : NATURAL                                     := 576;
    g_nof_streams     : NATURAL                                     := 12;                          -- number of input streams
    g_data_w          : NATURAL                                     := 14;                          -- data with of input data vectors
    g_block_size      : NATURAL                                     := 1024;
    g_bim             : NATURAL                                     := 54
  );
  PORT (
    clk               : IN  STD_LOGIC                               := '0';
    rst               : IN  STD_LOGIC;
    in_sosi           : IN  t_dp_sosi                               := c_dp_sosi_init;              -- input data
    in_bsn            : IN  STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);
    out_siso          : IN  t_dp_siso;
    out_sosi_arr      : OUT t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_dp_sosi_init);  -- output data
    out_ready         : OUT STD_LOGIC
  );
END ddrctrl_output;


ARCHITECTURE str OF ddrctrl_output IS

  -- constant for readability
  CONSTANT  c_out_data_w  : NATURAL     := g_nof_streams*g_data_w;                                    -- the input data width for ddrctrl_repack 168

  -- fifo
  CONSTANT  c_fifo_size   : NATURAL     := 2;


  -- signals for connecting the components
  SIGNAL    sosi              : t_dp_sosi := c_dp_sosi_init;
  SIGNAL    out_sosi          : t_dp_sosi := c_dp_sosi_init;
--  SIGNAL    out_sosi          : t_dp_sosi := c_dp_sosi_init;
--  SIGNAL    fifo_snk_in_sosi  : t_dp_sosi := c_dp_sosi_init;
  SIGNAL    q_out_siso        : t_dp_siso := c_dp_siso_rst;
  SIGNAL    q_q_out_siso      : t_dp_siso := c_dp_siso_rst;
  SIGNAL    unpack_state_off  : STD_LOGIC := '0';
--  SIGNAL    siso              : t_dp_siso := c_dp_siso_rst;
--  SIGNAL    fifo_src_out_sosi : t_dp_sosi := c_dp_sosi_init;
--  SIGNAL    fifo_usedw        : STD_LOGIC_VECTOR(ceil_log2(c_fifo_size)-1 DOWNTO 0)  := (OTHERS => '0');

BEGIN

  -- makes one data vector out of all the data from the t_dp_sosi_arr
  u_ddrctrl_output_unpack : ENTITY work.ddrctrl_output_unpack
  GENERIC MAP(
    g_tech_ddr        => g_tech_ddr,
    g_in_data_w       => g_in_data_w,
    g_out_data_w      => c_out_data_w,
    g_block_size      => g_block_size,
    g_bim             => g_bim
  )
  PORT MAP(
    clk               => clk,
    rst               => rst,
    in_sosi           => in_sosi,                                                                       -- input data
    in_bsn            => in_bsn,
    out_siso          => out_siso,
    out_sosi          => out_sosi,                                                                      -- output data
    out_ready         => out_ready,
    state_off         => unpack_state_off
  );

  -- resizes the input data vector so that the output data vector can be stored into the ddr memory
  u_ddrctrl_output_repack : ENTITY work.ddrctrl_output_repack
  GENERIC MAP(
  g_nof_streams       => g_nof_streams,
  g_data_w            => g_data_w
  )
  PORT MAP(
    in_sosi           => sosi,
    out_sosi_arr      => out_sosi_arr
  );


--  u_fifo : ENTITY dp_lib.dp_fifo_dc_mixed_widths
--  GENERIC MAP (
--    g_technology        => g_technology,
--    g_wr_data_w         => c_out_data_w,
--    g_rd_data_w         => c_out_data_w,
--    g_use_ctrl          => FALSE,
--    g_wr_fifo_size      => c_fifo_size,
--    g_wr_fifo_af_margin => 0,
--    g_rd_fifo_rl        => 0
--  )
--  PORT MAP (
--    wr_rst         => rst,
--    wr_clk         => clk,
--    rd_rst         => rst,
--    rd_clk         => clk,
--
--    snk_out        => OPEN,
--    snk_in         => fifo_snk_in_sosi,
--  
--    wr_ful         => OPEN,
--    wr_usedw       => fifo_usedw,
--    rd_usedw       => OPEN,
--    rd_emp         => OPEN,
--
--    src_in         => siso,
--    src_out        => fifo_src_out_sosi
--  );


  p_out_siso_ready : PROCESS(out_siso, clk, out_sosi, q_out_siso)

  VARIABLE sosi_valid : STD_LOGIC := '0';

  BEGIN

    IF out_siso.ready = '0' AND NOT (q_out_siso.ready = out_siso.ready) THEN
      sosi              <= out_sosi;
      sosi_valid        := '0';
      -- assert false report "sosi.valid = '0'" severity note;
    ELSIF q_out_siso.ready = '1' AND NOT (q_q_out_siso.ready = q_out_siso.ready) AND unpack_state_off = '0' THEN
      sosi              <= out_sosi;
      sosi_valid        := '1';
      -- assert false report "sosi.valid = '1'" severity note;
    ELSE
      sosi              <= out_sosi;
      sosi_valid        := out_sosi.valid;
    END IF;
    IF rising_edge(clk) THEN
      q_q_out_siso        <= q_out_siso;
      q_out_siso          <= out_siso;
    END IF;
    sosi.valid  <= sosi_valid;
    sosi.sop    <= sosi_valid AND out_sosi.sop;
    sosi.eop    <= sosi_valid AND out_sosi.eop;
  END PROCESS;

END str;