axi_i2s_adi: Overhaul CDC

* Generate a separate synchronous reset for the data clock domain.
* Add missing stage to toggle synchronizers.
* Give a common prefix to CDC elements and add the proper constraints to the
  XDC file
* Remove some unnecessary resets

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
main
Lars-Peter Clausen 2015-04-16 15:37:03 +02:00
parent 8289262807
commit dfc22fc7de
4 changed files with 109 additions and 46 deletions

View File

@ -0,0 +1,26 @@
set ctrl_clk [get_clocks -of_objects [get_ports S_AXI_ACLK]]
set data_clk [get_clocks -of_objects [get_ports DATA_CLK_I]]
set_property ASYNC_REG TRUE \
[get_cells -hier cdc_sync_stage1_*_reg] \
[get_cells -hier cdc_sync_stage2_*_reg]
set_false_path \
-from [get_cells -hier cdc_sync_stage0_*_reg -filter {PRIMITIVE_SUBGROUP == flop}] \
-to [get_cells -hier cdc_sync_stage1_*_reg -filter {PRIMITIVE_SUBGROUP == flop}]
# TX FIFO
set_max_delay \
-from $ctrl_clk \
-to [get_cells -hier out_data_reg* -filter {PRIMITIVE_SUBGROUP == flop && NAME =~ *tx_sync*}] \
[get_property PERIOD $data_clk] -datapath_only
# RX FIFO
set_max_delay \
-from $data_clk \
-to [get_cells -hier out_data_reg* -filter {PRIMITIVE_SUBGROUP == flop && NAME =~ *rx_sync*}] \
[get_property PERIOD $ctrl_clk] -datapath_only
# Reset
set_false_path \
-to [get_pins -hier data_reset_vec_reg*/PRE]

View File

@ -15,9 +15,12 @@ adi_ip_files axi_i2s_adi [list \
"i2s_tx.vhd" \
"i2s_clkgen.vhd" \
"fifo_synchronizer.vhd" \
"axi_i2s_adi.vhd" ]
"axi_i2s_adi.vhd" \
"axi_i2s_adi_constr.xdc" \
]
adi_ip_properties_lite axi_i2s_adi
adi_ip_constraints axi_spdif_tx axi_i2s_adi_constr.xdc late
adi_add_bus "DMA_ACK_RX" "slave" \
"xilinx.com:interface:axis_rtl:1.0" \

View File

@ -45,13 +45,14 @@ entity fifo_synchronizer is
WIDTH : integer := 2
);
port (
resetn : in std_logic;
in_clk : in std_logic;
in_resetn : in std_logic;
in_data : in std_logic_vector(WIDTH - 1 downto 0);
in_tick : in std_logic;
out_clk : in std_logic;
out_resetn : in std_logic;
out_data : out std_logic_vector(WIDTH - 1 downto 0);
out_tick : out std_logic
);
@ -65,22 +66,31 @@ architecture impl of fifo_synchronizer is
signal rd_addr : natural range 0 to DEPTH - 1;
signal wr_addr : natural range 0 to DEPTH - 1;
signal cdc_sync_stage0_tick : std_logic;
signal cdc_sync_stage1_tick : std_logic;
signal cdc_sync_stage2_tick : std_logic;
signal cdc_sync_stage3_tick : std_logic;
signal tick : std_logic;
signal tick_d1 : std_logic;
signal tick_d2 : std_logic;
begin
process (in_clk)
begin
if rising_edge(in_clk) then
if resetn = '0' then
if in_tick = '1' then
cdc_sync_stage0_tick <= not cdc_sync_stage0_tick;
fifo(wr_addr) <= in_data;
end if;
end if;
end process;
process (in_clk)
begin
if rising_edge(in_clk) then
if in_resetn = '0' then
wr_addr <= 0;
tick <= '0';
else
if in_tick = '1' then
fifo(wr_addr) <= in_data;
wr_addr <= (wr_addr + 1) mod DEPTH;
tick <= not tick;
end if;
end if;
end if;
@ -89,20 +99,34 @@ begin
process (out_clk)
begin
if rising_edge(out_clk) then
if resetn = '0' then
rd_addr <= 0;
tick_d1 <= '0';
tick_d2 <= '0';
else
tick_d1 <= tick;
tick_d2 <= tick_d1;
out_tick <= tick_d1 xor tick_d2;
if (tick_d1 xor tick_d2) = '1' then
rd_addr <= (rd_addr + 1) mod DEPTH;
out_data <= fifo(rd_addr);
cdc_sync_stage1_tick <= cdc_sync_stage0_tick;
cdc_sync_stage2_tick <= cdc_sync_stage1_tick;
cdc_sync_stage3_tick <= cdc_sync_stage2_tick;
end if;
end process;
tick <= cdc_sync_stage2_tick xor cdc_sync_stage3_tick;
out_tick <= tick;
process (out_clk)
begin
if rising_edge(out_clk) then
if tick = '1' then
out_data <= fifo(rd_addr);
end if;
end if;
end process;
process (out_clk)
begin
if rising_edge(out_clk) then
if out_resetn = '0' then
rd_addr <= 0;
else
if tick = '1' then
rd_addr <= (rd_addr + 1) mod DEPTH;
end if;
end if;
end if;
end process;
end;

