library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use std.textio.all;
use IEEE.std_logic_textio.all;

entity dds_pulse_intfc_x4 is
  port(
    s_axi_aclk_in                                 : in std_logic;
    s_axi_aresetn_in                              : in std_logic;

    cmd_idx_in                                    : in  std_logic_vector( 2 downto 0);
    dac_holdoff_in                                : in  std_logic;
    
    cmd_send_0_in                                 : in  std_logic;
    scale_0_in                                    : in  std_logic_vector(15 downto 0);
    dds_phase_inc_dwell_time_0_in                 : in  std_logic_vector(31 downto 0);
    dds_phase_inc_step_size_0_in                  : in  std_logic_vector(31 downto 0);
    idle_samples_0_in                             : in  std_logic_vector(31 downto 0);
    dds_samples_0_in                              : in  std_logic_vector(31 downto 0);
    phase_inc_0_in                                : in  std_logic_vector(31 downto 0);
    phase_off_0_in                                : in  std_logic_vector(31 downto 0);
    swap_sf_0_in                                  : in  std_logic_vector(31 downto 0);

    cmd_send_1_in                                 : in  std_logic;
    scale_1_in                                    : in  std_logic_vector(15 downto 0);
    dds_phase_inc_dwell_time_1_in                 : in  std_logic_vector(31 downto 0);
    dds_phase_inc_step_size_1_in                  : in  std_logic_vector(31 downto 0);
    idle_samples_1_in                             : in  std_logic_vector(31 downto 0);
    dds_samples_1_in                              : in  std_logic_vector(31 downto 0);
    phase_inc_1_in                                : in  std_logic_vector(31 downto 0);
    phase_off_1_in                                : in  std_logic_vector(31 downto 0);
    swap_sf_1_in                                  : in  std_logic_vector(31 downto 0);

    cmd_send_2_in                                 : in  std_logic;
    scale_2_in                                    : in  std_logic_vector(15 downto 0);
    dds_phase_inc_dwell_time_2_in                 : in  std_logic_vector(31 downto 0);
    dds_phase_inc_step_size_2_in                  : in  std_logic_vector(31 downto 0);
    idle_samples_2_in                             : in  std_logic_vector(31 downto 0);
    dds_samples_2_in                              : in  std_logic_vector(31 downto 0);
    phase_inc_2_in                                : in  std_logic_vector(31 downto 0);
    phase_off_2_in                                : in  std_logic_vector(31 downto 0);
    swap_sf_2_in                                  : in  std_logic_vector(31 downto 0);

    cmd_send_3_in                                 : in  std_logic;
    scale_3_in                                    : in  std_logic_vector(15 downto 0);
    dds_phase_inc_dwell_time_3_in                 : in  std_logic_vector(31 downto 0);
    dds_phase_inc_step_size_3_in                  : in  std_logic_vector(31 downto 0);
    idle_samples_3_in                             : in  std_logic_vector(31 downto 0);
    dds_samples_3_in                              : in  std_logic_vector(31 downto 0);
    phase_inc_3_in                                : in  std_logic_vector(31 downto 0);
    phase_off_3_in                                : in  std_logic_vector(31 downto 0);
    swap_sf_3_in                                  : in  std_logic_vector(31 downto 0);

    m_axis_aclk_in                                : in  std_logic;
    m_axis_aresetn_in                             : in  std_logic;
    m0_axis_tdata_out                             : out std_logic_vector(127 downto 0);
    m0_axis_tvalid_out                            : out std_logic;
    m0_axis_tready_in                             : in  std_logic;

    m1_axis_tdata_out                             : out std_logic_vector(127 downto 0);
    m1_axis_tvalid_out                            : out std_logic;
    m1_axis_tready_in                             : in  std_logic;

    cnt_reset_in                                  : in  std_logic;
    m0_axis_tvalid_cnt_out                        : out std_logic_vector(31 downto 0);
    m0_dds_pulse_data_cnt_out                     : out std_logic_vector(31 downto 0);
    m1_axis_tvalid_cnt_out                        : out std_logic_vector(31 downto 0);
    m1_dds_pulse_data_cnt_out                     : out std_logic_vector(31 downto 0)
    );
