From 6091a9254df9abd19675a3512e8304fd70cc1cb9 Mon Sep 17 00:00:00 2001 From: Manuel Penschuck Date: Mon, 22 Sep 2014 18:16:25 +0200 Subject: [PATCH] CBMNet: First version of sync-module (not fully tested yet), small changes to PHY --- base/txt_util.vhd | 588 ++++++++++++++++++++ cbmnet/code/cbmnet_interface_pkg.vhd | 58 ++ cbmnet/code/cbmnet_phy_ecp3.vhd | 19 +- cbmnet/code/cbmnet_phy_rx_gear.vhd | 12 +- cbmnet/code/cbmnet_phy_tx_gear.vhd | 29 +- cbmnet/code/cbmnet_readout_event_packer.vhd | 212 +++++++ cbmnet/code/cbmnet_sync_module.vhd | 462 +++++++++++++++ cbmnet/code/pos_edge_strech_sync.vhd | 27 + 8 files changed, 1380 insertions(+), 27 deletions(-) create mode 100644 base/txt_util.vhd create mode 100644 cbmnet/code/cbmnet_readout_event_packer.vhd create mode 100644 cbmnet/code/cbmnet_sync_module.vhd create mode 100644 cbmnet/code/pos_edge_strech_sync.vhd diff --git a/base/txt_util.vhd b/base/txt_util.vhd new file mode 100644 index 0000000..db9ac7f --- /dev/null +++ b/base/txt_util.vhd @@ -0,0 +1,588 @@ +-- taken from www.stefanvhdl.com/vhdl/vhdl/txt_util.vhd + +library ieee; +use ieee.std_logic_1164.all; +use std.textio.all; + + +package txt_util is + + -- prints a message to the screen + procedure print(text: string); + + -- prints the message when active + -- useful for debug switches + procedure print(active: boolean; text: string); + + -- converts std_logic into a character + function chr(sl: std_logic) return character; + + -- converts std_logic into a string (1 to 1) + function str(sl: std_logic) return string; + + -- converts std_logic_vector into a string (binary base) + function str(slv: std_logic_vector) return string; + + -- converts boolean into a string + function str(b: boolean) return string; + + -- converts an integer into a single character + -- (can also be used for hex conversion and other bases) + function chr(int: integer) return character; + + -- converts integer into string using specified base + function str(int: integer; base: integer) return string; + + -- converts integer to string, using base 10 + function str(int: integer) return string; + + -- convert std_logic_vector into a string in hex format + function hstr(slv: std_logic_vector) return string; + + + -- functions to manipulate strings + ----------------------------------- + + -- convert a character to upper case + function to_upper(c: character) return character; + + -- convert a character to lower case + function to_lower(c: character) return character; + + -- convert a string to upper case + function to_upper(s: string) return string; + + -- convert a string to lower case + function to_lower(s: string) return string; + + + + -- functions to convert strings into other formats + -------------------------------------------------- + + -- converts a character into std_logic + function to_std_logic(c: character) return std_logic; + + -- converts a string into std_logic_vector + function to_std_logic_vector(s: string) return std_logic_vector; + + + + -- file I/O + ----------- + + -- read variable length string from input file + procedure str_read(file in_file: TEXT; + res_string: out string); + + -- print string to a file and start new line + procedure print(file out_file: TEXT; + new_string: in string); + + -- print character to a file and start new line + procedure print(file out_file: TEXT; + char: in character); + +end txt_util; + + + + +package body txt_util is + + + + + -- prints text to the screen + + procedure print(text: string) is + variable msg_line: line; + begin + write(msg_line, text); + writeline(output, msg_line); + end print; + + + + + -- prints text to the screen when active + + procedure print(active: boolean; text: string) is + begin + if active then + print(text); + end if; + end print; + + + -- converts std_logic into a character + + function chr(sl: std_logic) return character is + variable c: character; + begin + case sl is + when 'U' => c:= 'U'; + when 'X' => c:= 'X'; + when '0' => c:= '0'; + when '1' => c:= '1'; + when 'Z' => c:= 'Z'; + when 'W' => c:= 'W'; + when 'L' => c:= 'L'; + when 'H' => c:= 'H'; + when '-' => c:= '-'; + end case; + return c; + end chr; + + + + -- converts std_logic into a string (1 to 1) + + function str(sl: std_logic) return string is + variable s: string(1 to 1); + begin + s(1) := chr(sl); + return s; + end str; + + + + -- converts std_logic_vector into a string (binary base) + -- (this also takes care of the fact that the range of + -- a string is natural while a std_logic_vector may + -- have an integer range) + + function str(slv: std_logic_vector) return string is + variable result : string (1 to slv'length); + variable r : integer; + begin + r := 1; + for i in slv'range loop + result(r) := chr(slv(i)); + r := r + 1; + end loop; + return result; + end str; + + + function str(b: boolean) return string is + + begin + if b then + return "true"; + else + return "false"; + end if; + end str; + + + -- converts an integer into a character + -- for 0 to 9 the obvious mapping is used, higher + -- values are mapped to the characters A-Z + -- (this is usefull for systems with base > 10) + -- (adapted from Steve Vogwell's posting in comp.lang.vhdl) + + function chr(int: integer) return character is + variable c: character; + begin + case int is + when 0 => c := '0'; + when 1 => c := '1'; + when 2 => c := '2'; + when 3 => c := '3'; + when 4 => c := '4'; + when 5 => c := '5'; + when 6 => c := '6'; + when 7 => c := '7'; + when 8 => c := '8'; + when 9 => c := '9'; + when 10 => c := 'A'; + when 11 => c := 'B'; + when 12 => c := 'C'; + when 13 => c := 'D'; + when 14 => c := 'E'; + when 15 => c := 'F'; + when 16 => c := 'G'; + when 17 => c := 'H'; + when 18 => c := 'I'; + when 19 => c := 'J'; + when 20 => c := 'K'; + when 21 => c := 'L'; + when 22 => c := 'M'; + when 23 => c := 'N'; + when 24 => c := 'O'; + when 25 => c := 'P'; + when 26 => c := 'Q'; + when 27 => c := 'R'; + when 28 => c := 'S'; + when 29 => c := 'T'; + when 30 => c := 'U'; + when 31 => c := 'V'; + when 32 => c := 'W'; + when 33 => c := 'X'; + when 34 => c := 'Y'; + when 35 => c := 'Z'; + when others => c := '?'; + end case; + return c; + end chr; + + + + -- convert integer to string using specified base + -- (adapted from Steve Vogwell's posting in comp.lang.vhdl) + + function str(int: integer; base: integer) return string is + + variable temp: string(1 to 10); + variable num: integer; + variable abs_int: integer; + variable len: integer := 1; + variable power: integer := 1; + + begin + + -- bug fix for negative numbers + abs_int := abs(int); + + num := abs_int; + + while num >= base loop -- Determine how many + len := len + 1; -- characters required + num := num / base; -- to represent the + end loop ; -- number. + + for i in len downto 1 loop -- Convert the number to + temp(i) := chr(abs_int/power mod base); -- a string starting + power := power * base; -- with the right hand + end loop ; -- side. + + -- return result and add sign if required + if int < 0 then + return '-'& temp(1 to len); + else + return temp(1 to len); + end if; + + end str; + + + -- convert integer to string, using base 10 + function str(int: integer) return string is + + begin + + return str(int, 10) ; + + end str; + + + + -- converts a std_logic_vector into a hex string. + function hstr(slv: std_logic_vector) return string is + variable hexlen: integer; + variable longslv : std_logic_vector(67 downto 0) := (others => '0'); + variable hex : string(1 to 16); + variable fourbit : std_logic_vector(3 downto 0); + begin + hexlen := (slv'left+1)/4; + if (slv'left+1) mod 4 /= 0 then + hexlen := hexlen + 1; + end if; + longslv(slv'left downto 0) := slv; + for i in (hexlen -1) downto 0 loop + fourbit := longslv(((i*4)+3) downto (i*4)); + case fourbit is + when "0000" => hex(hexlen -I) := '0'; + when "0001" => hex(hexlen -I) := '1'; + when "0010" => hex(hexlen -I) := '2'; + when "0011" => hex(hexlen -I) := '3'; + when "0100" => hex(hexlen -I) := '4'; + when "0101" => hex(hexlen -I) := '5'; + when "0110" => hex(hexlen -I) := '6'; + when "0111" => hex(hexlen -I) := '7'; + when "1000" => hex(hexlen -I) := '8'; + when "1001" => hex(hexlen -I) := '9'; + when "1010" => hex(hexlen -I) := 'A'; + when "1011" => hex(hexlen -I) := 'B'; + when "1100" => hex(hexlen -I) := 'C'; + when "1101" => hex(hexlen -I) := 'D'; + when "1110" => hex(hexlen -I) := 'E'; + when "1111" => hex(hexlen -I) := 'F'; + when "ZZZZ" => hex(hexlen -I) := 'z'; + when "UUUU" => hex(hexlen -I) := 'u'; + when "XXXX" => hex(hexlen -I) := 'x'; + when others => hex(hexlen -I) := '?'; + end case; + end loop; + return hex(1 to hexlen); + end hstr; + + + + -- functions to manipulate strings + ----------------------------------- + + + -- convert a character to upper case + + function to_upper(c: character) return character is + + variable u: character; + + begin + + case c is + when 'a' => u := 'A'; + when 'b' => u := 'B'; + when 'c' => u := 'C'; + when 'd' => u := 'D'; + when 'e' => u := 'E'; + when 'f' => u := 'F'; + when 'g' => u := 'G'; + when 'h' => u := 'H'; + when 'i' => u := 'I'; + when 'j' => u := 'J'; + when 'k' => u := 'K'; + when 'l' => u := 'L'; + when 'm' => u := 'M'; + when 'n' => u := 'N'; + when 'o' => u := 'O'; + when 'p' => u := 'P'; + when 'q' => u := 'Q'; + when 'r' => u := 'R'; + when 's' => u := 'S'; + when 't' => u := 'T'; + when 'u' => u := 'U'; + when 'v' => u := 'V'; + when 'w' => u := 'W'; + when 'x' => u := 'X'; + when 'y' => u := 'Y'; + when 'z' => u := 'Z'; + when others => u := c; + end case; + + return u; + + end to_upper; + + + -- convert a character to lower case + + function to_lower(c: character) return character is + + variable l: character; + + begin + + case c is + when 'A' => l := 'a'; + when 'B' => l := 'b'; + when 'C' => l := 'c'; + when 'D' => l := 'd'; + when 'E' => l := 'e'; + when 'F' => l := 'f'; + when 'G' => l := 'g'; + when 'H' => l := 'h'; + when 'I' => l := 'i'; + when 'J' => l := 'j'; + when 'K' => l := 'k'; + when 'L' => l := 'l'; + when 'M' => l := 'm'; + when 'N' => l := 'n'; + when 'O' => l := 'o'; + when 'P' => l := 'p'; + when 'Q' => l := 'q'; + when 'R' => l := 'r'; + when 'S' => l := 's'; + when 'T' => l := 't'; + when 'U' => l := 'u'; + when 'V' => l := 'v'; + when 'W' => l := 'w'; + when 'X' => l := 'x'; + when 'Y' => l := 'y'; + when 'Z' => l := 'z'; + when others => l := c; + end case; + + return l; + + end to_lower; + + + + -- convert a string to upper case + + function to_upper(s: string) return string is + + variable uppercase: string (s'range); + + begin + + for i in s'range loop + uppercase(i):= to_upper(s(i)); + end loop; + return uppercase; + + end to_upper; + + + + -- convert a string to lower case + + function to_lower(s: string) return string is + + variable lowercase: string (s'range); + + begin + + for i in s'range loop + lowercase(i):= to_lower(s(i)); + end loop; + return lowercase; + + end to_lower; + + + +-- functions to convert strings into other types + + +-- converts a character into a std_logic + +function to_std_logic(c: character) return std_logic is + variable sl: std_logic; + begin + case c is + when 'U' => + sl := 'U'; + when 'X' => + sl := 'X'; + when '0' => + sl := '0'; + when '1' => + sl := '1'; + when 'Z' => + sl := 'Z'; + when 'W' => + sl := 'W'; + when 'L' => + sl := 'L'; + when 'H' => + sl := 'H'; + when '-' => + sl := '-'; + when others => + sl := 'X'; + end case; + return sl; + end to_std_logic; + + +-- converts a string into std_logic_vector + +function to_std_logic_vector(s: string) return std_logic_vector is + variable slv: std_logic_vector(s'high-s'low downto 0); + variable k: integer; +begin + k := s'high-s'low; + for i in s'range loop + slv(k) := to_std_logic(s(i)); + k := k - 1; + end loop; + return slv; +end to_std_logic_vector; + + + + + + +---------------- +-- file I/O -- +---------------- + + + +-- read variable length string from input file + +procedure str_read(file in_file: TEXT; + res_string: out string) is + + variable l: line; + variable c: character; + variable is_string: boolean; + + begin + + readline(in_file, l); + -- clear the contents of the result string + for i in res_string'range loop + res_string(i) := ' '; + end loop; + -- read all characters of the line, up to the length + -- of the results string + for i in res_string'range loop + read(l, c, is_string); + res_string(i) := c; + if not is_string then -- found end of line + exit; + end if; + end loop; + +end str_read; + + +-- print string to a file +procedure print(file out_file: TEXT; + new_string: in string) is + + variable l: line; + + begin + + write(l, new_string); + writeline(out_file, l); + +end print; + + +-- print character to a file and start new line +procedure print(file out_file: TEXT; + char: in character) is + + variable l: line; + + begin + + write(l, char); + writeline(out_file, l); + +end print; + + + +-- appends contents of a string to a file until line feed occurs +-- (LF is considered to be the end of the string) + +procedure str_write(file out_file: TEXT; + new_string: in string) is + begin + + for i in new_string'range loop + print(out_file, new_string(i)); + if new_string(i) = LF then -- end of string + exit; + end if; + end loop; + +end str_write; + + + + +end txt_util; + + + + diff --git a/cbmnet/code/cbmnet_interface_pkg.vhd b/cbmnet/code/cbmnet_interface_pkg.vhd index d0aa0bf..669f149 100644 --- a/cbmnet/code/cbmnet_interface_pkg.vhd +++ b/cbmnet/code/cbmnet_interface_pkg.vhd @@ -522,6 +522,64 @@ package cbmnet_interface_pkg is FILLED_IN : in std_logic; FILLED_OUT : out std_logic ); + end component; + + component pos_edge_strech_sync is + generic ( + LENGTH : positive := 2 + ); + port ( + IN_CLK_IN : std_logic; + DATA_IN : std_logic; + OUT_CLK_IN : std_logic; + DATA_OUT : std_logic + ); + end component; + + component cbmnet_sync_module is + port( + -- TRB + TRB_CLK_IN : in std_logic; + TRB_RESET_IN : in std_logic; + TRB_TRIGGER_OUT: out std_logic; + + --data output for read-out + TRB_TRIGGER_IN : in std_logic; + TRB_RDO_VALID_IN : in std_logic; + TRB_RDO_DATA_OUT : out std_logic_vector(31 downto 0); + TRB_RDO_WRITE_OUT : out std_logic; + TRB_RDO_STATUSBIT_OUT: out std_logic_vector(31 downto 0); + TRB_RDO_FINISHED_OUT : out std_logic; + + -- reg io + TRB_REGIO_ADDR_IN : in std_logic_vector(15 downto 0); + TRB_REGIO_DATA_IN : in std_logic_vector(31 downto 0); + TRB_REGIO_READ_ENABLE_IN : in std_logic; + TRB_REGIO_WRITE_ENABLE_IN : in std_logic; + TRB_REGIO_DATA_OUT : out std_logic_vector(31 downto 0); + TRB_REGIO_DATAREADY_OUT : out std_logic; + TRB_REGIO_WRITE_ACK_OUT : out std_logic; + TRB_REGIO_UNKNOWN_ADDR_OUT : out std_logic; + + -- CBMNET + CBM_CLK_IN : in std_logic; + CBM_RESET_IN : in std_logic; + CBM_PHY_BARREL_SHIFTER_POS_IN : in std_logic_vector(3 downto 0); + + -- DLM port + CBM_DLM_REC_IN : in std_logic_vector(3 downto 0); + CBM_DLM_REC_VALID_IN : in std_logic; + CBM_DLM_SENSE_OUT : out std_logic; + CBM_PULSER_OUT : out std_logic; -- connect to TDC + + -- Ctrl port + CBM_CTRL_DATA_IN : in std_logic_vector(15 downto 0); + CBM_CTRL_DATA_START_IN : in std_logic; + CBM_CTRL_DATA_END_IN : in std_logic; + CBM_CTRL_DATA_STOP_OUT : out std_logic; + + DEBUG_OUT : out std_logic_vector(31 downto 0) + ); end component; end package cbmnet_interface_pkg; diff --git a/cbmnet/code/cbmnet_phy_ecp3.vhd b/cbmnet/code/cbmnet_phy_ecp3.vhd index 6965a10..99e529c 100755 --- a/cbmnet/code/cbmnet_phy_ecp3.vhd +++ b/cbmnet/code/cbmnet_phy_ecp3.vhd @@ -56,20 +56,19 @@ entity cbmnet_phy_ecp3 is CTRL_OP : in std_logic_vector ( 15 downto 0) := (others => '0'); DEBUG_OUT : out std_logic_vector (511 downto 0) := (others => '0') ); + + attribute BLOCKNET : boolean; + attribute BLOCKNET of DEBUG_OUT : signal is true; end entity; architecture cbmnet_phy_ecp3_arch of cbmnet_phy_ecp3 is -- Placer Directives - attribute HGROUP : string; - -- for whole architecture - attribute HGROUP of cbmnet_phy_ecp3_arch : architecture is "cbmnet_phy_group"; - - attribute syn_hier: string; - attribute syn_hier of cbmnet_phy_ecp3_arch : architecture is "hard"; - - - attribute syn_sharing : string; - attribute syn_sharing of cbmnet_phy_ecp3_arch : architecture is "off"; +-- attribute syn_hier: string; +-- attribute syn_hier of cbmnet_phy_ecp3_arch : architecture is "hard"; +-- +-- +-- attribute syn_sharing : string; +-- attribute syn_sharing of cbmnet_phy_ecp3_arch : architecture is "off"; constant WA_FIXATION : integer := c_YES; signal DETERMINISTIC_LATENCY_C : std_logic; diff --git a/cbmnet/code/cbmnet_phy_rx_gear.vhd b/cbmnet/code/cbmnet_phy_rx_gear.vhd index f0f0166..ee5799d 100644 --- a/cbmnet/code/cbmnet_phy_rx_gear.vhd +++ b/cbmnet/code/cbmnet_phy_rx_gear.vhd @@ -32,8 +32,8 @@ entity CBMNET_PHY_RX_GEAR is end entity; architecture CBMNET_PHY_RX_GEAR_ARCH of CBMNET_PHY_RX_GEAR is - attribute HGROUP : string; - attribute HGROUP of CBMNET_PHY_RX_GEAR_ARCH : architecture is "cbmnet_phy_rx_gear"; +-- attribute HGROUP : string; +-- attribute HGROUP of CBMNET_PHY_RX_GEAR_ARCH : architecture is "cbmnet_phy_rx_gear"; type FSM_STATES_T is (FSM_START, FSM_WAIT_FOR_LOCK, FSM_LOCK_WAIT1, FSM_LOCK_WAIT2, FSM_LOCK_WAIT3, FSM_RESET, FSM_LOCKED); @@ -55,7 +55,8 @@ architecture CBMNET_PHY_RX_GEAR_ARCH of CBMNET_PHY_RX_GEAR is signal data_in_buf_i : std_logic_vector( 8 downto 0); - + signal delay_clock_x_i : std_logic; + signal delay_clock_buf_i : std_logic; signal delay_clock_buf1_i : std_logic; signal last_delay_clock_i : std_logic := '0'; @@ -78,6 +79,7 @@ begin RESET_OUT <= '1'; reset_timer_i <= '0'; delay_clock_i <= '0'; + delay_clock_x_i <= delay_clock_i; case (fsm_i) is when FSM_START => @@ -156,7 +158,7 @@ begin -- Implement the 2:1 gearing and clock down-sampling --delay_clock_buf1_i <= delay_clock_i when rising_edge(CLK_250_IN); - delay_clock_buf_i <= delay_clock_i when rising_edge(CLK_250_IN); + delay_clock_buf_i <= delay_clock_x_i when rising_edge(CLK_250_IN); proc_ctrl_gear: process @@ -193,7 +195,7 @@ begin CLK_125_OUT <= clk_125_i; -- when rising_edge(CLK_250_IN); DEBUG_OUT(3 downto 0) <= STD_LOGIC_VECTOR(fsm_state_i); - DEBUG_OUT(4) <= delay_clock_i; + --DEBUG_OUT(4) <= delay_clock_i; DEBUG_OUT(5) <= indi_alignment_i; DEBUG_OUT(6) <= indi_misalignment_i; diff --git a/cbmnet/code/cbmnet_phy_tx_gear.vhd b/cbmnet/code/cbmnet_phy_tx_gear.vhd index ca0ff1e..7ebdcb9 100644 --- a/cbmnet/code/cbmnet_phy_tx_gear.vhd +++ b/cbmnet/code/cbmnet_phy_tx_gear.vhd @@ -32,13 +32,14 @@ entity CBMNET_PHY_TX_GEAR is end entity; architecture CBMNET_PHY_TX_GEAR_ARCH of CBMNET_PHY_TX_GEAR is - attribute HGROUP : string; - attribute HGROUP of CBMNET_PHY_TX_GEAR_ARCH : architecture is "cbmnet_phy_tx_gear"; +-- attribute HGROUP : string; +-- attribute HGROUP of CBMNET_PHY_TX_GEAR_ARCH : architecture is "cbmnet_phy_tx_gear"; - type FSM_STATES is (FSM_HIGH, FSM_LOW); + type FSM_STATES is (FSM_LOCKING, FSM_HIGH, FSM_LOW); signal fsm_i : FSM_STATES; signal data_in_buf125_i : std_logic_vector(17 downto 0); + signal data_in_buf125_0_i : std_logic_vector(17 downto 0); signal data_in_buf250_i : std_logic_vector(17 downto 0); signal data_in_buf250_0_i : std_logic_vector(17 downto 0); @@ -53,15 +54,11 @@ begin process is begin wait until rising_edge(CLK_250_IN); - if RESET_IN='1' then - delay_counter_i <= TO_UNSIGNED(0,16); - end if; - data_in_buf250_0_i <= data_in_buf125_i; data_in_buf250_i <= data_in_buf250_0_i; - clk_125_xfer_buf_i <= clk_125_xfer_i; + clk_125_xfer_buf_i <= CLK_125_IN; clk_125_xfer_del_i <= clk_125_xfer_buf_i; CLK_125_OUT <= '0'; @@ -79,19 +76,27 @@ begin -- end if; - when others => + when FSM_LOW => DATA_OUT <= delay_data_i; fsm_i <= FSM_HIGH; + + when others => + if clk_125_xfer_del_i = '0' and clk_125_xfer_buf_i = '1' then + fsm_i <= FSM_HIGH; + end if; end case; + + if RESET_IN='1' then + fsm_i <= FSM_LOCKING; + end if; end process; TX_READY_OUT <= not RESET_IN; process is begin wait until rising_edge(CLK_125_IN); - - data_in_buf125_i <= DATA_IN; - clk_125_xfer_i <= not clk_125_xfer_i; + data_in_buf125_0_i <= DATA_IN; + data_in_buf125_i <= data_in_buf125_0_i; end process; DEBUG_OUT <= (others => '0'); -- x"0000" & STD_LOGIC_VECTOR( delay_counter_i ); diff --git a/cbmnet/code/cbmnet_readout_event_packer.vhd b/cbmnet/code/cbmnet_readout_event_packer.vhd new file mode 100644 index 0000000..21bbc56 --- /dev/null +++ b/cbmnet/code/cbmnet_readout_event_packer.vhd @@ -0,0 +1,212 @@ +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + +entity CBMNET_READOUT_EVENT_PACKER is + port ( + -- TrbNet + CLK_IN : in std_logic; + RESET_IN : in std_logic; + + -- connect to hub + HUB_CTS_NUMBER_IN : in std_logic_vector (15 downto 0); + HUB_CTS_CODE_IN : in std_logic_vector (7 downto 0); + HUB_CTS_INFORMATION_IN : in std_logic_vector (7 downto 0); + HUB_CTS_READOUT_TYPE_IN : in std_logic_vector (3 downto 0); + GBE_CTS_STATUS_BITS_IN : in std_logic_vector (31 downto 0); + + + -- connect to decoder + DEC_EVT_INFO_IN : in std_logic_vector(31 downto 0); + DEC_LENGTH_IN : in std_logic_vector(15 downto 0); + DEC_SOURCE_IN : in std_logic_vector(15 downto 0); + DEC_DATA_IN : in std_logic_vector(15 downto 0); + DEC_DATA_READY_IN : in std_logic; + DEC_ACTIVE_IN : in std_logic; + DEC_ERROR_IN : in std_logic; + + DEC_DATA_READ_OUT : out std_logic; + DEC_RESET_OUT : out std_logic; + + -- connect to fifo + WADDR_STORE_OUT : out std_logic; + WADDR_RESTORE_OUT: out std_logic; + WDATA_OUT : out std_logic_vector(17 downto 0); + WENQUEUE_OUT : out std_logic; + WPACKET_COMPLETE_OUT: out std_logic; + WFULL_IN : in std_logic; + + DEBUG_OUT : out std_logic_vector(31 downto 0) + ); +end entity; + +architecture cbmnet_readout_event_packer_arch of CBMNET_READOUT_EVENT_PACKER is + type FSM_STATES_T is ( + WAIT_FOR_IDLE, IDLE, + HDR_SIZE_H, HDR_SIZE_L, + HDR_DECODING_H, HDR_DECODING_L, + HDR_ID_H, HDR_ID_L, + HDR_NUMBER_H, HDR_NUMBER_L, + PAYLOAD, + TRL_TRAILER_H, TRL_TRAILER_L, + TRL_STATUS_H, TRL_STATUS_L + ); + + type FSM_STATES_ENC_T is array(FSM_STATES_T) of std_logic_vector(3 downto 0); + constant fsm_states_enc_c : FSM_STATES_ENC_T := ( + WAIT_FOR_IDLE => x"0", + IDLE => x"1", + HDR_SIZE_H => x"2", + HDR_SIZE_L => x"3", + HDR_DECODING_H=> x"4", + HDR_DECODING_L=> x"5", + HDR_ID_H => x"6", + HDR_ID_L => x"7", + HDR_NUMBER_H => x"8", + HDR_NUMBER_L => x"9", + PAYLOAD => x"a", + TRL_TRAILER_H => x"b", + TRL_TRAILER_L => x"c", + TRL_STATUS_H => x"d", + TRL_STATUS_L => x"e" + ); + + signal fsm_i : FSM_STATES_T; + signal header_data_i : std_logic_vector(15 downto 0); + signal header_enqueue_i : std_logic; + signal header_token_i : std_logic_vector(1 downto 0); + + signal copy_payload_i : std_logic; + + signal data_read_i, data_read_delayed_i : std_logic; + +-- local buffers + signal wenqueue_i : std_logic; + signal wpacket_complete_i : std_logic; + signal waddr_restore_i : std_logic; + signal waddr_store_i : std_logic; +begin + THE_PACKER: process is + begin + wait until rising_edge(CLK_IN); + + waddr_store_i <= '0'; + waddr_restore_i <= '0'; + DEC_RESET_OUT <= '0'; + copy_payload_i <= '0'; + header_data_i <= (others => '-'); + header_enqueue_i <= '0'; + wpacket_complete_i <= '0'; + header_token_i <= "00"; + + if RESET_IN='1' then + fsm_i <= WAIT_FOR_IDLE; + + elsif fsm_i /= IDLE and (DEC_ERROR_IN = '1' or WFULL_IN = '1') then + waddr_restore_i <= '1'; + DEC_RESET_OUT <= '1'; + fsm_i <= WAIT_FOR_IDLE; + + else + case(fsm_i) is + when WAIT_FOR_IDLE => + if DEC_ACTIVE_IN='0' then + fsm_i <= IDLE; + end if; + + when IDLE => + if DEC_ACTIVE_IN='1' then + waddr_store_i <= '1'; + fsm_i <= HDR_SIZE_H; + end if; + + when HDR_SIZE_H => + header_token_i <= "01"; + header_data_i <= x"0000"; + header_enqueue_i <= '1'; + fsm_i <= HDR_SIZE_L; + + when HDR_SIZE_L => + header_token_i <= "10"; + + header_data_i <= STD_LOGIC_VECTOR(UNSIGNED(DEC_LENGTH_IN) + TO_UNSIGNED(16+8, 16)); -- 8 words of SE-Hdr and 4 words for SE-trailer + header_enqueue_i <= '1'; + fsm_i <= HDR_DECODING_H; + + when HDR_DECODING_H => + header_data_i <= x"0002"; + header_enqueue_i <= '1'; + fsm_i <= HDR_DECODING_L; + when HDR_DECODING_L => + header_data_i <= x"00" & HUB_CTS_READOUT_TYPE_IN & x"1"; + header_enqueue_i <= '1'; + fsm_i <= HDR_ID_H; + + when HDR_ID_H => + header_data_i <= x"0000"; + header_enqueue_i <= '1'; + fsm_i <= HDR_ID_L; + when HDR_ID_L => + header_data_i <= x"beaf"; + header_enqueue_i <= '1'; + fsm_i <= HDR_NUMBER_H; + + when HDR_NUMBER_H => + header_data_i <= x"00" & HUB_CTS_NUMBER_IN(15 downto 8); + header_enqueue_i <= '1'; + fsm_i <= HDR_NUMBER_L; + when HDR_NUMBER_L => + header_data_i <= HUB_CTS_NUMBER_IN(7 downto 0) & HUB_CTS_CODE_IN; + header_enqueue_i <= '1'; + fsm_i <= PAYLOAD; + + when PAYLOAD => + if DEC_ACTIVE_IN = '0' then + fsm_i <= TRL_TRAILER_H; + else + copy_payload_i <= '1'; + end if; + + when TRL_TRAILER_H => + header_data_i <= x"0001"; + header_enqueue_i <= '1'; + fsm_i <= TRL_TRAILER_L; + when TRL_TRAILER_L => + header_data_i <= x"5555"; + header_enqueue_i <= '1'; + fsm_i <= TRL_STATUS_H; + + when TRL_STATUS_H => + header_data_i <= GBE_CTS_STATUS_BITS_IN(31 downto 16); + header_enqueue_i <= '1'; + fsm_i <= TRL_STATUS_L; + when TRL_STATUS_L => + header_token_i <= "11"; + header_data_i <= GBE_CTS_STATUS_BITS_IN(15 downto 0); + header_enqueue_i <= '1'; + wpacket_complete_i <= '1'; + fsm_i <= IDLE; + + end case; + end if; + end process; + + WDATA_OUT(17 downto 0) <= "00" & DEC_DATA_IN when copy_payload_i='1' else header_token_i & header_data_i; + wenqueue_i <= header_enqueue_i or data_read_i; + + data_read_i <= copy_payload_i and DEC_DATA_READY_IN; + DEC_DATA_READ_OUT <= data_read_i; + data_read_delayed_i <= data_read_i when rising_edge(CLK_IN); + +-- Outputs + WADDR_STORE_OUT <= waddr_store_i; + WADDR_RESTORE_OUT <= waddr_restore_i; + WENQUEUE_OUT <= wenqueue_i; + WPACKET_COMPLETE_OUT <= wpacket_complete_i; + +-- Debug + DEBUG_OUT( 3 downto 0) <= fsm_states_enc_c(fsm_i); + DEBUG_OUT( 7 downto 4) <= DEC_DATA_READY_IN & DEC_ACTIVE_IN & DEC_ERROR_IN & data_read_i; + DEBUG_OUT(11 downto 8) <= wpacket_complete_i & waddr_restore_i & waddr_store_i & wenqueue_i; + DEBUG_OUT(15 downto 12) <= "000" & WFULL_IN; +end architecture; \ No newline at end of file diff --git a/cbmnet/code/cbmnet_sync_module.vhd b/cbmnet/code/cbmnet_sync_module.vhd new file mode 100644 index 0000000..ddf5853 --- /dev/null +++ b/cbmnet/code/cbmnet_sync_module.vhd @@ -0,0 +1,462 @@ +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + use work.cbmnet_interface_pkg.all; + +entity cbmnet_sync_module is + port( + -- TRB + TRB_CLK_IN : in std_logic; + TRB_RESET_IN : in std_logic; + TRB_TRIGGER_OUT: out std_logic; + + --data output for read-out + TRB_TRIGGER_IN : in std_logic; + TRB_RDO_VALID_IN : in std_logic; + TRB_RDO_DATA_OUT : out std_logic_vector(31 downto 0); + TRB_RDO_WRITE_OUT : out std_logic; + TRB_RDO_STATUSBIT_OUT: out std_logic_vector(31 downto 0); + TRB_RDO_FINISHED_OUT : out std_logic; + + -- reg io + TRB_REGIO_ADDR_IN : in std_logic_vector(15 downto 0); + TRB_REGIO_DATA_IN : in std_logic_vector(31 downto 0); + TRB_REGIO_READ_ENABLE_IN : in std_logic; + TRB_REGIO_WRITE_ENABLE_IN : in std_logic; + TRB_REGIO_DATA_OUT : out std_logic_vector(31 downto 0); + TRB_REGIO_DATAREADY_OUT : out std_logic; + TRB_REGIO_WRITE_ACK_OUT : out std_logic; + TRB_REGIO_UNKNOWN_ADDR_OUT : out std_logic; + + -- CBMNET + CBM_CLK_IN : in std_logic; + CBM_RESET_IN : in std_logic; + CBM_PHY_BARREL_SHIFTER_POS_IN : in std_logic_vector(3 downto 0); + + -- DLM port + CBM_DLM_REC_IN : in std_logic_vector(3 downto 0); + CBM_DLM_REC_VALID_IN : in std_logic; + CBM_DLM_SENSE_OUT : out std_logic; + CBM_PULSER_OUT : out std_logic; -- connect to TDC + + -- Ctrl port + CBM_CTRL_DATA_IN : in std_logic_vector(15 downto 0); + CBM_CTRL_DATA_START_IN : in std_logic; + CBM_CTRL_DATA_END_IN : in std_logic; + CBM_CTRL_DATA_STOP_OUT : out std_logic; + + DEBUG_OUT : out std_logic_vector(31 downto 0) + ); +end entity; + +architecture cbmnet_sync_module_arch of cbmnet_sync_module is +-- DETECT DLMs + signal trb_dlm_sense_mask_i : std_logic_vector(15 downto 0); + signal cbm_crs_trb_dlm_sense_mask_i : std_logic_vector(15 downto 0); + + signal cbm_dlm_sensed_i : std_logic; + signal trb_crs_cbm_dlm_sensed_i : std_logic; + +-- EPOCH + signal cbm_crs_trb_epoch_update_scheme_i : std_logic_vector(1 downto 0); + + signal cbm_current_epoch_i : std_logic_vector(31 downto 0); + signal cbm_current_epoch_updated_i : std_logic; + + signal trb_next_epoch_i : std_logic_vector(31 downto 0); + signal trb_next_epoch_updated_i : std_logic; + + signal cbm_next_epoch_i : std_logic_vector(31 downto 0); + signal cbm_next_epoch_updated_i : std_logic; + + + signal cbm_crs_trb_next_epoch_i : std_logic_vector(31 downto 0); + signal cbm_crs_trb_next_epoch_updated_i : std_logic; + signal trb_crs_cbm_current_epoch_i : std_logic_vector(31 downto 0); + signal trb_crs_cbm_current_epoch_updated_i : std_logic; + +-- PULSER + signal trb_pulser_threshold_i : std_logic_vector(31 downto 0); + signal cbm_crs_trb_pulser_threshold_i : unsigned(31 downto 0); + signal cbm_pulser_i : unsigned(31 downto 0); + signal cbm_pulse_i : std_logic; + signal trb_crs_cbm_pulse_i : std_logic; + +-- TIMESTAMPS + signal trb_timestamp_i : unsigned(31 downto 0); + signal trb_timestamp_last_dlm_i : unsigned(31 downto 0); + signal trb_timestamp_last_pulse_i : unsigned(31 downto 0); + signal trb_reset_counter_i : unsigned(15 downto 0); + + signal cbm_timestamp_i : unsigned(31 downto 0); + signal cbm_timestamp_last_dlm_i : unsigned(31 downto 0); + signal cbm_timestamp_last_pulse_i : unsigned(31 downto 0); + signal cbm_reset_counter_i : unsigned(15 downto 0); + signal cbm_dlm_counter_i : unsigned(31 downto 0); + signal cbm_pulser_counter_i : unsigned(31 downto 0); + signal cbm_epoch_i : std_logic_vector(31 downto 0); + + -- same signals as above, but in trbnet clock domain + signal trb_crs_cbm_timestamp_i : unsigned(31 downto 0); + signal trb_crs_cbm_timestamp_last_dlm_i : unsigned(31 downto 0); + signal trb_crs_cbm_timestamp_last_pulse_i : unsigned(31 downto 0); + signal trb_crs_cbm_reset_counter_i : unsigned(15 downto 0); + signal trb_crs_cbm_dlm_counter_i : unsigned(31 downto 0); + signal trb_crs_cbm_pulser_counter_i : unsigned(31 downto 0); + + +-- CBMNET slow control + signal cbm_next_epoch_half_buf_i : std_logic_vector(15 downto 0); + type CBM_SLOW_CTRL_FSM_T is (WAIT_FOR_START, SHIFT_LOW_WORD); + signal cbm_slow_ctrl_fsm_i : CBM_SLOW_CTRL_FSM_T; + +-- TrbNet slow control + constant trb_sync_lowest_address_c : integer := 3; + + type TRB_SYNC_BUFFER_T is array (trb_sync_lowest_address_c+1 to trb_sync_lowest_address_c+9) of std_logic_vector(31 downto 0); + signal trb_sync_buffer_i : TRB_SYNC_BUFFER_T; + signal trb_regio_addr_i : integer range 0 to 15; + signal trb_epoch_update_scheme_i : std_logic_vector(1 downto 0); + +-- TrbNet read-out + type TRB_RDO_BUFFER_T is array (0 to 10) of std_logic_vector(31 downto 0); + signal trb_rdo_buffer_i : TRB_RDO_BUFFER_T; + type TRB_RDO_FSM_T is (WAIT_FOR_TRIGGER, WAIT_FOR_VALID, COPY_DATA, FINISH); + signal trb_rdo_fsm_i : TRB_RDO_FSM_T; + signal trb_rdo_fsm_state_i : std_logic_vector(3 downto 0); + signal trb_rdo_counter_i : integer range 0 to 16; + + +begin +-- TRBNet read-out + TRBNET_READOUT_PROC: process is + variable header_v : std_logic_vector(31 downto 0); + begin + wait until rising_edge(TRB_CLK_IN); + header_v := (others => '0'); -- prevent storage + + TRB_RDO_WRITE_OUT <= '0'; + TRB_RDO_STATUSBIT_OUT <= (others => '0'); + TRB_RDO_FINISHED_OUT <= '0'; + trb_rdo_counter_i <= 0; + + if TRB_RESET_IN='1' then + trb_rdo_fsm_i <= WAIT_FOR_TRIGGER; + else + case (trb_rdo_fsm_i) is + when WAIT_FOR_TRIGGER => + trb_rdo_fsm_state_i <= x"0"; + if TRB_TRIGGER_IN = '1' then + -- store data + header_v(31 downto 28) := x"1"; -- version + header_v(23 downto 8) := trb_pulser_threshold_i(15 downto 0); + header_v( 7 downto 4) := CBM_PHY_BARREL_SHIFTER_POS_IN; + header_v( 3 downto 0) := trb_crs_cbm_current_epoch_updated_i & "0" & trb_epoch_update_scheme_i; + + trb_rdo_buffer_i( 0) <= header_v; + trb_rdo_buffer_i( 1) <= trb_crs_cbm_current_epoch_i; + trb_rdo_buffer_i( 2) <= trb_crs_cbm_timestamp_i; + trb_rdo_buffer_i( 3) <= trb_crs_cbm_timestamp_last_dlm_i; + trb_rdo_buffer_i( 4) <= trb_crs_cbm_timestamp_last_pulse_i; + trb_rdo_buffer_i( 5) <= trb_timestamp_i; + trb_rdo_buffer_i( 6) <= trb_timestamp_last_dlm_i; + trb_rdo_buffer_i( 7) <= trb_timestamp_last_pulse_i; + trb_rdo_buffer_i( 8) <= trb_crs_cbm_dlm_counter_i; + trb_rdo_buffer_i( 9) <= trb_crs_cbm_pulser_counter_i; + trb_rdo_buffer_i(10) <= STD_LOGIC_VECTOR(trb_reset_counter_i) & STD_LOGIC_VECTOR(trb_crs_cbm_reset_counter_i); + + -- fsm + trb_rdo_fsm_i <= WAIT_FOR_VALID; + elsif TRB_RDO_VALID_IN = '1' then + trb_rdo_fsm_i <= FINISH; + + end if; + + when WAIT_FOR_VALID => + trb_rdo_fsm_state_i <= x"1"; + if TRB_RDO_VALID_IN = '1' then + trb_rdo_fsm_i <= COPY_DATA; + end if; + + when COPY_DATA => + trb_rdo_fsm_state_i <= x"2"; + TRB_RDO_DATA_OUT <= trb_rdo_buffer_i(trb_rdo_counter_i); + TRB_RDO_WRITE_OUT <= '1'; + + if trb_rdo_counter_i = TRB_RDO_DATA_OUT'high then + trb_rdo_fsm_i <= FINISH; + end if; + trb_rdo_counter_i <= trb_rdo_counter_i + 1; + + when FINISH => + trb_rdo_fsm_state_i <= x"3"; + TRB_RDO_FINISHED_OUT <= '1'; + trb_rdo_fsm_i <= WAIT_FOR_TRIGGER; + + + end case; + end if; + end process; + +-- TRBNet slow control + trb_regio_addr_i <= to_integer(UNSIGNED(TRB_REGIO_ADDR_IN(3 downto 0))); + + TRB_SLOW_CTRL_PROC: process is + begin + wait until rising_edge(TRB_CLK_IN); + + TRB_REGIO_DATAREADY_OUT <= TRB_REGIO_READ_ENABLE_IN; + TRB_REGIO_WRITE_ACK_OUT <= TRB_REGIO_WRITE_ENABLE_IN; + TRB_REGIO_UNKNOWN_ADDR_OUT <= '0'; + TRB_REGIO_DATA_OUT <= (others => '0'); + + if trb_crs_cbm_dlm_sensed_i = '1' then + trb_next_epoch_updated_i <= '0'; + end if; + + if TRB_RESET_IN = '1' then + trb_dlm_sense_mask_i <= x"0000"; + trb_epoch_update_scheme_i <= "00"; + trb_pulser_threshold_i <= (others => '0'); + + trb_next_epoch_updated_i <= '0'; + trb_next_epoch_i <= x"deadc0de"; + + else + case (trb_regio_addr_i) is + when 0 => + TRB_REGIO_DATA_OUT(31 downto 16) <= trb_dlm_sense_mask_i; + TRB_REGIO_DATA_OUT(11 downto 8) <= trb_rdo_fsm_state_i; + TRB_REGIO_DATA_OUT(4) <= trb_crs_cbm_current_epoch_updated_i; + TRB_REGIO_DATA_OUT( 3 downto 0) <= "00" & trb_epoch_update_scheme_i; + + when 1 => + TRB_REGIO_DATA_OUT <= trb_pulser_threshold_i; + + when 2 => + TRB_REGIO_DATA_OUT <= trb_next_epoch_i; + + when trb_sync_lowest_address_c => + TRB_REGIO_DATA_OUT <= trb_crs_cbm_current_epoch_i; + trb_sync_buffer_i(trb_sync_lowest_address_c+1) <= trb_crs_cbm_timestamp_i; + trb_sync_buffer_i(trb_sync_lowest_address_c+2) <= trb_crs_cbm_timestamp_last_dlm_i; + trb_sync_buffer_i(trb_sync_lowest_address_c+3) <= trb_crs_cbm_timestamp_last_pulse_i; + trb_sync_buffer_i(trb_sync_lowest_address_c+4) <= trb_timestamp_i; + trb_sync_buffer_i(trb_sync_lowest_address_c+5) <= trb_timestamp_last_dlm_i; + trb_sync_buffer_i(trb_sync_lowest_address_c+6) <= trb_timestamp_last_pulse_i; + trb_sync_buffer_i(trb_sync_lowest_address_c+7) <= trb_crs_cbm_dlm_counter_i; + trb_sync_buffer_i(trb_sync_lowest_address_c+8) <= trb_crs_cbm_pulser_counter_i; + trb_sync_buffer_i(trb_sync_lowest_address_c+9) <= STD_LOGIC_VECTOR(trb_reset_counter_i) & STD_LOGIC_VECTOR(trb_crs_cbm_reset_counter_i); + + when trb_sync_lowest_address_c + 1 to trb_sync_lowest_address_c + trb_sync_buffer_i'high => + TRB_REGIO_DATA_OUT <= trb_sync_buffer_i(trb_regio_addr_i); + + when others => + TRB_REGIO_UNKNOWN_ADDR_OUT <= TRB_REGIO_READ_ENABLE_IN or TRB_REGIO_WRITE_ENABLE_IN; + + end case; + + if TRB_REGIO_WRITE_ENABLE_IN = '1' then + case (trb_regio_addr_i) is + when 0 => + trb_dlm_sense_mask_i <= TRB_REGIO_DATA_IN(31 downto 16); + trb_epoch_update_scheme_i <= TRB_REGIO_DATA_IN(1 downto 0); + + when 1 => + trb_pulser_threshold_i <= TRB_REGIO_DATA_IN; + + when 2 => + trb_next_epoch_i <= TRB_REGIO_DATA_IN; + trb_next_epoch_updated_i <= '1'; + + when others => + TRB_REGIO_UNKNOWN_ADDR_OUT <= '1'; + end case; + end if; + end if; + end process; + +-- CBMNet slow control + CBMNET_SLOW_CTRL_PROC: process is + begin + wait until rising_edge(CBM_CLK_IN); + + if CBM_RESET_IN = '1' then + CBM_CTRL_DATA_STOP_OUT <= '1'; + cbm_next_epoch_updated_i <= '0'; + cbm_slow_ctrl_fsm_i <= WAIT_FOR_START; + + else + CBM_CTRL_DATA_STOP_OUT <= '0'; + case cbm_slow_ctrl_fsm_i is + when WAIT_FOR_START => + if CBM_CTRL_DATA_START_IN = '1' then + cbm_next_epoch_half_buf_i <= CBM_CTRL_DATA_IN; + cbm_slow_ctrl_fsm_i <= SHIFT_LOW_WORD; + end if; + + when SHIFT_LOW_WORD => + cbm_slow_ctrl_fsm_i <= WAIT_FOR_START; + if CBM_CTRL_DATA_END_IN = '1' then + cbm_next_epoch_i <= cbm_next_epoch_half_buf_i & CBM_CTRL_DATA_IN; + cbm_next_epoch_updated_i <= '1'; + end if; + end case; + + if cbm_dlm_sensed_i = '1' then + cbm_next_epoch_updated_i <= '0'; + end if; + end if; + end process; + +-- CBMNet DLM selection + CBM_DLM_SENSE_PROC: process is + variable dlm_v : integer range 0 to 15; + variable sensed_v : std_logic; + begin + wait until rising_edge(CBM_CLK_IN); + + dlm_v := to_integer(UNSIGNED(CBM_DLM_REC_IN)); + sensed_v := cbm_crs_trb_dlm_sense_mask_i(dlm_v) and CBM_DLM_REC_VALID_IN; + cbm_dlm_sensed_i <= sensed_v; + + if CBM_RESET_IN='1' then + cbm_dlm_counter_i <= 0; + elsif sensed_v='1' then + cbm_dlm_counter_i <= cbm_dlm_counter_i + 1; + end if; + end process; + + CBM_DLM_SENSE_OUT <= cbm_dlm_sensed_i; + + CBM_EPOCH_PROC: process is + begin + wait until rising_edge(CBM_CLK_IN); + + if CBM_RESET_IN = '1' then + cbm_current_epoch_updated_i <= '0'; + cbm_current_epoch_i <= (others => '0'); + + elsif cbm_dlm_sensed_i = '1' then + case cbm_crs_trb_epoch_update_scheme_i is + when "01" => -- TRB defined + cbm_current_epoch_i <= cbm_crs_trb_next_epoch_i; + cbm_current_epoch_updated_i <= cbm_crs_trb_next_epoch_updated_i; + + when "10" => -- CBM defined + cbm_current_epoch_i <= cbm_next_epoch_i; + cbm_current_epoch_updated_i <= cbm_next_epoch_updated_i; + + when others => + cbm_current_epoch_i <= STD_LOGIC_VECTOR(UNSIGNED(cbm_current_epoch_i) + TO_UNSIGNED(1,32)); + cbm_current_epoch_updated_i <= '1'; + + end case; + end if; + end process; + +-- TIMESTAMPS + CBM_CLOCK_PROC: process is + variable last_reset_v : std_logic := '1'; + begin + wait until rising_edge(CBM_CLK_IN); + if CBM_RESET_IN='1' then + cbm_timestamp_i <= (others => '0'); + if last_reset_v = '0' then + cbm_reset_counter_i <= cbm_reset_counter_i + 1; + end if; + else + if cbm_dlm_sensed_i = '1' then + cbm_timestamp_last_dlm_i <= cbm_timestamp_i; + end if; + + cbm_timestamp_i <= cbm_timestamp_i + 1; + end if; + last_reset_v := CBM_RESET_IN; + end process; + + CBM_PULSER_PROC: process is + begin + wait until rising_edge(CBM_CLK_IN); + + cbm_crs_trb_pulser_threshold_i <= trb_pulser_threshold_i; + cbm_pulse_i <= '0'; + + if CBM_RESET_IN='1' then + cbm_pulser_counter_i <= 0; + end if; + + + if CBM_RESET_IN='1' or cbm_crs_trb_pulser_threshold_i=x"00000000" then + cbm_pulser_i <= 0; + + elsif cbm_pulser_i = cbm_crs_trb_pulser_threshold_i then + cbm_pulser_i <= 0; + cbm_pulser_counter_i <= cbm_pulser_counter_i + 1; + cbm_timestamp_last_pulse_i <= cbm_timestamp_i; + cbm_pulse_i <= '1'; + + elsif cbm_pulser_i > cbm_crs_trb_pulser_threshold_i then + cbm_pulser_i <= 0; + + else + cbm_pulser_i <= cbm_pulser_i + 1; + + end if; + end process; + CBM_PULSER_OUT <= cbm_pulse_i; + + TRB_CLOCK_PROC: process is + variable last_reset_v : std_logic := '1'; + begin + wait until rising_edge(TRB_CLK_IN); + if TRB_RESET_IN='1' then + trb_timestamp_i <= (others => '0'); + if last_reset_v = '0' then + trb_reset_counter_i <= trb_reset_counter_i + 1; + end if; + else + if trb_crs_cbm_dlm_sensed_i = '1' then + trb_timestamp_last_dlm_i <= trb_timestamp_i; + end if; + + if trb_crs_cbm_pulse_i = '1' then + trb_timestamp_last_pulse_i <= trb_timestamp_i; + end if; + + trb_timestamp_i <= trb_timestamp_i + 1; + end if; + last_reset_v := TRB_RESET_IN; + end process; + +-- Clock Domain Crossing CBM -> TRB + THE_PULSE_SYNC: pos_edge_strech_sync port map ( + IN_CLK_IN => CBM_CLK_IN, OUT_CLK_IN => TRB_CLK_IN, + DATA_IN => cbm_pulse_i, + DATA_OUT => trb_crs_cbm_pulse_i + ); + + THE_DLM_SENSE_SYNC: pos_edge_strech_sync port map ( + IN_CLK_IN => CBM_CLK_IN, OUT_CLK_IN => TRB_CLK_IN, + DATA_IN => cbm_dlm_sensed_i, + DATA_OUT => trb_crs_cbm_dlm_sensed_i + ); + + trb_crs_cbm_timestamp_i <= cbm_timestamp_i when rising_edge(TRB_CLK_IN); + trb_crs_cbm_timestamp_last_dlm_i <= cbm_timestamp_last_dlm_i when rising_edge(TRB_CLK_IN); + trb_crs_cbm_reset_counter_i <= cbm_reset_counter_i when rising_edge(TRB_CLK_IN); + trb_crs_cbm_dlm_counter_i <= cbm_dlm_counter_i when rising_edge(TRB_CLK_IN); + trb_crs_cbm_pulser_counter_i <= cbm_pulser_counter_i when rising_edge(TRB_CLK_IN); + trb_crs_cbm_timestamp_last_pulse_i <= cbm_timestamp_last_pulse_i when rising_edge(TRB_CLK_IN); + + trb_crs_cbm_current_epoch_i <= cbm_current_epoch_i when rising_edge(TRB_CLK_IN); + trb_crs_cbm_current_epoch_updated_i <= cbm_current_epoch_updated_i when rising_edge(TRB_CLK_IN); + +-- Clock Domain Crossing TRB -> CBM + cbm_crs_trb_epoch_update_scheme_i <= trb_epoch_update_scheme_i when rising_edge(CBM_CLK_IN); + cbm_crs_trb_next_epoch_i <= trb_next_epoch_i when rising_edge(CBM_CLK_IN); + cbm_crs_trb_next_epoch_updated_i <= trb_next_epoch_updated_i when rising_edge(CBM_CLK_IN); + cbm_crs_trb_dlm_sense_mask_i <= trb_dlm_sense_mask_i when rising_edge(CBM_CLK_IN); + + +end architecture; \ No newline at end of file diff --git a/cbmnet/code/pos_edge_strech_sync.vhd b/cbmnet/code/pos_edge_strech_sync.vhd new file mode 100644 index 0000000..b8f1321 --- /dev/null +++ b/cbmnet/code/pos_edge_strech_sync.vhd @@ -0,0 +1,27 @@ +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + use work.trb_net_std.all; + +entity pos_edge_strech_sync is + generic ( + LENGTH : positive := 2 + ); + port ( + IN_CLK_IN : std_logic; + DATA_IN : std_logic; + OUT_CLK_IN : std_logic; + DATA_OUT : std_logic + ); +end entity; + +architecture RTL of pos_edge_strech_sync is + signal in_buffer_i : std_logic_vector(LENGTH - 1 downto 0); + signal in_buffer_aggr_i : std_logic; + signal out_buffer_i : std_logic; +begin + in_buffer_i <= in_buffer_i(LENGTH-2 downto 0) & DATA_IN when rising_edge(OUT_CLK_IN); + in_buffer_aggr_i <= OR_ALL(in_buffer_i); + + out_buffer_i <= not out_buffer_i and in_buffer_aggr_i when rising_edge(OUT_CLK_IN); +end architecture; \ No newline at end of file -- 2.43.0