Вам нужен синхронизатор строба.
Синхронизатор строба преобразует передний фронт на входе в изменение уровня (T-FF). Это изменение уровня передается во второй тактовый домен через синхронизатор 2-FF. Затем информация восстанавливается с помощью шлюза XOR. (Примечание: T-FF - это D-FF с XOR для инвертирования состояния на каждом высоком входном сигнале.)
Кроме того, состояние занятости может быть рассчитано для уведомления отправляющего тактового домена о состоянии всей цепи. Этот сигнал занятости может использоваться для блокировки обнаружения переднего фронта входа.
Схема выглядит следующим образом:
Исходный код для нескольких битов одновременно:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
library PoC;
use PoC.sync.all;
entity sync_Strobe is
generic (
BITS : positive := 1; -- number of bit to be synchronized
GATED_INPUT_BY_BUSY : boolean := TRUE; -- use gated input (by busy signal)
SYNC_DEPTH : T_MISC_SYNC_DEPTH := T_MISC_SYNC_DEPTH'low -- generate SYNC_DEPTH many stages, at least 2
);
port (
Clock1 : in std_logic; -- <Clock> input clock domain
Clock2 : in std_logic; -- <Clock> output clock domain
Input : in std_logic_vector(BITS - 1 downto 0); -- @Clock1: input bits
Output : out std_logic_vector(BITS - 1 downto 0); -- @Clock2: output bits
Busy : out std_logic_vector(BITS - 1 downto 0) -- @Clock1: busy bits
);
end entity;
architecture rtl of sync_Strobe is
attribute SHREG_EXTRACT : string;
signal syncClk1_In : std_logic_vector(BITS - 1 downto 0);
signal syncClk1_Out : std_logic_vector(BITS - 1 downto 0);
signal syncClk2_In : std_logic_vector(BITS - 1 downto 0);
signal syncClk2_Out : std_logic_vector(BITS - 1 downto 0);
begin
gen : for i in 0 to BITS - 1 generate
signal D0 : std_logic := '0';
signal T1 : std_logic := '0';
signal D2 : std_logic := '0';
signal Changed_Clk1 : std_logic;
signal Changed_Clk2 : std_logic;
signal Busy_i : std_logic;
-- Prevent XST from translating two FFs into SRL plus FF
attribute SHREG_EXTRACT of D0 : signal is "NO";
attribute SHREG_EXTRACT of T1 : signal is "NO";
attribute SHREG_EXTRACT of D2 : signal is "NO";
begin
process(Clock1)
begin
if rising_edge(Clock1) then
-- input delay for rising edge detection
D0 <= Input(i);
-- T-FF to converts a strobe to a flag signal
if GATED_INPUT_BY_BUSY then
T1 <= (Changed_Clk1 and not Busy_i) xor T1;
else
T1 <= Changed_Clk1 xor T1;
end if;
end if;
end process;
-- D-FF for level change detection (both edges)
D2 <= syncClk2_Out(i) when rising_edge(Clock2);
-- assign syncClk*_In signals
syncClk2_In(i) <= T1;
syncClk1_In(i) <= syncClk2_Out(i); -- D2
Changed_Clk1 <= not D0 and Input(i); -- rising edge detection
Changed_Clk2 <= syncClk2_Out(i) xor D2; -- level change detection; restore strobe signal from flag
Busy_i <= T1 xor syncClk1_Out(i); -- calculate busy signal
-- output signals
Output(i) <= Changed_Clk2;
Busy(i) <= Busy_i;
end generate;
syncClk2 : entity PoC.sync_Bits
generic map (
BITS => BITS, -- number of bit to be synchronized
SYNC_DEPTH => SYNC_DEPTH
)
port map (
Clock => Clock2, -- <Clock> output clock domain
Input => syncClk2_In, -- @async: input bits
Output => syncClk2_Out -- @Clock: output bits
);
syncClk1 : entity PoC.sync_Bits
generic map (
BITS => BITS, -- number of bit to be synchronized
SYNC_DEPTH => SYNC_DEPTH
)
port map (
Clock => Clock1, -- <Clock> output clock domain
Input => syncClk1_In, -- @async: input bits
Output => syncClk1_Out -- @Clock: output bits
);
end architecture;
Исходный код можно найти здесь: PoC.misc.sync.Strobe