end entity dds_pulse_intfc_x4;

architecture imp of dds_pulse_intfc_x4 is

  signal m0_dds_intfc_tdata_0                     : std_logic_vector(31 downto 0);
  signal m0_dds_intfc_tvalid_0                    : std_logic;
  signal m1_dds_intfc_tdata_0                     : std_logic_vector(31 downto 0);
  signal m1_dds_intfc_tvalid_0                    : std_logic;

  signal m0_dds_intfc_tdata_1                     : std_logic_vector(31 downto 0);
  signal m0_dds_intfc_tvalid_1                    : std_logic;
  signal m1_dds_intfc_tdata_1                     : std_logic_vector(31 downto 0);
  signal m1_dds_intfc_tvalid_1                    : std_logic;

  signal m0_dds_intfc_tdata_2                     : std_logic_vector(31 downto 0);
  signal m0_dds_intfc_tvalid_2                    : std_logic;
  signal m1_dds_intfc_tdata_2                     : std_logic_vector(31 downto 0);
  signal m1_dds_intfc_tvalid_2                    : std_logic;

  signal m0_dds_intfc_tdata_3                     : std_logic_vector(31 downto 0);
  signal m0_dds_intfc_tvalid_3                    : std_logic;
  signal m1_dds_intfc_tdata_3                     : std_logic_vector(31 downto 0);
  signal m1_dds_intfc_tvalid_3                    : std_logic;

  signal m0_dds_intfc_tdata                       : std_logic_vector(127 downto 0);
  signal m0_dds_intfc_tvalid                      : std_logic;
  signal m0_dds_intfc_tready                      : std_logic;
  signal s0_axis_tready_pipe                      : std_logic;
  signal m0_axis_tvalid_pipe                      : std_logic;
  signal m0_axis_tvalid_data_pipe_cnt_r           : std_logic_vector(31 downto 0) := (others => '0');
  signal m0_dds_intfc_tvalid_data_cnt_r           : std_logic_vector(31 downto 0) := (others => '0');

  signal m1_dds_intfc_tdata                       : std_logic_vector(127 downto 0);
  signal m1_dds_intfc_tvalid                      : std_logic;
  signal m1_dds_intfc_tready                      : std_logic;
  signal s1_axis_tready_pipe                      : std_logic;
  signal m1_axis_tvalid_pipe                      : std_logic;
  signal m1_axis_tvalid_data_pipe_cnt_r           : std_logic_vector(31 downto 0) := (others => '0');
  signal m1_dds_intfc_tvalid_data_cnt_r           : std_logic_vector(31 downto 0) := (others => '0');

