From c1e25456ca1fa6e1295e24a037007ccc2212a81c Mon Sep 17 00:00:00 2001
From: Eric Kooistra <kooistra@astron.nl>
Date: Tue, 22 Feb 2022 17:40:40 +0100
Subject: [PATCH] Use generic g_switch_en, instead of signal, to support zero
 input to output latency when g_switch_en = FALSE.

---
 libraries/dsp/fft/src/vhdl/fft_switch.vhd   | 130 ++++++++++++--------
 libraries/dsp/fft/src/vhdl/fft_unswitch.vhd | 130 ++++++++++++--------
 libraries/dsp/fft/tb/vhdl/tb_fft_switch.vhd |  15 ++-
 3 files changed, 162 insertions(+), 113 deletions(-)

diff --git a/libraries/dsp/fft/src/vhdl/fft_switch.vhd b/libraries/dsp/fft/src/vhdl/fft_switch.vhd
index 3825d52de8..6f10f0c712 100644
--- a/libraries/dsp/fft/src/vhdl/fft_switch.vhd
+++ b/libraries/dsp/fft/src/vhdl/fft_switch.vhd
@@ -31,13 +31,13 @@
 --   blocks of c_nof_clk_per_block samples to the FFT.
 -- Remark: Copy from applications/lofar1/RSP/pft2/src/vhdl/pft_switch.vhd
 
-LIBRARY IEEE, common_lib, dp_lib;
+LIBRARY IEEE, common_lib;
 USE IEEE.std_logic_1164.ALL;
 USE common_lib.common_pkg.ALL;
-USE dp_lib.dp_stream_pkg.ALL;
 
 ENTITY fft_switch IS
   GENERIC (
+    g_switch_en : BOOLEAN := FALSE;
     g_fft_sz_w  : NATURAL;
     g_dat_w     : NATURAL
   );
@@ -45,7 +45,6 @@ ENTITY fft_switch IS
     in_re       : IN  STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);  -- real input A
     in_im       : IN  STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);  -- real input B
     in_val      : IN  STD_LOGIC;
-    switch_en   : IN  STD_LOGIC := '1';
     out_re      : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
     out_im      : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
     out_val     : OUT STD_LOGIC;
@@ -59,6 +58,9 @@ ARCHITECTURE rtl OF fft_switch IS
 
   CONSTANT c_nof_clk_per_block  : NATURAL := 2**g_fft_sz_w;
 
