]> git.the-white-hart.net Git - vhdl/commitdiff
Clean up clock synchronization utilities
authorrs <>
Wed, 12 Nov 2025 04:29:04 +0000 (22:29 -0600)
committerrs <>
Wed, 12 Nov 2025 04:29:04 +0000 (22:29 -0600)
libraries/nexys2/usb.vhd
libraries/utility/fifo_xclk.vhd
libraries/utility/power_on_reset_opt.vhd
libraries/utility/sync_rst.vhd [deleted file]
libraries/utility/sync_sig.vhd [new file with mode: 0644]
libraries/utility/sync_vec.vhd [new file with mode: 0644]
libraries/utility/tests/test_sync_rst.vhd [deleted file]
libraries/utility/tests/test_sync_sig.vhd [new file with mode: 0644]
libraries/utility/tests/test_sync_vec.vhd [new file with mode: 0644]
libraries/utility/xclk_sig.vhd [deleted file]
libraries/utility/xclk_vec.vhd [deleted file]

index 6f0a00249ef8268c83c3dd6ed6ccafd4046e451e..50cdc5f4a827f8a524e623cd8319e5d1b89fdbbf 100644 (file)
@@ -18,13 +18,13 @@ entity usb_cypress is
                EppDSTB_DstmFLAGB: in    std_logic;
                EppWAIT_DstmSLRD:  out   std_logic;
                DstmIFCLK:         in    std_logic;
-               DstmSLCS:          in    std_logic;
+               DstmSLCS:          in    std_logic;  -- STMEN
                DstmADR:           out   std_logic_vector(1 downto 0);
                DstmSLWR:          out   std_logic;
                DstmSLOE:          out   std_logic;
                DstmPKTEND:        out   std_logic;
-               UsbMode:           in    std_logic;
-               UsbRdy:            in    std_logic;
+               UsbMode:           in    std_logic;  -- I think this is EPPEN, which is referenced in documentation but not defined anywhere
+               UsbRdy:            in    std_logic;  -- High when USB is plugged in and the controller is ready
 
                -- EPP-Wishbone interface
                epp_clk_i:         in    std_logic;
@@ -106,28 +106,28 @@ begin
        ------------------------------------------------------------------------
        -- Synchronize reset signal to all clock domains
 
-       e_sync_rst_ifclk: entity utility.sync_rst
+       e_sync_rst_ifclk: entity utility.sync_sig
                generic map (SYNC_STAGES => SYNC_STAGES+1)
                port map (
                        rst_i => rst_i,
                        clk_i => DstmIFCLK,
-                       rst_o => ifclk_rst
+                       sig_o => ifclk_rst
                );
 
-       e_sync_rst_epp: entity utility.sync_rst
+       e_sync_rst_epp: entity utility.sync_sig
                generic map (SYNC_STAGES => SYNC_STAGES+1)
                port map (
                        rst_i => rst_i,
                        clk_i => epp_clk_i,
-                       rst_o => epp_rst
+                       sig_o => epp_rst
                );
 
-       e_sync_rst_stm: entity utility.sync_rst
+       e_sync_rst_stm: entity utility.sync_sig
                generic map (SYNC_STAGES => SYNC_STAGES+1)
                port map (
                        rst_i => rst_i,
                        clk_i => stm_clk_i,
-                       rst_o => stm_rst
+                       sig_o => stm_rst
                );
 
 
@@ -176,21 +176,39 @@ begin
        -- EPP Interface
 
        -- EPP clock domain crossing
-       e_xclk_eppen: entity utility.xclk_sig
+       e_xclk_eppen: entity utility.sync_sig
                generic map (SYNC_STAGES => SYNC_STAGES, INIT => '0')
-               port map (a_sig_i => epp_en,    b_clk_i => epp_clk_i, b_sig_o => xclk_eppen);
+               port map (
+                       rst_i => epp_rst,
+                       clk_i => epp_clk_i,
+                       sig_i => epp_en,
+                       sig_o => xclk_eppen
+               );
 
-       e_xclk_astb: entity utility.xclk_sig
-               generic map (SYNC_STAGES => SYNC_STAGES, INIT => '1')
-               port map (a_sig_i => epp_astb,  b_clk_i => epp_clk_i, b_sig_o => xclk_astb);
+       e_xclk_astb: entity utility.sync_sig
+               generic map (SYNC_STAGES => SYNC_STAGES)
+               port map (
+                       clk_i => epp_clk_i,
+                       sig_i => epp_astb,
+                       sig_o => xclk_astb
+               );
 
