-------------------------------------------------------------------------------
--
-- 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: Folding a stream of data into a mm data configuration so it can be
-- stored in a DDR RAM-stick.
--
-- Description:
--  First the data from the sosi array gets collected into one data vector.
--  After that this data vector gets resized to the right size data vector in 
--  order to make it storable in a DDR RAM-stick.
--  After that a address gets assigned to the data so the data can be found back.
--
-- Remark:
--  Use VHDL coding template from:
--  https://support.astron.nl/confluence/display/SBe/VHDL+design+patterns+for+RTL+coding
--  The maximum value of the address is determend by g_tech_ddr.

LIBRARY IEEE, technology_lib, tech_ddr_lib, common_lib, dp_lib, io_ddr_lib;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
USE technology_lib.technology_pkg.ALL;
USE technology_lib.technology_select_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;
USE io_ddr_lib.ALL;


ENTITY ddrctrl IS
  GENERIC (
    g_tech_ddr        : t_c_tech_ddr;                                                                                         -- type of memory
    g_sim_model       : BOOLEAN                                             := TRUE;                                          -- determens if this is a simulation
    g_technology      : NATURAL                                             := c_tech_select_default;
    g_nof_streams     : NATURAL                                             := 12;                                            -- number of input streams
    g_data_w          : NATURAL                                             := 14;                                            -- data with of input data vectors
    g_stop_percentage : NATURAL                                             := 50
  );
  PORT (
    clk               : IN  STD_LOGIC                                       := '0';
    rst               : IN  STD_LOGIC;
    mm_clk            : IN  STD_LOGIC                                       := '0';
    mm_rst            : IN  STD_LOGIC                                       := '0';
    in_sosi_arr       : IN  t_dp_sosi_arr;                                                                                    -- input data
    wr_not_rd         : IN  STD_LOGIC                                       := '0';
    stop_in           : IN  STD_LOGIC                                       := '0';


    term_ctrl_out     : OUT   t_tech_ddr3_phy_terminationcontrol;
    term_ctrl_in      : IN    t_tech_ddr3_phy_terminationcontrol            := c_tech_ddr3_phy_terminationcontrol_rst;

    -- DDR3 PHY external interface
    phy3_in           : IN    t_tech_ddr3_phy_in                            := c_tech_ddr3_phy_in_x;
    phy3_io           : INOUT t_tech_ddr3_phy_io;
    phy3_ou           : OUT   t_tech_ddr3_phy_ou;

    -- DDR4 PHY external interface
    phy4_in           : IN    t_tech_ddr4_phy_in                            := c_tech_ddr4_phy_in_x;
    phy4_io           : INOUT t_tech_ddr4_phy_io;
    phy4_ou           : OUT   t_tech_ddr4_phy_ou
  );
END ddrctrl;


ARCHITECTURE str OF ddrctrl IS

  -- constant for readability
  CONSTANT  c_io_ddr_data_w   : NATURAL                                     := func_tech_ddr_ctlr_data_w( g_tech_ddr );
  CONSTANT  c_wr_fifo_depth   : NATURAL                                     := 256;                                           -- defined at DDR side of the FIFO, >=16 and independent of wr burst size, default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K
  CONSTANT  c_rd_fifo_depth   : NATURAL                                     := 256;                                           -- defined at DDR side of the FIFO, >=16 AND > max number of rd burst sizes (so > c_rd_fifo_af_margin), default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K

  -- signals for connecting the components
  SIGNAL    ctrl_clk     : STD_LOGIC;
  SIGNAL    ctrl_rst     : STD_LOGIC;
  SIGNAL    out_of       : NATURAL                                          := 0;
  SIGNAL    out_sosi     : t_dp_sosi                                        := c_dp_sosi_init;
  SIGNAL    out_adr      : NATURAL                                          := 0;
  SIGNAL    dvr_mosi     : t_mem_ctlr_mosi                                  := c_mem_ctlr_mosi_rst;
  SIGNAL    wr_sosi      : t_dp_sosi                                        := c_dp_sosi_init;
  SIGNAL    rd_siso      : t_dp_siso                                        := c_dp_siso_rst;