+  SIGNAL in_sop        : STD_LOGIC;
+  SIGNAL in_eop        : STD_LOGIC;
+
   SIGNAL cnt           : STD_LOGIC_VECTOR(g_fft_sz_w DOWNTO 0) := (OTHERS => '0');
   SIGNAL nxt_cnt       : STD_LOGIC_VECTOR(cnt'RANGE);
 
@@ -71,60 +73,84 @@ ARCHITECTURE rtl OF fft_switch IS
 
 BEGIN
 
-  p_reg : PROCESS (rst, clk)
-  BEGIN
-    IF rst = '1' THEN
-      cnt       <= (OTHERS => '0');
-      out_val   <= '0';
-      out_re    <= (OTHERS => '0');
-      out_im    <= (OTHERS => '0');
-    ELSIF rising_edge(clk) THEN
-      cnt       <= nxt_cnt;
-      out_val   <= in_val;
-      out_re    <= nxt_out_re;
-      out_im    <= nxt_out_im;
-    END IF;
-  END PROCESS;
-
-  p_counter: PROCESS(cnt, in_val)
-  BEGIN
-    nxt_cnt <= cnt;        
-    IF in_val = '1' THEN
-      nxt_cnt <= INCR_UVEC(cnt, 1);
-    END IF;
-  END PROCESS;
-  
-  p_lfsr_ctrl: PROCESS(cnt, in_val)
-  BEGIN
-    if TO_SINT(cnt) = -1 AND in_val = '1' THEN
-      lfsr_en <= '1';
-    ELSE
-      lfsr_en <= '0';
-    END IF;
-  END PROCESS;
-
-  p_out: PROCESS(in_re, in_im, switch_en, cnt, lfsr_bit1, lfsr_bit2)
-  BEGIN
-    nxt_out_re <= in_re;
-    nxt_out_im <= in_im;
-
-    IF switch_en = '1' THEN
+  -- Create input strobes to view data blocks for debugging
+  u_in_strobes : ENTITY common_lib.common_create_strobes_from_valid
+  GENERIC MAP (
+    g_pipeline          => FALSE,
+    g_nof_clk_per_sync  => c_nof_clk_per_block * 16,  -- void value, sync is not used
+    g_nof_clk_per_block => c_nof_clk_per_block
+  )
+  PORT MAP (
+    rst       => rst,
+    clk       => clk,
+    in_val    => in_val,
+    out_val   => OPEN,  -- out_val = in_val, because g_pipeline = FALSE
+    out_sop   => in_sop,
+    out_eop   => in_eop,
+    out_sync  => OPEN
+  );
+
+  no_switch : IF g_switch_en = FALSE GENERATE
+    -- wire inputs to outputs
+    out_re <= in_re;
+    out_im <= in_im;
+    out_val <= in_val;
+  END GENERATE;
+
+  gen_switch : IF g_switch_en = TRUE GENERATE
+    p_reg : PROCESS (rst, clk)
+    BEGIN
+      IF rst = '1' THEN
+        cnt       <= (OTHERS => '0');
+        out_val   <= '0';
+        out_re    <= (OTHERS => '0');
+        out_im    <= (OTHERS => '0');
+      ELSIF rising_edge(clk) THEN
+        cnt       <= nxt_cnt;
+        out_val   <= in_val;
+        out_re    <= nxt_out_re;
+        out_im    <= nxt_out_im;
+      END IF;
+    END PROCESS;
+
+    p_counter: PROCESS(cnt, in_val)
+    BEGIN
+      nxt_cnt <= cnt;
+      IF in_val = '1' THEN
+        nxt_cnt <= INCR_UVEC(cnt, 1);
+      END IF;
+    END PROCESS;
+
+    p_lfsr_ctrl: PROCESS(cnt, in_val)
+    BEGIN
+      if TO_SINT(cnt) = -1 AND in_val = '1' THEN
+        lfsr_en <= '1';
+      ELSE
+        lfsr_en <= '0';
+      END IF;
+    END PROCESS;
+
+    p_out: PROCESS(in_re, in_im, cnt, lfsr_bit1, lfsr_bit2)
+    BEGIN
+      nxt_out_re <= in_re;
+      nxt_out_im <= in_im;
+
       IF lfsr_bit1 = cnt(cnt'HIGH) THEN
         nxt_out_re <= NEGATE_SVEC(in_re, g_dat_w);  -- negate block of input A samples
       END IF;
       IF lfsr_bit2 = cnt(cnt'HIGH) THEN
         nxt_out_im <= NEGATE_SVEC(in_im, g_dat_w);  -- negate block of input B samples
       END IF;
-    END IF;
-  END PROCESS;
-    
-  u_fft_lfsr: ENTITY work.fft_lfsr
-  PORT MAP (
-    clk      => clk,
-    rst      => rst,
-    in_en    => lfsr_en,
-    out_bit1 => lfsr_bit1,
-    out_bit2 => lfsr_bit2
-  ); 
+    END PROCESS;
+
+    u_fft_lfsr: ENTITY work.fft_lfsr
+    PORT MAP (
+      clk      => clk,
+      rst      => rst,
+      in_en    => lfsr_en,
+      out_bit1 => lfsr_bit1,
+      out_bit2 => lfsr_bit2
+    );
+  END GENERATE;
 
 END rtl;
diff --git a/libraries/dsp/fft/src/vhdl/fft_unswitch.vhd b/libraries/dsp/fft/src/vhdl/fft_unswitch.vhd
index 9f32850800..b8a7de8c7b 100644
--- a/libraries/dsp/fft/src/vhdl/fft_unswitch.vhd
+++ b/libraries/dsp/fft/src/vhdl/fft_unswitch.vhd
@@ -26,13 +26,13 @@
 --   c_nof_clk_per_block samples, forever after rst release.
 -- Remark: Copy from applications/lofar1/RSP/pft2/src/vhdl/pft_unswitch.vhd
 
-LIBRARY IEEE, common_lib, dp_lib;
+LIBRARY IEEE, common_lib;
 USE IEEE.std_logic_1164.ALL;
 USE common_lib.common_pkg.ALL;
-USE dp_lib.dp_stream_pkg.ALL;
 
 ENTITY fft_unswitch IS
   GENERIC (
+    g_switch_en : BOOLEAN := FALSE;
     g_fft_sz_w  : NATURAL;
     g_dat_w     : NATURAL
   );
@@ -40,7 +40,6 @@ ENTITY fft_unswitch IS
     in_re       : IN STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
     in_im       : IN STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
     in_val      : IN STD_LOGIC;
-    switch_en   : IN STD_LOGIC := '1';
     out_re      : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
     out_im      : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
     out_val     : OUT STD_LOGIC;
@@ -53,7 +52,8 @@ ARCHITECTURE rtl OF fft_unswitch IS
 
   CONSTANT c_nof_clk_per_block  : NATURAL := 2**g_fft_sz_w;
 
-  SIGNAL in_sosi       : t_dp_sosi;
+  SIGNAL in_sop        : STD_LOGIC;
+  SIGNAL in_eop        : STD_LOGIC;
 
   SIGNAL cnt           : STD_LOGIC_VECTOR(g_fft_sz_w DOWNTO 0) := (OTHERS => '0');
   SIGNAL nxt_cnt       : STD_LOGIC_VECTOR(cnt'RANGE);
@@ -68,44 +68,68 @@ ARCHITECTURE rtl OF fft_unswitch IS
 
 BEGIN
 
-  p_reg : PROCESS (rst, clk)
-  BEGIN
-    IF rst = '1' THEN
-      cnt       <= (OTHERS => '0');
-      out_val   <= '0';
-      out_re    <= (OTHERS => '0');
-      out_im    <= (OTHERS => '0');
-    ELSIF rising_edge(clk) THEN
-      cnt       <= nxt_cnt;
-      out_val   <= in_val;
-      out_re    <= nxt_out_re;
-      out_im    <= nxt_out_im;
-    END IF;
-  END PROCESS;
-
-  p_counter: PROCESS(cnt, in_val)
-  BEGIN
-    nxt_cnt <= cnt;        
-    IF in_val = '1' THEN
-      nxt_cnt <= INCR_UVEC(cnt, 1);
-    END IF;
-  END PROCESS;
-  
-  p_lfsr_ctrl: PROCESS(cnt, in_val)
-  BEGIN
-    if TO_SINT(cnt) = -1 AND in_val = '1' THEN
-      lfsr_en <= '1';
-    ELSE
-      lfsr_en <= '0';
-    END IF;
-  END PROCESS;
-
-  p_out: PROCESS(in_re, in_im, switch_en, cnt, lfsr_bit1, lfsr_bit2)
-  BEGIN
-    nxt_out_re  <= in_re;
-    nxt_out_im  <= in_im;
-
-    IF switch_en = '1' THEN
+  -- Create input strobes to view data blocks for debugging
+  u_in_strobes : ENTITY common_lib.common_create_strobes_from_valid
+  GENERIC MAP (
+    g_pipeline          => FALSE,
+    g_nof_clk_per_sync  => c_nof_clk_per_block * 16,  -- void value, sync is not used
+    g_nof_clk_per_block => c_nof_clk_per_block
+  )
+  PORT MAP (
+    rst       => rst,
+    clk       => clk,
+    in_val    => in_val,
+    out_val   => OPEN,  -- out_val = in_val, because g_pipeline = FALSE
+    out_sop   => in_sop,
+    out_eop   => in_eop,
+    out_sync  => OPEN
+  );
+
+  no_switch : IF g_switch_en = FALSE GENERATE
+    -- wire inputs to outputs
+    out_re <= in_re;
+    out_im <= in_im;
+    out_val <= in_val;
+  END GENERATE;
+
+  gen_switch : IF g_switch_en = TRUE GENERATE
+    p_reg : PROCESS (rst, clk)
+    BEGIN
+      IF rst = '1' THEN
+        cnt       <= (OTHERS => '0');
+        out_val   <= '0';
+        out_re    <= (OTHERS => '0');
+        out_im    <= (OTHERS => '0');
+      ELSIF rising_edge(clk) THEN
+        cnt       <= nxt_cnt;
+        out_val   <= in_val;
+        out_re    <= nxt_out_re;
+        out_im    <= nxt_out_im;
+      END IF;
+    END PROCESS;
+
+    p_counter: PROCESS(cnt, in_val)
+    BEGIN
+      nxt_cnt <= cnt;
+      IF in_val = '1' THEN
+        nxt_cnt <= INCR_UVEC(cnt, 1);
+      END IF;
+    END PROCESS;
+
+    p_lfsr_ctrl: PROCESS(cnt, in_val)
+    BEGIN
+      if TO_SINT(cnt) = -1 AND in_val = '1' THEN
+        lfsr_en <= '1';
+      ELSE
+        lfsr_en <= '0';
+      END IF;
+    END PROCESS;
+
+    p_out: PROCESS(in_re, in_im, cnt, lfsr_bit1, lfsr_bit2)
+    BEGIN
+      nxt_out_re  <= in_re;
+      nxt_out_im  <= in_im;
+
       -- multiplexed spectrum for input A at index 0, B at index 1
       IF cnt(0) = '0' THEN
         IF cnt(cnt'HIGH) = lfsr_bit1 THEN  -- negate spectrum to undo negate of block of real input A
@@ -118,16 +142,16 @@ BEGIN
           nxt_out_im <= NEGATE_SVEC(in_im, g_dat_w);
         END IF;
       END IF;
-    END IF;
-  END PROCESS;
-    
-  u_fft_lfsr: ENTITY work.fft_lfsr
-  PORT MAP (
-    clk      => clk,
-    rst      => rst,
-    in_en    => lfsr_en,
-    out_bit1 => lfsr_bit1,
-    out_bit2 => lfsr_bit2
-  );
+    END PROCESS;
+
+    u_fft_lfsr: ENTITY work.fft_lfsr
+    PORT MAP (
+      clk      => clk,
+      rst      => rst,
+      in_en    => lfsr_en,
+      out_bit1 => lfsr_bit1,
+      out_bit2 => lfsr_bit2
+    );
+  END GENERATE;
 
 END rtl;
diff --git a/libraries/dsp/fft/tb/vhdl/tb_fft_switch.vhd b/libraries/dsp/fft/tb/vhdl/tb_fft_switch.vhd
index 9d41bcb2dd..08d04ee3e9 100644
--- a/libraries/dsp/fft/tb/vhdl/tb_fft_switch.vhd
+++ b/libraries/dsp/fft/tb/vhdl/tb_fft_switch.vhd
@@ -55,6 +55,7 @@ USE common_lib.tb_common_pkg.ALL;
 
 ENTITY tb_fft_switch IS
   GENERIC (
+    g_switch_en          : BOOLEAN := TRUE;
     g_in_val_gaps        : BOOLEAN := TRUE;
     g_increment_at_val   : BOOLEAN := TRUE;
     g_fft_size_w         : NATURAL := 3;
@@ -87,7 +88,6 @@ ARCHITECTURE tb OF tb_fft_switch IS
   SIGNAL in_eop            : STD_LOGIC := '0';
   SIGNAL in_sync           : STD_LOGIC := '0';
 
-  SIGNAL switch_en         : STD_LOGIC := '1';
   SIGNAL switch_a          : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
   SIGNAL switch_b          : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
   SIGNAL switch_val        : STD_LOGIC;
@@ -101,7 +101,6 @@ ARCHITECTURE tb OF tb_fft_switch IS
   SIGNAL mux_im            : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0) := (OTHERS => '0');
   SIGNAL mux_val           : STD_LOGIC := '0';
 
-  SIGNAL unswitch_en       : STD_LOGIC := '1';
   SIGNAL unswitch_re       : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
   SIGNAL unswitch_im       : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
   SIGNAL unswitch_val      : STD_LOGIC := '0';
@@ -185,14 +184,14 @@ BEGIN
 
   u_fft_switch : ENTITY work.fft_switch
   GENERIC MAP (
-    g_fft_sz_w => g_fft_size_w,
-    g_dat_w    => c_dat_w
+    g_switch_en => g_switch_en,
+    g_fft_sz_w  => g_fft_size_w,
+    g_dat_w     => c_dat_w
   )
   PORT MAP (
     in_re      => in_a,
     in_im      => in_b,
     in_val     => in_val,
-    switch_en  => switch_en,
     out_re     => switch_a,
     out_im     => switch_b,
     out_val    => switch_val,
@@ -227,14 +226,14 @@ BEGIN
 
   u_fft_unswitch : ENTITY work.fft_unswitch
   GENERIC MAP (
-    g_fft_sz_w => g_fft_size_w,
-    g_dat_w    => c_dat_w
+    g_switch_en => g_switch_en,
+    g_fft_sz_w  => g_fft_size_w,
+    g_dat_w     => c_dat_w
   )
   PORT MAP (
     in_re      => mux_re,
     in_im      => mux_im,
     in_val     => mux_val,
-    switch_en  => unswitch_en,
     out_re     => unswitch_re,
     out_im     => unswitch_im,
     out_val    => unswitch_val,
-- 
GitLab