View File

@ -86,9 +86,10 @@ constant NUM_RX : integer := C_HAS_RX * C_NUM_CH;
signal enable : Boolean;
signal tick : std_logic;
signal tick_d1 : std_logic;
signal tick_d2 : std_logic;
signal cdc_sync_stage0_tick : std_logic;
signal cdc_sync_stage1_tick : std_logic;
signal cdc_sync_stage2_tick : std_logic;
signal cdc_sync_stage3_tick : std_logic;
signal BCLK_O_int : std_logic;
signal LRCLK_O_int : std_logic;
@ -114,37 +115,43 @@ signal tx_sync_fifo_in : std_logic_vector(3 + NUM_TX downto 0);
signal rx_sync_fifo_out : std_logic_vector(3 + NUM_RX downto 0);
signal rx_sync_fifo_in : std_logic_vector(3 + NUM_RX downto 0);
signal data_resetn : std_logic;
signal data_reset_vec : std_logic_vector(2 downto 0);
begin
enable <= rx_enable or tx_enable;
const_1 <= '1';
process (data_clk, resetn)
begin
if resetn = '0' then
data_reset_vec <= (others => '1');
elsif rising_edge(data_clk) then
data_reset_vec(2 downto 1) <= data_reset_vec(1 downto 0);
data_reset_vec(0) <= '0';
end if;
end process;
data_resetn <= not data_reset_vec(2);
-- Generate tick signal in the DATA_CLK_I domain
process (data_clk)
begin
if rising_edge(data_clk) then
if resetn = '0' then
tick <= '0';
else
tick <= not tick;
end if;
cdc_sync_stage0_tick <= not cdc_sync_stage0_tick;
end if;
end process;
process (clk)
begin
if rising_edge(clk) then
if resetn = '0' then
tick_d1 <= '0';
tick_d2 <= '0';
else
tick_d1 <= tick;
tick_d2 <= tick_d1;
end if;
cdc_sync_stage1_tick <= cdc_sync_stage0_tick;
cdc_sync_stage2_tick <= cdc_sync_stage1_tick;
cdc_sync_stage3_tick <= cdc_sync_stage2_tick;
end if;
end process;
tx_tick <= tick_d2 xor tick_d1;
tx_tick <= cdc_sync_stage2_tick xor cdc_sync_stage3_tick;
tx_sync_fifo_in(0) <= tx_channel_sync;
tx_sync_fifo_in(1) <= tx_frame_sync;
@ -152,10 +159,11 @@ begin
tx_sync_fifo_in(3) <= tx_lrclk;
tx_sync_fifo_in(3 + NUM_TX downto 4) <= tx_sdata;
process (data_clk)
begin
if rising_edge(data_clk) then
if resetn = '0' then
if data_resetn = '0' then
BCLK_O <= (others => '1');
LRCLK_O <= (others => '1');
SDATA_O <= (others => '0');
@ -190,11 +198,12 @@ begin
WIDTH => NUM_TX + 4
)
port map (
resetn => resetn,
in_resetn => resetn,
in_clk => clk,
in_data => tx_sync_fifo_in,
in_tick => tx_tick,
out_resetn => data_resetn,
out_clk => data_clk,
out_data => tx_sync_fifo_out
);
@ -271,11 +280,12 @@ begin
WIDTH => NUM_RX + 4
)
port map (
resetn => resetn,
in_resetn => data_resetn,
in_clk => data_clk,
in_data => rx_sync_fifo_in,
in_tick => const_1,
out_resetn => resetn,
out_clk => clk,
out_data => rx_sync_fifo_out
);