-- Haodan Huang
-- 
-- This component is basically a 26-bit counter
--
-- When the counter is 1, irq will be '1'
-- The irq is reset to '0' by the cpu, when the cpu wants to write to this
-- component, the irq will become '0'
--
-- The address, readdata, and writedata are effectively ignored

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity irComp is port (
  clk, reset_n, chipselect, read, write, address : in std_logic;
  readdata  : out std_logic_vector(15 downto 0);
  writedata : in  std_logic_vector(15 downto 0);
  irq       : out std_logic);
end irComp;

architecture rtl of irComp is 
  signal data    : std_logic_vector(15 downto 0);
  signal counter : unsigned(25 downto 0);
  signal counter_max : unsigned(25 downto 0);
  signal flag : integer := 0;
  signal f_flag: integer := 0;
begin
  
  process (clk)
  begin
    if rising_edge(clk) then
      if reset_n = '0' then
        data <= (others => '0');
      else
        if chipselect = '1' then
          if address = '1' then
            if write = '1' then
              data <= writedata;
            elsif read = '1' then
              readdata <= data;
            end if;
          end if;
        end if;
      end if;
    end if;
  end process;
  
process (clk)
begin 
  if rising_edge(clk) then
     if reset_n = '0' then
       counter_max <= (others => '0');
   else 
     if data(1 downto 0) = "00" then
       counter_max <= "11111111111111111111111111";
     elsif data(1 downto 0) = "01" then
       counter_max <= "01111111111111111111111111";
     elsif data(1 downto 0) = "10" then
       counter_max <= "01111111111111111111111111";
     end if;
  end if;
 end if;
end process;

  process (clk)
  begin
    if rising_edge(clk) then
      if reset_n = '0' then
        counter <= (others => '0');
      else
        counter <= counter +1 ;
      end if;
      if counter = counter_max then
        counter <= (others => '0');
        flag <= 1;
      end if;
     if f_flag = 1 then
       flag <= 0;
     end if;
    end if;
  end process;
    
  process (clk)
  begin
    if rising_edge(clk) then
      if reset_n = '0' then
        irq <= '0';
      else
         if flag = 0 then
          f_flag <= 0;
         end if;
        if flag = 1 then
          irq <= '1';
          f_flag <= 1;
        elsif write = '1' and chipselect = '1' then
          irq <= '0';  -- important to reset the irq
        end if;
      end if;
    end if;
  end process;
  
end rtl;


