library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity tick_gen is
  generic(
    CLOCK_SPEED_MHZ                       : integer := 100
    );
  port(
    clk_in                                : in  std_logic;

    tick_1us_out                          : out std_logic;
    tick_1ms_out                          : out std_logic;
    tick_500ms_out                        : out std_logic;
    tick_750ms_out                        : out std_logic;
    tick_1s_out                           : out std_logic;

    prog_us_tick_rate_in                  : in  std_logic_vector(31 downto 0);
    prog_us_tick_out                      : out std_logic;    

    reset_in                              : in  std_logic    
    );
end entity tick_gen;

architecture imp of tick_gen is

  signal sysclk_cnt_r                     : integer range 0 to CLOCK_SPEED_MHZ-1;
  signal usec_cnt_r                       : integer range 0 to 999;
  signal msec_cnt_r                       : integer range 0 to 499;
  signal msec_cnt1_r                      : integer range 0 to 999;
  signal tick_1us_r                       : std_logic;
  signal tick_1ms_r                       : std_logic;
  signal tick_500ms_r                     : std_logic;
  signal tick_750ms_r                     : std_logic;
  signal tick_1s_r                        : std_logic;

  signal prog_usec_cnt_r                  : std_logic_vector(31 downto 0);
  signal prog_us_tick_r                   : std_logic;
  
begin

  tick_1us_out      <= tick_1us_r;
  tick_1ms_out      <= tick_1ms_r;
  tick_500ms_out    <= tick_500ms_r;  
  tick_750ms_out    <= tick_750ms_r;  
  tick_1s_out       <= tick_1s_r;  
  prog_us_tick_out  <= prog_us_tick_r;

  process(clk_in, reset_in)
  begin
    if(reset_in = '1') then
      sysclk_cnt_r      <= 0;
      usec_cnt_r        <= 0;
      msec_cnt_r        <= 0;
      msec_cnt1_r       <= 0;
      tick_1us_r        <= '1';
      tick_1ms_r        <= '0';
      tick_500ms_r      <= '0';
      tick_750ms_r      <= '0';
      tick_1s_r         <= '0';
      prog_usec_cnt_r   <= (others => '0');
      prog_us_tick_r    <= '0';
    elsif rising_edge(clk_in) then
      tick_1ms_r        <= '0';
      tick_500ms_r      <= '0';
      tick_750ms_r      <= '0';
      tick_1s_r         <= '0';
      prog_us_tick_r    <= '0';

      if(sysclk_cnt_r = CLOCK_SPEED_MHZ-1) then
        sysclk_cnt_r    <= 0;
        tick_1us_r      <= '1';
      else
        sysclk_cnt_r    <= sysclk_cnt_r + 1;
        tick_1us_r      <= '0';
      end if;

      if(tick_1us_r = '1') then
        if(usec_cnt_r = 999) then  -- 1000us 
          usec_cnt_r    <= 0;
          tick_1ms_r    <= '1';
        else
          usec_cnt_r    <= usec_cnt_r + 1;
        end if;
      end if;

      if(tick_1ms_r = '1') then
        if(msec_cnt_r = 499) then  -- 500ms 
          msec_cnt_r    <= 0;
          tick_500ms_r  <= '1';
        else
          msec_cnt_r    <= msec_cnt_r + 1;
        end if;
      end if;

      if(tick_1ms_r = '1') then
        if(msec_cnt1_r = 749) then  -- 750ms 
          tick_750ms_r    <= '1';
        end if;
        if(msec_cnt1_r = 999) then  -- 1s 
          msec_cnt1_r     <= 0;
          tick_1s_r       <= '1';
        else
          msec_cnt1_r     <= msec_cnt1_r + 1;
        end if;
      end if;

      if(tick_1us_r = '1') then
        if(prog_usec_cnt_r = prog_us_tick_rate_in) then  
          prog_usec_cnt_r     <= (others => '0');
          prog_us_tick_r      <= '1';
        else
          prog_usec_cnt_r     <= prog_usec_cnt_r + 1;
        end if;
      end if;

    end if;
  end process;

end architecture imp;