--=============================================================================
--! @file wishboneTransactionGenerator_behavioural.vhd
--=============================================================================
--! Standard library
library IEEE;
--! Standard packages
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
--! Package containg type definition and constants
use work.BFMTypes.all;

use std.TEXTIO.all;

-------------------------------------------------------------------------------
-- --
-- University of Bristol, High Energy Physics Group.
-- --
-------------------------------------------------------------------------------
-- unit name: wishboneTransactionGenerator 
--
--! @brief Loops Generating transactions to send to BFM
--
--! @author David Cussans , David.Cussans@bristol.ac.uk
--
--! @date 2\1\2012
--
--! @version v0.1
--
--! @details
--! Must be compiled with VHDL-2008 ( uses HREAD and HWRITE ). 
--! \li Pause = 2 [delay]
--! \li Pulse (delay,width in 100ps ticks) = 3 [delay before pulse] [width]
--! \li IPBus transaction = 0 [ipbus params]
--! \li IPBus write = 0 0 [addr] [data]
--! \li IPBus read = 0 1 [addr] [dummy]
--! <b>Dependencies:</b>\n
--! None
--!
--! <b>References:</b>\n
--! referenced by ipbusMarocADC_tb \n
--!
--! <b>Modified by:</b>\n
--! Author: 
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
--! 9/March/2012 DGC - changing address and data to be STD_LOGIC_VECTOR. \n
--!                    using HWRITE / HREAD for Hexidecimal IO 
--! 1/March/2020 DGC - repurposed for AIDA-2020 TLU work. Changed syntax
-------------------------------------------------------------------------------
--! @todo <next thing to do> \n
--! <another thing to do> \n
--
--------------------------------------------------------------------------------

entity wishboneTransactionGenerator is
  generic (
    g_BUSWIDTH : integer := c_BUSWIDTH;   --! Number of bits in each word
    BFMINPUT   : string  := "$BFMINPUT";  --! File containing list of commands 
    BFMOUTPUT  : string  := "$BFMOUTPUT"  --! Output file
    );
  port (
    wb_transaction_o      : out t_wbTransaction;  -- ! signal that carries transaction to
                                                  -- IPBus interface
    wb_returned_data_i    : in  t_wbTransactionReturn;  -- ! Carrys data back from BFM
    pulse_transaction_o   : out t_pulseTransaction;
    pulse_returned_data_i : in  t_pulseTransactionReturn;

    --! Signal to clock generator
    endOfSim_o : out boolean            --! Take high to stop simulation.
    );
end wishboneTransactionGenerator;

architecture behavioural of wishboneTransactionGenerator is

  signal s_command_time : time;  -- Store the time the commands are issued.

begin  -- behavioural



  p_commandLoop : process

    file COMMANDS   : text;
    file DATA       : text;
    variable status : file_open_status;
    variable Lin    : line;
    variable Lout   : line;
    -- variable debugL : line;

    variable v_comment : string(1 to c_MAX_COMMAND_LINE_LENGTH);

    variable v_wb_returned_data   : t_wbTransactionReturn;
    variable v_currentWbTransaction : t_wbTransaction;

    variable v_pulse_returned_data   : t_pulseTransactionReturn;
    variable v_currentPulseTransaction : t_pulseTransaction;
    
    variable textLine : line;

    variable v_transactor_id   : integer := 999;  --! Halt with error if
                                                  --transactor ID not set...
    variable v_transactionType : integer := 999;

    variable v_pauseValue : integer;

	--variable v_wb_returned_data : t_wbTransactionReturn ;

  begin

    -- open input and output files
    FILE_OPEN(status, COMMANDS, BFMINPUT, read_mode);
    FILE_OPEN(status, DATA, BFMOUTPUT, write_mode);

    endOfSim_o <= false;

    while not ENDFILE(COMMANDS) loop --! Loop over commands from BFMINPUT

      s_command_time <= NOW;

      READLINE(COMMANDS, Lin);

      READ(Lin, v_transactionType);  --! Read the transaction type as the first item on line

      if (v_transactionType = PULSE) then

        for pulseChan in 0 to c_NPULSE_CHANNELS-1 loop
          READ(Lin, v_currentPulseTransaction(pulseChan).r_delay);
          READ(Lin, v_currentPulseTransaction(pulseChan).r_width);
        end loop;  -- pulseChan
        
        pulse_transaction_o <= v_currentPulseTransaction;
        wait on pulse_returned_data_i'transaction;  -- read the data returned by BFM
        v_pulse_returned_data := pulse_returned_data_i;

        -- bodge up a return printout
        WRITE(Lout, v_pulse_returned_data, left, 20);

      elsif (v_transactionType = COMMENT) then

        -- read in comment string..
        assert Lin'length < v_comment'length;  -- make sure S is big enough
        v_comment := (others => ' ');  -- make sure that the previous line is overwritten

        if Lin'length > 0 then
          read(Lin, v_comment(1 to Lin'length));
        end if;

        -- we have a comment
        WRITE(Lout, v_comment, left, v_comment'length);

      elsif (v_transactionType = IPBUS) then

        -- we have an IPBus transaction
        -- Read line of form
        -- r/w addr data

        READ(Lin, v_currentWbTransaction.r_read_write);
        HREAD(Lin, v_currentWbTransaction.r_addr);
        HREAD(Lin, v_currentWbTransaction.r_data);  -- Need to provide dummy data for reads.

        -- Issue transaction to Wishbone (IPBus) port
        wb_transaction_o <= v_currentWbTransaction;
        wait on wb_returned_data_i'transaction;  -- read the data returned by BFM
        v_wb_returned_data  := wb_returned_data_i;

        write(LOut,
              "transaction type, addr, data, returned data, current time:   " &
              to_hstring(to_unsigned(v_currentWbTransaction.r_read_write, 32)) & string'("  ") &
              to_hstring(unsigned(v_currentWbTransaction.r_addr)) & string'("  ") &
              to_hstring(unsigned(v_currentWbTransaction.r_data)) & string'("  ") &
              to_hstring(unsigned(v_wb_returned_data)) & string'("  ") &
              time'image(s_command_time)
              );
        
      elsif (v_transactionType = PAUSE) then

        -- Read number of time ticks ( 100ps ) to pause for
        READ(Lin, v_pauseValue);

        report "BFM: Pausing for clock cycles = " & to_string(v_pauseValue) & " starting at " & time'image(s_command_time) severity note;
        wait for v_pauseValue * TIMEUNIT;

      else

        report "BFM: Bad command type. Exiting" severity error;

      end if;



      WRITELINE(DATA, Lout);
      --! Flush the buffers every time we write a line....
      FLUSH(DATA);

    end loop;  -- idx

    report "Ending simulation" severity note;
    endOfSim_o <= true;
    wait;

  end process p_commandLoop;




end behavioural;
