--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- WR2RF_VME core
-- https://ohwr.org/project/vme-rf-wr-bobr
--------------------------------------------------------------------------------
--
-- unit name:   ch_vtu
--
-- description: Per channel vtu
--
--------------------------------------------------------------------------------
-- Copyright (c) 2020 CERN (home.cern)
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library unisim;
use unisim.vcomponents.all;

entity ch_vtu is
    port (
      --  System clock (125Mhz or 62.5Mhz)
      clk_sys    : in  std_logic;
      --  Systen reset clock (> 50ns)
      rst_sys    : in  std_logic;

      rst_vtu_i  : in  std_logic;

      --  Reference clock for delays.  200Mhz.
      clk_refclk : in  std_logic;

      -- RF clock (~200Mhz)
      rf_clk_n_i : in  std_logic;
      rf_clk_p_i : in  std_logic;
      
      -- Sync pulse generated by the reset/sync logic, but from a pad.
      sync_i : in  std_logic;

      -- Generated trigger pulse
      trig_n_o : out std_logic;
      trig_p_o : out std_logic;

      --  FIXME: temporary control and status regs.
      vtu_mode              : in  std_logic_vector(2 downto 0);
      vtu_bvalue            : in  std_logic_vector(63 downto 0);
      vtu_wrongb            : out std_logic;
      vtu_use_sync_as_start : in  std_logic;
      vtu_htvalue           : in  std_logic_vector (63 downto 0 );
      vtu_htswitching       : in  std_logic;
      vtu_wronght           : out std_logic;
      vtu_wvalue            : in  std_logic_vector(63 downto 0 );
      vtu_wrongw            : out std_logic;
      vtu_running           : out std_logic
    );
end ch_vtu;

architecture rtl of ch_vtu is
    -- Incoming RF_CLK from pad.
    signal rf_clk : std_logic;
    signal rf_clk_n : std_logic;

    -- RF_CLK for SERDES.
    signal rf_clk_io : std_logic;

    -- The main clock, RF_CLK / 8
    signal vtu_clk : std_logic;

    -- Delayed sync_i signal.
    signal sync_del : std_logic;

    --  Delay value for sync and write signal.
    signal sync_idelay_in  : std_logic_vector (4 downto 0);
    signal sync_idelay_wr  : std_logic;

    --  Sync delay current value.
    signal sync_idelay_out : std_logic_vector (4 downto 0);

    --  Status: idelay cell is calibrated.
    signal idelay_rdy      : std_logic;

    signal vtu_start       : std_logic;
    signal vtu_stop        : std_logic;

    signal sync_data_in    : std_logic_vector(7 downto 0);
    signal sync_data_out   : std_logic_vector(7 downto 0);

    --  Trigger out, before delay.
    signal trig1_out       : std_logic;

    --  Delay value for trig1 and write signal.
    signal trig1_odelay_in  : std_logic_vector (4 downto 0);
    signal trig1_odelay_wr  : std_logic;

    --  Trig1 delay current value.
    signal trig1_odelay_out : std_logic_vector (4 downto 0);

    signal trig1_del : std_logic;

