----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    10:44:52 01/07/2010 
-- Design Name: 
-- Module Name:    adc_emulator - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
-- hds interface_start
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
USE ieee.std_logic_textio.all;
LIBRARY std;
USE std.textio.all;

ENTITY adc_emulator IS
   GENERIC( 
      INPUT_FILE : string := "filename"
   );
   PORT( 
      clk  : IN     std_logic;
      data : OUT    std_logic_vector (11 downto 0);
      otr  : OUT    std_logic;
      oeb  : IN     std_logic
   );

-- Declarations

END adc_emulator ;

architecture Behavioral of adc_emulator is
	
	-- type_rom_type has to be a multiple of 4 bit because HREAD is used
	type type_shift_reg is array (0 to 7) of std_logic_vector(12 downto 0);
	type type_rom_array is array (0 to 1024) of std_logic_vector(15 downto 0);
  
  -- 'InitRomFromFile' reads one column of 'rom_filename' and puts the returned value to 'rom(i)'
  impure function InitRomFromFile (rom_filename : in string) return type_rom_array is
    file rom_file : text open read_mode is rom_filename;
    variable rom_file_line: line;
    variable rom : type_rom_array;
  begin
    for i in 0 to 1023 loop
      readline(rom_file, rom_file_line);
      hread(rom_file_line, rom(i));
    end loop;
    return rom;
  end function InitRomFromFile;
	
	signal rom : type_rom_array := InitRomFromFile(INPUT_FILE);
	signal rom_reg : type_shift_reg;
	signal rom_addr : std_logic_vector(9 downto 0) := (others => '0');
	signal rom_data : std_logic_vector(12 downto 0);

begin

  rom_data <= rom(conv_integer(rom_addr))(12 downto 0);
  data <= rom_reg(7)(11 downto 0) when oeb = '0' else (others => 'Z');
  otr <= rom_reg(7)(12);

	fetch_data_proc: process(clk)
	begin
    if rising_edge(clk) then
		  if (oeb = '0') then
			  rom_addr <= rom_addr + 1;
			else
			  rom_addr <= (others => '0');    
			end if;
		end if;
	end process fetch_data_proc;
  
	
	ad_conv_proc: process(clk)
	begin
		if rising_edge(clk) then
		  if (oeb = '0') then
    			if (conv_integer(rom_data) > 2**12-1) then
    				rom_reg(0) <= '1' & X"FFF";			-- set OTR flag when rom_data is too high and set adc value to max
    			else
    				rom_reg(0) <= rom_data;			-- shifting input cause output is shifted 7 cycles
    			end if;
    			rom_reg(1) <= rom_reg(0);
    			rom_reg(2) <= rom_reg(1);
    			rom_reg(3) <= rom_reg(2);
    			rom_reg(4) <= rom_reg(3);
    			rom_reg(5) <= rom_reg(4);
    			rom_reg(6) <= rom_reg(5);
       rom_reg(7) <= rom_reg(6);
  			end if;
		end if;
	end process ad_conv_proc;
	
end Behavioral;