begin
  
  m0_axis_tvalid_cnt_out     <= m0_axis_tvalid_data_pipe_cnt_r;
  m0_dds_pulse_data_cnt_out  <= m0_dds_intfc_tvalid_data_cnt_r;
  m1_axis_tvalid_cnt_out     <= m1_axis_tvalid_data_pipe_cnt_r;
  m1_dds_pulse_data_cnt_out  <= m1_dds_intfc_tvalid_data_cnt_r;

  i_dds_pulse_wrapper_0 : entity work.dds_pulse_wrapper 
    port map ( 
      s_axi_aclk_in                   => s_axi_aclk_in,          
      s_axi_aresetn_in                => s_axi_aresetn_in,    
      cmd_idx_in                      => cmd_idx_in,                     
      cmd_send_in                     => cmd_send_0_in,                      

      mode_in                         => '0',                                       
      scale_in                        => scale_0_in,    
      dac_holdoff_in                  => dac_holdoff_in, 

      reserv1_in                      => x"00000000",                 
      dds_phase_inc_dwell_time_in     => dds_phase_inc_dwell_time_0_in,
      dds_phase_inc_step_size_in      => dds_phase_inc_step_size_0_in, 
      idle_samples_in                 => idle_samples_0_in,                     
      dds_samples_in                  => dds_samples_0_in,                       
      phase_inc_in                    => phase_inc_0_in,                           
      phase_off_in                    => phase_off_0_in,                           
      swap_sf_in                      => swap_sf_0_in,                               

      m_axis_aclk_in                  => m_axis_aclk_in,
      m_axis_aresetn_in               => m_axis_aresetn_in,
      m0_axis_tdata_out               => m0_dds_intfc_tdata_0,            
      m0_axis_tvalid_out              => m0_dds_intfc_tvalid_0,         
      m0_axis_tready_in               => m0_dds_intfc_tready,          
      m1_axis_tdata_out               => m1_dds_intfc_tdata_0,            
      m1_axis_tvalid_out              => m1_dds_intfc_tvalid_0,         
      m1_axis_tready_in               => m1_dds_intfc_tready          
      );

  i_dds_pulse_wrapper_1 : entity work.dds_pulse_wrapper 
    port map ( 
      s_axi_aclk_in                   => s_axi_aclk_in,          
      s_axi_aresetn_in                => s_axi_aresetn_in,    
      cmd_idx_in                      => cmd_idx_in,                     
      cmd_send_in                     => cmd_send_1_in,                      

      mode_in                         => '0',                                       
      scale_in                        => scale_1_in,      
      dac_holdoff_in                  => dac_holdoff_in, 

      reserv1_in                      => x"00000000",                 
      dds_phase_inc_dwell_time_in     => dds_phase_inc_dwell_time_1_in,
      dds_phase_inc_step_size_in      => dds_phase_inc_step_size_1_in, 
      idle_samples_in                 => idle_samples_1_in,                     
      dds_samples_in                  => dds_samples_1_in,                       
      phase_inc_in                    => phase_inc_1_in,                           
      phase_off_in                    => phase_off_1_in,                           
      swap_sf_in                      => swap_sf_1_in,                               

      m_axis_aclk_in                  => m_axis_aclk_in,
      m_axis_aresetn_in               => m_axis_aresetn_in,
      m0_axis_tdata_out               => m0_dds_intfc_tdata_1,            
      m0_axis_tvalid_out              => m0_dds_intfc_tvalid_1,         
      m0_axis_tready_in               => m0_dds_intfc_tready,          
      m1_axis_tdata_out               => m1_dds_intfc_tdata_1,            
      m1_axis_tvalid_out              => m1_dds_intfc_tvalid_1,         
      m1_axis_tready_in               => m1_dds_intfc_tready          
      );

  i_dds_pulse_wrapper_2 : entity work.dds_pulse_wrapper 
    port map ( 
      s_axi_aclk_in                   => s_axi_aclk_in,          
      s_axi_aresetn_in                => s_axi_aresetn_in,    
      cmd_idx_in                      => cmd_idx_in,                     
      cmd_send_in                     => cmd_send_2_in,                      

      mode_in                         => '0',                                       
      scale_in                        => scale_2_in,      
      dac_holdoff_in                  => dac_holdoff_in, 

      reserv1_in                      => x"00000000",                 
      dds_phase_inc_dwell_time_in     => dds_phase_inc_dwell_time_2_in,
      dds_phase_inc_step_size_in      => dds_phase_inc_step_size_2_in, 
      idle_samples_in                 => idle_samples_2_in,                     
      dds_samples_in                  => dds_samples_2_in,                        
      phase_inc_in                    => phase_inc_2_in,                              
      phase_off_in                    => phase_off_2_in,                              
      swap_sf_in                      => swap_sf_2_in,                                    

      m_axis_aclk_in                  => m_axis_aclk_in,
      m_axis_aresetn_in               => m_axis_aresetn_in,
      m0_axis_tdata_out               => m0_dds_intfc_tdata_2,            
      m0_axis_tvalid_out              => m0_dds_intfc_tvalid_2,         
      m0_axis_tready_in               => m0_dds_intfc_tready,          
      m1_axis_tdata_out               => m1_dds_intfc_tdata_2,            
      m1_axis_tvalid_out              => m1_dds_intfc_tvalid_2,         
      m1_axis_tready_in               => m1_dds_intfc_tready          
      );

  i_dds_pulse_wrapper_3 : entity work.dds_pulse_wrapper 
    port map ( 
      s_axi_aclk_in                   => s_axi_aclk_in,          
      s_axi_aresetn_in                => s_axi_aresetn_in,    
      cmd_idx_in                      => cmd_idx_in,                     
      cmd_send_in                     => cmd_send_3_in,                      

      mode_in                         => '0',                                       
      scale_in                        => scale_3_in,      
      dac_holdoff_in                  => dac_holdoff_in, 

      reserv1_in                      => x"00000000",                 
      dds_phase_inc_dwell_time_in     => dds_phase_inc_dwell_time_3_in,
      dds_phase_inc_step_size_in      => dds_phase_inc_step_size_3_in, 
      idle_samples_in                 => idle_samples_3_in,                           
      dds_samples_in                  => dds_samples_3_in,                              
      phase_inc_in                    => phase_inc_3_in,                                    
      phase_off_in                    => phase_off_3_in,                                    
      swap_sf_in                      => swap_sf_3_in,                                          

      m_axis_aclk_in                  => m_axis_aclk_in,
      m_axis_aresetn_in               => m_axis_aresetn_in,
      m0_axis_tdata_out               => m0_dds_intfc_tdata_3,            
      m0_axis_tvalid_out              => m0_dds_intfc_tvalid_3,         
      m0_axis_tready_in               => m0_dds_intfc_tready,          
      m1_axis_tdata_out               => m1_dds_intfc_tdata_3,            
      m1_axis_tvalid_out              => m1_dds_intfc_tvalid_3,         
      m1_axis_tready_in               => m1_dds_intfc_tready          
      );

