--
-- VHDL Architecture FACT_FAD_lib.data_generator.beha
--
-- Created:
--          by - FPGA_Developer.UNKNOWN (EEPC8)
--          at - 14:36:14 10.02.2010
--
-- using Mentor Graphics HDL Designer(TM) 2008.1 (Build 17)

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
library fact_fad_lib;
use fact_fad_lib.fad_definitions.all;

-- -- Uncomment the following library declaration if instantiating
-- -- any Xilinx primitives in this code.
-- library UNISIM;
-- use UNISIM.VComponents.all;

entity data_generator is
  generic(
    RAM_ADDR_WIDTH : integer := 12
  );
   port( 
      clk            : in     std_logic;
      data_out       : out    std_logic_vector (63 downto 0);
      addr_out       : out    std_logic_vector (RAM_ADDR_WIDTH-1 downto 0);
      write_ea       : out    std_logic_vector (0 downto 0) := "0";
      ram_start_addr : in    std_logic_vector (RAM_ADDR_WIDTH-1 downto 0);
      ram_write_ea : in std_logic;
      ram_write_ready : out std_logic := '0';
      config_start_mm, config_start_cm, config_start_spi : out std_logic := '0';
      config_ready_mm, config_ready_cm, config_ready_spi : in std_logic;
      config_started_mm, config_started_cm, config_started_spi : in std_logic;
      roi_array : in roi_array_type;
      roi_max : in roi_max_type;
      sensor_array : in sensor_array_type;
      sensor_ready : in std_logic;
      dac_array : in dac_array_type;
      package_length : in std_logic_vector (15 downto 0);
      board_id       : in std_logic_vector (3 downto 0);
      crate_id       : in std_logic_vector (1 downto 0);
      trigger_id     : in std_logic_vector (47 downto 0);
      trigger        : in std_logic;
      s_trigger      : in std_logic;
      new_config     : in std_logic;
      config_started : out std_logic := '0';
      adc_data_array : in adc_data_array_type;
      adc_oeb : out std_logic := '1';
      adc_clk_en : out std_logic := '0';
      adc_otr : in std_logic_vector (3 downto 0);
      drs_channel_id : out std_logic_vector (3 downto 0) := (others => '0');
      drs_dwrite : out std_logic := '1';
      drs_clk_en, drs_read_s_cell : out std_logic := '0';
      drs_read_s_cell_ready : in std_logic;
      drs_s_cell_array : in drs_s_cell_array_type
      );
end data_generator ;

architecture Behavioral of data_generator is

type state_generate_type is (INIT, CONFIG, CONFIG1, CONFIG2,CONFIG3, CONFIG4, WRITE_HEADER, WRITE_EXTERNAL_TRIGGER, WRITE_INTERNAL_TRIGGER, WRITE_BOARD_ID, WRITE_TEMPERATURES,
                             WRITE_DAC1, WRITE_DAC2, WRITE_CHANNEL_ID, WRITE_START_CELL, WRITE_ROI, WRITE_ADC_DATA, WRITE_DATA_END, WRITE_DATA_END_WAIT,
                             WRITE_END_FLAG, WRITE_DATA_STOP,
                             WRITE_DATA_IDLE, WAIT_FOR_ADC, WAIT_FOR_STOP_CELL, START_DRS_READING);

signal state_generate : state_generate_type := INIT;
signal start_addr : std_logic_vector (RAM_ADDR_WIDTH-1 downto 0) := (others => '0');

signal data_cntr : integer  range 0 to 1024 := 0;
signal evnt_cntr : std_logic_vector (31 downto 0) := (others => '0');
signal addr_cntr : integer range 0 to RAM_SIZE_64B := 0;    -- counts 64 bit words
signal channel_id : integer range 0 to 9 := 0;
signal adc_wait_cnt : integer range 0 to 7 := 0;


