--
-- adc_ctrl.vhd
--
-- Control For ADC Module
--
-- Also include simulation data SDRAM

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_misc.all;

library work;
use work.common_interface.all;

library UNISIM;
use UNISIM.vcomponents.all;

entity adc_ctrl is
  
  port (
    clk              : in  std_logic;
    rst              : in  std_logic;
    system_in  : in  std_logic_vector(system_width-1 downto 0);
    system_out : out std_logic_vector(system_width-1 downto 0);
    adc_in_0_0 : in std_logic_vector(13 downto 0);
    adc_in_0_1 : in std_logic_vector(13 downto 0);
    adc_in_0_2 : in std_logic_vector(13 downto 0);
    adc_in_1_0 : in std_logic_vector(13 downto 0);
    adc_in_1_1 : in std_logic_vector(13 downto 0);
    adc_in_1_2 : in std_logic_vector(13 downto 0);
    adc_in_2_0 : in std_logic_vector(13 downto 0);
    adc_in_2_1 : in std_logic_vector(13 downto 0);
    adc_in_2_2 : in std_logic_vector(13 downto 0);
    adc_out_0_0 : out std_logic_vector(13 downto 0);
    adc_out_0_1 : out std_logic_vector(13 downto 0);
    adc_out_0_2 : out std_logic_vector(13 downto 0);
    adc_out_1_0 : out std_logic_vector(13 downto 0);
    adc_out_1_1 : out std_logic_vector(13 downto 0);
    adc_out_1_2 : out std_logic_vector(13 downto 0);
    adc_out_2_0 : out std_logic_vector(13 downto 0);
    adc_out_2_1 : out std_logic_vector(13 downto 0);
    adc_out_2_2 : out std_logic_vector(13 downto 0);
    adc_enb    : out std_logic_vector(2 downto 0);
    syn_rst    : out std_logic;
    fref_test   : out std_logic;
    user_leds  : out std_logic_vector(1 downto 0));

end adc_ctrl;

architecture rtl of adc_ctrl is

  constant ncomponents : integer := 5;
  type     sys_bus_type is array (0 to ncomponents) of std_logic_vector(system_width-1 downto 0);
  signal s : sys_bus_type;

  
  signal adc_control_reg : std_logic_vector(31 downto 0);
  signal test_data_control_reg : std_logic_vector(31 downto 0);
  signal test_data_length_reg : std_logic_vector(31 downto 0);

  signal sdram_q : std_logic_vector(63 downto 0);
  signal sdram_addr : std_logic_vector(24 downto 0);
  signal sdram_qv : std_logic;
  signal sdram_r : std_logic;
  signal sdram_busy : std_logic;
  signal sdram_gnt : std_logic;
    
  component sync_fifo
    generic (
      width : natural := 32);
    port (
      clk     : in  std_logic;
      rst     : in  std_logic;
      wadv    : in  std_logic;
      wdata   : in  std_logic_vector(width-1 downto 0);
      wnfull  : out std_logic;
      wfull   : out std_logic;
      hfull   : out std_logic;
      radv    : in  std_logic;
      rdw_out : out std_logic_vector(width-1 downto 0);
      rempty  : out std_logic;
      rnempty : out std_logic);
  end component;


  signal start_addr : std_logic_vector(24 downto 0);
  signal read_running : std_logic;
  signal write_running : std_logic;
  signal count : std_logic_vector(24 downto 0);
  signal fifo_hfull : std_logic;
  signal rf_reg : std_logic;
  signal read_fifo : std_logic;
  signal fifo_empty : std_logic;
  signal fifo_data : std_logic_vector(63 downto 0);
  signal adc_sim_data : std_logic_vector(31 downto 0);
  signal mem_req : std_logic;

  signal adc_status : std_logic_vector(31 downto 0);
  
