--******************************************************************************
--* @short    Timing of Logic FPGA
--******************************************************************************
--* @author   SAKULIN Hannes  <hsakulin@dsy-srv3.cern.ch>
--* @date     $Date: 2005/01/31 15:17:30 $
--* @version  $Revision: 1.6 $
--******************************************************************************
--/
library ieee;
use ieee.std_logic_1164.all;

package LFTiming is

-- compute all the clock edges, here. The rather complicated approach is
-- necessary in order to be able to shift blocks inside the chip to start at
-- different edges and in order to shift the startind enge of the chip itself.
-- edges are therefore computed where needed and never hard-coded (except VME).
--
--    
-- first, latencies relative to the block are defined (basically for each FF):
-- syntax: [Chip]_RLAT_[block]_afteritem
--   e.g.: LF_RLAT_MU_DELTAETA := 2
--   note: this is the latency AFTER the item
--
-- then, latencies of blocks relative to the chip (earliest input) are defined:
-- e.g.: LF_LAT_MM_START
--
-- edges can then be calculated from the delay and the starting edge (i.e. edge
-- of the last FF) before the block.
-- 
-- point of reference is AFTER the input FF of the earliest input signal
--

-- Note on the distribution of clock signals:
-- ==========================================
--
-- * all inputs labelled 'clk' contain the clock (never the inverted clock)
--
-- * small blocks (only 1 FF) and LUTs can be passed a generic argument
--  named edge which decides on which edege of the clock the FF will work
--
-- * bigger blocks get the start latency (relative to the chip reference)
--   as generic parameter lat_start. From this and the Relatice latencies in
--   the block they can use teh fucntion calc_lf_edge to determine the edges of
--   various FFs.
--
-- * where different processing paths come together, the latencies of the signals
--   should be asserted
--
  

-- Matching Unit
constant LF_RLAT_MU_DELTAETA  : integer := 2;
constant LF_RLAT_MU_MQPAIR    : integer := 4;

-- Cancel-Out Units
constant LF_RLAT_COU_DELAY    : integer :=  1;
constant LF_RLAT_COU_MU       : integer :=  5;
constant LF_RLAT_COU_CDL      : integer :=  6;
constant LF_RLAT_COUINP_ISMATCHEDOTHER : integer := 5;
constant LF_RLAT_COUINP_ISMATCHEDMINE  : integer := 4;


-- Sort Rank Unit
constant LF_RLAT_SRU_LUT1    : integer := 1;  -- first stage sort-rank LUT
constant LF_RLAT_SRU_LUT2    : integer := 2;  -- second stage sort-rank LUT
constant LF_RLAT_SRU_OFFSADD : integer := 4;  -- offset adder

-- OVL Disable Hot Unit
constant LF_RLAT_DISHOT : integer := 1;

-- Merge Method Selector
constant LF_LAT_MMS_START : integer := 0;

constant LF_RLAT_MMS_LUT1    : integer := 1;  -- first stage sort-rank LUT
constant LF_RLAT_MMS_LUT2    : integer := 2;  -- second stage sort-rank LUT
constant LF_RLAT_MMS_DONE    : integer := 4;  -- offset adder

-- Sorter
constant LF_LAT_SORT_START : integer := 6; 

constant LF_RLAT_SORT_GEMatrix : integer := 1;  -- register GE matrix
constant LF_RLAT_SORT_DONE     : integer := 3;  -- last FF

-- Sort Rank Merger
constant LF_LAT_SRM_START : integer := 4;
constant LF_RLAT_SRM_DONE : integer := 2;  -- SRM takes 2 half-bx

-- Muon Merger
constant LF_LAT_MM_START : integer := 4;

constant LF_RLAT_MM_PTMIX : integer := 1;  
constant LF_RLAT_MM_DONE : integer := 2;  -- MM takes 2 half-bx


-- Conversion
constant LF_LAT_CONV_START : integer := 2;

constant LF_RLAT_CONV_DONE : integer := 2;

--Phi Projection Unit
constant LF_RLAT_PHIPRO_LUT : integer := 1;

--
-- Chip I/O latencies (relative to after the earliest input FF)
-- ( warning: the latencies here are 1/2 bx less than in the test bench)
-- 

constant LF_LAT_OUT_MYDTCSCISMATCHED   : integer := 4;
--assert LF_LAT_OUT_MYDTCSCISMATCHED = LF_DELAY_MU + 1
--  report "latency mismatch for LF_LAT_OUT_MYDTCSCISMATCHED" severity failure;
  
constant LF_LAT_IN_OTHERDTCSCISMATCHED : integer := 5;
--assert LF_LAT_IN_OTHERDTCSCISMATCHED = LF_DELAY_MU + 2
--  report "latency mismatch for LF_LAT_IN_OTHERDTCSCISMATCHED" severity failure;

constant LF_LAT_OUT_CANCELOTHERDTCSC : integer := 6;
--assert LF_LAT_OUT_CANCELOTHERDTCSC = LF_DELAY_COU + 1
--  report "latency mismatch for LF_LAT_OUT_CANCELOTHERDTCSC" severity failure;

constant LF_LAT_IN_CANCELDTCSC : integer := 7;

constant LF_LAT_IN_MIPISO : integer := 5;

constant LF_LAT_OUT : integer := 9;

constant LF_LAT_OUT_PM_DEBUG   : integer := 5;
constant LF_LAT_OUT_COU_DEBUG  : integer := 7;


-- reference edge for chip == edge of first chip input
-- this edge and the latency to some point define the edge at that point

constant LF_EDGE_REF : std_logic := '1';  -- the reference edge 
constant LF_EDGE_INPUT : std_logic := '1'; -- clk edge for muon data input (1 = rising)


-------------------------------------------------------------------------------
-- for VME, the edge is hard-coded
-------------------------------------------------------------------------------

constant LF_EDGE_VME : std_logic := '1'; -- clk edge for VME  data I/O (1 = rising)


function calc_lf_edge (constant latency : integer)
  return std_logic;


end package LFTiming;


package body LFTiming is

function calc_lf_edge (constant latency : integer)
  return std_logic is
    variable edge : std_logic;
    variable lat : integer;
  begin
    if (LF_EDGE_REF = '1') then
      lat := 1;
    else
      lat := 0;
    end if;
    lat := lat + latency;
    if ((lat mod 2) = 1) then
      edge := '1';
    else
      edge := '0';
    end if;
    return edge;
  end;
  
end package body LFTiming;