begin
  
  
	generate_data : process (clk)
	begin
		if rising_edge (clk) then
		  
      addr_out <= start_addr + conv_std_logic_vector(addr_cntr, RAM_ADDR_WIDTH);
	
			case state_generate is
			  when INIT =>
			    state_generate <= CONFIG;

        when CONFIG =>
          config_started <= '1';
          -- config config manager
          config_start_cm <= '1';
          if (config_started_cm = '1') then
            state_generate <= CONFIG1;
          end if;
        when CONFIG1 =>
          if (config_ready_cm = '1') then
            config_started <= '0';
            config_start_cm <= '0';
            config_start_mm <= '1';
          end if;
          if (config_started_mm = '1') then
            state_generate <= CONFIG2;
          end if;
        when CONFIG2 =>
          if (config_ready_mm = '1') then
            config_start_mm <= '0';
            config_start_spi <= '1';
          end if;
          if (config_started_spi = '1') then
            state_generate <= CONFIG3;
          end if;
        when CONFIG3 =>
          if (config_ready_spi = '1') then
            config_start_spi <= '0';
            state_generate <= WRITE_DATA_IDLE;
          end if;

        when WRITE_DATA_IDLE =>
          if (new_config = '1') then
            state_generate <= CONFIG;
          end if;
          if (ram_write_ea = '1' and (trigger = '1' or s_trigger = '1')) then
            -- stop drs, dwrite low
            drs_dwrite <= '0';
            -- start reading of drs stop cell
            drs_read_s_cell <= '1';
            -- enable adc output
            adc_oeb <= '0';
            -- switch on ADC_CLK
            adc_clk_en <= '1';
            start_addr <= ram_start_addr;
            state_generate <= WRITE_HEADER;
            evnt_cntr <= evnt_cntr + 1;
          end if;
				when WRITE_HEADER =>
				  write_ea <= "1";
          data_out <= X"0000" & PACKAGE_VERSION & PACKAGE_SUB_VERSION & package_length & X"FB01";
					addr_cntr <= addr_cntr + 3;
					state_generate <= WRITE_BOARD_ID;
        when WRITE_BOARD_ID =>     -- crate ID & board ID
          data_out <= (63 downto 10 => '0') & crate_id & "1000" & board_id;
          addr_cntr <= addr_cntr + 1;
          state_generate <= WRITE_TEMPERATURES;
        when WRITE_TEMPERATURES =>     -- temperatures
          if (sensor_ready = '1') then
            data_out <= conv_std_logic_vector (sensor_array (3), 16)
                      & conv_std_logic_vector (sensor_array (2), 16)
                      & conv_std_logic_vector (sensor_array (1), 16)
                      & conv_std_logic_vector (sensor_array (0), 16);
            addr_cntr <= addr_cntr + 1;
            state_generate <= WRITE_DAC1;
          end if;

        when WRITE_DAC1 =>
          data_out <= conv_std_logic_vector (dac_array (3), 16)
                    & conv_std_logic_vector (dac_array (2), 16)
                    & conv_std_logic_vector (dac_array (1), 16)
                    & conv_std_logic_vector (dac_array (0), 16);
          addr_cntr <= addr_cntr + 1;
          state_generate <= WRITE_DAC2;
        when WRITE_DAC2 =>
          data_out <= conv_std_logic_vector (dac_array (7), 16)
                    & conv_std_logic_vector (dac_array (6), 16)
                    & conv_std_logic_vector (dac_array (5), 16)
                    & conv_std_logic_vector (dac_array (4), 16);
          addr_cntr <= addr_cntr + 1;
          state_generate <= WAIT_FOR_STOP_CELL;

        when WAIT_FOR_STOP_CELL =>
          drs_read_s_cell <= '0';
          if (drs_read_s_cell_ready = '1') then
            state_generate <= START_DRS_READING;
          end if;
        
        when START_DRS_READING =>
          --drs channel number
          drs_channel_id <= conv_std_logic_vector (channel_id, 4);
          --starte drs-clocking
          --adc_oeb <= '0'; -- nur für Emulator
          drs_clk_en <= '1';
          adc_wait_cnt <= 0;
          state_generate <= WRITE_CHANNEL_ID;

        when WRITE_CHANNEL_ID =>    -- write DRS and Channel IDs
          data_out <= conv_std_logic_vector(0,10) & conv_std_logic_vector(3,2) & conv_std_logic_vector(channel_id,4)
                    & conv_std_logic_vector(0,10) & conv_std_logic_vector(2,2) & conv_std_logic_vector(channel_id,4)
                    & conv_std_logic_vector(0,10) & conv_std_logic_vector(1,2) & conv_std_logic_vector(channel_id,4)
                    & conv_std_logic_vector(0,10) & conv_std_logic_vector(0,2) & conv_std_logic_vector(channel_id,4);
          addr_cntr <= addr_cntr + 1;
          state_generate <= WRITE_START_CELL;
        when WRITE_START_CELL =>    -- write start cells
          data_out <= "000000" & drs_s_cell_array (3)
                    & "000000" & drs_s_cell_array (2)
                    & "000000" & drs_s_cell_array (1)
                    & "000000" & drs_s_cell_array (0); 
          addr_cntr <= addr_cntr + 1;
          state_generate <= WRITE_ROI;
        when WRITE_ROI =>    -- write ROI
          data_out <= "00000" & conv_std_logic_vector (roi_array((3) * 9 + channel_id), 11) 
                    & "00000" & conv_std_logic_vector (roi_array((2) * 9 + channel_id), 11)
                    & "00000" & conv_std_logic_vector (roi_array((1) * 9 + channel_id), 11)
                    & "00000" & conv_std_logic_vector (roi_array((0) * 9 + channel_id), 11);
          addr_cntr <= addr_cntr + 1;
          state_generate <= WAIT_FOR_ADC;
        when WAIT_FOR_ADC =>
          -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
          if (adc_wait_cnt < (4 + 3)) then -- anpassen!!!! -- 3 für Simulation, 4 für FPGA???
            adc_wait_cnt <= adc_wait_cnt + 1;
          else
            state_generate <= WRITE_ADC_DATA;
          end if;
        when WRITE_ADC_DATA =>
          if (data_cntr < roi_max (channel_id)) then
            data_out <= "000" & adc_otr(3) & adc_data_array(3)
                      & "000" & adc_otr(2) & adc_data_array(2)
                      & "000" & adc_otr(1) & adc_data_array(1)
                      & "000" & adc_otr(0) & adc_data_array(0);
