--
-- VHDL Architecture FACT_FAD_lib.memory_manager.beha
--
-- Created:
--          by - kai.UNKNOWN (E5PCXX)
--          at - 14:33:25 02.03.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;

-- library UNISIM;
-- use UNISIM.VComponents.all;
-- USE IEEE.NUMERIC_STD.all;

-- RAM_ADDR_WIDTH_64B is used for 
-- output ram_start_addr

-- RAM_ADDR_WIDTH_16B is used for
-- output wiz_ram_start_addr 


ENTITY memory_manager IS
  generic(
     RAM_ADDR_WIDTH_64B : integer := 12;
     RAM_ADDR_WIDTH_16B : integer := 14 
   );
   PORT( 
      clk : IN std_logic;
      config_start : IN std_logic;
      ram_write_ready : IN std_logic;
      roi_array : IN roi_array_type;
      ram_write_ea : OUT std_logic := '0';
      config_ready, config_started : OUT std_logic := '0';
      roi_max : OUT roi_max_type := (others => conv_std_logic_vector (0, 11));
      package_length : OUT std_logic_vector (15 downto 0) := (others => '0');
      wiz_ram_start_addr : OUT std_logic_vector (RAM_ADDR_WIDTH_16B-1 downto 0) := (others => '0');
      wiz_write_length : OUT std_logic_vector (16 downto 0) := (others => '0');
      wiz_number_of_channels : OUT std_logic_vector (3 downto 0) := (others => '0');
      wiz_write_ea : OUT std_logic := '0';
      wiz_write_header : OUT std_logic := '0';
      wiz_write_end : OUT std_logic := '0';
      wiz_busy : IN std_logic;
      ram_start_addr : OUT std_logic_vector (RAM_ADDR_WIDTH_64B-1 DOWNTO 0) := (others => '0')
   );

-- Declarations

END memory_manager ;

--
ARCHITECTURE beha OF memory_manager IS

type state_mm_type is (MM_CONFIG, MAX_ROI, MAX_ROI1, MAX_ROI2, FIFO_CALC, RAM_CALC, RAM_CALC1, RAM_CALC2, MM_MAIN, MM_MAIN1);
signal state_mm : state_mm_type := MM_CONFIG;

--type roi_array_type is array (0 to 35) of integer range 0 to 1024;
type roi_max_array_type is array (0 to 8) of integer range 0 to 1024;
type channel_size_type is array (0 to 8) of integer range 0 to W5300_TX_FIFO_SIZE;
type fifo_write_length_type is array (0 to 8) of integer range 0 to W5300_TX_FIFO_SIZE;
type fifo_channels_array_type is array (0 to 8) of integer range 0 to 9;
type fifo_package_size_ram_type is array (0 to 8) of integer range 0 to RAM_SIZE_16B;

signal roi_max_array : roi_max_array_type := (others => 0);

-- size of channel groups (16 bit)
signal channel_size : channel_size_type := (others => 0);
-- write length of packages (16 bit)
signal fifo_write_length : fifo_write_length_type := (others => 0);
-- number of channels per package
signal fifo_channels_array : fifo_channels_array_type := (others => 0);
-- size of packages in ram (16 bit)
signal fifo_package_size_ram : fifo_package_size_ram_type := (others => 0);
--
signal event_size_ram : integer range 0 to RAM_SIZE_16B := 0;
signal event_size_ram_64b : integer range 0 to RAM_SIZE_64B := 0;
signal event_size : integer range 0 to RAM_SIZE_16B := 0;

signal drs_id : integer range 0 to 4 := 0;
signal channel_id : integer range 0 to 9 := 0;
signal channel_index : integer range 0 to 9 := 0;
signal package_index : integer range 0 to 9 := 0;
signal number_of_packages : integer range 0 to 9 := 0;
signal max_events_ram, events_in_ram : integer range 0 to 2048;
signal event_start_addr : integer range 0 to (RAM_SIZE_64B - 1);
signal write_start_addr : integer range 0 to (RAM_SIZE_16B - 1);
signal event_ready_flag : std_logic := '0';

signal roi_index : integer range 0 to 45 := 0;
signal temp_roi : integer range 0 to 1024 := 0;