----------------m0
  m0_dds_intfc_tdata(31 downto 0)    <= m0_dds_intfc_tdata_0 when m0_dds_intfc_tvalid_0 = '1' else x"FFFF_0000";
  m0_dds_intfc_tdata(63 downto 32)   <= m0_dds_intfc_tdata_1 when m0_dds_intfc_tvalid_1 = '1' else x"FFFF_0000";
  m0_dds_intfc_tdata(95 downto 64)   <= m0_dds_intfc_tdata_2 when m0_dds_intfc_tvalid_2 = '1' else x"FFFF_0000";
  m0_dds_intfc_tdata(127 downto 96)  <= m0_dds_intfc_tdata_3 when m0_dds_intfc_tvalid_3 = '1' else x"FFFF_0000";

  m0_dds_intfc_tvalid <= '1' when m0_dds_intfc_tvalid_0 = '1' or m0_dds_intfc_tvalid_1 = '1' or m0_dds_intfc_tvalid_2 = '1' or m0_dds_intfc_tvalid_3 = '1' else '0';
  
  m0_dds_intfc_tready   <= '1' when m0_dds_intfc_tvalid = '1' and s0_axis_tready_pipe = '1' else '0';

  i_axis_register_slice_128_m0 : entity work.axis_register_slice_128  
    port map (
      aclk                              => m_axis_aclk_in,            -- in
      aresetn                           => m_axis_aresetn_in,         -- in
      s_axis_tdata                      => m0_dds_intfc_tdata,        -- in
      s_axis_tvalid                     => m0_dds_intfc_tvalid,       -- in
      s_axis_tready                     => s0_axis_tready_pipe,       -- out

      m_axis_tdata                      => m0_axis_tdata_out,         -- out
      m_axis_tvalid                     => m0_axis_tvalid_pipe,       -- out
      m_axis_tready                     => m0_axis_tready_in          -- in
    );

  m0_axis_tvalid_out       <= m0_axis_tvalid_pipe;
 
  process(m_axis_aclk_in)
  begin
    if (rising_edge(m_axis_aclk_in)) then 
      if (m_axis_aresetn_in = '0' or cnt_reset_in = '1') then  
        m0_axis_tvalid_data_pipe_cnt_r <= (others => '0');
      else  
          if (m0_axis_tvalid_pipe = '1' and m0_axis_tready_in = '1') then
            m0_axis_tvalid_data_pipe_cnt_r          <= m0_axis_tvalid_data_pipe_cnt_r + 1;
          end if;
       end if;
    end if;
  end process;
  
  process(m_axis_aclk_in)
  begin
    if (rising_edge(m_axis_aclk_in)) then  
      if (m_axis_aresetn_in = '0' or cnt_reset_in = '1') then  
          m0_dds_intfc_tvalid_data_cnt_r <= (others => '0');
      else     
          if (m0_dds_intfc_tvalid = '1' and m0_dds_intfc_tready = '1') then
            m0_dds_intfc_tvalid_data_cnt_r          <= m0_dds_intfc_tvalid_data_cnt_r + 1;
          end if;
      end if;
    end if;
  end process;
  
