library ieee;
use ieee.std_logic_1164.all;
--use ieee.numeric_std.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

library UNISIM;
use UNISIM.VCOMPONENTS.ALL;

entity qsfp_intfc_v1_1 is
  generic (
    -- Users to add parameters here
        FPGA_REVISION_DATE                    : std_logic_vector(31 downto 0) := x"0603_2024";
        MINOR_REV                             : std_logic_vector( 7 downto 0) := x"01";
    -- User parameters ends
    -- Do not modify the parameters beyond this line


    -- Parameters of Axi Slave Bus Interface S00_AXI
    C_S00_AXI_DATA_WIDTH                      : integer := 32;
    C_S00_AXI_ADDR_WIDTH                      : integer := 7
  );
  port (
    -- Users to add ports here
    clk_125_in                                : in  std_logic;
    clk_125_reset_n_in                        : in  std_logic;

    clk_250_in                                : in  std_logic;
    clk_250_reset_n_in                        : in  std_logic;

    rx_device_clk_in                          : in  std_logic;  
    tx_device_clk_in                          : in  std_logic;  

    clkin8_in                                 : in  std_logic;
--    sysref_in                                 : in  std_logic;
    ref_clk_div2_in                           : in  std_logic;

    QSFP1_RESETL_LS                           : out std_logic;     
    QSFP1_MODPRSL_LS                          : in  std_logic;      
    QSFP1_INTL_LS                             : in  std_logic;     
-----------------
    QSFP2_RESETL_LS                           : out std_logic;     
    QSFP2_MODPRSL_LS                          : in  std_logic;      
    QSFP2_INTL_LS                             : in  std_logic;     
-----------------
    QSFP3_RESETL_LS                           : out std_logic;     
    QSFP3_MODPRSL_LS                          : in  std_logic;      
    QSFP3_INTL_LS                             : in  std_logic;     
-----------------
    QSFP4_RESETL_LS                           : out std_logic;     
    QSFP4_MODPRSL_LS                          : in  std_logic;         
    QSFP4_INTL_LS                             : in  std_logic;  
----
    cmac_0_rx_tvalid_512b_cnt_in                     : in  std_logic_vector(31 downto 0);
    cmac_4_rx_tvalid_512b_cnt_in                     : in  std_logic_vector(31 downto 0);
    cmac_rx_tvalid_256b_cnt_in                     : in  std_logic_vector(31 downto 0);
    mem_xfer_tx_upload_tvalid_256b_cnt_in     : in  std_logic_vector(31 downto 0);
    dac_tvalid_256b_cnt_in                 : in  std_logic_vector(31 downto 0);

    adc_tvalid_256b_cnt_in                 : in  std_logic_vector(31 downto 0);
    cmac_0_tx_tvalid_512b_cnt_in                 : in  std_logic_vector(31 downto 0);
    cmac_4_tx_tvalid_512b_cnt_in                 : in  std_logic_vector(31 downto 0);
    
    cnt_reset_out                             : out std_logic;

    slv_reg9_out                              : out std_logic_vector(31 downto 0);
    slv_reg10_out                             : out std_logic_vector(31 downto 0);

    slv_reg31_out                             : out std_logic_vector(31 downto 0);

    slv_reg38_out                             : out std_logic_vector(31 downto 0);
                 
    slv_reg45_out                             : out std_logic_vector(31 downto 0);

    slv_reg52_out                             : out std_logic_vector(31 downto 0);

   
    -- User ports ends
    -- Do not modify the ports beyond this line

    -- Ports of Axi Slave Bus Interface S00_AXI
    sys_cpu_clk_in                            : in std_logic;
    s00_axi_aresetn_in                        : in std_logic;
    s00_axi_awaddr                            : in std_logic_vector(C_S00_AXI_ADDR_WIDTH-1 downto 0);
    s00_axi_awprot                            : in std_logic_vector(2 downto 0);
    s00_axi_awvalid                           : in std_logic;
    s00_axi_awready                           : out std_logic;
    s00_axi_wdata                             : in std_logic_vector(C_S00_AXI_DATA_WIDTH-1 downto 0);
    s00_axi_wstrb                             : in std_logic_vector((C_S00_AXI_DATA_WIDTH/8)-1 downto 0);
    s00_axi_wvalid                            : in std_logic;
    s00_axi_wready                            : out std_logic;
    s00_axi_bresp                             : out std_logic_vector(1 downto 0);
    s00_axi_bvalid                            : out std_logic;
    s00_axi_bready                            : in std_logic;
    s00_axi_araddr                            : in std_logic_vector(C_S00_AXI_ADDR_WIDTH-1 downto 0);
    s00_axi_arprot                            : in std_logic_vector(2 downto 0);
    s00_axi_arvalid                           : in std_logic;
    s00_axi_arready                           : out std_logic;
    s00_axi_rdata                             : out std_logic_vector(C_S00_AXI_DATA_WIDTH-1 downto 0);
    s00_axi_rresp                             : out std_logic_vector(1 downto 0);
    s00_axi_rvalid                            : out std_logic;
    s00_axi_rready                            : in std_logic
  );