BEGIN
  
  mm : process (clk)
  begin
    if rising_edge (clk) then
      case state_mm is
    
        when MM_CONFIG =>
          if (config_start = '1') then
            config_started <= '1';
            roi_max_array <= (others => 0);
            channel_size <= (others => 0);
            fifo_write_length <= (others => 0);
            fifo_channels_array <= (others => 0);
            event_size <= 0;
            ram_write_ea <= '0';
            state_mm <= MAX_ROI;
          end if;
        
        -- calculate max ROIs and channel sizes
        when MAX_ROI =>
          roi_index <= (drs_id * 9) + channel_id;
          state_mm <= MAX_ROI1;
        when MAX_ROI1 =>
          temp_roi <= roi_array (roi_index);
          state_mm <= MAX_ROI2;
        when MAX_ROI2 =>
          if (channel_id < 9) then
            if ( temp_roi > roi_max_array (channel_id)) then
              roi_max_array (channel_id) <= temp_roi;
            end if;
            channel_size (channel_id) <= channel_size (channel_id) + temp_roi + 3;
            drs_id <= drs_id + 1;
            state_mm <= MAX_ROI;
            if (drs_id = 3) then
              drs_id <= 0;
              channel_id <= channel_id + 1;
            end if;
          else
            drs_id <= 0;
            channel_id <= 0;
            channel_size (0) <= channel_size (0) + PACKAGE_HEADER_LENGTH;
            channel_size (8) <= channel_size (8) + PACKAGE_END_LENGTH;
            state_mm <= FIFO_CALC;
          end if;
        
        -- calculate number of channels that fit in FIFO
        when FIFO_CALC =>
          if (channel_id < 9) then
            if ((fifo_write_length (package_index) + channel_size (channel_id)) <= W5300_TX_FIFO_SIZE) then
              fifo_write_length (package_index) <= fifo_write_length (package_index) + channel_size (channel_id);
              fifo_channels_array (package_index) <= fifo_channels_array (package_index) + 1;
              channel_id <= channel_id + 1;
              event_size <= event_size + channel_size (channel_id);
            else
              package_index <= package_index + 1;
            end if;
          else
            number_of_packages <= package_index + 1;
            package_index <= 0;
            channel_index <= 0;
            channel_id <= 0;
            fifo_package_size_ram <= (others => 0);
            fifo_package_size_ram (0) <= PACKAGE_HEADER_LENGTH + 6; 
            event_size_ram <= 0;
            event_size_ram_64b <= 0;
            max_events_ram <= 0;           
            state_mm <= RAM_CALC;
          end if;
          
        when RAM_CALC =>
          if (package_index < number_of_packages) then
            if (channel_index < fifo_channels_array (package_index)) then
              fifo_package_size_ram (package_index) <= fifo_package_size_ram (package_index) + ((roi_max_array (channel_id) + 3) * 4);
              channel_index <= channel_index + 1;
              channel_id <= channel_id + 1;
            else
              package_index <= package_index + 1;
              event_size_ram <= event_size_ram + fifo_package_size_ram (package_index);
              channel_index <= 0;
            end if;
          else
            fifo_package_size_ram (package_index - 1) <= fifo_package_size_ram (package_index - 1) + 4;
            event_size_ram <= event_size_ram + 4; -- Size of Event in RAM (16 Bit), + CRC + Endflag + 2 Spare               
            state_mm <= RAM_CALC1;
          end if;
        when RAM_CALC1 =>
          max_events_ram <= max_events_ram + 1;
          if ((max_events_ram * event_size_ram) <= RAM_SIZE_16B) then
            state_mm <= RAM_CALC1;
          else
            max_events_ram <= max_events_ram - 1;
            state_mm <= RAM_CALC2;
          end if;
        when RAM_CALC2 =>
          event_size_ram_64b <= (event_size_ram / 4);
          events_in_ram <= 0;
          event_start_addr <= 0;
          write_start_addr <= 0;
          package_index <= 0;
          channel_id <= 0;
          ram_start_addr <= (others => '0');
          ram_write_ea <= '1';
          config_started <= '0';
          config_ready <= '1';
          package_length <= conv_std_logic_vector (event_size, 16);
          for i in 0 to 8 loop
            roi_max(i) <= conv_std_logic_vector(roi_max_array(i), 11);
          end loop;
          state_mm <= MM_MAIN;
          
        when MM_MAIN =>
          state_mm <= MM_MAIN1;
          if ((ram_write_ready = '1') and (event_ready_flag = '0')) then
            ram_write_ea <= '0';
            events_in_ram <= events_in_ram + 1;
            if ((event_start_addr + event_size_ram_64b) < (RAM_SIZE_64B - event_size_ram_64b)) then
              event_start_addr <= event_start_addr + event_size_ram_64b;
            else
              event_start_addr <= 0;
            end if;
            event_ready_flag <= '1';
          end if;
          wiz_write_ea <= '0'; -- ?????
    
        when MM_MAIN1 =>
          state_mm <= MM_MAIN;
          if (config_start = '1') then
            config_ready <= '0';
            if (events_in_ram = 0) then
              state_mm <= MM_CONFIG;
            end if;
          end if;
          if (event_ready_flag = '1') then
            if (events_in_ram < max_events_ram) then
              ram_write_ea <= '1';
              -- ram_start_addr <= conv_std_logic_vector(event_start_addr, 12);
              ram_start_addr <= conv_std_logic_vector(event_start_addr, RAM_ADDR_WIDTH_64B);
              event_ready_flag <= '0';
            end if;
          end if;
          if ((events_in_ram > 0) and (wiz_busy = '0')) then
            if (package_index < number_of_packages) then
              -- wiz_ram_start_addr <= conv_std_logic_vector(write_start_addr, 14);
              wiz_ram_start_addr <= conv_std_logic_vector(write_start_addr, RAM_ADDR_WIDTH_16B);
              wiz_write_length <= conv_std_logic_vector(fifo_write_length (package_index), 17);
              wiz_number_of_channels <= conv_std_logic_vector(fifo_channels_array (package_index), 4);
              wiz_write_ea <= '1';
              package_index <= package_index + 1;
              if (package_index = 0) then
                -- first package -> write header
                wiz_write_header <= '1';
              else
                wiz_write_header <= '0';
              end if;
              if (package_index = (number_of_packages - 1)) then
                -- last package -> write end-flag
                wiz_write_end <= '1';
                -- next address 
                if ((write_start_addr + event_size_ram + fifo_package_size_ram (package_index) )  < (RAM_SIZE_16B - event_size_ram)) then
                  --write_start_addr <= write_start_addr + event_size_ram;
                  write_start_addr <= write_start_addr + fifo_package_size_ram (package_index);
                else
                  write_start_addr <= 0;
                end if;
              else
                write_start_addr <= write_start_addr + fifo_package_size_ram (package_index);
                wiz_write_end <= '0';
              end if;
            else
              events_in_ram <= events_in_ram - 1;
              package_index <= 0;
            end if;
        end if;
        
          
      end case; -- state_mm
    end if;
  end process mm; 
  
   
  
END ARCHITECTURE beha;