----------------m1
  m1_dds_intfc_tdata(31 downto 0)    <= m1_dds_intfc_tdata_0 when m1_dds_intfc_tvalid_0 = '1' else x"FFFF_0000";
  m1_dds_intfc_tdata(63 downto 32)   <= m1_dds_intfc_tdata_1 when m1_dds_intfc_tvalid_1 = '1' else x"FFFF_0000";
  m1_dds_intfc_tdata(95 downto 64)   <= m1_dds_intfc_tdata_2 when m1_dds_intfc_tvalid_2 = '1' else x"FFFF_0000";
  m1_dds_intfc_tdata(127 downto 96)  <= m1_dds_intfc_tdata_3 when m1_dds_intfc_tvalid_3 = '1' else x"FFFF_0000";

  m1_dds_intfc_tvalid <= '1' when m1_dds_intfc_tvalid_0 = '1' or m1_dds_intfc_tvalid_1 = '1' or m1_dds_intfc_tvalid_2 = '1' or m1_dds_intfc_tvalid_3 = '1' else '0';
  
  m1_dds_intfc_tready <= '1' when m1_dds_intfc_tvalid = '1' and s1_axis_tready_pipe = '1' else '0';

  i_axis_register_slice_128_m1 : entity work.axis_register_slice_128  
    port map (
      aclk                              => m_axis_aclk_in,            -- in
      aresetn                           => m_axis_aresetn_in,         -- in
      s_axis_tdata                      => m1_dds_intfc_tdata,        -- in
      s_axis_tvalid                     => m1_dds_intfc_tvalid,       -- in
      s_axis_tready                     => s1_axis_tready_pipe,       -- out

      m_axis_tdata                      => m1_axis_tdata_out,         -- out
      m_axis_tvalid                     => m1_axis_tvalid_pipe,       -- out
      m_axis_tready                     => m1_axis_tready_in          -- in
    );

  m1_axis_tvalid_out       <= m1_axis_tvalid_pipe;
 
  process(m_axis_aclk_in)
  begin
    if (rising_edge(m_axis_aclk_in)) then 
      if (m_axis_aresetn_in = '0' or cnt_reset_in = '1') then  
        m1_axis_tvalid_data_pipe_cnt_r <= (others => '0');
      else  
          if (m1_axis_tvalid_pipe = '1' and m1_axis_tready_in = '1') then
            m1_axis_tvalid_data_pipe_cnt_r          <= m1_axis_tvalid_data_pipe_cnt_r + 1;
          end if;
       end if;
    end if;
  end process;
  
  process(m_axis_aclk_in)
  begin
    if (rising_edge(m_axis_aclk_in)) then  
      if (m_axis_aresetn_in = '0' or cnt_reset_in = '1') then  
          m1_dds_intfc_tvalid_data_cnt_r <= (others => '0');
      else     
          if (m1_dds_intfc_tvalid = '1' and m1_dds_intfc_tready = '1') then
            m1_dds_intfc_tvalid_data_cnt_r          <= m1_dds_intfc_tvalid_data_cnt_r + 1;
          end if;
      end if;
    end if;
  end process;
  
end architecture imp;
