-- 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 very short pulse across clock-domain boundaries
--
-- Description:
-- 
-- This module synchronizes multiple pulsed bits into the clock-domain ``Clock``.
-- The clock-domain boundary crossing is done by two synchronizer D-FFs. All bits
-- are independent from each other. If a known vendor like Altera or Xilinx are
-- recognized, a vendor specific implementation is chosen.
--
-- .. ATTENTION::
--    Use this synchronizer for very short signals (pulse).
--
-- 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 PoC.xil.sync.Pulse. Please attend to the notes of sync_Bits.vhdl.
--
--   Altera sdc file:
--     TODO
--
-- SeeAlso:
-- :doc:`PoC.misc.sync.Bits </IPCores/misc/sync/sync_Bits>`
--   For a common 2 D-FF synchronizer for *flag*-signals.
-- :doc:`PoC.misc.sync.Reset </IPCores/misc/sync/sync_Reset>`
--   For a special 2 D-FF synchronizer for *reset*-signals.
-- :doc:`PoC.misc.sync.Strobe </IPCores/misc/sync/sync_Strobe>`
--   For a synchronizer for *strobe*-signals.
-- :doc:`PoC.misc.sync.Vector </IPCores/misc/sync/sync_Vector>`
--   For a multiple bits capable synchronizer.
--
-- 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_Pulse is
	generic (
		BITS          : positive            := 1;                       -- number of bit to be synchronized
		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_vector(BITS - 1 downto 0);        -- @async:  input bits
		Output        : out std_logic_vector(BITS - 1 downto 0)         -- @Clock:  output bits
	);
end entity;


architecture [docs]rtl of sync_Pulse is
	constant DEV_INFO : T_DEVICE_INFO        := DEVICE_INFO;
begin
	genGeneric : if ((DEV_INFO.Vendor /= VENDOR_ALTERA) and (DEV_INFO.Vendor /= VENDOR_XILINX)) generate
		attribute ASYNC_REG              : string;
		attribute SHREG_EXTRACT          : string;
	begin
		gen : for i in 0 to BITS - 1 generate
			signal Data_async              : std_logic;
			signal Data_meta              : std_logic                                    := INIT_I(i);
			signal Data_sync              : std_logic_vector(SYNC_DEPTH - 1 downto 1)    := (others => INIT_I(i));

			-- Mark register DataSync_async's input as asynchronous and ignore timings (TIG)
			attribute ASYNC_REG      of Data_meta  : 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
			process(Input(i), Data_sync(Data_sync'high))
			begin
				if ((not Input(i) and Data_sync(Data_sync'high)) = '1') then
					Data_async <= '0';
				elsif rising_edge(Input) then
					Data_async <= '1';
				end if;
			end process;

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

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

	-- use dedicated and optimized 1+2 D-FF synchronizer for Altera FPGAs
	genAltera : if (DEV_INFO.Vendor = VENDOR_ALTERA) generate
		sync : sync_Pulse_Altera
			generic map (
				BITS        => BITS,
				SYNC_DEPTH  => SYNC_DEPTH
			)
			port map (
				Clock      => Clock,
				Input      => Input,
				Output    => Output
			);
	end generate;

	-- use dedicated and optimized 1+2 D-FF synchronizer for Xilinx FPGAs
	genXilinx : if (DEV_INFO.Vendor = VENDOR_XILINX) generate
		sync : sync_Pulse_Xilinx
			generic map (
				BITS        => BITS,
				SYNC_DEPTH  => SYNC_DEPTH
			)
			port map (
				Clock      => Clock,
				Input      => Input,
				Output    => Output
			);
	end generate;
end architecture;