From d69bd49323ab47764d2bc85f6cce40b5101850c3 Mon Sep 17 00:00:00 2001
From: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
Date: Thu, 16 Apr 2020 17:28:19 +0200
Subject: [PATCH] wb_fine_pulse_gen: use double clock rate on Kintex7
 Ultrascale, allowing for 1ns resolution

---
 .../fine_pulse_gen_kintexultrascale.vhd       | 139 +++++++++++++-----
 ...fine_pulse_gen_kintexultrascale_shared.vhd |  15 +-
 .../wb_fine_pulse_gen/xwb_fine_pulse_gen.vhd  |   1 +
 testbench/wishbone/wb_fine_pulse_gen/main.sv  |  14 +-
 4 files changed, 123 insertions(+), 46 deletions(-)

diff --git a/modules/wishbone/wb_fine_pulse_gen/fine_pulse_gen_kintexultrascale.vhd b/modules/wishbone/wb_fine_pulse_gen/fine_pulse_gen_kintexultrascale.vhd
index d7a6e6c3..b9e3ade0 100644
--- a/modules/wishbone/wb_fine_pulse_gen/fine_pulse_gen_kintexultrascale.vhd
+++ b/modules/wishbone/wb_fine_pulse_gen/fine_pulse_gen_kintexultrascale.vhd
@@ -16,9 +16,9 @@ entity fine_pulse_gen_kintexultrascale is
     );
   port
     (
+      clk_ref_i    : in std_logic;
       clk_par_i    : in std_logic;
       clk_serdes_i : in std_logic;
-
       rst_serdes_i : in std_logic;
       
       rst_sys_n_i : in std_logic;
@@ -62,9 +62,9 @@ architecture rtl of fine_pulse_gen_kintexultrascale is
       T      : in  std_ulogic);
   end component OSERDESE3;
   
-  signal par_data : std_logic_vector(7 downto 0);
-  
-  signal par_data_rev : std_logic_vector(7 downto 0);
+  signal par_data : std_logic_vector(15 downto 0);
+  signal par_data_125 : std_logic_vector(7 downto 0);
+  signal par_data_rev : std_logic_vector(15 downto 0);
 
   signal dout_predelay, dout_prebuf, dout_nodelay : std_logic;
   signal odelay_load                              : std_logic;
@@ -72,6 +72,7 @@ architecture rtl of fine_pulse_gen_kintexultrascale is
   signal odelay_ntaps                             : std_logic_vector(4 downto 0);
 
 
+
   signal trig_d : std_logic;
 
 --   function f_gen_bitmask (coarse : std_logic_vector; pol : std_logic; cont : std_logic) return std_logic_vector is
@@ -80,19 +81,25 @@ architecture rtl of fine_pulse_gen_kintexultrascale is
 
 -- end f_gen_bitmask;
 
-  signal mask       : std_logic_vector(15 downto 0);
+  signal mask       : std_logic_vector(31 downto 0);
   signal flip       : std_logic;
   signal dly_load_d : std_logic;
+
+  signal clk_ref_div2 : std_logic := '0';
+  signal clk_ref_div2_d0, clk_ref_div2_d1, gb_sync_p : std_logic;
+  
+  
+  
 begin
 
   rst <= not rst_sys_n_i;
 
 
 
-  process(clk_par_i)
-    variable rv : std_logic_vector(15 downto 0);
+  process(clk_ref_i)
+    variable rv : std_logic_vector(31 downto 0);
   begin
-    if rising_edge(clk_par_i) then
+    if rising_edge(clk_ref_i) then
 
       dly_load_d <= dly_load_i;
       if dly_load_i = '1' then
@@ -102,21 +109,37 @@ begin
 
           case coarse_i is
             when x"00" =>
-              rv := "1111000011110000";
+              rv := "11111111000000001111111100000000";
             when x"01" =>
