--! @file
--!
--! @brief Issues a pulse of variable width and delay. Based on pulseTransactor
--! @author David Cussans
--! @date 23\4\2013
--
--! Note - have to compile with VHDL-2008
--
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use STD.TEXTIO.all;
--! Declaration of transaction types for Bus Functional Model
use work.BFMTypes.all;

use std.TEXTIO.all;

entity variablePulseTransactor is
  generic(
    g_BUSWIDTH : integer := 32);  -- width for triggernumber and timestamp
  port(
    clk_i           : in  std_logic;
    trans_i         : in  t_pulseTransaction;
    returnedData_o  : out t_pulseTransactionReturn;
    signal_o        : out std_logic_vector(c_NPULSE_CHANNELS - 1 downto 0);  --! Signal pulses low-high-low
    triggerNumber_o : out std_logic_vector(g_BUSWIDTH - 1 downto 0);
    timeStamp_o     : out std_logic_vector(g_BUSWIDTH - 1 downto 0)
    );

end variablePulseTransactor;

architecture rtl of variablePulseTransactor is

  signal s_timeStamp         : unsigned(g_BUSWIDTH - 1 downto 0) := (others => '0');
  constant c_timeGranularity : time                              := 1 ps;
  signal s_pulseNum          : integer                           := 0;

begin  -- rtl

  p_pulseGen : process is
    variable v_pulseDelay : time := 0 ps;
    variable v_pulseWidth : time := 0 ps;
    variable v_lastEdge   : time := 0 ps;

  begin
    report "variablePulseBFM: waiting for transaction" severity note;

    signal_o <= (others => '0');

    wait on trans_i'transaction;
    report "variablePulseBFM: Got transaction" severity note;

    wait until rising_edge(clk_i);

    for chan in 0 to signal_o'length - 1 loop
      v_pulseDelay := trans_i(chan).r_delay * TIMEUNIT;
      v_pulseWidth := trans_i(chan).r_width * TIMEUNIT;

      if (v_pulseDelay + v_pulseWidth) > v_lastEdge then
        v_lastEdge := (v_pulseDelay + v_pulseWidth);
      end if;

      if trans_i(chan).r_delay >= 0 then
        report "Queing pulse . chan , delay , width " & integer'image(chan) & "   " & time'image(v_pulseDelay) & "  " & time'image(v_pulseWidth);
        signal_o(chan) <= '1' after v_pulseDelay, '0' after (v_pulseDelay + v_pulseWidth);
      else
        report "NO Pulse queued chr chan " & integer'image(chan);
      end if;


    end loop;

    report "Waiting until last edge finished. Delay = " & time'image(v_lastEdge) severity note;
    wait for v_lastEdge;

    -- Update trigger number
    s_pulseNum      <= s_pulseNum + 1;
    triggerNumber_o <= std_logic_vector(to_unsigned(s_pulseNum, g_BUSWIDTH));

    -- output current time-stamp
    timeStamp_o <= std_logic_vector(s_timeStamp);

    returnedData_o <= s_pulseNum;

  end process p_pulseGen;

  -- purpose: keeps a timestamp in terms of clock cycles
  -- type   : sequential
  -- inputs : clk_i,  s_timeStamp
  -- outputs: s_timeStamp
  p_timeStamp : process(clk_i)
  begin  -- process p_timeStamp
    if rising_edge(clk_i) then
      s_timeStamp <= s_timeStamp + 1;
    end if;
  end process p_timeStamp;
end rtl;
