#ifdef SYSTEMC
//#if defined(STATISTICS) or defined(VHDL_TESTBENCH)
/*
 * $Id: Read_queue_transition.cpp 117 2009-05-16 14:42:39Z rosiere $
 *
 * [ Description ]
 * 
 */

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

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


#undef  FUNCTION
#define FUNCTION "Read_queue::transition"
  void Read_queue::transition (void)
  {
    log_begin(Read_queue,FUNCTION);
    log_function(Read_queue,FUNCTION,_name.c_str());

    if (PORT_READ(in_NRESET) == 0)
      {
	// Flush queue
	// FIXME "queue reset"
	// > 1) flush one slot by cycle
	// > 2) flush all slot in one cycle

        while (_queue->empty() == false)
          {
            delete _queue->front();
            _queue->pop_front();
          }
        // _queue->clear();

	// Init, else error in registerfile
	_queue_head->_ooo_engine_id = 0;
      }
    else
      {
// 	cout << "Transition Begin  : Print queue_head" << endl;
// 	if (_queue->empty ())
// 	  cout << "queue is empty !!!" << endl;
// 	else
// 	  cout << (*_queue_head) << endl;

	log_printf(TRACE,Read_queue,FUNCTION,"  * Read_queue size (begin) : %d",(int)_queue->size());
	// Write to read_queue

	bool not_full      = not (_queue->size() == _param->_size_queue);
	bool     empty     =     _queue->empty();
	bool need_new_head = false;
	
	log_printf(TRACE,Read_queue,FUNCTION,"    * test transaction READ_QUEUE_IN  : %d,%d",PORT_READ(in_READ_QUEUE_IN_VAL), not_full);
	if ((PORT_READ(in_READ_QUEUE_IN_VAL) == 1) and not_full)
	  {
	    Tread_queue_entry_t * entry = new Tread_queue_entry_t;

	    if(_param->_have_port_context_id   )
	    entry->_context_id   = PORT_READ(in_READ_QUEUE_IN_CONTEXT_ID  );
	    if(_param->_have_port_front_end_id )
	    entry->_front_end_id = PORT_READ(in_READ_QUEUE_IN_FRONT_END_ID);
	    if(_param->_have_port_ooo_engine_id)
	    entry->_ooo_engine_id= PORT_READ(in_READ_QUEUE_IN_OOO_ENGINE_ID);
	    if(_param->_have_port_rob_ptr      )
	    entry->_rob_id       = PORT_READ(in_READ_QUEUE_IN_ROB_ID      );
	    entry->_operation    = PORT_READ(in_READ_QUEUE_IN_OPERATION   );
	    entry->_type         = PORT_READ(in_READ_QUEUE_IN_TYPE        );
	    entry->_store_queue_ptr_write = PORT_READ(in_READ_QUEUE_IN_STORE_QUEUE_PTR_WRITE);
	    if (_param->_have_port_load_queue_ptr)
	    entry->_load_queue_ptr_write  = PORT_READ(in_READ_QUEUE_IN_LOAD_QUEUE_PTR_WRITE );
	    entry->_has_immediat = PORT_READ(in_READ_QUEUE_IN_HAS_IMMEDIAT);
	    entry->_immediat     = PORT_READ(in_READ_QUEUE_IN_IMMEDIAT    );
	    entry->_read_ra      = PORT_READ(in_READ_QUEUE_IN_READ_RA     );
	    entry->_num_reg_ra   = PORT_READ(in_READ_QUEUE_IN_NUM_REG_RA  );
	    entry->_read_rb      = PORT_READ(in_READ_QUEUE_IN_READ_RB     );
	    entry->_num_reg_rb   = PORT_READ(in_READ_QUEUE_IN_NUM_REG_RB  );
	    entry->_read_rc      = PORT_READ(in_READ_QUEUE_IN_READ_RC     );
	    entry->_num_reg_rc   = PORT_READ(in_READ_QUEUE_IN_NUM_REG_RC  );
	    entry->_write_rd     = PORT_READ(in_READ_QUEUE_IN_WRITE_RD    );
	    entry->_num_reg_rd   = PORT_READ(in_READ_QUEUE_IN_NUM_REG_RD  );
	    entry->_write_re     = PORT_READ(in_READ_QUEUE_IN_WRITE_RE    );
	    entry->_num_reg_re   = PORT_READ(in_READ_QUEUE_IN_NUM_REG_RE  );

	    log_printf(TRACE,Read_queue,FUNCTION,"    * push (id : %d-%d)",entry->_context_id, entry->_rob_id);
	    _queue->push_back(entry);

	    // read next new head
	    if (empty)
	      {
		log_printf(TRACE,Read_queue,FUNCTION,"    * queue was    empty");
		need_new_head = true;
	      }
	  }

	// Read from read_queue
	log_printf(TRACE,Read_queue,FUNCTION,"  * test transaction READ_QUEUE_OUT : %d,%d",internal_READ_QUEUE_OUT_VAL, PORT_READ(in_READ_QUEUE_OUT_ACK));
	if ((    internal_READ_QUEUE_OUT_VAL  == 1) and 
	    (PORT_READ(in_READ_QUEUE_OUT_ACK) == 1))
	  {
	    // Pop the entry
	    log_printf(TRACE,Read_queue,FUNCTION,"    * pop  (id : %d-%d)",_queue->front()->_context_id, _queue->front()->_rob_id);
	    _queue->pop_front();

	    // read next new head
	    if (_queue->empty() == false)
	      {
		log_printf(TRACE,Read_queue,FUNCTION,"    * queue was not empty");
		need_new_head = true;
	      }
	  }
	else
	  {
	    // no transaction, update queue_head
	    _queue_head->_read_ra_val = internal_READ_QUEUE_OUT_READ_RA_VAL ;
	    _queue_head->_data_ra_val = internal_READ_QUEUE_OUT_DATA_RA_VAL ;
	    _queue_head->_data_ra     = internal_READ_QUEUE_OUT_DATA_RA     ;

	    _queue_head->_read_rb_val = internal_READ_QUEUE_OUT_READ_RB_VAL ;
	    _queue_head->_data_rb_val = internal_READ_QUEUE_OUT_DATA_RB_VAL ;
	    _queue_head->_data_rb     = internal_READ_QUEUE_OUT_DATA_RB     ;

	    _queue_head->_read_rc_val = internal_READ_QUEUE_OUT_READ_RC_VAL ;
	    _queue_head->_data_rc_val = internal_READ_QUEUE_OUT_DATA_RC_VAL ;
	    _queue_head->_data_rc     = internal_READ_QUEUE_OUT_DATA_RC     ;
	  }

	if (need_new_head == true)
	  {
	    log_printf(TRACE,Read_queue,FUNCTION,"  * new head");
	    (*_queue_head) = (*_queue->front());
	  }
	
// 	cout << "Transition End    : Print queue_head" << endl;
// 	if (_queue->empty ())
// 	  cout << "queue is empty !!!" << endl;
// 	else
// 	  cout << (*_queue_head) << endl;

#if (DEBUG >= DEBUG_TRACE) and (DEBUG_Read_queue == true)
	log_printf(TRACE,Read_queue,FUNCTION,"  * Dump Read_queue");
	log_printf(TRACE,Read_queue,FUNCTION,"    * size : %d / %d",(int)_queue->size(),_param->_size_queue);

        if (_queue->size()>0)
          {
            log_printf(TRACE,Read_queue,FUNCTION,"    * [%.4d] %.2d %.2d %.2d %.4d, %.2d %.3d, %.2d %.2d, %.1d %.8x, %.1d %.1d %.4d %.1d %.8x, %.1d %.1d %.4d %.1d %.8x, %.1d %.1d %.4d %.1d %.2x, %.1d %.4d, %.1d %.4d (%s)",
                       0,

                       _queue_head->_context_id           ,
                       _queue_head->_front_end_id         ,
                       _queue_head->_ooo_engine_id        ,
                       _queue_head->_rob_id               ,

                       _queue_head->_type                 ,
                       _queue_head->_operation            ,

                       _queue_head->_store_queue_ptr_write,
                       _queue_head->_load_queue_ptr_write ,

                       _queue_head->_has_immediat         ,
                       _queue_head->_immediat             ,

                       _queue_head->_read_ra              ,
                       _queue_head->_read_ra_val          ,
                       _queue_head->_num_reg_ra           ,
                       _queue_head->_data_ra_val          ,
                       _queue_head->_data_ra              ,

                       _queue_head->_read_rb              ,
                       _queue_head->_read_rb_val          ,
                       _queue_head->_num_reg_rb           ,
                       _queue_head->_data_rb_val          ,
                       _queue_head->_data_rb              ,

                       _queue_head->_read_rc              ,
                       _queue_head->_read_rc_val          ,
                       _queue_head->_num_reg_rc           ,
                       _queue_head->_data_rc_val          ,
                       _queue_head->_data_rc              ,

                       _queue_head->_write_rd             ,
                       _queue_head->_num_reg_rd           ,
                       
                       _queue_head->_write_re             ,
                       _queue_head->_num_reg_re           ,

                       toString(_queue_head->_type).c_str());


            std::list<Tread_queue_entry_t *>::iterator it=_queue->begin();
            ++it; // first is already printed
            uint32_t i=1;

            for (;it!=_queue->end(); ++it)
              {
                log_printf(TRACE,Read_queue,FUNCTION,"    * [%.4d] %.2d %.2d %.2d %.4d, %.2d %.3d, %.2d %.2d, %.1d %.8x, %.1d   %.4d           , %.1d   %.4d           , %.1d   %.4d     , %.1d %.4d, %.1d %.4d (%s)",
                           i,
                           
                           (*it)->_context_id           ,
                           (*it)->_front_end_id         ,
                           (*it)->_ooo_engine_id        ,
                           (*it)->_rob_id               ,
                           
                           (*it)->_type                 ,
                           (*it)->_operation            ,
                           
                           (*it)->_store_queue_ptr_write,
                           (*it)->_load_queue_ptr_write ,
                           
                           (*it)->_has_immediat         ,
                           (*it)->_immediat             ,
                           
                           (*it)->_read_ra              ,
//                         (*it)->_read_ra_val          ,
                           (*it)->_num_reg_ra           ,
//                         (*it)->_data_ra_val          ,
//                         (*it)->_data_ra              ,
                           
                           (*it)->_read_rb              ,
//                         (*it)->_read_rb_val          ,
                           (*it)->_num_reg_rb           ,
//                         (*it)->_data_rb_val          ,
//                         (*it)->_data_rb              ,
                           
                           (*it)->_read_rc              ,
//                         (*it)->_read_rc_val          ,
                           (*it)->_num_reg_rc           ,
//                         (*it)->_data_rc_val          ,
//                         (*it)->_data_rc              ,
                           
                           (*it)->_write_rd             ,
                           (*it)->_num_reg_rd           ,
                           
                           (*it)->_write_re             ,
                           (*it)->_num_reg_re           ,

                           toString((*it)->_type).c_str());

                ++i;
              }
          }
#endif
      }

#if defined(STATISTICS) or defined(VHDL_TESTBENCH)
        end_cycle ();
#endif

    log_end(Read_queue,FUNCTION);
  };

}; // end namespace read_queue
}; // 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
