Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding FPGA support for hardware timestamp from SFPs #177

Merged
merged 3 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion common/hdl/defines/top_defines.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,17 @@ type SFP_output_interface is
TXP_OUT : std_logic;
MGT_REC_CLK : std_logic;
LINK_UP : std_logic;
TS_SEC : std_logic_vector(31 downto 0);
TS_TICKS : std_logic_vector(31 downto 0);
end record SFP_output_interface;

constant SFP_o_init : SFP_output_interface := (TXN_OUT => 'Z',
TXP_OUT => 'Z',
MGT_REC_CLK => '0',
LINK_UP => '0');
LINK_UP => '0',
TS_SEC => (others => '0'),
TS_TICKS => (others => '0')
);


type seq_t is
Expand Down
6 changes: 6 additions & 0 deletions common/hdl/reg_top.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ port (
bit_bus_i : in bit_bus_t;
pos_bus_i : in pos_bus_t;
SLOW_FPGA_VERSION : in std_logic_vector(31 downto 0);
TS_SEC : in std_logic_vector(31 downto 0);
TS_TICKS : in std_logic_vector(31 downto 0);
-- Output signals
SFP_MAC_ADDR : out std32_array(2*NUM_SFP -1 downto 0) := (others => (others => '1'));
SFP_MAC_ADDR_WSTB : out std_logic_vector(2*NUM_SFP downto 0) := (others => '0');
Expand Down Expand Up @@ -202,6 +204,10 @@ begin
read_data_o <= POS_READ_CHANGES;
when REG_FPGA_CAPABILITIES =>
read_data_o <= FPGA_CAPABILITIES;
when REG_PCAP_TS_SEC =>
read_data_o <= TS_SEC;
when REG_PCAP_TS_TICKS =>
read_data_o <= TS_TICKS;
when others =>
read_data_o <= (others => '0');
end case;
Expand Down
46 changes: 46 additions & 0 deletions common/hdl/ts_mux.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.top_defines.all;
use work.support.all;

entity ts_mux is
generic (
NUM_SFP : natural := 1
);
port (
clk_i : in std_logic;
ts_src_i : in std_logic_vector(LOG2(NUM_SFP) downto 0);
latch_en_i : in std_logic;
ts_sec_i : in std32_array(NUM_SFP-1 downto 0);
ts_ticks_i : in std32_array(NUM_SFP-1 downto 0);
ts_sec_o : out std_logic_vector(31 downto 0);
ts_ticks_o : out std_logic_vector(31 downto 0)
);
end ts_mux;

architecture rtl of ts_mux is

begin

process(clk_i)
begin
if rising_edge(clk_i) then
if latch_en_i then
if unsigned(ts_src_i) = 0 then
ts_sec_o <= (others => '0');
ts_ticks_o <= (others => '0');
elsif unsigned(ts_src_i) <= NUM_SFP then
ts_sec_o <= ts_sec_i(to_integer(unsigned(ts_src_i))-1);
ts_ticks_o <= ts_ticks_i(to_integer(unsigned(ts_src_i))-1);
else
ts_sec_o <= (others => '0');
ts_ticks_o <= (others => '0');
end if;
end if;
end if;
end process;

end rtl;

6 changes: 6 additions & 0 deletions common/templates/registers_server
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ BLOCKS_COMPAT_VERSION = 0
PCAP_START_WRITE 8
PCAP_WRITE 9

# Hardware timestamps
# This starts at unix epoch (UTC)
PCAP_TS_SEC 10
# Ticks since PCAP_TS_SEC was updated
PCAP_TS_TICKS 11

# Position capture control
PCAP_ARM 13
PCAP_DISARM 14
Expand Down
4 changes: 3 additions & 1 deletion modules/pcap/hdl/pcap_top.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ port (
pos_bus_i : in pos_bus_t;
-- Output pulses
pcap_actv_o : out std_logic;
pcap_irq_o : out std_logic
pcap_irq_o : out std_logic;
pcap_start_event_o : out std_logic
);
end pcap_top;

Expand Down Expand Up @@ -124,6 +125,7 @@ signal pos_bus_i_dyd : pos_bus_t; -- pos_bus_i delayed
begin

pcap_actv_o <= pcap_active;
pcap_start_event_o <= pcap_start_event;

--------------------------------------------------------------------------
-- Pcap Block control interface (autogenerated)
Expand Down
25 changes: 8 additions & 17 deletions modules/sfp_eventr/hdl/sfp_dls_eventr_wrapper.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ signal txcharisk_i : std_logic_vector(1 downto 0);
signal bit1,bit2,bit3,bit4 : std_logic;

signal unix_time : std_logic_vector(31 downto 0);
signal unix_time_smpld : std_logic_vector(31 downto 0);
signal unix_time_ticks : std_logic_vector(31 downto 0);
signal err_cnt_smpld : std_logic_vector(31 downto 0);

-- ILA stuff
Expand Down Expand Up @@ -126,6 +126,8 @@ port map (

SFP_o.MGT_REC_CLK <= rxoutclk;
SFP_o.LINK_UP <= LINKUP(0);
SFP_o.TS_SEC <= unix_time;
SFP_o.TS_TICKS <= unix_time_ticks;

bit1_o(0) <= bit1;
bit2_o(0) <= bit2;
Expand All @@ -149,7 +151,7 @@ port map(

sfp_receiver_inst: entity work.sfp_receiver
port map(
clk_i => clk_i,
sysclk_i => clk_i,
event_clk_i => rxoutclk,
reset_i => reset_i,
rxdisperr_i => rxdisperr,
Expand All @@ -171,14 +173,15 @@ port map(
rx_link_ok_o => rx_link_ok_o,
loss_lock_o => loss_lock_o,
rx_error_o => rx_error_o,
utime_o => unix_time
utime_o => unix_time,
utime_ticks_o => unix_time_ticks
);


sfpgtx_event_receiver_inst: entity work.sfp_event_receiver
port map(
GTREFCLK => SFP_i.GTREFCLK,
sysclk_i => clk_i,
sysclk_i => clk_i,
event_reset_i => EVENT_RESET,
rxp_i => SFP_i.RXP_IN,
rxn_i => SFP_i.RXN_IN,
Expand Down Expand Up @@ -260,18 +263,6 @@ port map (
data_o => err_cnt_smpld
);

utime_latch : entity work.latched_sync
generic map (
DWIDTH => 32,
PERIOD => 125 -- 1 MHz for 125 MHz clock
)
port map (
src_clk => rxoutclk,
dest_clk => clk_i,
data_i => unix_time,
data_o => unix_time_smpld
);

---------------------------------------------------------------------------
-- FMC CSR Interface
---------------------------------------------------------------------------
Expand All @@ -284,7 +275,7 @@ port map (
pos_bus_i => pos_bus_i,

LINKUP => LINKUP,
UNIX_TIME => unix_time_smpld,
UNIX_TIME => unix_time,
ERROR_COUNT => err_cnt_smpld,
EVENT_RESET => open,
EVENT_RESET_WSTB => EVENT_RESET,
Expand Down
74 changes: 50 additions & 24 deletions modules/sfp_eventr/hdl/sfp_receiver.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ entity sfp_receiver is

generic (events : natural := 4);

port (clk_i : in std_logic;
port (sysclk_i : in std_logic;
event_clk_i : in std_logic;
reset_i : in std_logic;
rxdisperr_i : in std_logic_vector(1 downto 0);
Expand All @@ -28,7 +28,8 @@ entity sfp_receiver is
bit2_o : out std_logic;
bit3_o : out std_logic;
bit4_o : out std_logic;
utime_o : out std_logic_vector(31 downto 0)
utime_o : out std_logic_vector(31 downto 0);
utime_ticks_o : out std_logic_vector(31 downto 0)
);

end sfp_receiver;
Expand Down Expand Up @@ -131,7 +132,11 @@ signal disable_link_dly, disable_link_edge : std_logic;
signal disable_link_ctr : unsigned(31 downto 0);
signal total_ind_errors : unsigned(31 downto 0);


signal utime : std_logic_vector(31 downto 0);
signal utime_latch_tog : std_logic;
signal reset_event_tog : std_logic := '0';
signal reset_event_tog_sync : std_logic;
signal reset_event_tog_sync_del : std_logic;

begin

Expand Down Expand Up @@ -175,29 +180,50 @@ rx_link_ok_o <= rx_link_ok;
loss_lock_o <= loss_lock;
rx_error_o <= rx_error;

-- Unix time
-- Unix time calc on event clock domain
ps_shift_reg: process(event_clk_i)
begin
if rising_edge(event_clk_i) then
if reset_i = '1' then
-- Shift a '0' into the shift register
if rxdata_i(7 downto 0) = c_code_seconds_0 then
utime_shift_reg <= utime_shift_reg(30 downto 0) & '0';
-- Shift a '1' into the shift register
elsif rxdata_i(7 downto 0) = c_code_seconds_1 then
utime_shift_reg <= utime_shift_reg(30 downto 0) & '1';
-- Shift the unix time out
elsif rxdata_i(7 downto 0) = c_code_reset_event then
utime_shift_reg <= (others => '0');
utime_o <= (others => '0');
else
-- Shift a '0' into the shift register
if rxdata_i(7 downto 0) = c_code_seconds_0 then
utime_shift_reg <= utime_shift_reg(30 downto 0) & '0';
-- Shift a '1' into the shift register
elsif rxdata_i(7 downto 0) = c_code_seconds_1 then
utime_shift_reg <= utime_shift_reg(30 downto 0) & '1';
-- Shift the unix time out
elsif rxdata_i(7 downto 0) = c_code_reset_event then
utime_shift_reg <= (others => '0');
utime_o <= utime_shift_reg;
end if;
end if;
end if;
utime <= utime_shift_reg;
reset_event_tog <= not reset_event_tog;
end if;
end if;
end process ps_shift_reg;

-- synchronise reset event onto system clock
reset_event_sync: entity work.sync_bit
port map(
clk_i => sysclk_i,
bit_i => reset_event_tog,
bit_o => reset_event_tog_sync
);

-- Transfer unix time to system clock and generate fractional part of timestamp
ps_utime_sys: process(sysclk_i)
variable reset_event_tog_edge : std_logic;
variable utime_ticks_ctr : unsigned(31 downto 0); -- allows for up to ~34 seconds between reset events
begin
if rising_edge(sysclk_i) then
reset_event_tog_sync_del <= reset_event_tog_sync;
reset_event_tog_edge := reset_event_tog_sync xor reset_event_tog_sync_del;
if reset_event_tog_edge = '1' then
utime_o <= utime;
utime_ticks_ctr := (others => '0');
else
utime_ticks_ctr := utime_ticks_ctr + 1;
end if;
utime_ticks_o <= std_logic_vector(utime_ticks_ctr);
end if;
end process;

-- Assign the array outputs to individual bits
-- Done this to stop the outputs being high for 2 clocks instead of one
Expand All @@ -215,9 +241,9 @@ bit4_o <= event_bits_meta2(3) and not event_bits_dlyo(3) when EVENT4(8) = '0' el



ps_125MHz: process(clk_i)
ps_125MHz: process(sysclk_i)
begin
if rising_edge(clk_i) then
if rising_edge(sysclk_i) then
lp_meta: for i in 0 to events-1 loop
-- Resynch to the 125MHz domain
event_bits_meta1(i) <= event_bits_stretched(i);
Expand All @@ -229,9 +255,9 @@ end process ps_125MHz;


-- Generate a delay of the strobe to be used to stretch the strobe signal
ps_125MHz_stretched: process(clk_i)
ps_125MHz_stretched: process(sysclk_i)
begin
if rising_edge(clk_i) then
if rising_edge(sysclk_i) then
EVENT1_WSTB_dly <= EVENT1_WSTB;
EVENT2_WSTB_dly <= EVENT2_WSTB;
EVENT3_WSTB_dly <= EVENT3_WSTB;
Expand Down
Loading
Loading