diff --git a/boards/uniboard2b/designs/unb2b_minimal/quartus/qsys_unb2b_minimal.qsys b/boards/uniboard2b/designs/unb2b_minimal/quartus/qsys_unb2b_minimal.qsys
index dd4df7f0e7d6fe053ba6e65666bf8128aa983aa0..fa55630a3f4ea6599badd3466dd0bc36e2a091ab 100644
--- a/boards/uniboard2b/designs/unb2b_minimal/quartus/qsys_unb2b_minimal.qsys
+++ b/boards/uniboard2b/designs/unb2b_minimal/quartus/qsys_unb2b_minimal.qsys
@@ -78,7 +78,7 @@
    {
       datum baseAddress
       {
-         value = "952";
+         value = "960";
          type = "String";
       }
    }
@@ -120,7 +120,7 @@
       }
       datum sopceditor_expanded
       {
-         value = "0";
+         value = "1";
          type = "boolean";
       }
    }
@@ -128,7 +128,7 @@
    {
       datum baseAddress
       {
-         value = "944";
+         value = "912";
          type = "String";
       }
    }
@@ -202,7 +202,7 @@
    {
       datum baseAddress
       {
-         value = "936";
+         value = "952";
          type = "String";
       }
    }
@@ -223,7 +223,7 @@
    {
       datum baseAddress
       {
-         value = "928";
+         value = "944";
          type = "String";
       }
    }
@@ -273,7 +273,7 @@
       }
       datum sopceditor_expanded
       {
-         value = "1";
+         value = "0";
          type = "boolean";
       }
    }
@@ -302,7 +302,7 @@
    {
       datum baseAddress
       {
-         value = "920";
+         value = "936";
          type = "String";
       }
    }
@@ -323,7 +323,7 @@
    {
       datum baseAddress
       {
-         value = "912";
+         value = "928";
          type = "String";
       }
    }
@@ -4067,7 +4067,7 @@
                     <consumedSystemInfos>
                         <entry>
                             <key>ADDRESS_MAP</key>
-                            <value>&lt;address-map&gt;&lt;slave name='pio_system_info.mem' start='0x0' end='0x80' datawidth='32' /&gt;&lt;slave name='avs_eth_0.mms_reg' start='0x80' end='0xC0' datawidth='32' /&gt;&lt;slave name='reg_fpga_voltage_sens.mem' start='0xC0' end='0x100' datawidth='32' /&gt;&lt;slave name='reg_unb_pmbus.mem' start='0x100' end='0x200' datawidth='32' /&gt;&lt;slave name='reg_unb_sens.mem' start='0x200' end='0x300' datawidth='32' /&gt;&lt;slave name='timer_0.s1' start='0x300' end='0x320' datawidth='16' /&gt;&lt;slave name='reg_fpga_temp_sens.mem' start='0x320' end='0x340' datawidth='32' /&gt;&lt;slave name='reg_epcs.mem' start='0x340' end='0x360' datawidth='32' /&gt;&lt;slave name='reg_remu.mem' start='0x360' end='0x380' datawidth='32' /&gt;&lt;slave name='pio_wdi.s1' start='0x380' end='0x390' datawidth='32' /&gt;&lt;slave name='reg_mmdp_data.mem' start='0x390' end='0x398' datawidth='32' /&gt;&lt;slave name='reg_mmdp_ctrl.mem' start='0x398' end='0x3A0' datawidth='32' /&gt;&lt;slave name='reg_dpmm_data.mem' start='0x3A0' end='0x3A8' datawidth='32' /&gt;&lt;slave name='reg_dpmm_ctrl.mem' start='0x3A8' end='0x3B0' datawidth='32' /&gt;&lt;slave name='pio_pps.mem' start='0x3B0' end='0x3B8' datawidth='32' /&gt;&lt;slave name='jtag_uart_0.avalon_jtag_slave' start='0x3B8' end='0x3C0' datawidth='32' /&gt;&lt;slave name='avs_eth_0.mms_tse' start='0x1000' end='0x2000' datawidth='32' /&gt;&lt;slave name='avs_eth_0.mms_ram' start='0x2000' end='0x3000' datawidth='32' /&gt;&lt;slave name='reg_wdi.mem' start='0x3000' end='0x3008' datawidth='32' /&gt;&lt;slave name='ram_scrap.mem' start='0x3800' end='0x4000' datawidth='32' /&gt;&lt;slave name='cpu_0.debug_mem_slave' start='0x4000' end='0x4800' datawidth='32' /&gt;&lt;slave name='rom_system_info.mem' start='0x10000' end='0x18000' datawidth='32' /&gt;&lt;slave name='onchip_memory2_0.s1' start='0x20000' end='0x40000' datawidth='32' /&gt;&lt;/address-map&gt;</value>
+                            <value>&lt;address-map&gt;&lt;slave name='pio_system_info.mem' start='0x0' end='0x80' datawidth='32' /&gt;&lt;slave name='avs_eth_0.mms_reg' start='0x80' end='0xC0' datawidth='32' /&gt;&lt;slave name='reg_fpga_voltage_sens.mem' start='0xC0' end='0x100' datawidth='32' /&gt;&lt;slave name='reg_unb_pmbus.mem' start='0x100' end='0x200' datawidth='32' /&gt;&lt;slave name='reg_unb_sens.mem' start='0x200' end='0x300' datawidth='32' /&gt;&lt;slave name='timer_0.s1' start='0x300' end='0x320' datawidth='16' /&gt;&lt;slave name='reg_fpga_temp_sens.mem' start='0x320' end='0x340' datawidth='32' /&gt;&lt;slave name='reg_epcs.mem' start='0x340' end='0x360' datawidth='32' /&gt;&lt;slave name='reg_remu.mem' start='0x360' end='0x380' datawidth='32' /&gt;&lt;slave name='pio_wdi.s1' start='0x380' end='0x390' datawidth='32' /&gt;&lt;slave name='pio_pps.mem' start='0x390' end='0x3A0' datawidth='32' /&gt;&lt;slave name='reg_mmdp_data.mem' start='0x3A0' end='0x3A8' datawidth='32' /&gt;&lt;slave name='reg_mmdp_ctrl.mem' start='0x3A8' end='0x3B0' datawidth='32' /&gt;&lt;slave name='reg_dpmm_data.mem' start='0x3B0' end='0x3B8' datawidth='32' /&gt;&lt;slave name='reg_dpmm_ctrl.mem' start='0x3B8' end='0x3C0' datawidth='32' /&gt;&lt;slave name='jtag_uart_0.avalon_jtag_slave' start='0x3C0' end='0x3C8' datawidth='32' /&gt;&lt;slave name='avs_eth_0.mms_tse' start='0x1000' end='0x2000' datawidth='32' /&gt;&lt;slave name='avs_eth_0.mms_ram' start='0x2000' end='0x3000' datawidth='32' /&gt;&lt;slave name='reg_wdi.mem' start='0x3000' end='0x3008' datawidth='32' /&gt;&lt;slave name='ram_scrap.mem' start='0x3800' end='0x4000' datawidth='32' /&gt;&lt;slave name='cpu_0.debug_mem_slave' start='0x4000' end='0x4800' datawidth='32' /&gt;&lt;slave name='rom_system_info.mem' start='0x10000' end='0x18000' datawidth='32' /&gt;&lt;slave name='onchip_memory2_0.s1' start='0x20000' end='0x40000' datawidth='32' /&gt;&lt;/address-map&gt;</value>
                         </entry>
                         <entry>
                             <key>ADDRESS_WIDTH</key>
