----------------------------------------------------------------------------------
-- Company:     Erisys
-- Engineer:    Jason M Blevins
-- 
-- Create Date: 07/08/2023
-- Design Name: 
-- Module Name: dig_iq_p_intfc
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
Library xpm;
use xpm.vcomponents.all;

entity dig_iq_p_intfc is
  generic(
    SAME_CLKS           : natural range 0 to 1 := 0
    );
	port (
		reg_clk	            : in std_logic;
		reg_resetn	        : in std_logic;

    strb_in             : in  std_logic;
    addr_in             : in  std_logic_vector(11 downto 0);
    write_in            : in  std_logic;
    sel_in              : in  std_logic_vector(2 downto 0);
    wdata_in            : in  std_logic_vector(31 downto 0);
    ready_out           : out std_logic;
    rdata_out           : out std_logic_vector(31 downto 0);
    
    ----------------------------------------------------------   
    clk_125             : in std_logic;
    clk_125_resetn      : in std_logic;
    --
    p_addr              : out std_logic_vector(11 downto 0);
    p_write             : out std_logic;
    p_wdata             : out std_logic_vector(31 downto 0);
    --
    --p_enable_in_0       : out std_logic;    
    --p_enable_in_1       : out std_logic;
    --p_enable_in_2       : out std_logic;
    --p_enable_in_3       : out std_logic;
    --p_enable_out_0      : out std_logic;
    --p_enable_out_1      : out std_logic;
    p_enable            : out std_logic_vector(7 downto 0);
    --
    --p_ready_in_0        : in  std_logic;    
    --p_ready_in_1        : in  std_logic;    
    --p_ready_in_2        : in  std_logic;    
    --p_ready_in_3        : in  std_logic;    
    --p_ready_out_0       : in  std_logic;    
    --p_ready_out_1       : in  std_logic;
    p_ready             : in  std_logic_vector(7 downto 0);    
    --
    p_rdata_0         : in  std_logic_vector(31 downto 0);    
    p_rdata_1         : in  std_logic_vector(31 downto 0);
    p_rdata_2         : in  std_logic_vector(31 downto 0);
    p_rdata_3         : in  std_logic_vector(31 downto 0);
    p_rdata_4         : in  std_logic_vector(31 downto 0);
    p_rdata_5         : in  std_logic_vector(31 downto 0);
    p_rdata_6         : in  std_logic_vector(31 downto 0);
    p_rdata_7         : in  std_logic_vector(31 downto 0)
    );
end dig_iq_p_intfc;

architecture arch_imp of dig_iq_p_intfc is

  --signal  p_ready     : std_logic_vector(7 downto 0);
  signal  strb_in_r   : std_logic := '0';
  signal  strb_int    : std_logic;
  signal  addr_int    : std_logic_vector(11 downto 0);
  signal  sel_int     : std_logic_vector(2 downto 0);
  signal  write_int   : std_logic;
  signal  wdata_int   : std_logic_vector(31 downto 0);
  signal  p_addr_r    : std_logic_vector(11 downto 0) := (others => '0');
  signal  p_write_r   : std_logic := '0';
  signal  p_wdata_r   : std_logic_vector(31 downto 0) := (others => '0');
  signal  p_enable_r  : std_logic_vector(7 downto 0)  := (others => '0');
  signal  p_enable_r1 : std_logic_vector(7 downto 0)  := (others => '0');
  signal  p_strb_r    : std_logic := '0';
  signal  p_ready_r   : std_logic := '0';
  signal  p_rdata_r   : std_logic_vector(31 downto 0) := (others => '0');
  