end qsfp_intfc_v1_1;

architecture arch_imp of qsfp_intfc_v1_1 is

  signal fpga_revision_date_r             : std_logic_vector(31 downto 0) := (others => '0');
  attribute keep                          : string;
  attribute keep of fpga_revision_date_r  : signal is "true";

  signal minor_rev_r                      : std_logic_vector( 7 downto 0) := (others => '0');
  attribute keep of minor_rev_r           : signal is "true";

--
  signal qsfp1_reset_n                    : std_logic;   
  signal qsfp1_modprsl                    : std_logic;   
  signal qsfp1_intl                       : std_logic;   

  signal qsfp2_reset_n                    : std_logic;   
  signal qsfp2_modprsl                    : std_logic;   
  signal qsfp2_intl                       : std_logic;   

  signal qsfp3_reset_n                    : std_logic;   
  signal qsfp3_modprsl                    : std_logic;   
  signal qsfp3_intl                       : std_logic;   

  signal qsfp4_reset_n                    : std_logic;   
  signal qsfp4_modprsl                    : std_logic;   
  signal qsfp4_intl                       : std_logic;   
--
  signal tick_1ms                         : std_logic;

  signal clk_125_tick_1ms_r               : std_logic_vector(0 to 2) := (others => '0');
  signal clk_125_freq_r                   : std_logic_vector(31 downto 0) := (others => '0');
  signal clk_125_cnt_r                    : std_logic_vector(31 downto 0) := (others => '0');

  signal clk_250_tick_1ms_r               : std_logic_vector(0 to 2) := (others => '0');
  signal clk_250_freq_r                   : std_logic_vector(31 downto 0) := (others => '0');
  signal clk_250_cnt_r                    : std_logic_vector(31 downto 0) := (others => '0');

  signal rx_device_clk_tick_1ms_r           : std_logic_vector(0 to 2) := (others => '0');
  signal rx_device_clk_freq_r               : std_logic_vector(31 downto 0) := (others => '0');      
  signal rx_device_clk_cnt_r                : std_logic_vector(31 downto 0) := (others => '0');      

  signal tx_device_clk_tick_1ms_r           : std_logic_vector(0 to 2) := (others => '0');
  signal tx_device_clk_freq_r               : std_logic_vector(31 downto 0) := (others => '0');
  signal tx_device_clk_cnt_r                : std_logic_vector(31 downto 0) := (others => '0');

  signal clkin8_tick_1ms_r                  : std_logic_vector(0 to 2) := (others => '0');
  signal clkin8_freq_r                      : std_logic_vector(31 downto 0) := (others => '0');
  signal clkin8_cnt_r                       : std_logic_vector(31 downto 0) := (others => '0');

  signal sys_cpu_clk_tick_1ms_r             : std_logic_vector(0 to 2) := (others => '0');
  signal sys_cpu_clk_freq_r                 : std_logic_vector(31 downto 0) := (others => '0');
  signal sys_cpu_clk_cnt_r                  : std_logic_vector(31 downto 0) := (others => '0');

  signal ref_clk_div2_tick_1ms_r            : std_logic_vector(0 to 2) := (others => '0');
  signal ref_clk_div2_freq_r                : std_logic_vector(31 downto 0) := (others => '0');
  signal ref_clk_div2_cnt_r                 : std_logic_vector(31 downto 0) := (others => '0');

  signal slv_reg0                           : std_logic_vector(31 downto 0);
  signal slv_reg1                           : std_logic_vector(31 downto 0);
  signal slv_reg2                           : std_logic_vector(31 downto 0);
  signal slv_reg3                           : std_logic_vector(31 downto 0);
  signal slv_reg4                           : std_logic_vector(31 downto 0);
  signal slv_reg5                           : std_logic_vector(31 downto 0);
  signal slv_reg6                           : std_logic_vector(31 downto 0);
  signal slv_reg7                           : std_logic_vector(31 downto 0);
  signal slv_reg8                           : std_logic_vector(31 downto 0);

  signal vio_cnt_reset                      : std_logic;
  signal cnt_rst                            : std_logic;


  
  signal s00_axi_areset                   : std_logic;
  
