Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
io_ddr_cross_domain.vhd 4.66 KiB
--------------------------------------------------------------------------------
--
-- Copyright (C) 2014
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------

-- Purpose: Cross clock domain between dvr_clk and ctlr_clk
-- Description:
--
-- Remarks:
-- . If the dvr_clk=ctlr_clk then the clock domain crossing logic defaults
--   to wires. However dvr_clk could also be the dp_clk or the mm_clk and then 
--   the clock domain crossing logic is needed.
--   No need to cross dvr_start_address and dvr_nof_data, because these
--   are stable when the dvr_en is stable.
        
LIBRARY IEEE, technology_lib, tech_ddr_lib, common_lib, dp_lib;
USE IEEE.STD_LOGIC_1164.ALL;
USE common_lib.common_pkg.ALL;
USE technology_lib.technology_select_pkg.ALL;
USE technology_lib.technology_pkg.ALL;
USE tech_ddr_lib.tech_ddr_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;

ENTITY io_ddr_cross_domain IS
  GENERIC (
    g_cross_domain : BOOLEAN := TRUE;
    g_delay_len    : NATURAL := c_meta_delay_len
  );                      
  PORT (
    -- Driver clock domain
    dvr_clk                : IN  STD_LOGIC;
    dvr_rst                : IN  STD_LOGIC;
    
    dvr_done               : OUT STD_LOGIC;
    dvr_en                 : IN  STD_LOGIC;
    dvr_wr_not_rd          : IN  STD_LOGIC;
    dvr_start_address      : IN  STD_LOGIC_VECTOR;
    dvr_nof_data           : IN  STD_LOGIC_VECTOR;
    dvr_wr_flush_en        : IN  STD_LOGIC := '0';
    
    -- DDR controller clock domain
    ctlr_clk               : IN  STD_LOGIC;
    ctlr_rst               : IN  STD_LOGIC;
    
    ctlr_dvr_done          : IN  STD_LOGIC;
    ctlr_dvr_en            : OUT STD_LOGIC;
    ctlr_dvr_wr_not_rd     : OUT STD_LOGIC;
    ctlr_dvr_start_address : OUT STD_LOGIC_VECTOR;
    ctlr_dvr_nof_data      : OUT STD_LOGIC_VECTOR;
    ctlr_dvr_wr_flush_en   : OUT STD_LOGIC := '0'
  );
END io_ddr_cross_domain;

ARCHITECTURE str OF io_ddr_cross_domain IS

  SIGNAL dvr_en_busy  : STD_LOGIC;
  SIGNAL new_dvr_done : STD_LOGIC;
  
BEGIN 

  no_cross : IF g_cross_domain=FALSE GENERATE
    -- dvr_clk --> ctlr_clk
    ctlr_dvr_en            <= dvr_en;
    ctlr_dvr_wr_not_rd     <= dvr_wr_not_rd;
    ctlr_dvr_start_address <= dvr_start_address;
    ctlr_dvr_nof_data      <= dvr_nof_data;
    ctlr_dvr_wr_flush_en   <= dvr_wr_flush_en;
    
    -- ctlr_clk --> dvr_clk
    dvr_done               <= ctlr_dvr_done;
  END GENERATE;
  
  gen_cross : IF g_cross_domain=TRUE GENERATE
    -- dvr_clk --> ctlr_clk
    u_common_spulse_ctlr_dvr_en : ENTITY common_lib.common_spulse
    GENERIC MAP (
      g_delay_len => g_delay_len
    )
    PORT MAP (
      in_rst    => dvr_rst,
      in_clk    => dvr_clk,
      in_pulse  => dvr_en,
      in_busy   => dvr_en_busy,
      out_rst   => ctlr_rst,
      out_clk   => ctlr_clk,
      out_pulse => ctlr_dvr_en
    );
    
    -- Only register into the other clock domain
    ctlr_dvr_wr_not_rd     <= dvr_wr_not_rd     WHEN rising_edge(ctlr_clk);
    ctlr_dvr_start_address <= dvr_start_address WHEN rising_edge(ctlr_clk);
    ctlr_dvr_nof_data      <= dvr_nof_data      WHEN rising_edge(ctlr_clk);
    
    u_common_spulse_ctlr_dvr_wr_flush_en : ENTITY common_lib.common_spulse
    GENERIC MAP (
      g_delay_len => g_delay_len
    )
    PORT MAP (
      in_rst    => dvr_rst,
      in_clk    => dvr_clk,
      in_pulse  => dvr_wr_flush_en,
      out_rst   => ctlr_rst,
      out_clk   => ctlr_clk,
      out_pulse => ctlr_dvr_wr_flush_en
    );
    
    -- ctlr_clk --> dvr_clk
    u_common_async_dvr_done : ENTITY common_lib.common_async
    GENERIC MAP (
      g_rst_level => '0',
      g_delay_len => g_delay_len
    )
    PORT MAP (
      rst  => dvr_rst,
      clk  => dvr_clk,
      din  => ctlr_dvr_done,
      dout => new_dvr_done
    );
    
    -- Ensure previous dvr_done goes low after new dvr_en
    dvr_done <= new_dvr_done AND NOT dvr_en_busy;
      
  END GENERATE;
  
END str;