BEGIN


  -- input to io_ddr
  u_ddrctrl_input : ENTITY work.ddrctrl_input
  GENERIC MAP(
    g_tech_ddr                => g_tech_ddr,
    g_sim_model               => g_sim_model,
    g_nof_streams             => g_nof_streams,
    g_data_w                  => g_data_w
  )
  PORT MAP(
    clk                       => clk,
    rst                       => rst,
    in_sosi_arr               => in_sosi_arr,
    out_of                    => out_of,
    out_sosi                  => out_sosi,
    out_adr                   => out_adr
  );

  -- functions as a fifo buffer for input data into the sdram stick. also manages input to sdram stick.
  u_io_ddr : ENTITY io_ddr_lib.io_ddr
  GENERIC MAP(
    g_sim_model               => g_sim_model,
    g_technology              => g_technology,
    g_tech_ddr                => g_tech_ddr,
    g_cross_domain_dvr_ctlr   => FALSE,
    g_wr_data_w               => c_io_ddr_data_w,  
    g_wr_fifo_depth           => c_wr_fifo_depth,
    g_rd_fifo_depth           => c_rd_fifo_depth,
    g_rd_data_w               => c_io_ddr_data_w,
    g_wr_flush_mode           => "VAL",
    g_wr_flush_use_channel    => FALSE,
    g_wr_flush_start_channel  => 0,
    g_wr_flush_nof_channels   => 1
    )
    PORT MAP(

    -- DDR reference clock
    ctlr_ref_clk              => clk,
    ctlr_ref_rst              => rst,

    -- DDR controller clock domain
    ctlr_clk_out              => ctrl_clk,
    ctlr_rst_out              => ctrl_rst,
    
    ctlr_clk_in               => ctrl_clk,
    ctlr_rst_in               => ctrl_rst,
    
    -- MM clock + reset
    mm_rst                    => mm_rst,                                           
    mm_clk                    => mm_clk, 
    
    -- MM interface
    reg_io_ddr_mosi           => open,
    reg_io_ddr_miso           => open,
    
    -- Driver clock domain
    dvr_clk                   => clk,
    dvr_rst                   => rst,
    
    dvr_miso                  => open,
    dvr_mosi                  => dvr_mosi,
    
    -- Write FIFO clock domain
    wr_clk                    => clk,
    wr_rst                    => rst,

    wr_fifo_usedw             => open,
    wr_sosi                   => wr_sosi,
    wr_siso                   => open,
  
    -- Read FIFO clock domain
    rd_clk                    => clk,
    rd_rst                    => rst,
    
    rd_fifo_usedw             => open,
    rd_sosi                   => open,
    rd_siso                   => rd_siso,

    term_ctrl_out             => term_ctrl_out,
    term_ctrl_in              => term_ctrl_in,
    
    -- DDR3 PHY external interface
    phy3_in                   => phy3_in,
    phy3_io                   => phy3_io,
    phy3_ou                   => phy3_ou,
    
    -- DDR4 PHY external interface
    phy4_in                   => phy4_in,
    phy4_io                   => phy4_io,
    phy4_ou                   => phy4_ou
  );

  -- controller of ddrctrl
  u_ddrctrl_controller : ENTITY work.ddrctrl_controller
  GENERIC MAP(
    g_tech_ddr                => g_tech_ddr,
    g_stop_percentage         => g_stop_percentage
  )
  PORT MAP(
  clk                         => clk,
  rst                         => rst,
  
  inp_of                      => out_of,
  inp_sosi                    => out_sosi,
  inp_adr                     => out_adr,

  dvr_mosi                    => dvr_mosi,
  wr_sosi                     => wr_sosi,
  rd_siso                     => rd_siso,

  stop_in                     => stop_in
  );

END str;