begin

  cnt_reset_out     <= cnt_rst;--vio_cnt_reset when vio_enable = '1' else cnt_rst;
  s00_axi_areset    <= not s00_axi_aresetn_in;
  
  -- Instantiation of Axi Bus Interface S00_AXI
  qsfp_intfc_v1_0_S00_AXI_inst : entity work.qsfp_intfc_v1_0_S00_AXI
    generic map (
      C_S_AXI_DATA_WIDTH        => C_S00_AXI_DATA_WIDTH,
      C_S_AXI_ADDR_WIDTH        => C_S00_AXI_ADDR_WIDTH
    )
  port map (

    slv_reg0_in                 => slv_reg0,                                -- 0x8000_0000  
    slv_reg1_in                 => slv_reg1,                                -- 0x8000_0004         
    slv_reg2_in                 => slv_reg2,                                -- 0x8000_0008  
    slv_reg3_out                => slv_reg3,                                -- 0x8000_000C        
    slv_reg4_out                => slv_reg4,                                -- 0x8000_0010         
    slv_reg5_out                => slv_reg5,                                -- 0x8000_0014        
    slv_reg6_out                => slv_reg6,                                -- 0x8000_0018        
    slv_reg7_out                => slv_reg7,                                -- 0x8000_001C         
    slv_reg8_out                => slv_reg8,                                -- 0x8000_0020  

    slv_reg9_out                => slv_reg9_out,                            -- 0x8000_0024    
    slv_reg10_out               => slv_reg10_out,                           -- 0x8000_0028     

    slv_reg11_in                => clk_125_freq_r,                          -- 0x8000_002C 
    slv_reg12_in                => clk_125_cnt_r,                           -- 0x8000_0030
    slv_reg13_in                => clk_250_freq_r,                          -- 0x8000_0034
    slv_reg14_in                => clk_250_cnt_r,                           -- 0x8000_0038
    slv_reg15_in                => rx_device_clk_freq_r,                    -- 0x8000_003C 
    slv_reg16_in                => tx_device_clk_freq_r,                    -- 0x8000_0040
    slv_reg17_in                => (others => '0'),                       -- 0x8000_0044                 
    slv_reg18_in                => (others => '0'),                        -- 0x8000_0048                 
    slv_reg19_in                => (others => '0'),                       -- 0x8000_004C                     
    slv_reg20_in                => (others => '0'),                        -- 0x8000_0050                     

    slv_reg21_in                => (others => '0'),                       -- 0x8000_0054                 
    slv_reg22_in                => (others => '0'),                        -- 0x8000_0058
    slv_reg23_in                => (others => '0'),                       -- 0x8000_005C  
    slv_reg24_in                => (others => '0'),                        -- 0x8000_0060

    slv_reg25_in                => (others => '0'),             -- 0x8000_0064  
    slv_reg26_in                => (others => '0'),           -- 0x8000_0068  
    slv_reg27_in                => (others => '0'),        -- 0x8000_006C
    slv_reg28_in                => (others => '0'),              -- 0x8000_0070
    slv_reg29_in                => (others => '0'),             -- 0x8000_0074 
    slv_reg30_in                => (others => '0'),             -- 0x8000_0078
    slv_reg31_in                => (others => '0'),           -- 0x8000_007C  

    slv_reg32_in                => (others => '0'),        -- 0x8000_0080
    slv_reg33_in                => (others => '0'),        -- 0x8000_0084  
    slv_reg34_in                => (others => '0'),        -- 0x8000_0088  
    slv_reg35_in                => (others => '0'),        -- 0x8000_008C
    slv_reg36_in                => (others => '0'),        -- 0x8000_0090
    slv_reg37_in                => (others => '0'),        -- 0x8000_0094 
    slv_reg38_in                => (others => '0'),        -- 0x8000_0098  

    slv_reg39_in                => (others => '0'),      -- 0x8000_009C  
    slv_reg40_in                => (others => '0'),      -- 0x8000_00A0
    slv_reg41_in                => (others => '0'),      -- 0x8000_00A4  
    slv_reg42_in                => (others => '0'),      -- 0x8000_00A8  
    slv_reg43_in                => (others => '0'),      -- 0x8000_00AC
    slv_reg44_in                => (others => '0'),      -- 0x8000_00B0
    slv_reg45_in                => (others => '0'),      -- 0x8000_00B4  

    slv_reg46_in                => (others => '0'),     -- 0x8000_00B8
    slv_reg47_in                => (others => '0'),     -- 0x8000_00BC  
    slv_reg48_in                => (others => '0'),     -- 0x8000_00C0
    slv_reg49_in                => (others => '0'),     -- 0x8000_00C4  
    slv_reg50_in                => (others => '0'),     -- 0x8000_00C8  
    slv_reg51_in                => (others => '0'),     -- 0x8000_00CC
    slv_reg52_in                => (others => '0'),     -- 0x8000_00D0  

    slv_reg53_in                => adc_tvalid_256b_cnt_in,               -- 0x8000_00D4
    slv_reg54_in                => cmac_0_tx_tvalid_512b_cnt_in,         -- 0x8000_00D8
    slv_reg55_in                => cmac_4_tx_tvalid_512b_cnt_in,         -- 0x8000_00DC
    slv_reg56_in                => cmac_rx_tvalid_256b_cnt_in,           -- 0x8000_00E0
    slv_reg57_in                => mem_xfer_tx_upload_tvalid_256b_cnt_in,-- 0x8000_00E4
    slv_reg58_in                => cmac_0_rx_tvalid_512b_cnt_in,         -- 0x8000_00E8
    slv_reg59_in                => cmac_4_rx_tvalid_512b_cnt_in,         -- 0x8000_00EC
    slv_reg60_in                => dac_tvalid_256b_cnt_in,               -- 0x8000_00F0
    slv_reg61_in                => (others => '0'),                      -- 0x8000_00F4
    slv_reg62_in                => (others => '0'),                      -- 0x8000_00F8
    slv_reg63_in                => (others => '0'),                      -- 0x8000_00FC

    S_AXI_ACLK                  => sys_cpu_clk_in,
    S_AXI_ARESETN               => s00_axi_aresetn_in,
    S_AXI_AWADDR                => s00_axi_awaddr,
    S_AXI_AWPROT                => s00_axi_awprot,
    S_AXI_AWVALID               => s00_axi_awvalid,
    S_AXI_AWREADY               => s00_axi_awready,
    S_AXI_WDATA                 => s00_axi_wdata,
    S_AXI_WSTRB                 => s00_axi_wstrb,
    S_AXI_WVALID                => s00_axi_wvalid,
    S_AXI_WREADY                => s00_axi_wready,
    S_AXI_BRESP                 => s00_axi_bresp,
    S_AXI_BVALID                => s00_axi_bvalid,
    S_AXI_BREADY                => s00_axi_bready,
    S_AXI_ARADDR                => s00_axi_araddr,
    S_AXI_ARPROT                => s00_axi_arprot,
    S_AXI_ARVALID               => s00_axi_arvalid,
    S_AXI_ARREADY               => s00_axi_arready,
    S_AXI_RDATA                 => s00_axi_rdata,
    S_AXI_RRESP                 => s00_axi_rresp,
    S_AXI_RVALID                => s00_axi_rvalid,
    S_AXI_RREADY                => s00_axi_rready
  );