-       e_xclk_dstb: entity utility.xclk_sig
-               generic map (SYNC_STAGES => SYNC_STAGES, INIT => '1')
-               port map (a_sig_i => epp_dstb,  b_clk_i => epp_clk_i, b_sig_o => xclk_dstb);
+       e_xclk_dstb: entity utility.sync_sig
+               generic map (SYNC_STAGES => SYNC_STAGES)
+               port map (
+                       clk_i => epp_clk_i,
+                       sig_i => epp_dstb,
+                       sig_o => xclk_dstb
+               );
 
-       e_xclk_wait: entity utility.xclk_sig
+       e_xclk_wait: entity utility.sync_sig
                generic map (SYNC_STAGES => SYNC_STAGES, INIT => '0')  -- FIXME: is this the best initial value for WAIT?
-               port map (a_sig_i => xclk_wait, b_clk_i => DstmIFCLK, b_sig_o => epp_wait);
+               port map (
+                       rst_i => ifclk_rst,
+                       clk_i => DstmIFCLK,
+                       sig_i => xclk_wait,
+                       sig_o => epp_wait
+               );
 
        -- These signals are stable during the time that they're validated by the
        -- synchronized handshaking signals, so no clock synchronizing is needed
index 4709d934440040f5f344a6b9fd29615cf7ae0529..09691788e69ade9a24260b91d228ef71095c0be2 100644 (file)
@@ -49,20 +49,20 @@ begin
 
        -- Head logic
 
-       e_head_reset: entity utility.sync_rst
+       e_head_reset: entity utility.sync_sig
                generic map (SYNC_STAGES => SYNC_STAGES+1)
                port map (
                        rst_i => rst_i,
                        clk_i => head_clk_i,
-                       rst_o => head_rst
+                       sig_o => head_rst
                );
 
-       e_xclk_tail: entity utility.xclk_vec
+       e_xclk_tail: entity utility.sync_vec
                generic map (SYNC_STAGES => SYNC_STAGES)
                port map (
-                       a_sig_i => std_logic_vector(tail_adr_reg),
-                       b_clk_i => head_clk_i,
-                       b_sig_o => tail_adr_xclk
+                       clk_i => head_clk_i,
+                       sig_i => std_logic_vector(tail_adr_reg),
+                       sig_o => tail_adr_xclk
                );
 
        is_full <= '1' when std_logic_vector(head_adr_next) = tail_adr_xclk else '0';
@@ -85,20 +85,20 @@ begin
 
        -- Tail logic
 
-       e_tail_reset: entity utility.sync_rst
+       e_tail_reset: entity utility.sync_sig
                generic map (SYNC_STAGES => SYNC_STAGES+1)
                port map (
                        rst_i => rst_i,
                        clk_i => tail_clk_i,
-                       rst_o => tail_rst
+                       sig_o => tail_rst
                );
 
-       e_xclk_head: entity utility.xclk_vec
+       e_xclk_head: entity utility.sync_vec
                generic map (SYNC_STAGES => SYNC_STAGES)
                port map (
-                       a_sig_i => std_logic_vector(head_adr_reg),
-                       b_clk_i => tail_clk_i,
-                       b_sig_o => head_adr_xclk
+                       clk_i => tail_clk_i,
+                       sig_i => std_logic_vector(head_adr_reg),
+                       sig_o => head_adr_xclk
                );
 
        is_empty <= '1' when std_logic_vector(tail_adr_reg) = head_adr_xclk else '0';
index 73908d74994e563629fe028e5e72a79d6d4bb1f9..a1d551325f8fd362a5b4989195136c09cb39f293 100644 (file)
@@ -1,10 +1,25 @@
+--------------------------------------------------------------------------------
+-- power_on_reset_opt - power-on-reset generator and external reset synchronizer
+--
+-- This holds a design in reset after initial configuration and also
+-- synchronizes an active-high external reset.
+--
+-- After synchronizing the external reset, the reset output is held for an
+-- additional 16 clock cycles to give SRLs time to flush.
+--------------------------------------------------------------------------------
+
 library ieee;
 use ieee.std_logic_1164.all;
 use ieee.numeric_std.all;
 use ieee.std_logic_misc.all;
 