@@ -5478,7 +5478,7 @@
                         <name>coe_address_export</name>
                         <role>export</role>
                         <direction>Output</direction>
-                        <width>1</width>
+                        <width>2</width>
                         <lowerBound>0</lowerBound>
                         <vhdlType>STD_LOGIC_VECTOR</vhdlType>
                     </port>
@@ -5542,7 +5542,7 @@
                         <name>avs_mem_address</name>
                         <role>address</role>
                         <direction>Input</direction>
-                        <width>1</width>
+                        <width>2</width>
                         <lowerBound>0</lowerBound>
                         <vhdlType>STD_LOGIC_VECTOR</vhdlType>
                     </port>
@@ -5611,7 +5611,7 @@
                         </entry>
                         <entry>
                             <key>addressSpan</key>
-                            <value>8</value>
+                            <value>16</value>
                         </entry>
                         <entry>
                             <key>addressUnits</key>
@@ -6017,11 +6017,11 @@
                     <suppliedSystemInfos>
                         <entry>
                             <key>ADDRESS_MAP</key>
-                            <value>&lt;address-map&gt;&lt;slave name='mem' start='0x0' end='0x8' datawidth='32' /&gt;&lt;/address-map&gt;</value>
+                            <value>&lt;address-map&gt;&lt;slave name='mem' start='0x0' end='0x10' datawidth='32' /&gt;&lt;/address-map&gt;</value>
                         </entry>
                         <entry>
                             <key>ADDRESS_WIDTH</key>
-                            <value>3</value>
+                            <value>4</value>
                         </entry>
                         <entry>
                             <key>MAX_SLAVE_DATA_WIDTH</key>
@@ -15269,11 +15269,11 @@
                     <suppliedSystemInfos>
                         <entry>
                             <key>ADDRESS_MAP</key>
-                            <value>&lt;address-map&gt;&lt;slave name='mem' start='0x0' end='0x2000' datawidth='32' /&gt;&lt;/address-map&gt;</value>
+                            <value>&lt;address-map&gt;&lt;slave name='mem' start='0x0' end='0x8000' datawidth='32' /&gt;&lt;/address-map&gt;</value>
                         </entry>
                         <entry>
                             <key>ADDRESS_WIDTH</key>
-                            <value>13</value>
+                            <value>15</value>
                         </entry>
                         <entry>
                             <key>MAX_SLAVE_DATA_WIDTH</key>
@@ -16058,7 +16058,7 @@
    version="18.0"
    start="cpu_0.data_master"
    end="jtag_uart_0.avalon_jtag_slave">
-  <parameter name="baseAddress" value="0x03b8" />
+  <parameter name="baseAddress" value="0x03c0" />
  </connection>
  <connection
    kind="avalon"
@@ -16093,7 +16093,7 @@
    version="18.0"
    start="cpu_0.data_master"
    end="pio_pps.mem">
-  <parameter name="baseAddress" value="0x03b0" />
+  <parameter name="baseAddress" value="0x0390" />
  </connection>
  <connection
    kind="avalon"
@@ -16121,28 +16121,28 @@
    version="18.0"
    start="cpu_0.data_master"
    end="reg_dpmm_ctrl.mem">
-  <parameter name="baseAddress" value="0x03a8" />
+  <parameter name="baseAddress" value="0x03b8" />
  </connection>
  <connection
    kind="avalon"
    version="18.0"
    start="cpu_0.data_master"
    end="reg_dpmm_data.mem">
-  <parameter name="baseAddress" value="0x03a0" />
+  <parameter name="baseAddress" value="0x03b0" />
  </connection>
  <connection
    kind="avalon"
    version="18.0"
    start="cpu_0.data_master"
    end="reg_mmdp_ctrl.mem">
