-- EMACS settings: -*-  tab-width: 2; indent-tabs-mode: t -*-
-- vim: tabstop=2:shiftwidth=2:noexpandtab
-- kate: tab-width 2; replace-tabs off; indent-width 2;
-- =============================================================================
-- Authors:         Patrick Lehmann
--
-- Entity:          Synchronizes a reset signal across clock-domain boundaries
--
-- Description:
-- 
-- This module synchronizes an asynchronous reset signal to the clock
-- ``Clock``. The ``Input`` can be asserted and de-asserted at any time.
-- The ``Output`` is asserted asynchronously and de-asserted synchronously
-- to the clock.
--
-- .. ATTENTION::
--    Use this synchronizer only to asynchronously reset your design.
--    The 'Output' should be feed by global buffer to the destination FFs, so
--    that, it reaches their reset inputs within one clock cycle.
--
-- Constraints:
--   General:
--     Please add constraints for meta stability to all '_meta' signals and
--     timing ignore constraints to all '_async' signals.
--
--   Xilinx:
--     In case of a Xilinx device, this module will instantiate the optimized
--     module xil_SyncReset. Please attend to the notes of xil_SyncReset.
--
--   Altera sdc file:
--     TODO
--
-- License:
-- =============================================================================
-- Copyright 2007-2016 Technische Universitaet Dresden - Germany
--                     Chair of VLSI-Design, Diagnostics and Architecture
--
-- 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.
-- =============================================================================

library IEEE;
use     IEEE.STD_LOGIC_1164.all;

library PoC;
use     PoC.config.all;
use     PoC.utils.all;
use     PoC.sync.all;


entity [docs]sync_Reset is
	generic (
		SYNC_DEPTH    : T_MISC_SYNC_DEPTH   := T_MISC_SYNC_DEPTH'low    -- generate SYNC_DEPTH many stages, at least 2
	);
	port (
		Clock         : in  std_logic;                                  -- <Clock>  output clock domain
		Input         : in  std_logic;                                  -- @async:  reset input
		Output        : out std_logic                                   -- @Clock:  reset output
	);
end entity;


architecture [docs]rtl of sync_Reset is
begin
	genGeneric : if (VENDOR /= VENDOR_ALTERA) and (VENDOR /= VENDOR_XILINX) generate
		attribute ASYNC_REG                    : string;
		attribute SHREG_EXTRACT                : string;

		signal Data_async                      : std_logic;
		signal Data_meta                      : std_logic    := '1';
		signal Data_sync                      : std_logic_vector(SYNC_DEPTH - 1 downto 0)    := (others => '1');

		-- Mark registers as asynchronous
		attribute ASYNC_REG      of Data_meta  : signal is "TRUE";
		attribute ASYNC_REG      of Data_sync  : signal is "TRUE";

		-- Prevent XST from translating two FFs into SRL plus FF
		attribute SHREG_EXTRACT of Data_meta  : signal is "NO";
		attribute SHREG_EXTRACT of Data_sync  : signal is "NO";

	begin
		Data_async  <= Input;

		process(Clock, Data_async)
		begin
			if (Data_async = '1') then
				Data_meta    <= '1';
				Data_sync    <= (others => '1');
			elsif rising_edge(Clock) then
				Data_meta    <= '0';
				Data_sync    <= Data_sync(Data_sync'high - 1 downto 0) & Data_meta;
			end if;
		end process;

		Output    <= Data_sync(Data_sync'high);
	end generate;

	-- use dedicated and optimized 2 D-FF synchronizer for Altera FPGAs
	genAltera : if VENDOR = VENDOR_ALTERA generate
		sync : sync_Reset_Altera
			generic map (
				SYNC_DEPTH  => SYNC_DEPTH
			)
			port map (
				Clock       => Clock,
				Input       => Input,
				Output      => Output
			);
	end generate;

	-- use dedicated and optimized 2 D-FF synchronizer for Xilinx FPGAs
	genXilinx : if VENDOR = VENDOR_XILINX generate
		sync : sync_Reset_Xilinx
			generic map (
				SYNC_DEPTH  => SYNC_DEPTH
			)
			port map (
				Clock       => Clock,
				Input       => Input,
				Output      => Output
			);
	end generate;
end architecture;