--              data_out <= "00000" & conv_std_logic_vector (data_cntr, 11) 
--                          & "00010" & conv_std_logic_vector (data_cntr, 11) 
--                          & "00100" & conv_std_logic_vector (data_cntr, 11) 
--                          & "00110" & conv_std_logic_vector (data_cntr, 11) ;
            addr_cntr <= addr_cntr + 1;
            state_generate <= WRITE_ADC_DATA;
            data_cntr <= data_cntr + 1;
          else
            drs_clk_en <= '0';
            --adc_oeb <= '1'; -- nur für Emulator
            if (channel_id = 8) then
              state_generate <= WRITE_EXTERNAL_TRIGGER;
              adc_oeb <= '1';
              -- switch off ADC_CLK
              adc_clk_en <= '0';
            else
              channel_id <= channel_id + 1;     -- increment channel_id 
              state_generate <= START_DRS_READING;
              data_cntr <= 0;
            end if;
          end if;
          
          
        when WRITE_EXTERNAL_TRIGGER =>    -- external trigger ID
          addr_out <= start_addr + conv_std_logic_vector(1, RAM_ADDR_WIDTH);
          data_out <= X"0000" & trigger_id(39 downto 32) & trigger_id(47 downto 40) & trigger_id(15 downto 0) & trigger_id(31 downto 16);
          state_generate <= WRITE_INTERNAL_TRIGGER;
        when WRITE_INTERNAL_TRIGGER =>    -- internal trigger ID
          addr_out <= start_addr + conv_std_logic_vector(2, RAM_ADDR_WIDTH);
          data_out <= X"0000" & trigger_id(39 downto 32) & trigger_id(47 downto 40) & evnt_cntr(15 downto 0) & evnt_cntr(31 downto 16);
          state_generate <= WRITE_END_FLAG;
 				when WRITE_END_FLAG =>
          data_out <= (63 downto 32 => '0') & X"04FE" & X"4242";
          addr_cntr <= addr_cntr + 1;
          state_generate <= WRITE_DATA_END;
				when WRITE_DATA_END =>
				  write_ea <= "0";
					ram_write_ready <= '1';
					state_generate <= WRITE_DATA_END_WAIT;
				when WRITE_DATA_END_WAIT =>
				  state_generate <= WRITE_DATA_STOP;
      		when WRITE_DATA_STOP =>
          drs_dwrite <= '1';
					data_cntr <= 0;
					addr_cntr <= 0;
					channel_id <= 0;
					ram_write_ready <= '0';
					state_generate <= WRITE_DATA_IDLE;
				
				when others =>
					null;
					
			end case; -- state_generate
		end if; -- rising_edge (clk)
	end process generate_data;

end Behavioral;