------------
  slv_reg0                  <= fpga_revision_date_r;        -- 0x8000_0000       
------------
  slv_reg1(0)               <= '0';              
  slv_reg1(1)               <= qsfp1_modprsl; 
  slv_reg1(2)               <= qsfp1_intl;    
  slv_reg1(3)               <= '0';
  slv_reg1(4)               <= '0';              
  slv_reg1(5)               <= qsfp2_modprsl; 
  slv_reg1(6)               <= qsfp2_intl;    
  slv_reg1(7)               <= '0';
  slv_reg1(8)               <= '0';              
  slv_reg1(9)               <= qsfp3_modprsl; 
  slv_reg1(10)              <= qsfp3_intl;    
  slv_reg1(11)              <= '0';
  slv_reg1(12)              <= '0';              
  slv_reg1(13)              <= qsfp4_modprsl; 
  slv_reg1(14)              <= qsfp4_intl;    
  slv_reg1(15)              <= '0';

  slv_reg1(23 downto 16)    <= (others => '0');                     
  slv_reg1(31 downto 24)    <= minor_rev_r;                                       -- 0x8000_0004         
------------
  slv_reg2                  <= (others => '0');                -- 0x8000_0008        
------------
--
--            <= slv_reg3(17 downto 16);         
--           <= slv_reg3(12);                                    -- 0x8000_0014 
--           <= slv_reg3(11 downto 0);                           -- 0x8000_000C
------------
--             <= slv_reg4(17 downto 16);                                         -- 0x8000_0010 
------------
  qsfp1_reset_n           <= slv_reg5(0);                                         -- 0x8000_0014 
