library IEEE;
use IEEE.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity resync_sdr is
generic(
width : integer := 4; -- width of the external interface
with_in_reg : boolean := true; -- with input register
with_out_reg : boolean := true); -- with output register
port(
clear_n : in std_logic; -- clear, synchronized inside
clk_in : in std_logic; -- incoming clk_in signal
valid_in : in std_logic; -- incoming data valid
data_in : in std_logic_vector(width-1 downto 0); -- incoming data sync. to clk_in
clk_out : in std_logic; -- read clock
valid_out : out std_logic; -- outgoing data valid signal
data_out : out std_logic_vector(width-1 downto 0)); -- data output, sync. to clk_out
end resync_sdr;
architecture v of resync_sdr is
-- next value of the 2-bit Gray code
function gray2next(ain : std_logic_vector(1 downto 0))
return std_logic_vector is
begin
return ain(0) & not ain(1);
end gray2next;
subtype data_type is std_logic_vector(data_in'range);
type data_block is array(0 to 3) of data_type;
signal data_in_i : data_type;
signal dreg : data_block;
signal gray_cnt, old_cnt,
new_cnt : std_logic_vector(1 downto 0);
signal data_o_i : data_type;
signal valid_in_i : std_logic;
signal valid_i : std_logic;
signal clear_n_in : std_logic;
signal clear_n_out : std_logic;
begin
-- input register
irg1: if with_in_reg generate
process(clk_in)
begin
if rising_edge(clk_in) then
valid_in_i <= valid_in;
data_in_i <= data_in;
end if;
end process;
end generate;
-- no input register
irg0: if not with_in_reg generate
valid_in_i <= valid_in;
data_in_i <= data_in;
end generate;
-- fetch data_in on rising edge of clk_in into one of four registers
-- depending on the Gray counter 'gray_cnt' and increment 'gray_cnt'
grayc_in: process(clk_in)
begin
if rising_edge(clk_in) then
clear_n_in <= clear_n; -- synchronize the clear signal
if clear_n_in = '0' then
gray_cnt <= (others => '0');
elsif valid_in_i = '1' then
gray_cnt <= gray2next(gray_cnt); -- Gray counter
end if;
if valid_in_i = '1' then
dreg(conv_integer(gray_cnt)) <= data_in_i; -- write
end if;
end if;
end process;
-- data is valid if new_cnt and old_cnt differ
valid_i <= '1' when new_cnt /= old_cnt else '0';
-- sync register and output Gray counter
to_clk_out: process(clk_out)
begin
if rising_edge(clk_out) then
clear_n_out <= clear_n; -- synchronize to the output clock
if clear_n_out = '0' then
new_cnt <= (others => '0');
old_cnt <= (others => '0');
else
new_cnt <= gray_cnt; -- clock domain crossing
if valid_i = '1' then
old_cnt <= gray2next(old_cnt); -- Gray counter
end if;
end if;
end if;
end process;
-- output mux, old_cnt is the read pointer
data_o_i <= dreg(conv_integer(old_cnt));
-- registered output
org1: if with_out_reg generate
process(clk_out)
begin
if clk_out'event and clk_out='1' then
valid_out <= valid_i;
data_out <= data_o_i;
end if;
end process;
end generate;
-- without output register
org0: if not with_out_reg generate
valid_out <= valid_i;
data_out <= data_o_i;
end generate;
end;