-              rv := "0111100001111000";
+              rv := "01111111100000000111111110000000";
             when x"02" =>
-              rv := "0011110000111100";
+              rv := "00111111110000000011111111000000";
             when x"03" =>
-              rv := "0001111000011110";
+              rv := "00011111111000000001111111100000";
             when x"04" =>
-              rv := "0000111100001111";
+              rv := "00001111111100000000111111110000";
             when x"05" =>
-              rv := "1000011110000111";
+              rv := "00000111111110000000011111111000";
             when x"06" =>
-              rv := "1100001111000011";
+              rv := "00000011111111000000001111111100";
             when x"07" =>
-              rv := "1110000111100001";
+              rv := "00000001111111100000000111111110";
+            when x"08" =>
+              rv := "00000000111111110000000011111111";
+            when x"09" =>
+              rv := "00000000011111111000000001111111";
+            when x"0a" =>
+              rv := "00000000001111111100000000111111";
+            when x"0b" =>
+              rv := "00000000000111111110000000011111";
+            when x"0c" =>
+              rv := "00000000000011111111000000001111";
+            when x"0d" =>
+              rv := "00000000000001111111100000000111";
+            when x"0e" =>
+              rv := "00000000000000111111110000000011";
+            when x"0f" =>
+              rv := "00000000000000011111111000000001";
             when others =>
               rv := (others => '0');
           end case;
@@ -125,21 +148,37 @@ begin
         else
           case coarse_i is
             when x"00" =>
-              rv := "1111000000000000";
+              rv := "11111111000000000000000000000000";
             when x"01" =>
-              rv := "0111100000000000";
+              rv := "01111111100000000000000000000000";
             when x"02" =>
-              rv := "0011110000000000";
+              rv := "00111111110000000000000000000000";
             when x"03" =>
-              rv := "0001111000000000";
+              rv := "00011111111000000000000000000000";
             when x"04" =>
-              rv := "0000111100000000";
+              rv := "00001111111100000000000000000000";
             when x"05" =>
-              rv := "0000011110000000";
+              rv := "00000111111110000000000000000000";
             when x"06" =>
-              rv := "0000001111000000";
+              rv := "00000011111111000000000000000000";
             when x"07" =>
-              rv := "0000000111100000";
+              rv := "00000001111111100000000000000000";
+            when x"08" =>
+              rv := "00000000111111110000000000000000";
+            when x"09" =>
+              rv := "00000000011111111000000000000000";
+            when x"0a" =>
+              rv := "00000000001111111100000000000000";
+            when x"0b" =>
+              rv := "00000000000111111110000000000000";
+            when x"0c" =>
+              rv := "00000000000011111111000000000000";
+            when x"0d" =>
+              rv := "00000000000001111111100000000000";
+            when x"0e" =>
+              rv := "00000000000000111111110000000000";
+            when x"0f" =>
+              rv := "00000000000000011111111000000000";
             when others =>
               rv := (others => '0');
           end case;
@@ -159,17 +198,17 @@ begin
       trig_d <= trig_p_i;
 
       if trig_p_i = '1' then
-        par_data <= mask(15 downto 8);
+        par_data <= mask(31 downto 16);
         flip     <= '0';
       elsif trig_d = '1' then
-        par_data <= mask(7 downto 0);
+        par_data <= mask(15 downto 0);
       else
 
         if cont_i = '1' then
           if flip = '1' then
-            par_data <= mask(7 downto 0);
+            par_data <= mask(15 downto 0);
           else
-            par_data <= mask(15 downto 8);
+            par_data <= mask(31 downto 16);
           end if;
         else
           if pol_i = '1' then
@@ -183,6 +222,34 @@ begin
   end process;
 
 