begin
    inst_rf_clk_IBUFDS: IBUFDS_DIFF_OUT
        generic map (
            DIFF_TERM    => FALSE, --Differential Termination
            IBUF_LOW_PWR => TRUE,  --Lowpower (TRUE) vs. performance (FALSE) setting for referenced I/O standards
            IOSTANDARD   => "DEFAULT")
        port map(
            O => rf_clk,
            OB => rf_clk_n,
            I => rf_clk_p_i,
            IB => rf_clk_n_i);

    inst_rf_clk_io_BUFIO: BUFIO
        port map (
            I => rf_clk,
            O => rf_clk_io);

    inst_rf_clk_BUFR: BUFR
        generic map (
            BUFR_DIVIDE => "8",
            SIM_DEVICE => "7SERIES")
        port map (
            O => vtu_clk,
            CE  => '1',
            CLR => '0',
            I   => rf_clk);

    inst_sync_IDELAYE2 : IDELAYE2
        generic map (
            CINVCTRL_SEL => "FALSE",         -- Enable dynamic clock inversion (FALSE, TRUE)
            DELAY_SRC => "IDATAIN",          -- Delay input (IDATAIN, DATAIN)
            HIGH_PERFORMANCE_MODE => "TRUE", -- Reduced jitter ("TRUE"), Reduced power ("FALSE")
            IDELAY_TYPE => "VAR_LOAD",       -- FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
            IDELAY_VALUE => 0,               -- Input delay tap setting (0-31)
            PIPE_SEL => "FALSE",             -- Select pipelined mode, FALSE, TRUE
            REFCLK_FREQUENCY => 200.0,       -- IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
            SIGNAL_PATTERN => "DATA"         -- DATA, CLOCK input signal
            )
        port map (
            CNTVALUEOUT => sync_idelay_in,   -- output: Counter value output
            DATAOUT => sync_del,             -- output: Delayed data output
            C => clk_sys,                    -- input: Clock input
            CE => '0',                       -- input: Active high enable increment/decrement input
            CINVCTRL => '0',                 -- input: Dynamic clock inversion input
            CNTVALUEIN => sync_idelay_out,   -- input: Counter value input
            DATAIN => '0',                   -- input: Internal delay data input
            IDATAIN => sync_i,               -- input: Data input from the I/O
            INC => '0',                      -- input: Increment / Decrement tap delay input
            LD => sync_idelay_wr,            -- input: Load IDELAY_VALUE input
            LDPIPEEN => '0',                 -- input: Enable PIPELINE register to load data input
            REGRST => rst_sys);              -- input: Active-high reset tap-delay input
    
    inst_IDELAYCTRL : IDELAYCTRL
        port map (
            RDY => idelay_rdy,               -- 1-bit output: Ready output
            REFCLK => clk_refclk,            -- 1-bit input: Reference clock input
            RST => rst_sys);                 -- 1-bit input: Active high reset input

    inst_ISERDESE2 : ISERDESE2
        generic map (
            DATA_RATE => "SDR",              -- DDR, SDR
            DATA_WIDTH => 8,                 -- Parallel data width (2-8,10,14)
            DYN_CLKDIV_INV_EN => "FALSE",    -- Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE)
            DYN_CLK_INV_EN => "FALSE",       -- Enable DYNCLKINVSEL inversion (FALSE, TRUE)
            INIT_Q1 => '0',                  -- INIT_Q1 - INIT_Q4: Initial value on the Q outputs (0/1)
            INIT_Q2 => '0',
            INIT_Q3 => '0',
            INIT_Q4 => '0',
            INTERFACE_TYPE => "NETWORKING",  -- MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE
            IOBDELAY => "IFD",               -- NONE, BOTH, IBUF, IFD
            NUM_CE => 1,                     -- Number of clock enables (1,2)
            OFB_USED => "FALSE",             -- Select OFB path (FALSE, TRUE)
            SERDES_MODE => "MASTER",         -- MASTER, SLAVE            
            SRVAL_Q1 => '0',                 -- SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1)
            SRVAL_Q2 => '0',
            SRVAL_Q3 => '0',
            SRVAL_Q4 => '0'
            )
        port map (
            O => open,                       -- 1-bit output: Combinatorial output
            Q1 => sync_data_in(0),           -- Q1 - Q8: 1-bit (each) output: Registered data outputs
            Q2 => sync_data_in(1),           -- FIXME: check order
            Q3 => sync_data_in(2),
            Q4 => sync_data_in(3),
            Q5 => sync_data_in(4),
            Q6 => sync_data_in(5),
            Q7 => sync_data_in(6),
            Q8 => sync_data_in(7),
            SHIFTOUT1 => open,               -- SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports
            SHIFTOUT2 => open,
            BITSLIP => '0',                  -- The BITSLIP pin performs a Bitslip operation synchronous
            CE1 => '1',                      -- CE1, CE2: 1-bit (each) input: Data register clock enable inputs
            CE2 => '1',
            CLKDIVP => '0',                  -- 1-bit input: TBD
            CLK => rf_clk_io,                -- Clocks: 1-bit (each) input: ISERDESE2 clock input ports
            CLKB => rf_clk_n,
            CLKDIV => vtu_clk,               -- 1-bit input: Divided clock
            OCLK => '0',                     -- 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY"
            DYNCLKDIVSEL => '0',             -- 1-bit input: Dynamic CLKDIV inversion
            DYNCLKSEL => '0',                -- 1-bit input: Dynamic CLK/CLKB inversion
            D => sync_i,                     -- 1-bit input: Data input
            DDLY => sync_del,                -- 1-bit input: Serial data from IDELAYE2
            OFB => '0',                      -- 1-bit input: Data feedback from OSERDESE2
            OCLKB => '0',                    -- 1-bit input: High speed negative edge output clock
            RST => rst_vtu_i,                -- 1-bit input: Active high asynchronous reset            
            SHIFTIN1 => '0',                 -- SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports
            SHIFTIN2 => '0'
            );
    
    inst_vtu1 : entity work.vtuCore
        port map (
            --  Interface to the memory for the play memory mode.
            Mem_RdDone => '1',
            Mem_Addr => open,
            Mem_RdData => x"00",
            Mem_RdEna => open,
              
            Mode => vtu_mode, -- : in std_logic_vector(2 downto 0 );
              
            bValue => vtu_bvalue, -- : in std_logic_vector(63 downto 0 );
            wrongB => vtu_wrongb, -- : out std_logic;
            UseSyncAsStart => vtu_use_sync_as_start, -- : in std_logic;
              
            htValue => vtu_htvalue, -- : in std_logic_vector(63 downto 0 );
            htSwitching => vtu_htswitching, -- : in std_logic;
            wrongHT => vtu_wronght, -- : out std_logic;
              
            wValue => vtu_wvalue, -- : in std_logic_vector(63 downto 0 );
            wrongW => vtu_wrongw, -- : out std_logic;
              
            Start => vtu_start, -- : in std_logic;
            Stop => vtu_stop, -- : in std_logic;
              
            DataIn => sync_data_in,
            DataOut => sync_data_out, -- : out std_logic_vector(7 downto 0 );
              
            Mem_LastBit => (others => '0'),
            Mem_LastElem => (others => '0'),
              
            SyncPulse => open,
            Rst => rst_vtu_i,
            Run => vtu_running,
            Clk => vtu_clk);

    inst_trig1_OSERDESE2 : OSERDESE2
        generic map (
            DATA_RATE_OQ => "SDR",          -- DDR, SDR
            DATA_RATE_TQ => "SDR",          -- DDR, BUF, SDR
            DATA_WIDTH => 8,                -- Parallel data width (2-8,10,14)
            INIT_OQ => '0',                 -- Initial value of OQ output (1'b0,1'b1)
            INIT_TQ => '0',                 -- Initial value of TQ output (1'b0,1'b1)
            SERDES_MODE => "MASTER",        -- MASTER, SLAVE
            SRVAL_OQ => '0',                -- OQ output value when SR is used (1'b0,1'b1)
            SRVAL_TQ => '0',                -- TQ output value when SR is used (1'b0,1'b1)
            TBYTE_CTL => "FALSE",           -- Enable tristate byte operation (FALSE, TRUE)
            TBYTE_SRC => "FALSE",           -- Tristate byte source (FALSE, TRUE)
            TRISTATE_WIDTH => 1             -- 3-state converter width (1,4)
            )
        port map (
            OFB => trig1_out,               -- 1-bit output: Feedback path for data
            OQ => open,                     -- 1-bit output: Data path output
            SHIFTOUT1 => open,              -- SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
            SHIFTOUT2 => open,
            TBYTEOUT => open,               -- 1-bit output: Byte group tristate
            TFB => open,                    -- 1-bit output: 3-state control
            TQ => open,                     -- 1-bit output: 3-state control
            CLK => rf_clk_io,               -- 1-bit input: High speed clock
            CLKDIV => vtu_clk,              -- 1-bit input: Divided clock
            D1 => sync_data_out(0),         -- D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
            D2 => sync_data_out(1),
            D3 => sync_data_out(2),
            D4 => sync_data_out(3),
            D5 => sync_data_out(4),
            D6 => sync_data_out(5),
            D7 => sync_data_out(6),
            D8 => sync_data_out(7),
            OCE => '1',                     -- 1-bit input: Output data clock enable
            RST => rst_vtu_i,               -- 1-bit input: Reset
            SHIFTIN1 => '0',                -- SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
            SHIFTIN2 => '0',
            T1 => '0',                      -- T1 - T4: 1-bit (each) input: Parallel 3-state inputs
            T2 => '0',
            T3 => '0',
            T4 => '0',
            TBYTEIN => '0',                 -- 1-bit input: Byte group tristate
            TCE => '0'                     -- 1-bit input: 3-state clock enable
        );
    inst_trig1_ODELAYE2 : ODELAYE2
        generic map (
            CINVCTRL_SEL => "FALSE",         -- Enable dynamic clock inversion (FALSE, TRUE)
            DELAY_SRC => "ODATAIN",          -- Delay input (ODATAIN, CLKIN)
            HIGH_PERFORMANCE_MODE => "TRUE", -- Reduced jitter ("TRUE"), Reduced power ("FALSE")
            ODELAY_TYPE => "VAR_LOAD",       -- FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
            ODELAY_VALUE => 0,               -- Output delay tap setting (0-31)
            PIPE_SEL => "FALSE",             -- Select pipelined mode, FALSE, TRUE
            REFCLK_FREQUENCY => 200.0,       -- IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
            SIGNAL_PATTERN => "DATA"         -- DATA, CLOCK input signal
            )
        port map (
            CNTVALUEOUT => trig1_odelay_out, -- output: Counter value output
            DATAOUT => trig1_del,            -- output: Delayed data/clock output
            C => clk_sys,                    -- input: Clock input
            CE => '0',                       -- input: Active high enable increment/decrement input
            CINVCTRL => '0',                 -- input: Dynamic clock inversion input
            CLKIN => '0',                    -- input: Clock delay input
            CNTVALUEIN => trig1_odelay_in,   -- input: Counter value input
            INC => '0',                      -- input: Increment / Decrement tap delay input
            LD => trig1_odelay_wr,           -- input: Loads ODELAY_VALUE tap delay in VARIABLE mode
            LDPIPEEN => '0',                 -- input: Enables the pipeline register to load data
            ODATAIN => trig1_out,            -- input: Output delay data input
            REGRST => rst_sys                -- input: Active-high reset tap-delay input
        );

    inst_trig1_OBUFDS : OBUFDS
        generic map (
            IOSTANDARD => "DEFAULT",
            SLEW => "SLOW")
        port map (
            O  => trig_p_o,  -- Diff_p output
            OB => trig_n_o,  -- Diff_n output
            I => trig1_del);
end rtl;
