--------------------------------------------------------------------------------
-- CERN BE-CO-HT
--
-- https://www.ohwr.org/projects/wr2rf-vme
--------------------------------------------------------------------------------
--
-- unit name:   wr2rf_gen_10mhz
--
-- description: Provides a 10 MHz clock for front panel
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- 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 wr2rf_gen_10mhz is

    port (
        clk125m_i       : in  std_logic;
        rst_clk125m_i   : in  std_logic;

        clk500m_i       : in  std_logic;
        rst_clk500m_i   : in  std_logic;

        pps_i           : in  std_logic;
        pps_valid_i     : in  std_logic;
        
        clk10m_o        : out std_logic );

    attribute keep_hierarchy : string;
    attribute keep_hierarchy of wr2rf_gen_10mhz : entity is "yes";

end entity;

architecture rtl of wr2rf_gen_10mhz is
   
   constant d4width : integer := 4;
   subtype  d4_t    is std_logic_vector(d4width-1 downto 0);
   type     v4_t    is array (natural range <>) of d4_t;
   signal pat_rom   : v4_t(24 downto 0) := (X"0",
                                            X"0", X"0", X"0", X"0", X"0", X"7",
                                            X"f", X"f", X"f", X"f", X"f", X"c",
                                            X"0", X"0", X"0", X"0", X"0", X"1",
                                            X"f", X"f", X"f", X"f", X"f", X"f");
   signal idx         : unsigned(4 downto 0);
   signal idx_r       : unsigned(4 downto 0);
   signal pat_syncd   : std_logic;
   signal pat_syncd_r : std_logic;
   signal pattern     : std_logic_vector(3 downto 0);
   signal pattern_r   : std_logic_vector(3 downto 0);
   signal clk10m      : std_logic;   
      
begin

   pat_syncd <= '0'           when pps_valid_i = '0'                 else
                '1'           when pps_valid_i = '1' and pps_i = '1' else pat_syncd_r;
   idx     <= (others => '0') when pat_syncd   = '0' or  idx_r = 24  else idx_r + 1;
   pattern <= (others => '0') when pat_syncd   = '0'                 else pat_rom(to_integer(idx_r));

   process (clk125m_i) is
   begin
      if rising_edge(clk125m_i) then
         if rst_clk125m_i = '1' then
            pat_syncd_r <= '0';
            idx_r       <= (others => '0');
            pattern_r   <= (others => '0');
         else
            pat_syncd_r <= pat_syncd;            
            idx_r       <= idx;
            pattern_r   <= pattern;
         end if;
      end if;
   end process;

   inst_10mhz_oserdes : OSERDESE2
      generic map (
         DATA_RATE_OQ   => "SDR",    -- DDR, SDR
         DATA_RATE_TQ   => "SDR",    -- DDR, BUF, SDR
         DATA_WIDTH     => 4,        -- 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       => open,          -- 1-bit output: Feedback path for data
         OQ        => clk10m_o,      -- 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       => clk500m_i,     -- 1-bit input: High speed clock
         CLKDIV    => clk125m_i,     -- 1-bit input: Divided clock
         D1        => pattern_r(0),  -- D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
         D2        => pattern_r(1),
         D3        => pattern_r(2),
         D4        => pattern_r(3),
         D5        => '0',
         D6        => '0',
         D7        => '0',
         D8        => '0',
         OCE       => '1',           -- 1-bit input: Output data clock enable
         RST       => rst_clk125m_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
      
end architecture;
