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_wrapper 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);
    cmd_send_in                                   : in std_logic;

    mode_in                                       : in std_logic;
    scale_in                                      : in std_logic_vector(15 downto 0);
    dac_holdoff_in                                : in std_logic;

    reserv1_in                                    : in std_logic_vector(31 downto 0);
    dds_phase_inc_dwell_time_in                   : in std_logic_vector(31 downto 0);
    dds_phase_inc_step_size_in                    : in std_logic_vector(31 downto 0);
    idle_samples_in                               : in std_logic_vector(31 downto 0);
    dds_samples_in                                : in std_logic_vector(31 downto 0);
    phase_inc_in                                  : in std_logic_vector(31 downto 0);
    phase_off_in                                  : in std_logic_vector(31 downto 0);
    swap_sf_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(31 downto 0);
    m0_axis_tvalid_out                            : out std_logic;
    m0_axis_tready_in                             : in  std_logic;
    m1_axis_tdata_out                             : out std_logic_vector(31 downto 0);
    m1_axis_tvalid_out                            : out std_logic;
    m1_axis_tready_in                             : in  std_logic
    );
end entity dds_pulse_wrapper;
  
architecture imp of dds_pulse_wrapper is

  attribute keep                                  : string;

  constant ok_clk_in_period                       : time := 10 ns;    

  signal reset_n                                  : std_logic;
  signal s_axi_areset                             : std_logic;
  signal m_axi_areset                             : std_logic;

  signal s_axis_tready_0                          : std_logic;
  signal s_axis_tready_1                          : std_logic;

  signal cmd_idx                                  : std_logic_vector( 2 downto 0);
  signal cmd_send                                 : std_logic;

  signal mode                                     : std_logic;
  signal scale                                    : std_logic_vector(15 downto 0);
  signal dac_holdoff                              : std_logic;


  signal reserv1                                  : std_logic_vector(31 downto 0);
  signal dds_phase_inc_dwell_time                 : std_logic_vector(31 downto 0);
  signal dds_phase_inc_step_size                  : std_logic_vector(31 downto 0);
  signal idle_samples                             : std_logic_vector(31 downto 0);
  signal dds_samples                              : std_logic_vector(31 downto 0);
  signal phase_inc                                : std_logic_vector(31 downto 0);
  signal phase_off                                : std_logic_vector(31 downto 0);
  signal swap_sf                                  : std_logic_vector(31 downto 0);

  signal dds_pulse_dval                           : std_logic;
  signal dds_pulse_data                           : std_logic_vector(31 downto 0);
  signal pulse_i                                  : std_logic_vector(15 downto 0);
  signal pulse_q                                  : std_logic_vector(15 downto 0);

  signal pipe_in_ch1_fifo_rden                    : std_logic;
  signal pipe_in_ch1_fifo_rd_data                 : std_logic_vector(31 downto 0);
  signal pipe_in_ch1_fifo_rd_dval                 : std_logic;
  signal pipe_in_ch1_fifo_empty                   : std_logic;  
  signal pipe_in_ch2_fifo_rden                    : std_logic;
  
  signal cmd_send_r                               : std_logic := '0';
  signal cmd_send_cnt_r                           : std_logic_vector(31 downto 0) := (others => '0');
  signal pipe_in_ch1_fifo_rden_cnt_r              : std_logic_vector(31 downto 0) := (others => '0');
  signal dds_pulse_data_cnt_r                     : std_logic_vector(31 downto 0) := (others => '0');
  signal dds_pulse_data_overflow_cnt_r            : std_logic_vector(31 downto 0) := (others => '0');
  
  signal tick_1ms                                 : std_logic;

  signal s_axi_aclk_tick_1ms_r                    : std_logic_vector(0 to 2) := (others => '0');
  signal s_axi_aclk_freq_r                        : std_logic_vector(31 downto 0) := (others => '0');
  signal s_axi_aclk_cnt_r                         : std_logic_vector(31 downto 0) := (others => '0');
  
