--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+use work.trb_net_std.all;
+use work.trb_net_components.all;
+use work.trb3_components.all;
+
+
+entity DLM_CTS_generator is
+ generic (
+ INCL_REGIO : integer range c_NO to c_YES := c_YES
+ );
+ port(
+ CLK : in std_logic; -- e.g. 100 MHz
+ RESET_IN : in std_logic; -- could be used after busy_release to make sure entity is in correct state
+
+ -- recovered clock, synchronous to DLM
+ CLK_RCV : in std_logic; -- e.g. 240 MHz recovered from SERDES
+
+ --DLM inputs
+ DLM_IN : in std_logic; -- DLM trigger
+ DLM_MSG_IN : in std_logic_vector(7 downto 0); -- DLM data word
+
+ --trigger outputs
+ TRG_ASYNC_OUT : out std_logic; -- asynchronous rising edge, length varying, here: approx. 110 ns
+ TRG_SYNC_OUT : out std_logic; -- sync. to CLK
+
+ --data output for read-out
+ TRIGGER_IN : in std_logic;
+
+ -- Data connection to Streamer
+ DATA_OUT : out std_logic_vector(31 downto 0);
+ WRITE_OUT : out std_logic;
+ STATUSBIT_OUT : out std_logic_vector(31 downto 0) := (others => '0');
+ FINISHED_OUT : out std_logic;
+
+ --Registers / Debug
+ REGIO_IN : in CTRLBUS_RX := (data => x"00000000", addr => x"0000", others => '0');
+ REGIO_OUT : out CTRLBUS_TX;
+
+
+ -- Ctrl and Status registers are only in use, if INCL_REGIO = c_NO ("ETM" mode)
+ CONTROL_REG_IN : in std_logic_vector(31 downto 0);
+ STATUS_REG_OUT : out std_logic_vector(31 downto 0) := (others => '0');
+ HEADER_REG_OUT : out std_logic_vector( 1 downto 0);
+ DEBUG : out std_logic_vector(31 downto 0)
+ );
+
+ --attribute syn_useioff : boolean;
+ --no IO-FF for MBS input
+ --attribute syn_useioff of MBS_IN : signal is false;
+end entity;
+
+
+architecture DLM_CTS_generator_arch of DLM_CTS_generator is
+
+ signal dlm_i : std_logic;
+ signal dlm_ii : std_logic;
+ signal dlm_iii : std_logic;
+ signal trg_async : std_logic;
+
+ signal dlm_ready : std_logic := '0';
+
+ type rdo_state_t is (RDO_IDLE, RDO_WAIT, RDO_WRITE, RDO_FINISH);
+ signal rdostate : rdo_state_t;
+
+ signal number_reg : std_logic_vector(7 downto 0);
+ signal subtrigger : std_logic_vector(7 downto 0) := x"00";
+
+ signal status_reg : std_logic_vector(1 downto 0);
+ signal error_reg : std_logic;
+
+ signal trg_sync_i : std_logic;
+ signal last_trg_sync_i : std_logic;
+
+ signal dlm_msg_i : std_logic_vector(7 downto 0);
+ signal last_DLM_in : std_logic_vector(7 downto 0);
+
+ signal config_rdo_disable_i : std_logic;
+
+ signal rec_counter_i : unsigned(31 downto 0) := (others => '0');
+ signal act_counter_i : unsigned(31 downto 0) := (others => '0');
+ signal high_counter_i : unsigned(31 downto 0) := (others => '0');
+
+
+
+begin
+ HEADER_REG_OUT <= b"01"; -- we tell the CTS that we send one word of over DATA_OUT
+
+ PROC_TRIG_ASYN: process
+ begin
+ wait until rising_edge(CLK_RCV);
+ dlm_i <= DLM_IN;
+ dlm_ii <= dlm_i;
+ dlm_iii <= dlm_ii;
+ trg_async <= dlm_i xor dlm_ii xor dlm_iii;
+ end process;
+
+ TRG_ASYNC_OUT <= trg_async;
+ TRG_SYNC_OUT <= trg_sync_i;
+
+ -- handle DLM message to generate the Microtimeslice ID from it.
+ -- If same DLM mes is incoming as before, this indicates a second trigger in the same microtimeslice. A subtrigger is increased.
+
+ PROC_DLM_MSG: process
+ begin
+ wait until rising_edge(CLK);
+ if RESET_IN = '1' then
+ dlm_ready <= '1';
+ trg_sync_i <= '0';
+ last_trg_sync_i <= '0';
+ last_DLM_in <= (others => '0');
+ subtrigger <= x"00";
+ rec_counter_i <= (others => '0');
+ error_reg <= '0';
+ else
+ trg_sync_i <= trg_async; -- high for 1 or 2 clock cycles.
+ last_trg_sync_i <= trg_sync_i;
+
+ -- To Think About: use dlm_ready in this if? Better or worse?
+ if last_trg_sync_i = '0' and trg_sync_i = '1' then --rising edge detection
+ rec_counter_i <= rec_counter_i + 1;-- cntr for RegIO
+
+ number_reg <= DLM_MSG_IN; -- wait until trigge rarrives
+ last_DLM_in <= DLM_MSG_IN;
+
+ if DLM_MSG_IN = last_DLM_in then -- next trigger in same microtimeslice
+ subtrigger <= std_logic_vector(unsigned(subtrigger) + 1);
+ --if subtrigger = x"FF" then
+ -- error_reg <= '1';
+ --end if;
+ else -- new microtimeslice
+ subtrigger <= x"00";
+ end if;
+
+ dlm_ready <= '1';
+ end if;
+
+ if rdostate = RDO_FINISH then
+ dlm_ready <= '0';
+ error_reg <= '0';
+ end if;
+
+ status_reg <= "00";
+ dlm_ready <= '1';
+
+ end if;
+ end process;
+
+
+
+ PROC_RDO : process
+ begin
+ wait until rising_edge(CLK);
+ WRITE_OUT <= '0';
+ FINISHED_OUT <= config_rdo_disable_i;
+ case rdostate is
+ when RDO_IDLE =>
+ if TRIGGER_IN = '1' and config_rdo_disable_i = '0' then
+ if dlm_ready = '0' then
+ rdostate <= RDO_WAIT;
+ else
+ rdostate <= RDO_WRITE;
+ end if;
+ end if;
+
+ when RDO_WAIT =>
+ if dlm_ready = '1' then
+ rdostate <= RDO_WRITE;
+ end if;
+
+ when RDO_WRITE =>
+ rdostate <= RDO_FINISH;
+ DATA_OUT <= error_reg & status_reg & "0000" & '0' & x"00"& number_reg & subtrigger;
+ WRITE_OUT <= '1';
+
+ when RDO_FINISH =>
+ FINISHED_OUT <= '1';
+ rdostate <= RDO_IDLE;
+ end case;
+ end process;
+
+ STATUSBIT_OUT(23) <= error_reg when rising_edge(CLK);
+ STATUS_REG_OUT <= error_reg & '1' & "000000" & x"00"& number_reg & subtrigger; -- TODO ?? --'0' was previously MBS_IN
+ DEBUG <= x"00000000";
+
+
+-- REGIO
+ GEN_REGIO: if INCL_REGIO = c_YES generate
+ proc_regio: process is
+ variable addr : integer range 0 to 3;
+ begin
+ wait until rising_edge(CLK);
+
+ addr := to_integer(UNSIGNED(REGIO_IN.addr(1 downto 0)));
+ REGIO_OUT.rack <= REGIO_IN.read;
+ REGIO_OUT.wack <= REGIO_IN.write;
+ REGIO_OUT.nack <= '0';
+ REGIO_OUT.unknown <= '0';
+ REGIO_OUT.data <= (others => '0');
+
+ case addr is
+ when 0 =>
+ REGIO_OUT.data( 1 downto 0) <= '0' & (not config_rdo_disable_i);
+ REGIO_OUT.data(7) <= error_reg;
+ REGIO_OUT.data(31 downto 8) <= x"00" & number_reg & subtrigger;
+
+ when 1 =>
+ REGIO_OUT.data <= std_logic_vector(rec_counter_i);
+
+ when 2 =>
+ REGIO_OUT.data <= (others => '0');--std_logic_vector(act_counter_i);
+
+ when 3 =>
+ REGIO_OUT.data <= (others => '0');--std_logic_vector(high_counter_i);
+
+ end case;
+
+ if REGIO_IN.write='1' then
+ if addr=0 then
+ config_rdo_disable_i <= not REGIO_IN.data(0);
+ else
+ REGIO_OUT.unknown <= '1';
+ end if;
+ end if;
+
+ if RESET_IN = '1' then
+ config_rdo_disable_i <= '0';
+ end if;
+ end process;
+
+-- proc_stats: process is
+-- variable this_mbs : std_logic;
+-- variable last_mbs : std_logic;
+-- variable last_trg_sync : std_logic;
+-- begin
+-- wait until rising_edge(CLK);
+--
+-- this_mbs := reg_MBS_IN or reg_MBS_DELAY;
+--
+-- -- if this_mbs = '1' then
+-- -- high_counter_i <= high_counter_i + 1;
+-- -- end if;
+--
+-- --if trg_sync = '1' and last_trg_sync='0' then
+-- -- rec_counter_i <= rec_counter_i + 1;
+-- --end if;
+--
+-- --if this_mbs /= last_mbs then
+-- -- act_counter_i <= act_counter_i + 1;
+-- --end if;
+--
+-- --if RESET_IN='1' then
+-- --high_counter_i <= (others => '0');
+-- -- rec_counter_i <= (others => '0');
+-- --act_counter_i <= (others => '0');
+-- --end if;
+--
+-- last_trg_sync := trg_sync;
+-- last_mbs := this_mbs;
+-- end process;
+ end generate;
+
+ GEN_NO_REGIO: if INCL_REGIO /= c_YES generate
+ config_rdo_disable_i <= CONTROL_REG_IN(0);
+ REGIO_OUT.unknown <= REGIO_IN.read or REGIO_IN.write;
+ end generate;
+end architecture;