begin

  SAME_CLKS_FALSE_GEN :
    if SAME_CLKS = 0 generate
      begin
      
        i_cdc_pulse_strb : xpm_cdc_pulse
        generic map (
          DEST_SYNC_FF => 7,   -- DECIMAL; range: 2-10
          INIT_SYNC_FF => 0,   -- DECIMAL; 0=disable simulation init values, 1=enable simulation init values
          REG_OUTPUT => 1,     -- DECIMAL; 0=disable registered output, 1=enable registered output
          RST_USED => 0,       -- DECIMAL; 0=no reset, 1=implement reset
          SIM_ASSERT_CHK => 0  -- DECIMAL; 0=disable simulation messages, 1=enable simulation messages
          )
        port map (
          dest_rst    => '0',
          dest_pulse  => strb_int,
          dest_clk    => clk_125,      
          src_clk     => reg_clk,    
          src_pulse   => strb_in,                      
          src_rst     => '0'
          );

        i_cdc_array_addr : xpm_cdc_array_single
        generic map (
          DEST_SYNC_FF => 4,   -- DECIMAL; range: 2-10
          INIT_SYNC_FF => 0,   -- DECIMAL; 0=disable simulation init values, 1=enable simulation init values
          SIM_ASSERT_CHK => 0, -- DECIMAL; 0=disable simulation messages, 1=enable simulation messages
          SRC_INPUT_REG => 0,  -- DECIMAL; 0=do not register input, 1=register input
          WIDTH => 12          -- DECIMAL; range: 1-1024
          )
        port map (
          dest_out  => addr_int,
          dest_clk  => clk_125,
          src_in    => addr_in,
          src_clk   => '0' 
          );

        i_cdc_array_sel : xpm_cdc_array_single
        generic map (
          DEST_SYNC_FF => 4,   -- DECIMAL; range: 2-10
          INIT_SYNC_FF => 0,   -- DECIMAL; 0=disable simulation init values, 1=enable simulation init values
          SIM_ASSERT_CHK => 0, -- DECIMAL; 0=disable simulation messages, 1=enable simulation messages
          SRC_INPUT_REG => 0,  -- DECIMAL; 0=do not register input, 1=register input
          WIDTH => 3           -- DECIMAL; range: 1-1024
          )
        port map (
          dest_out  => sel_int,
          dest_clk  => clk_125,
          src_in    => sel_in,
          src_clk   => '0' 
          );
          
        i_cdc_array_wdata : xpm_cdc_array_single
        generic map (
          DEST_SYNC_FF => 4,   -- DECIMAL; range: 2-10
          INIT_SYNC_FF => 0,   -- DECIMAL; 0=disable simulation init values, 1=enable simulation init values
          SIM_ASSERT_CHK => 0, -- DECIMAL; 0=disable simulation messages, 1=enable simulation messages
          SRC_INPUT_REG => 0,  -- DECIMAL; 0=do not register input, 1=register input
          WIDTH => 32          -- DECIMAL; range: 1-1024
          )
        port map (
          dest_out  => wdata_int,
          dest_clk  => clk_125,
          src_in    => wdata_in,
          src_clk   => '0' 
          );

        i_cdc_single_write : xpm_cdc_single
        generic map (
          DEST_SYNC_FF    => 4,   
          INIT_SYNC_FF    => 0,   
          SIM_ASSERT_CHK  => 0, 
          SRC_INPUT_REG   => 0   
          )
        port map (
          dest_out  => write_int,
          dest_clk  => clk_125,          
          src_clk   => '0',                     
          src_in    => write_in    
          );
          
        i_cdc_single_ready : xpm_cdc_single
        generic map (
          DEST_SYNC_FF    => 4,   
          INIT_SYNC_FF    => 0,   
          SIM_ASSERT_CHK  => 0, 
          SRC_INPUT_REG   => 0   
          )
        port map (
          dest_out  => ready_out,
          dest_clk  => reg_clk,          
          src_clk   => '0',                     
          src_in    => p_ready_r    
          );
          
        i_cdc_array_rdata : xpm_cdc_array_single
        generic map (
          DEST_SYNC_FF => 4,   -- DECIMAL; range: 2-10
          INIT_SYNC_FF => 0,   -- DECIMAL; 0=disable simulation init values, 1=enable simulation init values
          SIM_ASSERT_CHK => 0, -- DECIMAL; 0=disable simulation messages, 1=enable simulation messages
          SRC_INPUT_REG => 0,  -- DECIMAL; 0=do not register input, 1=register input
          WIDTH => 32          -- DECIMAL; range: 1-1024
          )
        port map (
          dest_out  => rdata_out,
          dest_clk  => reg_clk,
          src_in    => p_rdata_r,
          src_clk   => '0' 
          );      
      
      end generate;

  SAME_CLKS_TRUE_GEN :
    if SAME_CLKS = 1 generate
      begin
      
        strb_int    <= not(strb_in_r) and strb_in; 
        addr_int    <= addr_in;
        sel_int     <= sel_in;
        wdata_int   <= wdata_in;
        write_int   <= write_in;
        ready_out   <= p_ready_r;
        rdata_out   <= p_rdata_r;
        
      end generate;
  ---------------------------------------
  

  
  -- APB Interface Ports
  p_addr          <=  p_addr_r;
  p_write         <=  p_write_r;
  p_wdata         <=  p_wdata_r;
  
  p_enable        <=  p_enable_r1;
  --p_enable_in_0   <=  p_enable_r1(0);
  --p_enable_in_1   <=  p_enable_r1(1);
  --p_enable_in_2   <=  p_enable_r1(2);
  --p_enable_in_3   <=  p_enable_r1(3);
  --p_enable_out_0  <=  p_enable_r1(4);
  --p_enable_out_1  <=  p_enable_r1(5);
  
  --p_ready(0)      <=  p_ready_in_0;
  --p_ready(1)      <=  p_ready_in_1;
  --p_ready(2)      <=  p_ready_in_2;
  --p_ready(3)      <=  p_ready_in_3;
  --p_ready(4)      <=  p_ready_out_0;
  --p_ready(5)      <=  p_ready_out_1;
  
  
  process(clk_125)
  begin
    if(rising_edge(clk_125))then
      if(clk_125_resetn = '0')then
        strb_in_r         <= '0';
        p_addr_r          <= (others => '0');
        p_write_r         <= '0';
        p_wdata_r         <= (others => '0');
        p_enable_r        <= (others => '0');
        p_enable_r1       <= (others => '0');
        p_strb_r          <= '0'; 
        p_ready_r         <= '0';
        p_rdata_r         <= (others => '0');       
      else
        strb_in_r <= strb_in;
      
        p_strb_r  <= strb_int;
        
        if(strb_int = '1')then
          p_addr_r      <=  addr_int;
          p_write_r     <=  write_int;
          p_wdata_r     <=  wdata_int;
          
          case sel_int is
            when "000" =>
              p_enable_r <= "00000001";
            when "001" =>
              p_enable_r <= "00000010";
            when "010" =>
              p_enable_r <= "00000100";
            when "011" =>
              p_enable_r <= "00001000";
            when "100" =>
              p_enable_r <= "00010000";
            when "101" =>
              p_enable_r <= "00100000";
            when "110" =>
              p_enable_r <= "01000000";
            when "111" =>
              p_enable_r <= "10000000";
            when others =>
              p_enable_r <= "00000000";
          end case;

        end if;
        
        if(p_strb_r = '1')then
        
          p_enable_r1   <=  p_enable_r;
          if(p_enable_r /= "00000000")then
            p_ready_r    <=  '0';
          end if;
          
        else
        
          if(p_ready = "11111111")then
            p_enable_r1     <=  (others => '0');
            p_ready_r       <=  '1';
            
            case sel_int is
              when "000" =>
                p_rdata_r <= p_rdata_0;
              when "001" =>
                p_rdata_r <= p_rdata_1;
              when "010" =>
                p_rdata_r <= p_rdata_2;
              when "011" =>
                p_rdata_r <= p_rdata_3;
              when "100" =>
                p_rdata_r <= p_rdata_4;
              when "101" =>
                p_rdata_r <= p_rdata_5;
              when "110" =>
                p_rdata_r <= p_rdata_6;
              when "111" =>
                p_rdata_r <= p_rdata_7;
              when others =>
                p_rdata_r <= x"DEADBEEF";
            end case; 
            
          end if;

        end if;

      end if;
    end if;
  end process;


end arch_imp;