-  <parameter name="baseAddress" value="0x0398" />
+  <parameter name="baseAddress" value="0x03a8" />
  </connection>
  <connection
    kind="avalon"
    version="18.0"
    start="cpu_0.data_master"
    end="reg_mmdp_data.mem">
-  <parameter name="baseAddress" value="0x0390" />
+  <parameter name="baseAddress" value="0x03a0" />
  </connection>
  <connection
    kind="avalon"
diff --git a/boards/uniboard2b/designs/unb2b_minimal/src/vhdl/qsys_unb2b_minimal_pkg.vhd b/boards/uniboard2b/designs/unb2b_minimal/src/vhdl/qsys_unb2b_minimal_pkg.vhd
index bf055078658ba689bfd1404f05e8a7f4d0539c62..fdaca584e15cf4cfcae57e3fb3fad11d4988668b 100644
--- a/boards/uniboard2b/designs/unb2b_minimal/src/vhdl/qsys_unb2b_minimal_pkg.vhd
+++ b/boards/uniboard2b/designs/unb2b_minimal/src/vhdl/qsys_unb2b_minimal_pkg.vhd
@@ -50,7 +50,7 @@ PACKAGE qsys_unb2b_minimal_pkg IS
             avs_eth_0_tse_write_export         : out std_logic;                                        -- export
             avs_eth_0_tse_writedata_export     : out std_logic_vector(31 downto 0);                    -- export
             clk_clk                            : in  std_logic                     := 'X';             -- clk
-            pio_pps_address_export             : out std_logic_vector(0 downto 0);                     -- export
+            pio_pps_address_export             : out std_logic_vector(1 downto 0);                     -- export
             pio_pps_clk_export                 : out std_logic;                                        -- export
             pio_pps_read_export                : out std_logic;                                        -- export
             pio_pps_readdata_export            : in  std_logic_vector(31 downto 0) := (others => 'X'); -- export
diff --git a/boards/uniboard2b/libraries/unb2b_board/src/vhdl/unb2b_board_peripherals_pkg.vhd b/boards/uniboard2b/libraries/unb2b_board/src/vhdl/unb2b_board_peripherals_pkg.vhd
index 68a57ffd73a5cdb997b3d3f8dfcf9990f64a5aad..47d0e1390b2e2ce81898ee294cf60bf51078c686 100644
--- a/boards/uniboard2b/libraries/unb2b_board/src/vhdl/unb2b_board_peripherals_pkg.vhd
+++ b/boards/uniboard2b/libraries/unb2b_board/src/vhdl/unb2b_board_peripherals_pkg.vhd
@@ -165,7 +165,7 @@ PACKAGE unb2b_board_peripherals_pkg IS
     reg_unb_pmbus_adr_w        : NATURAL;  -- = 6
   END RECORD;
   
-  CONSTANT c_unb2b_board_peripherals_mm_reg_default    : t_c_unb2b_board_peripherals_mm_reg := (TRUE, 10, 4, 10, 5, 13, 1, 1, 6, 1, 1, 1, 1, 1, 3, 3, 3, 16, 4, 6, 2, 2, 1, 4, 3, 6, 13, 12, 2, 32, 8, 2, 8, 10, 16, 1024, 14, 5, 3, 11, 2, 3, 5, 16, 11, 3, 1, 3, 4, 6);
+  CONSTANT c_unb2b_board_peripherals_mm_reg_default    : t_c_unb2b_board_peripherals_mm_reg := (TRUE, 10, 4, 10, 5, 13, 1, 2, 6, 1, 1, 1, 1, 1, 3, 3, 3, 16, 4, 6, 2, 2, 1, 4, 3, 6, 13, 12, 2, 32, 8, 2, 8, 10, 16, 1024, 14, 5, 3, 11, 2, 3, 5, 16, 11, 3, 1, 3, 4, 6);
   
 END unb2b_board_peripherals_pkg;
 
diff --git a/libraries/base/common/src/vhdl/common_interval_monitor.vhd b/libraries/base/common/src/vhdl/common_interval_monitor.vhd
index 6bfdba86062b8e11cadb8c044876eafccc7310ff..03342546aa7430be58d7e93e4dbfae9266fd1573 100644
--- a/libraries/base/common/src/vhdl/common_interval_monitor.vhd
+++ b/libraries/base/common/src/vhdl/common_interval_monitor.vhd
@@ -41,14 +41,15 @@ ENTITY common_interval_monitor IS
     in_val        : IN  STD_LOGIC := '1';
     in_evt        : IN  STD_LOGIC;
     -- MM
-    interval_cnt  : OUT STD_LOGIC_VECTOR(g_interval_cnt_w-1 DOWNTO 0)
+    interval_cnt  : OUT STD_LOGIC_VECTOR(g_interval_cnt_w-1 DOWNTO 0);
+    clk_cnt       : OUT STD_LOGIC_VECTOR(g_interval_cnt_w-1 DOWNTO 0)
   );
 END common_interval_monitor;
 
 
 ARCHITECTURE rtl OF common_interval_monitor IS
 
