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

entity dds_cmd_gen is
  port(
    clk_in                          : in  std_logic;
    cmd_idx_in                      : in  std_logic_vector( 2 downto 0);
    cmd_send_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);
        
    fifo_rd_clk_in                  : in  std_logic;
    fifo_rd_data_out                : out std_logic_vector(31 downto 0);
    fifo_rd_dval_out                : out std_logic;
    fifo_rd_rd_en_in                : in  std_logic;    
    fifo_rd_empty_out               : out std_logic;
    
    rst_in                          : in  std_logic 
    );
end entity dds_cmd_gen;
  
architecture imp of dds_cmd_gen is

  signal fifo_wr_data_r                 : std_logic_vector(31 downto 0) := (others => '0');
  signal fifo_wr_en_r                   : std_logic := '0';

  signal cmd_idx_r                      : integer range 0 to 4 := 0;
  signal cmd_send_r                     : std_logic := '0';

  type fsm_state                        is (IDLE, SEND, DONE);
  signal state_r                        : fsm_state := IDLE;
  signal state_cnt_r                    : integer := 0;  

  type array_32b_type                   is array (0 to 7) of std_logic_vector(31 downto 0);
  type dds_command_list                 is array (integer range <>) of array_32b_type;

-- **EXAMPLE SWEEP**  Sweep from 1 MHz to 11 MHz in 100us using a 250MSps DAC rate. Then  sweep backwards from 11 MHz to 1 MHz
--
-- Phase Inc Start = 2^32 * (1/250) = 17179869
--  -- We will stop at 11 MHz, which corresponds to a Phase Inc Stop = 2^32 * (11/250) = 188978561
--  -- Phase Inc Stop - Phase Inc Start = 188978561 - 17179869 = 171,798,692
--      -- Thus, 171,798,692  is the TOTAL amount that must get added to the Phase Inc Start over the entire duration of the pulse.
--  -- Number of Pulse Samples = 100us / 4ns = 25,000.
--      -- Thus, we must linearly increase our initial phase increment (Phase Inc Start) by a total of 171,798,692 during the 25,000 sample pulse.
--          -- Easiest solution is to update the Phase Increment every sample (DDS PHASE INC DWELL CNT = 0).
--              -- DDS PHASE INCREMENT STEP = 171,798,692 / 25,000 = 6871.94768. We have to round this up/down so lets use 6872.
--


  signal dds_command_set                : dds_command_list(0 to 0) := 
  (
    -- WFM 0
    -- FREQUENCY SWEEP (UP-SWEEP) - sweep up from 1MHz to 5MHz in 5uS  -- = 2^32 * (desired freq / sample rate) = 2^32 * (5/250) = 85,899,345 
    0 => (x"00000000", --RESERVED1
          x"00000000", --DDS_PHASE_INC_DWELL_TIME
          x"0000D6BF", --DDS_PHASE_INC_STEP_SIZE (~1 MHz/us) (Phase Inc Stop - Phase Inc Start)/duration = 85899345 - 17179869 = 68719476/1250 = 54,975 = 0x0000_D6BF
          x"00000000", --IDLE_SAMPLES
          x"000004E2", --DDS_SAMPLES (~5 us)   = duration / sample_rate = 5us/4ns = 1250 = 0x4e2
          x"010624DD", --PHASE_INC (~1 MHz)    = 2^32 * (desired freq / sample rate) = 2^32 * (1/250) = 17179869 = 0x010624DD
          x"00000000", --PHASE_OFF
          x"00008000" --RESERVED_SWAP_SF -- Scale Factor = 1.0
         ) 
--      -- WFM 1
--      -- FREQUENCY SWEEP (DOWN-SWEEP) - sweep down from 6MHz to 1MHz in 5uS
--    1 => (x"00000000", --RESERVED1
--          x"00000000", --DDS_PHASE_INC_DWELL_TIME  
--          x"00FEF391", --DDS_PHASE_INC_STEP_SIZE (~1 MHz/us) (Phase Inc Stop - Phase Inc Start)/duration = 17179869 - 103079215 = -85899346/1250 = -68719 = 0x00FE_F391
--          x"00000000", --IDLE_SAMPLES
--          x"000004E2", --DDS_SAMPLES (~5 us)   = duration / sample_rate = 5us/4ns = 1250 = 0x4e2
--          x"0624DD2F", --PHASE_INC (~6 MHz)    = 2^32 * (desired freq / sample rate) = 2^32 * (6/250) = 103079215 = 0x0624DD2F
--          x"00000000", --PHASE_OFF
--          x"00008000"  --RESERVED_SWAP_SF -- Scale Factor = 1.0
--         ), 
--      -- WFM 2
--      -- CW TONE
--    2 => (x"00000000", --RESERVED1
--          x"00000000", --DDS_PHASE_INC_DWELL_TIME
--          x"00000000", --DDS_PHASE_INC_STEP_SIZE (No step, continuous tone)
--          x"00000000", --IDLE_SAMPLES     
--        x"000004E2", --DDS_SAMPLES (~5 us)     - 0x4e2 = 1250 * 4nS = 5 uS
----        x"000FFFFF", --DDS_SAMPLES (~5 us)  - 0xFFFFF = 1048575 * 4nS = 4.1943 mSec
----          x"00000E00", --DDS_SAMPLES (~5 us)  - 0x00000E00 = 3584 * 4nS = 14.336 uSec                    
----        x"000FFFFF", --DDS_SAMPLES (~5 us)
--          x"0624DD2F", --PHASE_INC (~6 MHz)
--          x"00000000", --PHASE_OFF
--          x"00008000"  --RESERVED_SWAP_SF -- Scale Factor = 1.0
--         ), 
--      -- WFM 3
--    -- FREQUENCY SWEEP (UP-SWEEP) - sweep up from 1MHz to 10MHz in 10uS
--    3 => (x"00000000", --RESERVED1
--          x"00000000", --DDS_PHASE_INC_DWELL_TIME
--          x"0000F197", --DDS_PHASE_INC_STEP_SIZE (~1 MHz/us) (Phase Inc Start - Phase Inc Stop)/duration = 171798692 - 17179869 = 154618823/2500 = 61848 = 0x0000_F197
--          x"000000FF", --IDLE_SAMPLES
--          x"000009C4", --DDS_SAMPLES (~10 us)   = duration / sample_rate = 10us/4ns = 2500 = 0x9C4
--          x"010624DD", --PHASE_INC (~1 MHz)    = 2^32 * (desired freq / sample rate) = 2^32 * (1/250) = 17179869 = 0x010624DD
--          x"00000000", --PHASE_OFF
--          x"00008000" --RESERVED_SWAP_SF -- Scale Factor = 1.0
--         ), 
--      -- WFM 4
--      -- ??????
--    4 => (x"00000000", --RESERVED1
--          x"00000000", --DDS_PHASE_INC_DWELL_TIME
--          x"00000000", --DDS_PHASE_INC_STEP_SIZE (~1 MHz/us)
--          x"00000000", --IDLE_SAMPLES
--          x"00000000", --DDS_SAMPLES (~5 us)
--          x"00000000", --PHASE_INC (~6 MHz)
--          x"00000000", --PHASE_OFF
--          x"00008000"  --RESERVED_SWAP_SF -- Scale Factor = 1.0
--         ) 
     );


  signal test_state_r      : std_logic_vector(1 downto 0) := (others => '0');
  
