--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

entity autotrigger is
  port (
    clk         : in  std_logic;        -- 40 MHz
    reset       : in  std_logic;
    triggerFreq : in  std_logic_vector(3 downto 0);
    triggerOut  : out std_logic
  );
end entity;

architecture arch of autotrigger is
  -- Tipos para registro
  type cnt_type is array(15 downto 0) of std_logic_vector(7 downto 0);
  type reg_type is record
    pulseFormer1  : std_logic;
    clkReduced    : std_logic_vector(15 downto 0);
    cntReductor   : cnt_type;
  end record;

  constant regDefault : reg_type := (
    pulseFormer1  => '0',
    clkReduced    => (others => '0'),
    cntReductor   => (others => (others => '0'))
  );
  signal reg, nextReg : reg_type := regDefault;

begin
  --**********************************************************
  -- Proceso combinacional
  --
  COMB : process(reg, triggerFreq)
    variable var    : reg_type;
    variable muxOut : std_logic_vector(15 downto 0);  -- Muxer salida

  begin
    var := reg; -- Inicialización de variable
    --
    -- "Loop" para evitar escribir lo mismo 10 veces: creación de contadores,
    -- relojes desmultiplicados, reset síncrono de contadores y conexión
    -- con el multiplexor de salida.
    --
    for i in 0 to 15 loop
      var.cntReductor(i) := reg.cntReductor(i) + '1';
      --
      -- Para conseguir un reloj de "N" kHz a partir de uno de 40 MHz basta
      -- con invertir una señal (clkReduced) una vez cada:
      --         X = 200/frecuencia_en_centenares_de_kilohercios
      -- siendo "X" el semiperíodo del nuevo reloj.
      -- En la línea siguiente se le resta 1 unidad para tener en cuenta
      -- que los contadores se inician en 0, y que hace falta un ciclo de
      -- reloj (de 40 MHz) adicional para que tenga lugar el "reset"
      -- correspondiente.
      --
      if reg.cntReductor(i) = std_logic_vector(to_unsigned(200/(i+1)-1, 8))
      then 
        var.clkReduced(i)   := not reg.clkReduced(i);
        -- Reset síncrono de los contadores.
        var.cntReductor(i)  := std_logic_vector(to_unsigned(0, 8));
      end if;
   
      muxOut(i) := reg.clkReduced(i);
    end loop;

    -- Registro adicional para conformar el pulso: lo retrasa un ciclo.
    var.pulseFormer1 := muxOut(to_integer(unsigned(triggerFreq)));

    --*****************************************
    -- Resultado del proceso combinacional como siguiente valor de registro
    nextReg <= var;

    --*****************************************
    -- Actualización de salidas
    triggerOut <= muxOut(to_integer(unsigned(triggerFreq))) and 
                  not reg.pulseFormer1;
  end process;

  --**********************************************************
  -- Proceso secuencial
  --
  SEC : process(clk, reset)
  begin
    if reset = '1' then
      reg <= regDefault;
    elsif clk = '1' and clk'event then
      reg <= nextReg;
    end if;
  end process;

end architecture;