---------------------------------------------------------------------------- -- Lawrence Berkeley National Laboratory (c) 1997 -- BaBar Trigger Electronics ---------------------------------------------------------------------------- -- Description: -- State machine, controlling the latching of commands and data, as well -- as the strobe timing. ---------------------------------------------------------------------------- -- Structure: -- sm: -- state machine body: 16 header and 16 data states. the state machine -- can loop multiple times over all header and all data states to -- transmit 4 byte headers or multiple word data. -- output:- output generator for latch and loop control signals. -- output_dta: -- differentiate data and header cycles -- ff: -- synchronous logic for loop control signals -- d_strobe: -- data handshake control logic ---------------------------------------------------------------------------- -- Timing: -- Output data stream is generated once the first data word is latched. -- following data words have to be presented no later than 12 ticks after -- a valid next data. ---------------------------------------------------------------------------- -- Author: Armin Karcher -- History: -- Karcher 03/97 - First Version -- Karcher 1-99 - Block read version, all latencies fixed ---------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; ---------------------------------------------------------------------------- --PORT DECLARATION ---------------------------------------------------------------------------- entity sm0_dlink is port( clk : in std_logic; -- clk60 input, distributed rst : in std_logic; -- global reset clk_30 : in std_logic; -- clk30 data_vld : in std_logic; -- register or external data valid lst_data : in std_logic; -- last data word dt_lng : in std_logic; -- two word data rd_blk : in std_logic; -- block read blk_done : in std_logic; -- block done rd_evt : in std_logic; -- read event cmd_str : in std_logic; -- command strobe rd_dt_str : in std_logic; -- read data strobe reg_acc : in std_logic; -- csr register access st_spare1 : in std_logic; -- board ID st_spare2 : in std_logic; -- board ID dt_sel : out std_logic_vector(2 downto 0); --header/data select rd_inc : out std_logic; -- increment block counter latch : out std_logic; -- latch data dl_rd : out std_logic; -- busy reading event data next_data : out std_logic -- next data word ); end sm0_dlink; architecture rtl of sm0_dlink is ---------------------------------------------------------------------------- --SIGNAL DECLARATION ---------------------------------------------------------------------------- type states is (idle,h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13,h14,h15 ,d0,d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15); signal state : states; signal lst_data_pend : std_logic; -- last data word is transferred signal evt_pend : std_logic; -- bussy sending event data signal evt_end : std_logic; -- state machine will return to idle -- after this cycle signal transfer_start : std_logic; -- start data transfer -- (delay read_event header) signal cnt : std_logic_vector(11 downto 0); -- delay counter signal cnt_en : std_logic; -- delay counter enable signal ct_one : std_logic; -- first cycle completed signal ct_two : std_logic; -- second cycle (end of full delay) signal ct_shrt : std_logic; -- short delay completed signal wait_long : std_logic; -- use full-length delay counter signal latch_i : std_logic; -- latch data signal latch_end : std_logic; -- latch data derived signals, used signal latch_del : std_logic; -- for next data strobe alignment signal bit : std_logic; -- loop control bit signal bit_clr : std_logic; -- clear loop control bit signal bit_set : std_logic; -- set loop control bit signal clr : std_logic; -- end of cycle mark signal dta : std_logic; -- data/header flag signal acc_del : std_logic; -- delayed version of reg_acc strobe begin ---------------------------------------------------------------------------- --PROCESS DECLARATION ---------------------------------------------------------------------------- dly_rd_evt: process (clk,rst) begin if (rst = '1') then -- reset all variables transfer_start <= '0'; cnt_en <= '0'; ct_one <= '0'; ct_two <= '0'; ct_shrt <= '0'; wait_long <= '0'; elsif (clk'event and clk = '1') then -- rising edge if (rd_dt_str = '1' OR (rd_evt ='1' AND cmd_str ='1')) then cnt_en <= '1'; -- start delay counter elsif (transfer_start ='1') then cnt_en <= '0'; -- disable and reset counter end if; if (ct_one ='1') then ct_two <= '1'; -- remember first cycle elsif (transfer_start ='1') then ct_two <= '0'; -- finished second cycle end if; -- if ( rd_evt ='1' AND st_spare1 ='0' AND st_spare2 ='0') then -- eventually reduce latency for PTD/BLT/GLT read event if ( rd_evt ='1') then wait_long <= '1'; -- wait long only for TSF read events elsif (transfer_start ='1') then -- waiting completed wait_long <= '0'; end if; if ((wait_long ='1' AND ct_two ='1' AND ct_one ='1') OR -- read event (wait_long ='0' AND ct_shrt ='1')) then -- read data transfer_start <='1'; -- finished appropriate delay counting else transfer_start <='0'; -- finished transfer cycle normally low end if; if (cnt ="010000000000")then ct_one <= '1'; else ct_one <= '0'; end if; if (cnt(4 downto 0) ="11111")then ct_shrt <= '1'; else ct_shrt <= '0'; end if; end if; end process dly_rd_evt; dly_ctr : process (rst,clk,cnt_en) -- read event delay counter variable ia_tmp : unsigned (11 downto 0); begin -- blk_counter if (rst='1' OR cnt_en = '0') then --SECRET: use local reset for speed cnt <= (others => '0'); elsif (clk'event and clk='1') then ia_tmp := unsigned(cnt) + 1; cnt <= std_logic_vector(ia_tmp); end if; end process dly_ctr; --process sm: glitch free Mealy state machine sm: process (clk,rst) begin if (rst = '1') then -- reset all variables state <= idle; elsif (clk'event and clk = '1') then -- rising edge case state is when idle => if (transfer_start = '1' or data_vld ='1') then state <= h0; end if; when h0 => state <= h1; when h1 => state <= h2; when h2 => state <= h3; when h3 => state <= h4; when h4 => state <= h5; when h5 => state <= h6; when h6 => state <= h7; when h7 => state <= h8; when h8 => state <= h9; when h9 => state <= h10; when h10 => state <= h11; when h11 => state <= h12; when h12 => state <= h13; when h13 => state <= h14; when h14 => state <= h15; when h15 => if (evt_pend ='1' AND bit = '0') then state <= h0; else state <= d0; end if; when d0 => state <= d1; when d1 => state <= d2; when d2 => state <= d3; when d3 => state <= d4; when d4 => state <= d5; when d5 => state <= d6; when d6 => state <= d7; when d7 => state <= d8; when d8 => state <= d9; when d9 => state <= d10; when d10 => state <= d11; when d11 => state <= d12; when d12 => state <= d13; when d13 => state <= d14; when d14 => state <= d15; when d15 => if (evt_end ='1') then state <= idle; else state <= d0; end if; when others => state <= idle; end case; end if; end process sm; output: process (state,clk,rst) begin if (rst = '1') then -- reset all variables bit_clr <= '0'; bit_set <= '0'; latch_i <= '0'; clr <= '0'; elsif (clk'event and clk = '1') then -- rising edge case state is when idle => bit_clr <= '1'; bit_set <= '0'; latch_i <= '0'; clr <= '0'; when h0 => bit_clr <= '0'; bit_set <= '0'; latch_i <= '1'; clr <= '0'; when d0 => bit_clr <= '0'; bit_set <= '0'; latch_i <= '1'; clr <= '0'; when h15 => bit_clr <= '0'; bit_set <= '1'; latch_i <= '0'; clr <= '0'; when d15 => bit_clr <= '0'; bit_set <= '0'; latch_i <= '0'; clr <= '1'; when others => bit_clr <= '0'; bit_set <= '0'; latch_i <= '0'; clr <= '0'; end case; end if; end process output; output_dta: process (state,clk,rst) begin if (rst = '1') then -- reset all variables dta <= '0'; elsif (clk'event and clk = '1') then -- rising edge case state is when idle => dta <= '0'; when h0 => dta <= '0'; when h1 => dta <= '0'; when h2 => dta <= '0'; when h3 => dta <= '0'; when h4 => dta <= '0'; when h5 => dta <= '0'; when h6 => dta <= '0'; when h7 => dta <= '0'; when h8 => dta <= '0'; when h9 => dta <= '0'; when h10 => dta <= '0'; when h11 => dta <= '0'; when h12 => dta <= '0'; when h13 => dta <= '0'; when h14 => dta <= '0'; when h15 => dta <= '0'; when d0 => dta <= '1'; when d1 => dta <= '1'; when d2 => dta <= '1'; when d3 => dta <= '1'; when d4 => dta <= '1'; when d5 => dta <= '1'; when d6 => dta <= '1'; when d7 => dta <= '1'; when d8 => dta <= '1'; when d9 => dta <= '1'; when d10 => dta <= '1'; when d11 => dta <= '1'; when d12 => dta <= '1'; when d13 => dta <= '1'; when d14 => dta <= '1'; when d15 => dta <= '1'; when others => dta <= '0'; end case; end if; end process output_dta; ff: process (clk,rst) begin if (rst = '1') then -- reset all variables evt_pend <= '0'; evt_end <= '0'; bit <= '0'; rd_inc <= '0'; lst_data_pend <= '0'; acc_del <= '0'; elsif (clk'event and clk = '1') then -- rising edge acc_del <= reg_acc; if ((lst_data ='1' AND rd_blk = '0')OR blk_done ='1' OR evt_end = '1') then lst_data_pend <= '1'; elsif (bit_clr ='1') then lst_data_pend <= '0'; end if; if ((rd_evt ='1' AND cmd_str ='1') OR (rd_blk='1' AND rd_dt_str ='1')) then evt_pend <= '1'; elsif (evt_end ='1') then evt_pend <= '0'; end if; if (bit_clr ='1') then evt_end <= '0'; elsif ((lst_data_pend ='1' AND latch_i ='1') OR (evt_pend ='0' AND (dt_lng ='0' OR (dt_lng ='1' AND clr ='1')))) then evt_end <= '1'; end if; if (bit_set ='1') then bit <= '1'; elsif (bit_clr ='1') then bit <= '0'; end if; rd_inc <= clr AND NOT lst_data_pend; end if; end process ff; d_strobe: process (clk,rst) begin if (rst = '1') then -- reset all variables latch_del <= '0'; latch_end <= '0'; next_data <= '0'; elsif (clk'event and clk = '1') then -- rising edge latch_del <= (latch_i AND dta); latch_end <= (clk_30 AND ((latch_i AND dta) OR latch_del)); next_data <= (latch_end OR (clk_30 AND ((latch_i AND dta) OR latch_del))) AND NOT lst_data_pend; end if; end process d_strobe; dt_sel(0) <= dta; dt_sel(1) <= bit; dt_sel(2) <= evt_pend; latch <= latch_i; dl_rd <= evt_pend; end rtl;