-  SIGNAL clk_cnt          : STD_LOGIC_VECTOR(interval_cnt'RANGE);
+  SIGNAL i_clk_cnt        : STD_LOGIC_VECTOR(interval_cnt'RANGE);
   SIGNAL nxt_clk_cnt      : STD_LOGIC_VECTOR(interval_cnt'RANGE);
   SIGNAL i_interval_cnt   : STD_LOGIC_VECTOR(interval_cnt'RANGE);
   SIGNAL nxt_interval_cnt : STD_LOGIC_VECTOR(interval_cnt'RANGE);
@@ -56,34 +57,35 @@ ARCHITECTURE rtl OF common_interval_monitor IS
 BEGIN
 
   interval_cnt <= i_interval_cnt;
+  clk_cnt      <= i_clk_cnt;
 
   p_clk: PROCESS(clk, rst)
   BEGIN
     IF rst='1' THEN
-      clk_cnt        <= (OTHERS=>'1');
+      i_clk_cnt        <= (OTHERS=>'1');
       i_interval_cnt <= (OTHERS=>'1');
     ELSIF rising_edge(clk) THEN
-      clk_cnt        <= nxt_clk_cnt;
+      i_clk_cnt        <= nxt_clk_cnt;
       i_interval_cnt <= nxt_interval_cnt;
     END IF;
   END PROCESS;
 
-  p_counter : PROCESS(clk_cnt, i_interval_cnt, in_evt, in_val)
+  p_counter : PROCESS(i_clk_cnt, i_interval_cnt, in_evt, in_val)
   BEGIN
-    nxt_clk_cnt      <= clk_cnt;
+    nxt_clk_cnt      <= i_clk_cnt;
     nxt_interval_cnt <= i_interval_cnt;
     
     IF in_evt='1' THEN
-      -- If there is an in_evt pulse, then capture the clk_cnt into interval_cnt and restart clk_cnt
+      -- If there is an in_evt pulse, then capture the i_clk_cnt into interval_cnt and restart i_clk_cnt
       nxt_clk_cnt      <= (OTHERS=>'0');
-      nxt_interval_cnt <= INCR_UVEC(clk_cnt, 1);
-    ELSIF SIGNED(clk_cnt)=-1 THEN
-      -- If there occur no in_evt pulses, then clk_cnt will eventually stop at maximum (= -1)
+      nxt_interval_cnt <= INCR_UVEC(i_clk_cnt, 1);
+    ELSIF SIGNED(i_clk_cnt)=-1 THEN
+      -- If there occur no in_evt pulses, then i_clk_cnt will eventually stop at maximum (= -1)
       nxt_clk_cnt      <= (OTHERS=>'1');
       nxt_interval_cnt <= (OTHERS=>'1');
     ELSIF in_val='1' THEN
       -- Increment for valid clk cycles
-      nxt_clk_cnt <= INCR_UVEC(clk_cnt, 1);
+      nxt_clk_cnt <= INCR_UVEC(i_clk_cnt, 1);
     END IF;
   END PROCESS;
   
diff --git a/libraries/io/ppsh/ppsh.peripheral.yaml b/libraries/io/ppsh/ppsh.peripheral.yaml
index c6af948356d4b093cc19e9d5eace4ccf7571eb51..f3b7cd60ae05e8705cd514d890b861324aea573c 100644
--- a/libraries/io/ppsh/ppsh.peripheral.yaml
+++ b/libraries/io/ppsh/ppsh.peripheral.yaml
@@ -25,6 +25,9 @@ peripherals:
           - - field_name    : control
               address_offset: 0x4
               field_description: " ppsh control "
+          - - field_name    : offset
+              address_offset: 0x8
+              field_description: " ppsh offset count "
         slave_discription: " "
     
     peripheral_description: |
@@ -38,5 +41,7 @@ peripherals:
          |toggle[31], stable[30]   xxx                       capture_cnt = [29:0]|  0 |
          |-----------------------------------------------------------------------|----|
          |edge[31],                xxx                      expected_cnt = [29:0]|  1 |
+         |-----------------------------------------------------------------------|----|
+         |                         xxx                        offset_cnt = [29:0]|  2 |
          +----------------------------------------------------------------------------+"
     
diff --git a/libraries/io/ppsh/src/vhdl/mms_ppsh.vhd b/libraries/io/ppsh/src/vhdl/mms_ppsh.vhd
index 407223ebefa07cf14118ebb415bf87e17cbf06af..b9a44ad727df7423db06f33781fcbfddcd027c2d 100644
--- a/libraries/io/ppsh/src/vhdl/mms_ppsh.vhd
+++ b/libraries/io/ppsh/src/vhdl/mms_ppsh.vhd
@@ -65,6 +65,7 @@ ARCHITECTURE str OF mms_ppsh IS
   SIGNAL st_pps_toggle      : STD_LOGIC;
   SIGNAL st_pps_stable      : STD_LOGIC;
   SIGNAL st_capture_cnt     : STD_LOGIC_VECTOR(ceil_log2(g_st_clk_freq)-1 DOWNTO 0);  -- counts the number of clk clock cycles between subsequent pps_ext pulses
+  SIGNAL st_offset_cnt      : STD_LOGIC_VECTOR(ceil_log2(g_st_clk_freq)-1 DOWNTO 0);  -- counts the number of clk clock cycles between now and last pps_ext pulse
   
   SIGNAL st_pps_stable_ack  : STD_LOGIC;
   
@@ -96,6 +97,7 @@ BEGIN
     pps_toggle       => st_pps_toggle,
     pps_stable       => st_pps_stable,
     capture_cnt      => st_capture_cnt,
+    offset_cnt       => st_offset_cnt,
     pps_stable_ack   => st_pps_stable_ack,
     capture_edge     => st_capture_edge,
     expected_cnt     => st_expected_cnt
@@ -126,6 +128,7 @@ BEGIN
     st_pps_stable       => st_pps_stable,
     st_pps_stable_ack   => st_pps_stable_ack,
     st_capture_cnt      => st_capture_cnt,
+    st_offset_cnt       => st_offset_cnt,
     st_capture_edge     => st_capture_edge,
     st_expected_cnt     => st_expected_cnt
   );
diff --git a/libraries/io/ppsh/src/vhdl/ppsh.vhd b/libraries/io/ppsh/src/vhdl/ppsh.vhd
index 9a6332cdd961f9006dc1aa9d7dd1b95f7c0342d6..eb9dc3991bc07bdc52047bc83ff0b70ca0e0e026 100644
--- a/libraries/io/ppsh/src/vhdl/ppsh.vhd
+++ b/libraries/io/ppsh/src/vhdl/ppsh.vhd
@@ -68,6 +68,7 @@ ENTITY ppsh IS
     pps_toggle     : OUT STD_LOGIC;           -- pps toggle level signal in clk domain (i.e. 0.5 Hz square wave)
     pps_stable     : OUT STD_LOGIC;           -- pps stable signal in clk domain
     capture_cnt    : OUT STD_LOGIC_VECTOR(ceil_log2(g_clk_freq)-1 DOWNTO 0);  -- counts the number of clk clock cycles between subsequent pps_ext pulses
+    offset_cnt     : OUT STD_LOGIC_VECTOR(ceil_log2(g_clk_freq)-1 DOWNTO 0);  -- counts the number of clk clock cycles between now and last pps_ext pulse
     pps_stable_ack : IN  STD_LOGIC := '0';    -- pps stable acknowledge in clk domain
     capture_edge   : IN  STD_LOGIC := '0';                                    -- when '0' then clock pps_ext on rising edge of clk, else use falling edge of clk
     expected_cnt   : IN  STD_LOGIC_VECTOR(ceil_log2(g_clk_freq)-1 DOWNTO 0) := (OTHERS=> '1') -- expected number of clk clock cycles between subsequent pps_ext pulses
@@ -102,7 +103,7 @@ ARCHITECTURE rtl OF ppsh IS
 BEGIN
 
   capture_cnt <= i_capture_cnt;
-  pps_toggle <= i_pps_toggle;
+  pps_toggle  <= i_pps_toggle;
 
   pps_ext_delayed(0) <= pps_ext;  -- no input delay support
   
@@ -171,7 +172,8 @@ BEGIN
     in_val        => '1',
     in_evt        => pps_ext_revt,
     -- MM
-    interval_cnt  => i_capture_cnt
+    interval_cnt  => i_capture_cnt,
+    clk_cnt       => offset_cnt
   );
   
   -- Output the pps_sys with extra pipelining to ease timing of pps_sys fan out
diff --git a/libraries/io/ppsh/src/vhdl/ppsh_reg.vhd b/libraries/io/ppsh/src/vhdl/ppsh_reg.vhd
index 51efde2ff71ddcd645f5445a3b39a4e1197137a7..31789f7f36f640e0344ecb210d18011c69bda76c 100644
--- a/libraries/io/ppsh/src/vhdl/ppsh_reg.vhd
+++ b/libraries/io/ppsh/src/vhdl/ppsh_reg.vhd
@@ -31,6 +31,23 @@
 --  |-----------------------------------------------------------------------|
 --  |edge[31],                xxx                       expected_cnt = [n:0]|  1
 --  |-----------------------------------------------------------------------|
+--  |                         xxx                         offset_cnt = [n:0]|  2
+--  |-----------------------------------------------------------------------|
+
+
+-- Info from L2SDP-78 ticket.
+-- Add a new offset_cnt field to the PPSH register that reports the current capture_cnt value at the moment that this MM read access occurs.
+-- The offset_cnt reports the time since last PPSH in units of the dp_clk, so 5 ns (at 200MHz). The host can use this offset_cnt value to
+-- determine the alignment between its local Time of Day and the PPS in the FPGA.
+-- 
+-- The offset_cnt needs to be supported in the pi_ppsh.py and util_ppsh.py. Please also use the option --rep to quickly repeat the reading
+-- of the PPSH registers. This is useful to show that the offset_cnt increases and then restarts after every new PPS. The PPS in the FPGA is
+-- also represented by the pps_toggle field in the PPSH registers.
+-- 
+-- The PPSH is part of unb2_minimal. To fit the PPSH register the span in QSYS and in the mmm file needs to be increased from 2 words to 4 words.
+--  
+-- Also prepare unb2c_minimal by updating the PPSH register span there.
+
 
 LIBRARY IEEE, common_lib;
 USE IEEE.STD_LOGIC_1164.ALL;
@@ -57,6 +74,7 @@ ENTITY ppsh_reg IS
     st_pps_toggle     : IN  STD_LOGIC;
     st_pps_stable     : IN  STD_LOGIC;
     st_capture_cnt    : IN  STD_LOGIC_VECTOR(ceil_log2(g_st_clk_freq)-1 DOWNTO 0);  -- counts the number of clk clock cycles between subsequent pps_ext pulses
+    st_offset_cnt     : IN  STD_LOGIC_VECTOR(ceil_log2(g_st_clk_freq)-1 DOWNTO 0);  -- counts the number of clk clock cycles between now and last pps_ext pulse
     
     st_pps_stable_ack : OUT STD_LOGIC;
     
@@ -70,9 +88,9 @@ ARCHITECTURE rtl OF ppsh_reg IS
 
   -- Define the actual size of the MM slave register
   CONSTANT c_mm_reg : t_c_mem := (latency  => 1,
-                                  adr_w    => ceil_log2(2),
+                                  adr_w    => ceil_log2(4),
                                   dat_w    => c_word_w,       -- Use MM bus data width = c_word_w = 32 for all MM registers
-                                  nof_dat  => 2,
+                                  nof_dat  => 4,
                                   init_sl  => '0');
                                                
   -- Register access control signal in mm_clk domain
@@ -85,6 +103,7 @@ ARCHITECTURE rtl OF ppsh_reg IS
   
   SIGNAL mm_capture_cnt    : STD_LOGIC_VECTOR(ceil_log2(g_st_clk_freq)-1 DOWNTO 0);
   SIGNAL mm_expected_cnt   : STD_LOGIC_VECTOR(ceil_log2(g_st_clk_freq)-1 DOWNTO 0);
+  SIGNAL mm_offset_cnt     : STD_LOGIC_VECTOR(ceil_log2(g_st_clk_freq)-1 DOWNTO 0);
     
 BEGIN
 
@@ -139,6 +158,9 @@ BEGIN
             -- Read back PPSH control
             sla_out.rddata(31)          <= mm_capture_edge;
             sla_out.rddata(29 DOWNTO 0) <= RESIZE_UVEC(mm_expected_cnt, 30);
+          WHEN 2 =>
+            -- Read PPSH offset count
+            sla_out.rddata(29 DOWNTO 0) <= RESIZE_UVEC(mm_offset_cnt, 30);
           WHEN OTHERS => NULL;  -- not used MM addresses
         END CASE;
       END IF;
@@ -166,6 +188,7 @@ BEGIN
     mm_pps_toggle      <= st_pps_toggle;
     mm_pps_stable      <= st_pps_stable;
     mm_capture_cnt     <= st_capture_cnt;
+    mm_offset_cnt      <= st_offset_cnt;
     
     st_pps_stable_ack  <= mm_pps_stable_ack;
     
@@ -209,6 +232,18 @@ BEGIN
       out_new     => OPEN
     );
 
+    u_offset_cnt : ENTITY common_lib.common_reg_cross_domain
+    PORT MAP (
+      in_rst      => st_rst,
+      in_clk      => st_clk,
+      in_dat      => st_offset_cnt,
+      in_done     => OPEN,
+      out_rst     => mm_rst,
+      out_clk     => mm_clk,
+      out_dat     => mm_offset_cnt,
+      out_new     => OPEN
+    );
+
     -- MM --> ST
     u_pps_stable_ack : ENTITY common_lib.common_spulse
     PORT MAP (
diff --git a/libraries/io/ppsh/tb/vhdl/tb_mms_ppsh.vhd b/libraries/io/ppsh/tb/vhdl/tb_mms_ppsh.vhd
index e6894f64e14e00b7fed5826306882d7aeae971fe..39e21de98a90bb33568d11fbeed94e304dc52444 100644
--- a/libraries/io/ppsh/tb/vhdl/tb_mms_ppsh.vhd
+++ b/libraries/io/ppsh/tb/vhdl/tb_mms_ppsh.vhd
@@ -35,37 +35,39 @@ ARCHITECTURE tb OF tb_mms_ppsh IS
   CONSTANT c_clk_freq     : NATURAL := 1000;                  -- clock frequency in Hz
   CONSTANT c_clk_period   : TIME    := 1000000 us / c_clk_freq;
   CONSTANT c_pps_period   : NATURAL := c_clk_freq;            -- 1 s takes c_clk_freq clk cycles
-  
+
   SIGNAL tb_end           : STD_LOGIC := '0';
   SIGNAL rst              : STD_LOGIC := '1';
   SIGNAL clk              : STD_LOGIC := '1';
-  
+
   -- DUT
   SIGNAL pps_ext          : STD_LOGIC;
   SIGNAL pps_sys          : STD_LOGIC;
-  
+
   SIGNAL reg_mosi         : t_mem_mosi := c_mem_mosi_rst;
   SIGNAL reg_miso         : t_mem_miso;
-  
+
   -- Verify
   SIGNAL bsn              : NATURAL;
   SIGNAL pps_toggle       : STD_LOGIC;
   SIGNAL pps_stable       : STD_LOGIC;
   SIGNAL capture_cnt      : NATURAL;
-  
+  SIGNAL offset_cnt       : NATURAL;
+  SIGNAL last_offset_cnt  : NATURAL;
+
 BEGIN
 
   -- Usage:
   -- > as 10
   -- > run -all
   -- p_verify assert when unexpected capture_cnt and pps_stable are read via MM
-  
+
   -----------------------------------------------------------------------------
   -- Stimuli
   -----------------------------------------------------------------------------
   rst <= '1', '0' AFTER 7*c_clk_period;
   clk <= NOT clk OR tb_end AFTER c_clk_period/2;
-  
+
   p_pps_ext : PROCESS
     VARIABLE v_pps_period : NATURAL := c_pps_period;
   BEGIN
@@ -85,42 +87,53 @@ BEGIN
       proc_common_wait_some_cycles(clk, 1);
       pps_ext <= '0';
     END LOOP;
-    
+
     WAIT;
   END PROCESS;
-  
+
   p_mm_stimuli : PROCESS
     VARIABLE v_word : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
   BEGIN
     proc_common_wait_until_low(clk, rst);                      -- Wait until reset has finished
     proc_common_wait_some_cycles(clk, 10);                     -- Wait an additional amount of cycles
-    
+
     v_word := '0' & TO_UVEC(c_pps_period, 31);   -- capture_edge = '0' = at rising edge
                                                  -- expected_cnt = c_pps_period = 1000
     proc_mem_mm_bus_wr(1, v_word, clk, reg_mosi);
-    
+
+
     -- Simulate reading PPS status every 10 PPS periods
     proc_common_wait_some_cycles(clk, 10);
     FOR I IN 0 TO 9 LOOP
       proc_common_wait_some_cycles(clk, c_pps_period*10);
-    
+
       proc_mem_mm_bus_rd(0, clk, reg_mosi);
-      proc_common_wait_some_cycles(clk, 1);   
+      proc_common_wait_some_cycles(clk, 1);
       pps_toggle  <= reg_miso.rddata(31);
       pps_stable  <= reg_miso.rddata(30);
       capture_cnt <= TO_UINT(reg_miso.rddata(ceil_log2(c_clk_freq)-1 DOWNTO 0));
     END LOOP;
-    
+
+    -- Simulate reading PPS offset counter every 0.1 PPS periods
+    proc_common_wait_some_cycles(clk, 10);
+    FOR I IN 0 TO 4 LOOP
+      proc_common_wait_some_cycles(clk, c_pps_period/10);
+      last_offset_cnt <= offset_cnt;
+      proc_mem_mm_bus_rd(2, clk, reg_mosi);
+      proc_common_wait_some_cycles(clk, 1);
+      offset_cnt <= TO_UINT(reg_miso.rddata(ceil_log2(c_clk_freq)-1 DOWNTO 0));
+    END LOOP;
+
     proc_common_wait_some_cycles(clk, 100);
     tb_end <= '1';
     WAIT;
   END PROCESS;
-  
+
   p_verify : PROCESS
   BEGIN
     proc_common_wait_until_low(clk, rst);                      -- Wait until reset has finished
     proc_common_wait_some_cycles(clk, 10);                     -- Wait an additional amount of cycles
-    
+
     proc_common_wait_some_cycles(clk, c_pps_period/2);         -- Verification offset
     -- 1
     proc_common_wait_some_cycles(clk, c_pps_period*10);
@@ -158,14 +171,20 @@ BEGIN
     proc_common_wait_some_cycles(clk, c_pps_period*10);
     ASSERT pps_stable='1'   REPORT "9) Wrong pps_stable" SEVERITY ERROR;
     ASSERT capture_cnt=1000 REPORT "9) Wrong capture_cnt" SEVERITY ERROR;
+    -- 10
+    proc_common_wait_some_cycles(clk, c_pps_period/10);
+    ASSERT offset_cnt=last_offset_cnt REPORT "10) Wrong offset_cnt" SEVERITY ERROR;
+    -- 11
+    proc_common_wait_some_cycles(clk, c_pps_period/10);
+    ASSERT offset_cnt=last_offset_cnt REPORT "11) Wrong offset_cnt" SEVERITY ERROR;
     WAIT;
   END PROCESS;
-  
-  
+
+
   -----------------------------------------------------------------------------
   -- DUT: PPSH
   -----------------------------------------------------------------------------
-  
+
   dut : ENTITY work.mms_ppsh
   GENERIC MAP (
     g_st_clk_freq    => c_clk_freq
@@ -177,11 +196,11 @@ BEGIN
     st_rst           => rst,
     st_clk           => clk,
     pps_ext          => pps_ext,
-    
+
     -- Memory-mapped clock domain
     reg_mosi         => reg_mosi,
     reg_miso         => reg_miso,
-    
+
     -- Streaming clock domain
     pps_sys          => pps_sys
   );
diff --git a/libraries/io/ppsh/tb/vhdl/tb_ppsh.vhd b/libraries/io/ppsh/tb/vhdl/tb_ppsh.vhd
index d3d492961a1ecef4311e535f6e467dd8312e9a85..4887a8489d1df8bb0245cf12ddb2f6c75c31dbca 100644
--- a/libraries/io/ppsh/tb/vhdl/tb_ppsh.vhd
+++ b/libraries/io/ppsh/tb/vhdl/tb_ppsh.vhd
@@ -33,7 +33,7 @@ ARCHITECTURE tb OF tb_ppsh IS
   CONSTANT c_clk_period   : TIME    := 1000000 us / c_clk_freq;
   CONSTANT c_pps_default_period   : NATURAL := c_clk_freq;            -- 1 s takes c_clk_freq clk cycles
   CONSTANT c_pps_skew     : TIME    := 7*c_clk_period/10;
-  
+
   -- The state name tells what kind of test is being done
   TYPE t_state_enum IS (
     s_idle,
@@ -49,31 +49,32 @@ ARCHITECTURE tb OF tb_ppsh IS
   SIGNAL rst              : STD_LOGIC := '1';
   SIGNAL clk              : STD_LOGIC := '1';
   SIGNAL pps              : STD_LOGIC;
-  
+
   -- DUT
   SIGNAL pps_ext          : STD_LOGIC;
   SIGNAL pps_sys          : STD_LOGIC;
   SIGNAL pps_toggle       : STD_LOGIC;
   SIGNAL capture_edge     : STD_LOGIC;
   SIGNAL capture_cnt      : STD_LOGIC_VECTOR(ceil_log2(c_clk_freq)-1 DOWNTO 0);
-  
+  SIGNAL offset_cnt       : STD_LOGIC_VECTOR(ceil_log2(c_clk_freq)-1 DOWNTO 0);
+
   -- Verify
-  
+
 BEGIN
 
   -- Usage: 'run -all', observe unsigned capture_cnt, there should occur no
   --        REPORT errors.
-  
+
   -----------------------------------------------------------------------------
   -- Stimuli
   -----------------------------------------------------------------------------
   rst <= '1', '0' AFTER 7*c_clk_period;
   clk <= NOT clk OR tb_end AFTER c_clk_period/2;
-  
+
   -- Verify that using the falling capture edge indeed does change timing by
   -- using a c_pps_skew that is > 0.5 c_clk_period and < c_clk_period
   capture_edge <= '0', '1' AFTER 5000 ms, '0' AFTER 7000 ms;
-  
+
   -- Verify the capture_cnt
   p_pps_default_period : PROCESS
   BEGIN
@@ -131,7 +132,7 @@ BEGIN
     END LOOP;
     -- Missing PPS pulses
     tb_state <= s_missing_pps;
-    
+
     -- End
     tb_state <= s_end;
     WAIT FOR c_pps_default_period*c_clk_period;
@@ -139,14 +140,14 @@ BEGIN
     WAIT;
   END PROCESS;
 
-  -- Apply some PPS to CLK skew  
+  -- Apply some PPS to CLK skew
   pps_ext <= TRANSPORT pps AFTER c_pps_skew;
-  
-  
+
+
   -----------------------------------------------------------------------------
   -- DUT: PPSH
   -----------------------------------------------------------------------------
-  
+
   dut : ENTITY work.ppsh
   GENERIC MAP (
     g_clk_freq    => c_clk_freq
@@ -160,13 +161,14 @@ BEGIN
     pps_toggle    => pps_toggle,
     -- MM control
     capture_edge  => capture_edge,
-    capture_cnt   => capture_cnt
+    capture_cnt   => capture_cnt,
+    offset_cnt    => offset_cnt
   );
 
   -----------------------------------------------------------------------------
   -- Verify capture_cnt
   -----------------------------------------------------------------------------
-  
+
   -- Simple verify scheme that matches the stimuli from p_pps_default_period
   p_verify : PROCESS(clk)
   BEGIN
@@ -179,69 +181,83 @@ BEGIN
          UNSIGNED(capture_cnt)/=2**capture_cnt'LENGTH-1 THEN
         REPORT "PPSH : Unexpected capture count value." SEVERITY ERROR;
       END IF;
-      
+
       -- Verify influence of PPS capture edge selection
       IF (NOW > 6000 ms) AND (NOW <= 6000 ms + c_clk_period) THEN
         IF UNSIGNED(capture_cnt)/=c_clk_freq+1 THEN
           REPORT "PPSH : Unexpected capture count value at 6 s." SEVERITY ERROR;
         END IF;
       END IF;
-      
+
       IF (NOW > 7000 ms) AND (NOW <= 7000 ms + c_clk_period) THEN
         IF UNSIGNED(capture_cnt)/=c_clk_freq THEN
           REPORT "PPSH : Unexpected capture count value at 7 s." SEVERITY ERROR;
         END IF;
       END IF;
-      
+
       IF (NOW > 8000 ms) AND (NOW <= 8000 ms + c_clk_period) THEN
         IF UNSIGNED(capture_cnt)/=c_clk_freq-1 THEN
           REPORT "PPSH : Unexpected capture count value at 8 s." SEVERITY ERROR;
         END IF;
       END IF;
-      
+
       -- Verify external PPS period fluctuations at specific stimuli moments
       IF (NOW > 10000 ms) AND (NOW <= 10000 ms + c_clk_period) THEN
         IF UNSIGNED(capture_cnt)/=c_clk_freq THEN
           REPORT "PPSH : Unexpected capture count value at 10 s." SEVERITY ERROR;
         END IF;
       END IF;
-      
+
       IF (NOW > 22000 ms) AND (NOW <= 22000 ms + c_clk_period) THEN
         IF UNSIGNED(capture_cnt)/=c_clk_freq-1 THEN
           REPORT "PPSH : Unexpected capture count value at 22 s." SEVERITY ERROR;
         END IF;
       END IF;
-      
+
       IF (NOW > 25000 ms) AND (NOW <= 25000 ms + c_clk_period) THEN
         IF UNSIGNED(capture_cnt)/=c_clk_freq THEN
           REPORT "PPSH : Unexpected capture count value at 25 s." SEVERITY ERROR;
         END IF;
       END IF;
-    
+
       IF (NOW > 28000 ms) AND (NOW <= 28000 ms + c_clk_period) THEN
         IF UNSIGNED(capture_cnt)/=c_clk_freq+1 THEN
           REPORT "PPSH : Unexpected capture count value at 28 s." SEVERITY ERROR;
         END IF;
       END IF;
-      
+
       IF (NOW > 30000 ms) AND (NOW <= 30000 ms + c_clk_period) THEN
         IF UNSIGNED(capture_cnt)/=c_clk_freq THEN
           REPORT "PPSH : Unexpected capture count value at 30 s." SEVERITY ERROR;
         END IF;
       END IF;
-      
+
       IF (NOW > 35000 ms) AND (NOW <= 35000 ms + c_clk_period) THEN
         IF UNSIGNED(capture_cnt)/=2**capture_cnt'LENGTH-1 THEN
           REPORT "PPSH : Unexpected capture count value at 35 s." SEVERITY ERROR;
         END IF;
       END IF;
-      
+
       IF (NOW > 49000 ms) AND (NOW <= 49000 ms + c_clk_period) THEN
         IF UNSIGNED(capture_cnt)/=2**capture_cnt'LENGTH-1 THEN
           REPORT "PPSH : Unexpected capture count value at 49 s." SEVERITY ERROR;
         END IF;
       END IF;
+
+      -- check if offset_cnt is counting
+      IF (NOW > 7500 ms) AND (NOW <= 7500 ms + c_clk_period) THEN
+        IF UNSIGNED(offset_cnt)/=475 THEN
+          REPORT "PPSH : Unexpected offset count value at 5.5 s." SEVERITY ERROR;
+        END IF;
+      END IF;
+
+      IF (NOW > 7700 ms) AND (NOW <= 7700 ms + c_clk_period) THEN
+        IF UNSIGNED(offset_cnt)/=675 THEN
+          REPORT "PPSH : Unexpected offset count value at 5.5 s." SEVERITY ERROR;
+        END IF;
+      END IF;
+
     END IF;
   END PROCESS;
-  
+
 END tb;