+  p_div_clk : process(clk_ref_i, rst_serdes_i )
+  begin
+    if rst_serdes_i = '1' then
+      clk_ref_div2 <= '0';
+    elsif rising_edge(clk_ref_i) then
+      clk_ref_div2 <= not clk_ref_div2;
+    end if;
+  end process;
+  
+  
+  p_gearbox : process(clk_par_i)
+  begin
+    if rising_edge(clk_par_i) then
+      clk_ref_div2_d0 <= clk_ref_div2;
+      clk_ref_div2_d1 <= clk_ref_div2_d0;
+      gb_sync_p <= clk_ref_div2_d0 xor clk_ref_div2_d1;
+
+      if gb_sync_p = '1' then
+        par_data_125 <= par_data(15 downto 8);
+      else
+        par_data_125 <= par_data(7 downto 0);
+      end if;
+    end if;
+  end process;
+  
+
+  
+
     U_Serdes : OSERDESE3
       generic map (
         DATA_WIDTH         => 8,
@@ -198,14 +265,14 @@ begin
         OQ     => pulse_o,
         CLK    => clk_serdes_i,
         CLKDIV => clk_par_i,
-        D(0)      => par_data(7),
-        D(1)      => par_data(6),
-        D(2)      => par_data(5),
-        D(3)      => par_data(4),
-        D(4)      => par_data(3),
-        D(5)      => par_data(2),
-        D(6)      => par_data(1),
-        D(7)      => par_data(0),
+        D(0)      => par_data_125(7),
+        D(1)      => par_data_125(6),
+        D(2)      => par_data_125(5),
+        D(3)      => par_data_125(4),
+        D(4)      => par_data_125(3),
+        D(5)      => par_data_125(2),
+        D(6)      => par_data_125(1),
+        D(7)      => par_data_125(0),
         RST    => rst_serdes_i,
         T => '0'
    );
diff --git a/modules/wishbone/wb_fine_pulse_gen/fine_pulse_gen_kintexultrascale_shared.vhd b/modules/wishbone/wb_fine_pulse_gen/fine_pulse_gen_kintexultrascale_shared.vhd
index 5f1fa366..64da9c25 100644
--- a/modules/wishbone/wb_fine_pulse_gen/fine_pulse_gen_kintexultrascale_shared.vhd
+++ b/modules/wishbone/wb_fine_pulse_gen/fine_pulse_gen_kintexultrascale_shared.vhd
@@ -136,6 +136,7 @@ architecture rtl of fine_pulse_gen_kintexultrascale_shared is
   end component BUFG;
 
   signal clk_ser_prebuf, mmcm_clk_fb_prebuf, mmcm_clk_fb : std_logic;
+  signal clk_par_prebuf : std_logic;
 
 begin
 
@@ -165,10 +166,14 @@ begin
         CLKFBOUT_PHASE       => 0.0,  -- Phase offset in degrees of CLKFB (-360.000-360.000)
         CLKFBOUT_USE_FINE_PS => "FALSE",
 
-        CLKOUT0_DIVIDE_F    => 4.0,     -- clk_ser: 250 MHz
+        CLKOUT0_DIVIDE_F    => 2.0,     -- clk_ser: 500 MHz
         CLKOUT0_DUTY_CYCLE  => 0.5,
         CLKOUT0_PHASE       => 0.0,
-        CLKOUT0_USE_FINE_PS => "FALSE"
+        CLKOUT1_DIVIDE    =>   8,     -- clk_par: 125 MHz
+        CLKOUT1_DUTY_CYCLE  => 0.5,
+        CLKOUT1_PHASE       => 0.0,
+        CLKOUT0_USE_FINE_PS => "FALSE",
+        CLKOUT1_USE_FINE_PS => "FALSE"
         )
       port map (
         -- Clock Inputs inputs: Clock inputs
@@ -176,6 +181,7 @@ begin
         CLKIN2   => '0',
         -- Clock Outputs outputs: User configurable clock outputs
         CLKOUT0  => clk_ser_prebuf,
+        CLKOUT1  => clk_par_prebuf,
         -- Feedback
         CLKFBOUT => mmcm_clk_fb_prebuf,
         CLKFBIN  => mmcm_clk_fb,
@@ -208,7 +214,10 @@ begin
         I => clk_ser_prebuf,
         O => clk_ser_o);
 