--                        <= slv_reg5(3 dwonto 1);
  qsfp2_reset_n           <= slv_reg5(4);
--                        <= slv_reg5(7 dwonto 5);
  qsfp3_reset_n           <= slv_reg5(8);
--                        <= slv_reg5(11 dwonto 9);
  qsfp4_reset_n           <= slv_reg5(12);
--                        <= slv_reg5(31 dwonto 13);
------------
  --        <= slv_reg6(31 downto 0);                             -- 0x8000_0018 
------------
  --        <= slv_reg7(0);                                       -- 0x8000_001C 
------------
--     <= slv_reg8(0);                                       -- 0x8000_0020 
--                          <= slv_reg8(24);
--                          <= slv_reg8(28);
  cnt_rst                   <= slv_reg8(31);

  QSFP1_RESETL_LS     <= qsfp1_reset_n; 
  qsfp1_modprsl       <= QSFP1_MODPRSL_LS;
  qsfp1_intl          <= QSFP1_INTL_LS;    
-------

  QSFP2_RESETL_LS     <= qsfp2_reset_n; 
  qsfp2_modprsl       <= QSFP2_MODPRSL_LS;
  qsfp2_intl          <= QSFP2_INTL_LS;    
-------

  QSFP3_RESETL_LS     <= qsfp3_reset_n; 
  qsfp3_modprsl       <= QSFP3_MODPRSL_LS;
  qsfp3_intl          <= QSFP3_INTL_LS;    
-------
  
  QSFP4_RESETL_LS     <= qsfp4_reset_n; 
  qsfp4_modprsl       <= QSFP4_MODPRSL_LS;  
  qsfp4_intl          <= QSFP4_INTL_LS;      
      