begin
  
  s_axi_areset  <= not s_axi_aresetn_in;    -- synchronous with s_axi_aclk_in
  m_axi_areset  <= not m_axis_aresetn_in;    -- synchronous with m_axis_aclk_in

--    i_vio_0 : entity work.vio_0
--      port map (
--        clk                         => s_axi_aclk_in,
--        probe_in0                   => cmd_send_cnt_r,                    -- 32
--        probe_in1                   => pipe_in_ch1_fifo_rden_cnt_r,       -- 32
--        probe_in2                   => dds_pulse_data_cnt_r,              -- 32
--        probe_in3                   => s_axi_aclk_freq_r,                 -- 32
--        probe_in4                   => s_axi_aclk_cnt_r,                  -- 32
--        probe_in5                   => dds_pulse_data_overflow_cnt_r,     -- 32
--        probe_in6                   => m_axis_tvalid_cnt_r,               -- 32

--      );
  
  mode                       <=   mode_in;                        
  scale                      <=   scale_in;                       
  dac_holdoff                <=   dac_holdoff_in;                 
  cmd_idx                    <=   cmd_idx_in;                     
  cmd_send                   <=   cmd_send_in;                    
                                                                  
  reserv1                    <=   reserv1_in;                     
  dds_phase_inc_dwell_time   <=   dds_phase_inc_dwell_time_in;    
  dds_phase_inc_step_size    <=   dds_phase_inc_step_size_in;     
  idle_samples               <=   idle_samples_in;                
  dds_samples                <=   dds_samples_in;                 
  phase_inc                  <=   phase_inc_in;                   
  phase_off                  <=   phase_off_in;                   
  swap_sf                    <=   swap_sf_in;                     
                                                                                      
  process(s_axi_aclk_in)
  begin
    if (rising_edge(s_axi_aclk_in)) then
      if (s_axi_aresetn_in = '0') then
        cmd_send_cnt_r      <= (others => '0');
        cmd_send_r          <= '0';
      else
        cmd_send_r          <= cmd_send;
        if (cmd_send = '1' and cmd_send_r = '0') then
          cmd_send_cnt_r    <= cmd_send_cnt_r + 1;
        end if;
      end if;
    end if;
  end process;

  i_dds_cmd_gen : entity work.dds_cmd_gen  
    port map (
      clk_in                          => s_axi_aclk_in,
      cmd_idx_in                      => cmd_idx,
      cmd_send_in                     => cmd_send,

      reserv1_in                      => reserv1,                 
      dds_phase_inc_dwell_time_in     => dds_phase_inc_dwell_time,
      dds_phase_inc_step_size_in      => dds_phase_inc_step_size, 
      idle_samples_in                 => idle_samples,            
      dds_samples_in                  => dds_samples,            
      phase_inc_in                    => phase_inc,               
      phase_off_in                    => phase_off,               
      swap_sf_in                      => swap_sf,                 
        
      fifo_rd_clk_in                  => m_axis_aclk_in,
      fifo_rd_data_out                => pipe_in_ch1_fifo_rd_data,
      fifo_rd_dval_out                => pipe_in_ch1_fifo_rd_dval,
      fifo_rd_rd_en_in                => pipe_in_ch1_fifo_rden,    
      fifo_rd_empty_out               => pipe_in_ch1_fifo_empty,

      rst_in                          => m_axi_areset
      );
 
