#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 {

#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]]._packet_id << " - "<< _queue[(*_queue_control)[j]]._context_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) 

#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)
      {
	// clear all element in control.
	_queue_nb_elt = 0;

	_queue_control->clear();
	for (uint32_t i=0; i<_param->_size_queue; i++)
	  _queue_control->push_back(i);
      }
    else
      {
	// ***** PUSH to reservation station
	if ((PORT_READ(in_RESERVATION_STATION_IN_VAL) == 1) and
	    (    internal_RESERVATION_STATION_IN_ACK  == 1))
	  {
	    log_printf(TRACE,Reservation_station,FUNCTION,"PUSH");

	    // Write in reservation station
	    uint32_t index = (*_queue_control)[_queue_nb_elt];
	    _queue_nb_elt ++;

	    log_printf(TRACE,Reservation_station,FUNCTION," * index         : %d",index);

  	    _queue[index]._context_id   = PORT_READ(in_RESERVATION_STATION_IN_CONTEXT_ID  );
  	    _queue[index]._packet_id    = PORT_READ(in_RESERVATION_STATION_IN_PACKET_ID   );
  	    _queue[index]._operation    = PORT_READ(in_RESERVATION_STATION_IN_OPERATION   );
  	    _queue[index]._type         = PORT_READ(in_RESERVATION_STATION_IN_TYPE        );
  	    _queue[index]._has_immediat = PORT_READ(in_RESERVATION_STATION_IN_HAS_IMMEDIAT);
  	    _queue[index]._immediat     = PORT_READ(in_RESERVATION_STATION_IN_IMMEDIAT    );
//	    _queue[index]._read_ra      = PORT_READ(in_RESERVATION_STATION_IN_READ_RA     );
  	    _queue[index]._num_reg_ra   = PORT_READ(in_RESERVATION_STATION_IN_NUM_REG_RA  );
  	    _queue[index]._data_ra_val  = PORT_READ(in_RESERVATION_STATION_IN_DATA_RA_VAL );
  	    _queue[index]._data_ra      = PORT_READ(in_RESERVATION_STATION_IN_DATA_RA     );
//	    _queue[index]._read_rb      = PORT_READ(in_RESERVATION_STATION_IN_READ_RB     );
  	    _queue[index]._num_reg_rb   = PORT_READ(in_RESERVATION_STATION_IN_NUM_REG_RB  );
  	    _queue[index]._data_rb_val  = PORT_READ(in_RESERVATION_STATION_IN_DATA_RB_VAL );
  	    _queue[index]._data_rb      = PORT_READ(in_RESERVATION_STATION_IN_DATA_RB     );
//	    _queue[index]._read_rc      = PORT_READ(in_RESERVATION_STATION_IN_READ_RC     );
  	    _queue[index]._num_reg_rc   = PORT_READ(in_RESERVATION_STATION_IN_NUM_REG_RC  );
  	    _queue[index]._data_rc_val  = PORT_READ(in_RESERVATION_STATION_IN_DATA_RC_VAL );
  	    _queue[index]._data_rc      = PORT_READ(in_RESERVATION_STATION_IN_DATA_RC     );
  	    _queue[index]._write_rd     = PORT_READ(in_RESERVATION_STATION_IN_WRITE_RD    );
  	    _queue[index]._num_reg_rd   = PORT_READ(in_RESERVATION_STATION_IN_NUM_REG_RD  );
  	    _queue[index]._write_re     = PORT_READ(in_RESERVATION_STATION_IN_WRITE_RE    );
  	    _queue[index]._num_reg_re   = PORT_READ(in_RESERVATION_STATION_IN_NUM_REG_RE  );
// 	    dump_queue();
	  }

	// ***** 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_nb_elt))-1;i>=0; i--)
	  {
	    uint32_t index = (*_queue_control)[i];
	    
	    if ((    internal_RESERVATION_STATION_OUT_VAL [index]  == 1) and
		(PORT_READ(in_RESERVATION_STATION_OUT_ACK [index]) == 1))
	      {
		log_printf(TRACE,Reservation_station,FUNCTION,"POP  [%d]",i);

		_queue_control->erase (_queue_control->begin()+i);
		_queue_control->push_back(index);
		_queue_nb_elt --;

		log_printf(TRACE,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; i<_queue_nb_elt; i++)
	  {
	    uint32_t index = (*_queue_control)[i];

	    // ***** bypass - gpr_write
	    for (uint32_t j=0; j<_param->_nb_gpr_write; j++)
	      {
		if ((PORT_READ(in_GPR_WRITE_VAL        [j]) == 1) and
		    (PORT_READ(in_GPR_WRITE_CONTEXT_ID [j]) == _queue[index]._context_id))
		  {
		    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++)
	      {
		if ((PORT_READ(in_SPR_WRITE_VAL        [j]) == 1)                         and
		    (PORT_READ(in_SPR_WRITE_CONTEXT_ID [j]) == _queue[index]._context_id) 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++)
	      {
		if (PORT_READ(in_BYPASS_WRITE_CONTEXT_ID [j]) == _queue[index]._context_id)
		  {
		    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++)
	      {
		if ((PORT_READ(in_BYPASS_MEMORY_VAL        [j]) == 1) and
		    (PORT_READ(in_BYPASS_MEMORY_CONTEXT_ID [j]) == _queue[index]._context_id))
		  {
		    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]);
		      }
		  }
	      }
	  }
      }

#ifdef STATISTICS
    _stat->add();
#endif    

#ifdef VHDL_TESTBENCH
    vhdl_testbench_transition ();
#endif

    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