------------------------------------------------
  i_tick_gen : entity work.tick_gen
    generic map (
      CLOCK_SPEED_MHZ                       => 100
      ) 
    port map (
      clk_in                                => sys_cpu_clk_in, 

      tick_1us_out                          => open,
      tick_1ms_out                          => tick_1ms,
      tick_500ms_out                        => open,
      tick_750ms_out                        => open,
      tick_1s_out                           => open,

      prog_us_tick_rate_in                  => x"0000_0000",
      prog_us_tick_out                      => open,  

      reset_in                              => s00_axi_areset
      );

  process(sys_cpu_clk_in)  
  begin
    if (rising_edge(sys_cpu_clk_in)) then
      fpga_revision_date_r              <= FPGA_REVISION_DATE;
      minor_rev_r                       <= MINOR_REV;
    end if;
  end process;

      
  process(clk_125_in)
  begin
    if (rising_edge(clk_125_in)) then
      clk_125_tick_1ms_r      <= clk_125_tick_1ms_r(1 to 2) & tick_1ms;
      if (clk_125_tick_1ms_r(0 to 1) = "01") then 
        clk_125_freq_r        <= clk_125_cnt_r;
        clk_125_cnt_r         <= (others => '0');
      else
        clk_125_cnt_r         <= clk_125_cnt_r + 1;
      end if;
    end if;
  end process;

  process(clk_250_in)
  begin
    if (rising_edge(clk_250_in)) then
      clk_250_tick_1ms_r      <= clk_250_tick_1ms_r(1 to 2) & tick_1ms;
      if (clk_250_tick_1ms_r(0 to 1) = "01") then 
        clk_250_freq_r        <= clk_250_cnt_r;
        clk_250_cnt_r         <= (others => '0');
      else
        clk_250_cnt_r         <= clk_250_cnt_r + 1;
      end if;
    end if;
  end process;


  process(rx_device_clk_in)
  begin
    if (rising_edge(rx_device_clk_in)) then
      rx_device_clk_tick_1ms_r      <= rx_device_clk_tick_1ms_r(1 to 2) & tick_1ms;
      if (rx_device_clk_tick_1ms_r(0 to 1) = "01") then 
        rx_device_clk_freq_r        <= rx_device_clk_cnt_r;
        rx_device_clk_cnt_r         <= (others => '0');
      else
        rx_device_clk_cnt_r         <= rx_device_clk_cnt_r + 1;
      end if;
    end if;
  end process;

  process(tx_device_clk_in)
  begin
    if (rising_edge(tx_device_clk_in)) then
      tx_device_clk_tick_1ms_r      <= tx_device_clk_tick_1ms_r(1 to 2) & tick_1ms;
      if (tx_device_clk_tick_1ms_r(0 to 1) = "01") then 
        tx_device_clk_freq_r        <= tx_device_clk_cnt_r;
        tx_device_clk_cnt_r         <= (others => '0');
      else
        tx_device_clk_cnt_r         <= tx_device_clk_cnt_r + 1;
      end if;
    end if;
  end process;
      
  process(clkin8_in)
  begin
    if (rising_edge(clkin8_in)) then
      clkin8_tick_1ms_r      <= clkin8_tick_1ms_r(1 to 2) & tick_1ms;
      if (clkin8_tick_1ms_r(0 to 1) = "01") then 
        clkin8_freq_r        <= clkin8_cnt_r;
        clkin8_cnt_r         <= (others => '0');
      else
        clkin8_cnt_r         <= clkin8_cnt_r + 1;
      end if;
    end if;
  end process;
  
  process(sys_cpu_clk_in)
  begin
    if (rising_edge(sys_cpu_clk_in)) then
      sys_cpu_clk_tick_1ms_r      <= sys_cpu_clk_tick_1ms_r(1 to 2) & tick_1ms;
      if (sys_cpu_clk_tick_1ms_r(0 to 1) = "01") then 
        sys_cpu_clk_freq_r        <= sys_cpu_clk_cnt_r;
        sys_cpu_clk_cnt_r         <= (others => '0');
      else
        sys_cpu_clk_cnt_r         <= sys_cpu_clk_cnt_r + 1;
      end if;
    end if;
  end process;
  
  process(ref_clk_div2_in)
  begin
    if (rising_edge(ref_clk_div2_in)) then
      ref_clk_div2_tick_1ms_r      <= ref_clk_div2_tick_1ms_r(1 to 2) & tick_1ms;
      if (ref_clk_div2_tick_1ms_r(0 to 1) = "01") then 
        ref_clk_div2_freq_r        <= ref_clk_div2_cnt_r;
        ref_clk_div2_cnt_r         <= (others => '0');
      else
        ref_clk_div2_cnt_r         <= ref_clk_div2_cnt_r + 1;
      end if;
    end if;
  end process;
  
  -- User logic ends

end arch_imp;