--  i_ila_4 : entity work.ila_4
--    port map (
--      clk                         => m_axis_aclk_in,
--      probe0                      => pipe_in_ch1_fifo_rd_data,  --32
--      probe1(0)                   => pipe_in_ch1_fifo_rd_dval,  --1
--      probe2(0)                   => pipe_in_ch1_fifo_rden,     --1
--      probe3(0)                   => pipe_in_ch1_fifo_empty     --1
--    );

  i_dds_pulse_2x_top : entity work.dds_pulse_2x_top
    port map(
      clk_in                      =>  m_axis_aclk_in,
      rst_in                      =>  m_axi_areset,
      mode_in                     =>  mode,  --  0=single, 1=dual   
      scale_in                    =>  scale,   
      fifo1_data_in               =>  pipe_in_ch1_fifo_rd_data,
      fifo1_dval_in               =>  pipe_in_ch1_fifo_rd_dval,
      fifo1_empty_in              =>  pipe_in_ch1_fifo_empty,
      fifo1_rden_out              =>  pipe_in_ch1_fifo_rden,
      fifo2_data_in               =>  x"00000000",--pipe_in_ch2_fifo_rd_data,
      fifo2_dval_in               =>  '0',--pipe_in_ch2_fifo_rd_dval,
      fifo2_empty_in              =>  '1',--pipe_in_ch2_fifo_empty,
      fifo2_rden_out              =>  pipe_in_ch2_fifo_rden,
      holdoff_in                  =>  dac_holdoff,    
      overflow_out                =>  open,
      underflow_out               =>  open,
      i_max_abs_out               =>  open,
      q_max_abs_out               =>  open,
      data_out                    =>  dds_pulse_data,
      dval_out                    =>  dds_pulse_dval   
      );
      
--  pulse_i <= dds_pulse_data(15 downto 0);
--  pulse_q <= dds_pulse_data(31 downto 16);


--  process(s_axi_aclk_in)
--    variable LineOut   : line;
--  begin
--    if (rising_edge(s_axi_aclk_in)) then
--      if (dds_pulse_dval = '1') then
--        hwrite(LineOut, dds_pulse_data);
--        writeline(DataFile, LineOut);
--      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') then
          dds_pulse_data_cnt_r          <= (others => '0');
          pipe_in_ch1_fifo_rden_cnt_r   <= (others => '0');
          dds_pulse_data_overflow_cnt_r <= (others => '0');
        else    
          if (dds_pulse_dval = '1' and s_axis_tready_0 = '1') then
            dds_pulse_data_cnt_r          <= dds_pulse_data_cnt_r + 1;
          end if;
    
          if (dds_pulse_dval = '1' and s_axis_tready_0 = '0') then
            dds_pulse_data_overflow_cnt_r          <= dds_pulse_data_overflow_cnt_r + 1;
          end if;
    
          if (pipe_in_ch1_fifo_rden = '1') then
            pipe_in_ch1_fifo_rden_cnt_r   <= pipe_in_ch1_fifo_rden_cnt_r + 1;
          end if;
          
       end if;
    end if;
  end process;

 i_axis_register_slice_32_0 : entity work.axis_register_slice_32  
    port map (
      aclk                              => m_axis_aclk_in,      -- in
      aresetn                           => m_axis_aresetn_in,   -- in
      s_axis_tdata                      => dds_pulse_data,      -- in
      s_axis_tvalid                     => dds_pulse_dval,      -- in
      s_axis_tready                     => s_axis_tready_0,     -- out

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


 i_axis_register_slice_32_1 : entity work.axis_register_slice_32  
    port map (
      aclk                              => m_axis_aclk_in,      -- in
      aresetn                           => m_axis_aresetn_in,   -- in
      s_axis_tdata                      => dds_pulse_data,      -- in
      s_axis_tvalid                     => dds_pulse_dval,      -- in
      s_axis_tready                     => s_axis_tready_1,     -- out

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


  i_tick_gen : entity work.tick_gen
    generic map (
      CLOCK_SPEED_MHZ                       => 100
      ) 
    port map (
      clk_in                                => s_axi_aclk_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"00000000",
      prog_us_tick_out                      => open,  

      reset_in                              => s_axi_areset   
      );

  process(s_axi_aclk_in)
  begin
    if (rising_edge(s_axi_aclk_in)) then
      s_axi_aclk_tick_1ms_r      <= s_axi_aclk_tick_1ms_r(1 to 2) & tick_1ms;
      if (s_axi_aclk_tick_1ms_r(0 to 1) = "01") then 
        s_axi_aclk_freq_r        <= s_axi_aclk_cnt_r;
        s_axi_aclk_cnt_r         <= (others => '0');
      else
        s_axi_aclk_cnt_r         <= s_axi_aclk_cnt_r + 1;
      end if;
    end if;
  end process;
  
end architecture imp;