-    clk_par_o <= clk_ref_i;
+    u_buf_mmcm_par : BUFG
+      port map (
+        I => clk_par_prebuf,
+        O => clk_par_o);
 
   end generate gen_use_int_serdes_clock;
 
diff --git a/modules/wishbone/wb_fine_pulse_gen/xwb_fine_pulse_gen.vhd b/modules/wishbone/wb_fine_pulse_gen/xwb_fine_pulse_gen.vhd
index db8cf11a..c7b0c27a 100644
--- a/modules/wishbone/wb_fine_pulse_gen/xwb_fine_pulse_gen.vhd
+++ b/modules/wishbone/wb_fine_pulse_gen/xwb_fine_pulse_gen.vhd
@@ -427,6 +427,7 @@ begin
         g_use_odelay => f_to_bool(g_use_odelay(i)) )
       port map (
         clk_par_i    => clk_par,
+        clk_ref_i => clk_ref_i,
         clk_serdes_i => clk_ser,
         rst_serdes_i => regs_out.csr_serdes_rst_o,
         rst_sys_n_i  => rst_sys_n_i,
diff --git a/testbench/wishbone/wb_fine_pulse_gen/main.sv b/testbench/wishbone/wb_fine_pulse_gen/main.sv
index 7a061ffb..a1ef59d0 100644
--- a/testbench/wishbone/wb_fine_pulse_gen/main.sv
+++ b/testbench/wishbone/wb_fine_pulse_gen/main.sv
@@ -43,8 +43,8 @@ class DDSSyncUnitDriver;
       
       
       int coarse_par = int'($floor (delta / 16.0));
-      int coarse_ser = int'($floor (delta / 2.0) - coarse_par * 8);
-      int fine = int'((delta / 2.0 - $floor(delta / 2.0)) * 2.0 / tap_size);
+      int coarse_ser = int'($floor (delta / 1.0) - coarse_par * 16);
+      int fine = int'((delta / 1.0 - $floor(delta / 1.0)) * 1.0 / tap_size);
       int mask = coarse_ser;
  //(1 << (7-coarse_ser+1)) - 1;
       uint32_t ocr;
@@ -149,7 +149,7 @@ module main;
 	       first_delay = dly;
 
 
-	     $display("t_pps %t t_pulse %t delta %d", t_pps, t_pulse, (t_pulse - t_pps) / 1ns );
+	     $display("t_pps %t t_pulse %t delta %.2f", t_pps, t_pulse, real'(t_pulse - t_pps) / real'(1ns) );
 	     
 	     
 /*	     delta = dly-first_delay;
@@ -173,14 +173,14 @@ module main;
    xwb_fine_pulse_gen
      #(
        .g_target_platform("KintexUltrascale"),
-       .g_use_external_serdes_clock(1),
+       .g_use_external_serdes_clock(0),
        .g_num_channels(1)
        )
    DUT
      (
       .rst_sys_n_i(rst_n),
 
-      .clk_ser_ext_i(clk_250m),
+//      .clk_ser_ext_i(clk_250m),
       .clk_sys_i (clk_62m5),
       .clk_ref_i (clk_62m5),
       
@@ -222,12 +222,12 @@ module main;
  -----/\----- EXCLUDED -----/\----- */
 
 
-      for (t = 1.0; t <= 200.9; t+=1.0)
+      for (t = 1.0; t <= 200.9; t+=0.1)
 	begin
 //	   $display("Pulse @ %f", t );
 	   
 	   dlys.push_back(t);
-	   drv.pulse(0, 0, 0, t);
+	   drv.pulse(0, 1, 0, t);
 	end
       
       
-- 
GitLab