#ifdef SYSTEMC
//#if defined(STATISTICS) or defined(VHDL_TESTBENCH)
/*
 * $Id$
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_Execute_loop/Execute_loop/Multi_Read_unit/Read_unit/Reservation_station/include/Reservation_station.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_execute_loop {
namespace execute_loop {
namespace multi_read_unit {
namespace read_unit {
namespace reservation_station {

#ifdef  SYSTEMC_VHDL_COMPATIBILITY
#define dump_queue() \
  do\
  {\
   log_printf(TRACE,Reservation_station,FUNCTION," * dump queue");\
   log_printf(TRACE,Reservation_station,FUNCTION,"   * nb_elt : %d",_queue_nb_elt);\
   for (uint32_t j=0;j<_param->_size_queue; j++)\
   {\
     cout << "\t"\
          << "[" << j << "] "\
          << "{" << _queue[j]._rob_id << " - "<< _queue[j]._context_id << "} " << " - "<< _queue[j]._front_end_id << "} " << " - "<< _queue[j]._ooo_engine_id << "} "\
          << _queue[j]._data_ra_val << ", "\
          << _queue[j]._num_reg_ra  << " - "\
          << _queue[j]._data_rb_val << ","\
          << _queue[j]._num_reg_rb  << " - "\
          << _queue[j]._data_rc_val << ","\
          << _queue[j]._num_reg_rc  \
          << endl;\
    }\
  } while (0) 
#else
#define dump_queue() \
  do\
  {\
   log_printf(TRACE,Reservation_station,FUNCTION," * dump queue");\
   log_printf(TRACE,Reservation_station,FUNCTION,"   * nb_elt : %d",_queue_nb_elt);\
   for (uint32_t j=0;j<_param->_size_queue; j++)\
   {\
     cout << "\t"\
          << "[" << (*_queue_control)[j] << "] "\
          << "{" << _queue[(*_queue_control)[j]]._rob_id << " - "<< _queue[(*_queue_control)[j]]._context_id << "} " << " - "<< _queue[(*_queue_control)[j]]._front_end_id << "} " << " - "<< _queue[(*_queue_control)[j]]._ooo_engine_id << "} "\
          << _queue[(*_queue_control)[j]]._data_ra_val << ", "\
          << _queue[(*_queue_control)[j]]._num_reg_ra  << " - "\
          << _queue[(*_queue_control)[j]]._data_rb_val << ","\
          << _queue[(*_queue_control)[j]]._num_reg_rb  << " - "\
          << _queue[(*_queue_control)[j]]._data_rc_val << ","\
          << _queue[(*_queue_control)[j]]._num_reg_rc  \
          << endl;\
    }\
  } while (0) 
#endif

#undef  FUNCTION
#define FUNCTION "Reservation_station::transition"
  void Reservation_station::transition (void)
  {
    log_printf(FUNC,Reservation_station,FUNCTION,"Begin");

    if (PORT_READ(in_NRESET) == 0)
      {
#ifdef  SYSTEMC_VHDL_COMPATIBILITY
	for (uint32_t i=0; i<_param->_size_queue; i++)
	  _queue_valid [i] = false;
#else
	_queue_control->clear();
#endif
      }
    else
      {
	// ***** POP from reservation station

	// scan in reverse order, because when we pop the queue there are an auto reorder
	//for (int32_t i=(static_cast<int32_t>(_queue_control->nb_elt()))-1;i>=0; i--)
	for (int32_t i=(static_cast<int32_t>(_param->_nb_inst_retire))-1;i>=0; i--)
	  {
	    if ((    internal_RETIRE_VAL [i]  == 1) and
		(PORT_READ(in_RETIRE_ACK [i]) == 1))
	      {
		//uint32_t index = (*_queue_control)[i];

		log_printf(NONE,Reservation_station,FUNCTION,"POP  [%d]",i);

		uint32_t index  = internal_RETIRE_SLOT[i];

#ifdef  SYSTEMC_VHDL_COMPATIBILITY
		_queue_valid [index] = false;
#else
		_queue_control->pop(index);
#endif
// 		cout << "========== Transition : " << endl
// 		     << " * i           : " << i << endl
// 		     << " * index       : " << index << endl;

		log_printf(NONE,Reservation_station,FUNCTION," * index         : %d",index);
	      }
	  }
	
// 	dump_queue();

	// ***** Bypass
	// Note : we can take this sequence code before the PUSH in the queue, because read_queue make the bypass !!!
	
	// scan all entry
	for (uint32_t i=0; 
#ifdef  SYSTEMC_VHDL_COMPATIBILITY
	     i<_param->_size_queue;
#else
	     i<_queue_control->nb_elt();
#endif
	     i++)
	  {
	    uint32_t index;
#ifdef  SYSTEMC_VHDL_COMPATIBILITY
	    index = i;
#else
	    index = (*_queue_control)[i];
#endif

	    // ***** bypass - gpr_write
	    for (uint32_t j=0; j<_param->_nb_gpr_write; j++)
	      {
		bool cmp;
		if (_param->_have_port_ooo_engine_id)
		  cmp = (PORT_READ(in_GPR_WRITE_OOO_ENGINE_ID [j]) == _queue[index]._ooo_engine_id);
		else
		  cmp = true;

		if ((PORT_READ(in_GPR_WRITE_VAL        [j]) == 1) and cmp)
		  {
		    if (PORT_READ(in_GPR_WRITE_NUM_REG [j]) == _queue[index]._num_reg_ra)
		      {
			log_printf(TRACE,Reservation_station,FUNCTION," -> GPR_WRITE     [%d] - Hit queue[%d]-GPR_RA[%d]",i,index,_queue[index]._num_reg_ra);
			_queue[index]._data_ra_val = 1;
			_queue[index]._data_ra     = PORT_READ(in_GPR_WRITE_DATA [j]);
		      }
		    if (PORT_READ(in_GPR_WRITE_NUM_REG [j]) == _queue[index]._num_reg_rb)
		      {
			log_printf(TRACE,Reservation_station,FUNCTION," -> GPR_WRITE     [%d] - Hit queue[%d]-GPR_RB[%d]",i,index,_queue[index]._num_reg_rb);
			_queue[index]._data_rb_val = 1;
			_queue[index]._data_rb     = PORT_READ(in_GPR_WRITE_DATA [j]);
		      }
		  }
	      }
	    // ***** bypass - spr_write
	    for (uint32_t j=0; j<_param->_nb_spr_write; j++)
	      {
		bool cmp;
		if (_param->_have_port_ooo_engine_id)
		  cmp = (PORT_READ(in_SPR_WRITE_OOO_ENGINE_ID [j]) == _queue[index]._ooo_engine_id);
		else
		  cmp = true;
		
		if ((PORT_READ(in_SPR_WRITE_VAL           [j]) == 1) and
		    cmp and
		    (PORT_READ(in_SPR_WRITE_NUM_REG       [j]) == _queue[index]._num_reg_rc))
		  {
		    log_printf(TRACE,Reservation_station,FUNCTION," -> SPR_WRITE     [%d] - Hit queue[%d]-SPR_RC[%d]",i,index,_queue[index]._num_reg_rc);
		    _queue[index]._data_rc_val = 1;
		    _queue[index]._data_rc     = PORT_READ(in_SPR_WRITE_DATA [j]);
		  }
	      }
	    // ***** bypass - bypass_write
	    for (uint32_t j=0; j<_param->_nb_bypass_write; j++)
	      {
		bool cmp;
		if (_param->_have_port_ooo_engine_id)
		  cmp = (PORT_READ(in_BYPASS_WRITE_OOO_ENGINE_ID [j]) == _queue[index]._ooo_engine_id);
		else
		  cmp = true;

		if (cmp)
		  {
		    if (PORT_READ(in_BYPASS_WRITE_GPR_VAL    [j]) == 1)
		      {
		    if (PORT_READ(in_BYPASS_WRITE_GPR_NUM_REG[j]) == _queue[index]._num_reg_ra)
		      {
			log_printf(TRACE,Reservation_station,FUNCTION," -> BYPASS_WRITE  [%d] - Hit queue[%d]-GPR_RA[%d]",i,index,_queue[index]._num_reg_ra);
			_queue[index]._data_ra_val = 1;
			_queue[index]._data_ra     = PORT_READ(in_BYPASS_WRITE_GPR_DATA [j]);
		      }
		    if (PORT_READ(in_BYPASS_WRITE_GPR_NUM_REG [j]) == _queue[index]._num_reg_rb)
		      {
			log_printf(TRACE,Reservation_station,FUNCTION," -> BYPASS_WRITE  [%d] - Hit queue[%d]-GPR_RB[%d]",i,index,_queue[index]._num_reg_rb);
			_queue[index]._data_rb_val = 1;
			_queue[index]._data_rb     = PORT_READ(in_BYPASS_WRITE_GPR_DATA [j]);
		      }
		      }
		    if ((PORT_READ(in_BYPASS_WRITE_SPR_VAL    [j]) == 1) and
			(PORT_READ(in_BYPASS_WRITE_SPR_NUM_REG[j]) == _queue[index]._num_reg_rc))
		      {
			log_printf(TRACE,Reservation_station,FUNCTION," -> BYPASS_WRITE  [%d] - Hit queue[%d]-SPR_RC[%d]",i,index,_queue[index]._num_reg_rc);
			_queue[index]._data_rc_val = 1;
			_queue[index]._data_rc     = PORT_READ(in_BYPASS_WRITE_SPR_DATA [j]);
		      }
		  }
	      }
	    // ***** bypass - bypass_memory
	    for (uint32_t j=0; j<_param->_nb_bypass_memory; j++)
	      {
		bool cmp;
		if (_param->_have_port_ooo_engine_id)
		  cmp = (PORT_READ(in_BYPASS_MEMORY_OOO_ENGINE_ID [j]) == _queue[index]._ooo_engine_id);
		else
		  cmp = true;

		if ((PORT_READ(in_BYPASS_MEMORY_VAL           [j]) == 1) and cmp)
		  {
		    if (PORT_READ(in_BYPASS_MEMORY_NUM_REG [j]) == _queue[index]._num_reg_ra)
		      {
			log_printf(TRACE,Reservation_station,FUNCTION," -> BYPASS_MEMORY [%d] - Hit queue[%d]-GPR_RA[%d]",i,index,_queue[index]._num_reg_ra);
			_queue[index]._data_ra_val = 1;
			_queue[index]._data_ra     = PORT_READ(in_BYPASS_MEMORY_DATA [j]);
		      }
		    if (PORT_READ(in_BYPASS_MEMORY_NUM_REG [j]) == _queue[index]._num_reg_rb)
		      {
			log_printf(TRACE,Reservation_station,FUNCTION," -> BYPASS_MEMORY [%d] - Hit queue[%d]-GPR_RB[%d]",i,index,_queue[index]._num_reg_rb);
			_queue[index]._data_rb_val = 1;
			_queue[index]._data_rb     = PORT_READ(in_BYPASS_MEMORY_DATA [j]);
		      }
		  }
	      }
	  }
	// ***** PUSH to reservation station
	if ((PORT_READ(in_INSERT_VAL) == 1) and
	    (    internal_INSERT_ACK  == 1))
	  {
	    log_printf(TRACE,Reservation_station,FUNCTION,"PUSH");

	    // Write in reservation station
	    uint32_t index;

#ifdef  SYSTEMC_VHDL_COMPATIBILITY
	    index = internal_INSERT_SLOT;
	    _queue_valid [internal_INSERT_SLOT] = true;
#else
	    index = _queue_control->push();
#endif
	    log_printf(TRACE,Reservation_station,FUNCTION," * index         : %d",index);

  	    if (_param->_have_port_context_id)
	    _queue[index]._context_id      = PORT_READ(in_INSERT_CONTEXT_ID     );
  	    if (_param->_have_port_front_end_id)
	    _queue[index]._front_end_id    = PORT_READ(in_INSERT_FRONT_END_ID   );
  	    if (_param->_have_port_ooo_engine_id)
	    _queue[index]._ooo_engine_id   = PORT_READ(in_INSERT_OOO_ENGINE_ID  );
  	    if (_param->_have_port_rob_id)
	    _queue[index]._rob_id          = PORT_READ(in_INSERT_ROB_ID         );
  	    _queue[index]._operation       = PORT_READ(in_INSERT_OPERATION      );
  	    _queue[index]._type            = PORT_READ(in_INSERT_TYPE           );
  	    _queue[index]._has_immediat    = PORT_READ(in_INSERT_HAS_IMMEDIAT   );
  	    _queue[index]._immediat        = PORT_READ(in_INSERT_IMMEDIAT       );
//	    _queue[index]._read_ra         = PORT_READ(in_INSERT_READ_RA        );
  	    _queue[index]._num_reg_ra      = PORT_READ(in_INSERT_NUM_REG_RA     );
  	    _queue[index]._data_ra_val     = PORT_READ(in_INSERT_DATA_RA_VAL    );
  	    _queue[index]._data_ra         = PORT_READ(in_INSERT_DATA_RA        );
//	    _queue[index]._read_rb         = PORT_READ(in_INSERT_READ_RB        );
  	    _queue[index]._num_reg_rb      = PORT_READ(in_INSERT_NUM_REG_RB     );
  	    _queue[index]._data_rb_val     = PORT_READ(in_INSERT_DATA_RB_VAL    );
  	    _queue[index]._data_rb         = PORT_READ(in_INSERT_DATA_RB        );
//	    _queue[index]._read_rc         = PORT_READ(in_INSERT_READ_RC        );
  	    _queue[index]._num_reg_rc      = PORT_READ(in_INSERT_NUM_REG_RC     );
  	    _queue[index]._data_rc_val     = PORT_READ(in_INSERT_DATA_RC_VAL    );
  	    _queue[index]._data_rc         = PORT_READ(in_INSERT_DATA_RC        );
  	    _queue[index]._write_rd        = PORT_READ(in_INSERT_WRITE_RD       );
  	    _queue[index]._num_reg_rd      = PORT_READ(in_INSERT_NUM_REG_RD     );
  	    _queue[index]._write_re        = PORT_READ(in_INSERT_WRITE_RE       );
  	    _queue[index]._num_reg_re      = PORT_READ(in_INSERT_NUM_REG_RE     );
// 	    dump_queue();
	  }
      }

    end_cycle ();

    log_printf(FUNC,Reservation_station,FUNCTION,"End");
  };

}; // end namespace reservation_station
}; // end namespace read_unit
}; // end namespace multi_read_unit
}; // end namespace execute_loop
}; // end namespace multi_execute_loop
}; // end namespace core

}; // end namespace behavioural
}; // end namespace morpheo              
#endif
//#endif