begin

  dds_command_set(0)(0) <= reserv1_in;
  dds_command_set(0)(1) <= dds_phase_inc_dwell_time_in;
  dds_command_set(0)(2) <= dds_phase_inc_step_size_in;
  dds_command_set(0)(3) <= idle_samples_in;
  dds_command_set(0)(4) <= dds_samples_in;
  dds_command_set(0)(5) <= phase_inc_in;
  dds_command_set(0)(6) <= phase_off_in;
  dds_command_set(0)(7) <= swap_sf_in;
  
  process(clk_in)
  begin
    if (rising_edge(clk_in)) then        
--      if (rst_in = '1') then
--        cmd_idx_r                 <= 0;
--        cmd_send_r                <= '0';
--        fifo_wr_en_r              <= '0';
--        state_cnt_r               <= 0;
--        state_r                   <= IDLE;
--      else
        cmd_send_r                <= cmd_send_in;
        fifo_wr_en_r              <= '0';

        case (state_r) is
          when IDLE =>
            if (cmd_send_in = '1' and cmd_send_r = '0') then
              cmd_idx_r           <= 0;--conv_integer(unsigned(cmd_idx_in));
              state_cnt_r         <= 0;
              state_r             <= SEND;
            else
              state_r             <= IDLE;
            end if;
            
          when SEND =>
            if (state_cnt_r = 8) then
              state_r             <= DONE;
            else
              fifo_wr_data_r      <= dds_command_set(0)(state_cnt_r);
              fifo_wr_en_r        <= '1';
              state_cnt_r         <= state_cnt_r + 1;
              state_r             <= SEND;
            end if;
            
          when DONE =>
            state_r               <= IDLE;
            
          when others =>
            state_r               <= IDLE;
            
        end case;
--      end if;
    end if;
  end process;

  test_state_r <= "00" when state_r = IDLE else
                  "01" when state_r = SEND else
                  "10" when state_r = DONE else
                  "11";

--    i_ila_1 : entity work.ila_2
--      port map (
--        clk                         => clk_in,
--        probe0                      => test_state_r,        -- 2
--        probe1                      => conv_std_logic_vector(state_cnt_r, 4),  -- 4
--        probe2                      => fifo_wr_data_r,      -- 32
--        probe3(0)                   => fifo_wr_en_r,        -- 1
--        probe4(0)                   => cmd_send_in,         -- 1
--        probe5(0)                   => cmd_send_r           -- 1
--      );

  i_pipe_in_ch1_fifo : entity work.afifo_32b_1024_pf512_latency1
    port map(
      wr_clk                      => clk_in,
      din                         => fifo_wr_data_r,
      wr_en                       => fifo_wr_en_r,
      full                        => open,
      overflow                    => open,

      rd_clk                      => fifo_rd_clk_in,
      dout                        => fifo_rd_data_out,
      valid                       => fifo_rd_dval_out,
      rd_en                       => fifo_rd_rd_en_in,
      empty                       => fifo_rd_empty_out,

      underflow                   => open,
      prog_full                   => open,
      wr_rst_busy                 => open,
      rd_rst_busy                 => open,   
      srst                        => rst_in
      );
  
end architecture imp;