begin  -- rtl

  s(0) <= system_in;
  
  creg0 : readable_control_register
    generic map (
      width => 32, addr => 1)
    port map (
      clk          => clk, rst => rst, system_in => s(0), system_out => s(1),
      control_data => adc_control_reg, control_wstb => open);

  creg1 : readable_control_register
    generic map (
      width => 32, addr => 3)
    port map (
      clk          => clk, rst => rst, system_in => s(1), system_out => s(2),
      control_data => test_data_control_reg, control_wstb => open);

  creg2 : readable_control_register
    generic map (
      width => 32, addr => 4)
    port map (
      clk          => clk, rst => rst, system_in => s(2), system_out => s(3),
      control_data => test_data_length_reg, control_wstb => open);


  sreg2 : status_register
    generic map (
      width => 32, addr => 5)
    port map (
      clk          => clk, rst => rst, system_in => s(3), system_out => s(4),
      status_data => adc_status);

  dram3 : external_memory
    generic map (
      width   => 64,
      depth   => 25,
      bank_id => 3)
    port map(
      clk        => clk,
      rst        => rst,
      system_in  => s(4),
      system_out => s(5),
      w          => '0',
      a          => sdram_addr,
      d          => X"0000000000000000",
      q          => sdram_q,
      qv         => sdram_qv,
      r          => sdram_r,
      full       => sdram_busy,
      req        => mem_req,
      gnt        => sdram_gnt);

  system_out <= s(5);
  
  rd_wr_sdram: process (clk, rst)
  begin  -- process rd_wr_sdram
    if rst = '1' then                   -- asynchronous reset (active low)
      sdram_addr <= (others => '0');
      sdram_r <= '0';
      read_running <= '0';
      write_running <= '0';
      rf_reg <= '0';
      read_fifo <= '0';
      adc_sim_data <= (others => '0');
      mem_req <= '0';
      adc_status <= (others => '0');
    elsif clk'event and clk = '1' then  -- rising clock edge
      start_addr <= test_data_control_reg(24 downto 0);
      mem_req <= test_data_control_reg(25);

      adc_status <= EXT(sdram_gnt & sdram_busy & fifo_hfull & write_running & read_running & sdram_addr,32);
      
      if test_data_control_reg(25) = '0' then
        read_running <= '0';
        write_running <= '0';
        sdram_r <= '0';
        read_fifo <= not fifo_empty;
      else
        sdram_r <= (not sdram_busy) and (sdram_gnt) and (not fifo_hfull);
        if read_running = '0' then
          read_running <= '1';
          sdram_addr <= test_data_control_reg(24 downto 0);
          count <= CONV_STD_LOGIC_VECTOR(1,25);
        else
          if sdram_busy = '0' and sdram_gnt = '1' and fifo_hfull = '0' then
            if count = test_data_length_reg(24 downto 0) then
              sdram_addr <= start_addr;
              count <= CONV_STD_LOGIC_VECTOR(1,25);
            else
              count <= count+1;
              sdram_addr <= sdram_addr+1;
            end if;         
          end if; 
        end if;
        if write_running = '0' then
          if fifo_hfull = '1' then
            write_running <= '1';
            rf_reg <= '0';
          end if;
        else
          rf_reg <= not rf_reg;
          read_fifo <= rf_reg;
          if rf_reg = '1' then
            adc_sim_data <= fifo_data(31 downto 0);
          else
            adc_sim_data <= fifo_data(63 downto 32);
          end if;       
        end if;        
      end if;
    end if;
  end process rd_wr_sdram;

  read_fifo0: sync_fifo
    generic map (
      width => 64)
    port map (
      clk        => clk,
      rst        => rst,
      wdata      => sdram_q,
      wadv       => sdram_qv,
      hfull   => fifo_hfull,
      wnfull  => open,
      wfull   => open,
      radv    => read_fifo,
      rdw_out => fifo_data,
      rempty  => fifo_empty);


  mux_data: process (clk)
  begin  -- process mux_data
    if clk'event and clk = '1' then  -- rising clock edge
      fref_test <= adc_sim_data(0);
      if adc_control_reg(0) = '1' then
        adc_out_0_0 <= adc_in_0_0;
      else
        adc_out_0_0 <= adc_sim_data(11 downto 1) & "000";
      end if;
      if adc_control_reg(1) = '1' then
        adc_out_0_1 <= adc_in_0_1;
      else
        adc_out_0_1 <= adc_sim_data(21 downto 12) & "0000" ;
      end if;
      if adc_control_reg(2) = '1' then
        adc_out_0_2 <= adc_in_0_2;
      else
        adc_out_0_2 <= adc_sim_data(31 downto 22) & "0000";
      end if;
      if adc_control_reg(3) = '1' then
        adc_out_1_0 <= adc_in_1_0;
      else
        adc_out_1_0 <= adc_sim_data(11 downto 1) & "000";
      end if;
      if adc_control_reg(4) = '1' then
        adc_out_1_1 <= adc_in_1_1;
      else
        adc_out_1_1 <= adc_sim_data(21 downto 12) & "0000";
      end if;
      if adc_control_reg(5) = '1' then
        adc_out_1_2 <= adc_in_1_2;
      else
        adc_out_1_2 <= adc_sim_data(31 downto 22) & "0000";
      end if;
      if adc_control_reg(6) = '1' then
        adc_out_2_0 <= adc_in_2_0;
      else
        adc_out_2_0 <= adc_sim_data(11 downto 1) & "000";
      end if;
      if adc_control_reg(7) = '1' then
        adc_out_2_1 <= adc_in_2_1;
      else
        adc_out_2_1 <= adc_sim_data(21 downto 12) & "0000";
      end if;
      if adc_control_reg(8) = '1' then
        adc_out_2_2 <= adc_in_2_2;
      else
        adc_out_2_2 <= adc_sim_data(31 downto 22) & "0000";
      end if;

      adc_enb <= adc_control_reg(6) & adc_control_reg(3) & adc_control_reg(0);
      syn_rst <= adc_control_reg(9);

      user_leds <= adc_control_reg(11 downto 10); 
      
    end if;
  end process mux_data;
  
  
end rtl;
