From aac0b7f4e8714a0f4ab2e1a003daa58d796f3034 Mon Sep 17 00:00:00 2001
From: Eric Kooistra <kooistra@astron.nl>
Date: Tue, 18 Feb 2020 16:55:47 +0100
Subject: [PATCH] Explained delta-cycles in VHDL simulation.

---
 libraries/base/common/hdllib.cfg              |   1 +
 .../common/tb/vhdl/tb_delta_cycle_demo.vhd    | 137 ++++++++++++++++++
 2 files changed, 138 insertions(+)
 create mode 100644 libraries/base/common/tb/vhdl/tb_delta_cycle_demo.vhd

diff --git a/libraries/base/common/hdllib.cfg b/libraries/base/common/hdllib.cfg
index d5624d00cb..df646d9c66 100644
--- a/libraries/base/common/hdllib.cfg
+++ b/libraries/base/common/hdllib.cfg
@@ -193,6 +193,7 @@ test_bench_files =
     tb/vhdl/tb_requantize.vhd
     tb/vhdl/tb_resize.vhd
     tb/vhdl/tb_round.vhd
+    tb/vhdl/tb_delta_cycle_demo.vhd
     
     tb/vhdl/tb_tb_common_add_sub.vhd
     tb/vhdl/tb_tb_common_adder_tree.vhd
diff --git a/libraries/base/common/tb/vhdl/tb_delta_cycle_demo.vhd b/libraries/base/common/tb/vhdl/tb_delta_cycle_demo.vhd
new file mode 100644
index 0000000000..c27c92bf26
--- /dev/null
+++ b/libraries/base/common/tb/vhdl/tb_delta_cycle_demo.vhd
@@ -0,0 +1,137 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2020
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+-- 
+-- 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.
+--
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+-- 
+-- Author: E. Kooistra
+-- Purpose: Demonstrate harmful effect of delta-cycle difference between a 
+--          clock and a copied clock and how to solve this.
+-- Description:
+-- 1) The problem:
+--   The assignment of clk2 <= clk1 causes that in simulation clk2 differs from
+--   clk1 by one delta cycle and that results in that in simulation d1 /= d2,
+--   while on hardware d1 = d2, because the delta cycle on the clk2 does not 
+--   impact synthesis, because in hardware clk1 and clk2 are the same clock
+--   tree. The clk1 is typically a clock that comes from an PLL in the design,
+--   so it is generated in the FPGA.
+--   
+-- 2) The solution
+-- a)If an assignment like clk2 <= clk1 is done, then make sure that this is
+--   the only place where clk1 is used.
+--
+-- b)For a clk1 that is needed within a certain component and also outside
+--   that component there are two solutions:
+--   1) Assign clk2_out <= clk1, where clk2_out is an OUT port on that
+--      component. The component then also needs a clk2 IN port and then both
+--      clk2_out OUT and clk2 IN are mapped to the same clk2 signal. The clk2
+--      signal has the same delta cycle phase inside the component and outside
+--      the component, because going through the component IO hierarchy does
+--      not cause extra delta-cycles delays. The PORT MAP of the instanciated
+--      component then has:
+--
+--      PORT MAP (
+--        ...
+--        clk2_out => clk2
+--        clk2     => clk2
+--        ---
+--      );
+--
+--      and both internally in the component and externally only clk2 is used
+--      for clocking logic.
+--    2) Balance the delta-cycle delays, so assign clk2_out <= clk1 for the
+--       OUT port and assign clk2_int <= clk1 for internal usage inside this
+--       component. Both clk2_out and  clk2_int have the same delta-cycle
+--       phase, so logic can be clocked at either clock without affecting the
+--       timing in simulation.
+--
+-- Conclusion:
+--    Scheme 2b1 is used in ctrl_unb*_board.vhd and in the io_ddr.vhd. However
+--    scheme 2b2 is preferred, because it avoids that clk1 has to traverse up
+--    and back down the hierarchy of one or more components in an FPGA design,
+--    to reach a common single high level that can source the clk1 back down
+--    to every where it is used..
+--
+-- Note that it is not allowed in VHDL to use (read) an OUT port. To read
+--   an OUT port it is necessary to use an auxiliary signal, e.g. i_xout for
+--   OUT xout and then do x_out <= i_x_out and i_xout can be used internally.
+--   This scheme cannot be used for clk2 OUT, because then clk2 <= i_clk2 
+--   would again cause the delta-cycle delay difference between i_clk2 and
+--   clk2 that needs to be avoided. Therefore the solution 2b is needed if a
+--   clk2 that is created inside a component (e.g. by an PLL) is also used
+--   outside this component.
+--
+-- Usage:
+--
+--   Modelsim> as 5
+--   Modelsim> run -a
+--   Observe in Wave Window that d1 /= d2.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+
+ENTITY tb_delta_cycle_demo IS
+END tb_delta_cycle_demo;
+
+ARCHITECTURE tb OF tb_delta_cycle_demo IS
+
+  CONSTANT clk_period   : TIME    := 10 ns;
+  
+  SIGNAL tb_end           : STD_LOGIC := '0';
+  SIGNAL clk1             : STD_LOGIC := '1';
+  SIGNAL clk2             : STD_LOGIC := '1';
+  SIGNAL data             : STD_LOGIC := '0';
+  SIGNAL d1               : STD_LOGIC;
+  SIGNAL d2               : STD_LOGIC;
+  
+BEGIN
+
+  -- Stimuli
+  clk1 <= NOT clk1 OR tb_end AFTER clk_period/2;
+  clk2 <= clk1;
+  
+  p_data : PROCESS
+  BEGIN
+    data <= '0';
+    FOR I IN 0 TO 2 LOOP WAIT UNTIL rising_edge(clk1); END LOOP;
+    data <= '1';
+    FOR I IN 0 TO 2 LOOP WAIT UNTIL rising_edge(clk1); END LOOP;
+  END PROCESS;
+  
+  p_clk1 : PROCESS (clk1)
+  BEGIN
+    IF rising_edge(clk1) THEN
+      d1 <= data;
+    END IF;
+  END PROCESS;
+  
+  p_clk2 : PROCESS (clk2)
+  BEGIN
+    IF rising_edge(clk2) THEN
+      d2 <= data;
+    END IF;
+  END PROCESS;
+  
+  tb_end <= '0', '1' AFTER 1 us;
+  
+END tb;
-- 
GitLab