+library work;
+
 
 entity power_on_reset_opt is
+       generic (
+               SYNC_STAGES: positive := 2
+       );
        port (
                rst_i: in  std_logic := '0';
                clk_i: in  std_logic;
@@ -15,7 +30,6 @@ end power_on_reset_opt;
 
 architecture behavioral of power_on_reset_opt is
 
-       signal shift_reg:     std_logic_vector(1 downto 0) := (others => '1');
        signal rst_sync:      std_logic;
 
        signal count_reg:     std_logic_vector(3 downto 0) := (others => '1');
@@ -24,15 +38,13 @@ architecture behavioral of power_on_reset_opt is
 begin
 
        -- Synchronize external asynchronous reset to internal clock
-       process (rst_i, clk_i, shift_reg)
-       begin
-               if rst_i = '1' then
-                       shift_reg <= (others => '1');
-               elsif rising_edge(clk_i) then
-                       shift_reg <= '0' & shift_reg(shift_reg'high downto 1);
-               end if;
-       end process;
-       rst_sync <= shift_reg(0);
+       e_sync_rst: entity work.sync_sig
+               generic map (SYNC_STAGES => SYNC_STAGES)
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+                       sig_o => rst_sync
+               );
 
        -- Continue to hold reset for 16 clock cycles to allow SRLs to flush
        process (rst_sync, clk_i, count_reg, count_running)
diff --git a/libraries/utility/sync_rst.vhd b/libraries/utility/sync_rst.vhd
deleted file mode 100644 (file)
index 42b6731..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-
-
-entity sync_rst is
-       generic (SYNC_STAGES: positive := 2);
-       port (
-               rst_i: in  std_logic;
-               clk_i: in  std_logic;
-               rst_o: out std_logic
-       );
-end sync_rst;
-
-
-architecture behavioral of sync_rst is
-
-       signal shift_reg: std_logic_vector(SYNC_STAGES-1 downto 0) := (others => '1');
-
-begin
-
-       rst_o <= shift_reg(0);
-
-       process (rst_i, clk_i)
-       begin
-               if rst_i = '1' then
-                       shift_reg <= (others => '1');
-               elsif rising_edge(clk_i) then
-                       shift_reg <= '0' & shift_reg(SYNC_STAGES-1 downto 1);
-               end if;
-       end process;
-
-end behavioral;
diff --git a/libraries/utility/sync_sig.vhd b/libraries/utility/sync_sig.vhd
new file mode 100644 (file)
index 0000000..ae761f0
--- /dev/null
@@ -0,0 +1,63 @@
+--------------------------------------------------------------------------------
+-- sync_sig - synchronize a signal into a clock domain
+--
+-- Generics:
+-- SYNC_STAGES - number of shift register stages to use
+-- INIT        - initial and reset signal value
+--
+-- Ports:
+-- rst_i       - asynchronous active high reset to force to INIT value
+-- clk_i       - the destination clock domain
+-- sig_i       - the source signal
+-- sig_o       - the synchronized signal
+--
+-- This can be used to both cross clock domains and synchronize reset signals.
+--
+-- To synchronize an active high reset into a clock domain:
+-- INIT  => '1' (default)
+-- rst_i => active high reset signal to synchronize
+-- sig_i => '0' (default)
+--
+-- For signals leaving the design, INIT and rst_i should be used.
+--
+-- For signals entering or within the design, reset can be elided as long as the
+-- rest of the design is left in reset for at least SYNC_STAGES cycles to allow
+-- the synchronizing registers to flush.
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity sync_sig is
+       generic (
+               SYNC_STAGES: positive := 2;
+               INIT: std_logic := '1'
+       );
+       port (
+               rst_i: in  std_logic := '0';
+               clk_i: in  std_logic;
+
+               sig_i: in  std_logic := '0';
+               sig_o: out std_logic
+       );
+end sync_sig;
+
+
+architecture behavioral of sync_sig is
+
+       signal shift_reg: std_logic_vector(SYNC_STAGES-1 downto 0) := (others => INIT);
+
+begin
+
+       process (clk_i, sig_i, shift_reg)
+       begin
+               if rst_i = '1' then
+                       shift_reg <= (others => INIT);
+               elsif rising_edge(clk_i) then
+                       shift_reg <= sig_i & shift_reg(SYNC_STAGES-1 downto 1);
+               end if;
+       end process;
+       sig_o <= shift_reg(0);
+
+end behavioral;
diff --git a/libraries/utility/sync_vec.vhd b/libraries/utility/sync_vec.vhd
new file mode 100644 (file)
index 0000000..fa75268
--- /dev/null
@@ -0,0 +1,62 @@
+--------------------------------------------------------------------------------
+-- sync_vec - synchronize a std_logic_vector into a clock domain
+--
+-- Generics:
+-- SYNC_STAGES - number of shift register stages to use
+--
+-- Ports:
+-- clk_i       - the destination clock domain
+-- sig_i       - the source signal
+-- sig_o       - the synchronized signal
+--
+-- This is probably not what you want.  This should only be used when sending
+-- a Gray-coded counter value across clock domains for things like dual-clocked
+-- FIFOs, not for synchronizing data busses.  Data busses should be held stable
+-- in their source domain while synchronized handshaking signals negotiate the
+-- crossing.
+--
+-- When sending a Gray-coded value across domains, make sure the value is
+-- registered!  Combinational logic to generate a Gray-code value for an integer
+-- can have glitches, which would defeat the purpose of this block if unreggied.
+--
+-- There is no reset logic, so the rest of the design should be held in reset
+-- for at least SYNC_STAGES cycles to flush the synchronizing registers.
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity sync_vec is
+       generic (
+               SYNC_STAGES: positive := 2
+       );
+       port (
+               clk_i: in  std_logic;
+
+               sig_i: in  std_logic_vector;
+               sig_o: out std_logic_vector
+       );
+end sync_vec;
+
+
+architecture behavioral of sync_vec is
+
+       type vec_array is array(natural range <>) of std_logic_vector(sig_i'high downto 0);
+
+       signal shift_reg: vec_array(SYNC_STAGES-1 downto 0);
+
+begin
+
+       process (clk_i, sig_i, shift_reg)
+       begin
+               if rising_edge(clk_i) then
+                       shift_reg(SYNC_STAGES-1) <= sig_i;
+                       for i in SYNC_STAGES-2 downto 0 loop
+                               shift_reg(i) <= shift_reg(i+1);
+                       end loop;
+               end if;
+       end process;
+       sig_o <= shift_reg(0);
+
+end behavioral;
diff --git a/libraries/utility/tests/test_sync_rst.vhd b/libraries/utility/tests/test_sync_rst.vhd
deleted file mode 100644 (file)
index 8529d93..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-
-library work;
-
-
-entity test_sync_rst is
-end test_sync_rst;
-
-
-architecture behavior of test_sync_rst is
-
-       signal rst_i: std_logic;
-       signal clk_i: std_logic;
-       signal rst_o: std_logic;
-
-begin
-
-       p_test: process
-       begin
-               rst_i <= '0';
-               wait until rst_o = '0';
-               wait for 40 ns;
-               rst_i <= '1';
-               wait for 2 ns;
-               rst_i <= '0';
-
-               wait;
-       end process;
-
-       e_uut: entity work.sync_rst
-               generic map (SYNC_STAGES => 5)
-               port map (
-                       rst_i => rst_i,
-                       clk_i => clk_i,
-                       rst_o => rst_o
-               );
-
-       p_clk: process
-       begin
-               clk_i <= '0';
-               wait for 10 ns;
-               clk_i <= '1';
-               wait for 10 ns;
-       end process;
-
-end;
diff --git a/libraries/utility/tests/test_sync_sig.vhd b/libraries/utility/tests/test_sync_sig.vhd
new file mode 100644 (file)
index 0000000..6379607
--- /dev/null
@@ -0,0 +1,68 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity test_sync_sig is
+end test_sync_sig;
+
+
+architecture behavior of test_sync_sig is
+
+       constant CLK_I_PERIOD: time := 20 ns;
+
+       signal rst_i: std_logic;
+       signal clk_i: std_logic;
+       signal sig_i: std_logic;
+       signal sig_o: std_logic;
+
+begin
+
+       p_test: process
+       begin
+               rst_i <= '0';
+               sig_i <= '0';
+
+               wait until sig_o = '0';
+               wait for CLK_I_PERIOD*3;
+
+               sig_i <= '1';
+               wait until sig_o = '1';
+               wait for CLK_I_PERIOD*3;
+
+               sig_i <= '0';
+               wait until sig_o = '0';
+               wait for CLK_I_PERIOD*3;
+
+               rst_i <= '1';
+               wait for 1 ns;
+               rst_i <= '0';
+               wait for 1 ns;
+               wait until sig_o = '0';
+               wait for CLK_I_PERIOD*3;
+
+               wait;
+       end process;
+
+       e_uut: entity work.sync_sig
+               generic map (
+                       SYNC_STAGES => 5,  -- For testing purposes.  Should probably be 2 or maybe 3 in a design.
+                       INIT        => '1'
+               )
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+                       sig_i => sig_i,
+                       sig_o => sig_o
+               );
+
+       p_clk: process
+       begin
+               clk_i <= '0';
+               wait for CLK_I_PERIOD/2;
+               clk_i <= '1';
+               wait for CLK_I_PERIOD/2;
+       end process;
+
+end;
diff --git a/libraries/utility/tests/test_sync_vec.vhd b/libraries/utility/tests/test_sync_vec.vhd
new file mode 100644 (file)
index 0000000..8658890
--- /dev/null
@@ -0,0 +1,52 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity test_sync_vec is
+end test_sync_vec;
+
+
+architecture behavior of test_sync_vec is
+
+       constant CLK_I_PERIOD: time := 20 ns;
+
+       signal clk_i: std_logic;
+       signal sig_i: std_logic_vector(7 downto 0);
+       signal sig_o: std_logic_vector(7 downto 0);
+
+begin
+
+       p_test: process
+       begin
+               sig_i <= x"a5";
+               wait until sig_o = x"a5";
+               wait for CLK_I_PERIOD*3;
+
+               sig_i <= x"c3";
+               wait until sig_o = x"c3";
+               wait for CLK_I_PERIOD*3;
+
+               wait;
+       end process;
+
+       e_uut: entity work.sync_vec
+               generic map (
+                       SYNC_STAGES => 5  -- For testing purposes.  Should probably be 2 or maybe 3 in a design.
+               )
+               port map (
+                       clk_i => clk_i,
+                       sig_i => sig_i,
+                       sig_o => sig_o
+               );
+
+       p_clk: process
+       begin
+               clk_i <= '0';
+               wait for CLK_I_PERIOD/2;
+               clk_i <= '1';
+               wait for CLK_I_PERIOD/2;
+       end process;
+
+end;
diff --git a/libraries/utility/xclk_sig.vhd b/libraries/utility/xclk_sig.vhd
deleted file mode 100644 (file)
index f253156..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-
-
-entity xclk_sig is
-       generic (
-               SYNC_STAGES: positive := 2;
-               INIT: std_logic := '0'
-       );
-       port (
-               a_sig_i: in  std_logic;
-
-               b_clk_i: in  std_logic;
-               b_sig_o: out std_logic
-       );
-end xclk_sig;
-
-
-architecture behavioral of xclk_sig is
-
-       signal sync_regs: std_logic_vector(SYNC_STAGES-1 downto 0) := (others => INIT);
-
-begin
-
-       process (b_clk_i, a_sig_i, sync_regs)
-       begin
-               if rising_edge(b_clk_i) then
-                       sync_regs <= a_sig_i & sync_regs(SYNC_STAGES-1 downto 1);
-               end if;
-       end process;
-       b_sig_o <= sync_regs(0);
-
-end behavioral;
diff --git a/libraries/utility/xclk_vec.vhd b/libraries/utility/xclk_vec.vhd
deleted file mode 100644 (file)
index a1662da..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-
-
-entity xclk_vec is
-       generic (SYNC_STAGES: positive := 2);
-       port (
-               a_sig_i: in  std_logic_vector;
-
-               b_clk_i: in  std_logic;
-               b_sig_o: out std_logic_vector
-       );
-end xclk_vec;
-
-
-architecture behavioral of xclk_vec is
-
-       type value_array is array(natural range <>) of std_logic_vector(a_sig_i'high downto 0);
-
-       signal sync_regs: value_array(SYNC_STAGES-1 downto 0);
-
-begin
-
-       process (b_clk_i, a_sig_i, sync_regs)
-       begin
-               if rising_edge(b_clk_i) then
-                       sync_regs(SYNC_STAGES-1) <= a_sig_i;
-                       for i in SYNC_STAGES-2 downto 0 loop
-                               sync_regs(i) <= sync_regs(i+1);
-                       end loop;
-               end if;
-       end process;
-       b_sig_o <= sync_regs(0);
-
-end behavioral;