#ifdef SYSTEMC
/*
 * $Id: Decod_queue_function_one_fifo_transition.cpp 111 2009-02-27 18:37:40Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_Front_end/Front_end/Decod_unit/Decod_queue/include/Decod_queue.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_front_end {
namespace front_end {
namespace decod_unit {
namespace decod_queue {


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

    if (PORT_READ(in_NRESET) == 0)
      {
	reg_QUEUE->clear();

	for (uint32_t i=0; i<_param->_nb_context; i++)
	  reg_NB_INST [i]=0;

        reg_LAST_SLOT = 0;
      }
    else
      {
	//--------------------------------------------------------------------
	//-----[ DECOD_IN ]---------------------------------------------------
	//--------------------------------------------------------------------	
        decod_queue_entry_t * entry = NULL;
        for (uint32_t i=0; i<_param->_nb_inst_decod; i++)
	  {
	    if (PORT_READ(in_DECOD_IN_VAL [i]) and internal_DECOD_IN_ACK[i])
	      {
		log_printf(TRACE,Decod_queue,FUNCTION,_("  * DECOD_IN  [%d]"),i);

		if (entry == NULL)
                 {
                   // Once creation and insert in queue
                   entry = new decod_queue_entry_t (_param->_nb_inst_decod);
                   reg_QUEUE->push_back(entry);

#ifdef STATISTICS
                   if (usage_is_set(_usage,USE_STATISTICS))
                     (*_stat_sum_transaction_decod_in) ++;
#endif
                 }

#ifdef STATISTICS
                if (usage_is_set(_usage,USE_STATISTICS))
                  (*_stat_sum_inst_enable) ++;
#endif

		Tcontext_t context = (_param->_have_port_context_id)?PORT_READ(in_DECOD_IN_CONTEXT_ID [i]):0;

		log_printf(TRACE,Decod_queue,FUNCTION,_("    * context : %d"),context);

		entry->_val           [i] = 1;
		entry->_context_id    [i] = context;
		entry->_depth         [i] = (_param->_have_port_depth)?PORT_READ(in_DECOD_IN_DEPTH [i]):0;
		entry->_type          [i] = PORT_READ(in_DECOD_IN_TYPE          [i]);
		entry->_operation     [i] = PORT_READ(in_DECOD_IN_OPERATION     [i]);
		entry->_no_execute    [i] = PORT_READ(in_DECOD_IN_NO_EXECUTE    [i]);
		entry->_is_delay_slot [i] = PORT_READ(in_DECOD_IN_IS_DELAY_SLOT [i]);
#ifdef DEBUG
		entry->_address       [i] = PORT_READ(in_DECOD_IN_ADDRESS       [i]);
#endif
		entry->_address_next  [i] = PORT_READ(in_DECOD_IN_ADDRESS_NEXT  [i]);
		entry->_has_immediat  [i] = PORT_READ(in_DECOD_IN_HAS_IMMEDIAT  [i]);
		entry->_immediat      [i] = PORT_READ(in_DECOD_IN_IMMEDIAT      [i]);
		entry->_read_ra       [i] = PORT_READ(in_DECOD_IN_READ_RA       [i]);
		entry->_num_reg_ra    [i] = PORT_READ(in_DECOD_IN_NUM_REG_RA    [i]);
		entry->_read_rb       [i] = PORT_READ(in_DECOD_IN_READ_RB       [i]);
		entry->_num_reg_rb    [i] = PORT_READ(in_DECOD_IN_NUM_REG_RB    [i]);
		entry->_read_rc       [i] = PORT_READ(in_DECOD_IN_READ_RC       [i]);
		entry->_num_reg_rc    [i] = PORT_READ(in_DECOD_IN_NUM_REG_RC    [i]);
		entry->_write_rd      [i] = PORT_READ(in_DECOD_IN_WRITE_RD      [i]);
		entry->_num_reg_rd    [i] = PORT_READ(in_DECOD_IN_NUM_REG_RD    [i]);
		entry->_write_re      [i] = PORT_READ(in_DECOD_IN_WRITE_RE      [i]);
		entry->_num_reg_re    [i] = PORT_READ(in_DECOD_IN_NUM_REG_RE    [i]);
		entry->_exception_use [i] = PORT_READ(in_DECOD_IN_EXCEPTION_USE [i]);
		entry->_exception     [i] = PORT_READ(in_DECOD_IN_EXCEPTION     [i]);

		reg_NB_INST [context] ++;

		log_printf(TRACE,Decod_queue,FUNCTION,_("    * nb_inst : %d"),reg_NB_INST [context]);
		log_printf(TRACE,Decod_queue,FUNCTION,_("    * PUSH queue"));
	      }
	  }

	//--------------------------------------------------------------------
	//-----[ DECOD_OUT ]--------------------------------------------------
	//--------------------------------------------------------------------
	if (not reg_QUEUE->empty())
	  {
 	    bool find = false;
	    
	    for (uint32_t i=0; i<_param->_nb_inst_decod; i++)
	      {
		// Test transaction : if ok then invalid slot
                // In order by rename logic
		if (internal_DECOD_OUT_VAL [i] and internal_DECOD_OUT_ACK[i])
		  {
		    log_printf(TRACE,Decod_queue,FUNCTION,_("  * DECOD_OUT [%d]"),i);
		
#ifdef DEBUG_TEST
                    if (reg_LAST_SLOT != i)
                      throw ERRORMORPHEO(FUNCTION,toString(_("reg_LAST_SLOT (%d) is different at decod_out port (%d)."),reg_LAST_SLOT,i));
#endif
                    reg_LAST_SLOT ++;

		    reg_QUEUE->front()->_val [i] = 0;

		    Tcontext_t context = reg_QUEUE->front()->_context_id [i];
		    log_printf(TRACE,Decod_queue,FUNCTION,_("    * context : %d"),context);
		    
		    reg_NB_INST [context] --;
		    log_printf(TRACE,Decod_queue,FUNCTION,_("    * nb_inst : %d"),reg_NB_INST [context]);
		  }
		// Test if slot is (again) valid, if yes, then have less one instruction in the entry
 		find |= reg_QUEUE->front()->_val [i];
	      }
	    
	    // test if can free the entry : test if have consume all entry
            if (not find) // no valid instruction in current slot
	      {
		log_printf(TRACE,Decod_queue,FUNCTION,_("    * POP  queue"));

		// can pop the slot
		delete reg_QUEUE->front();
		reg_QUEUE->pop_front();

                reg_LAST_SLOT = 0;
	      }
	  }
      }

#if defined(DEBUG) and defined(DEBUG_Decod_queue) and (DEBUG >= DEBUG_TRACE)
    log_printf(TRACE,Decod_queue,FUNCTION,"  * Dump decod_queue");
    log_printf(TRACE,Decod_queue,FUNCTION,"    * reg_LAST_SLOT : %d",reg_LAST_SLOT);
    uint32_t x=0;
    for (std::list<decod_queue_entry_t*>::iterator it=reg_QUEUE->begin();
	 it!=reg_QUEUE->end();
	 it++)
      {
	for (uint32_t i=0; i<_param->_nb_inst_decod; i++)
	  {
	    if ((*it)->_val [i])
	      log_printf(TRACE,Decod_queue,FUNCTION,"    * [%.4d][%.4d] %.1d, %.3d %.2d, %.2d %.3d %.1d %.1d, 0x%.8x (0x%.8x), %.1d 0x%.8x, %.1d %.2d, %.1d %.2d, %.1d %.2d, %.1d %.2d, %.1d %.2d, %.1d %.2d"
			 ,x
                         ,i
			 ,(*it)->_val           [i]
			 ,(*it)->_context_id    [i]
			 ,(*it)->_depth         [i]
			 ,(*it)->_type          [i]
			 ,(*it)->_operation     [i]
			 ,(*it)->_no_execute    [i]
			 ,(*it)->_is_delay_slot [i]
			 ,(*it)->_address       [i]
			 ,(*it)->_address       [i]<<2
			 ,(*it)->_has_immediat  [i]
			 ,(*it)->_immediat      [i]
			 ,(*it)->_read_ra       [i]
			 ,(*it)->_num_reg_ra    [i]
			 ,(*it)->_read_rb       [i]
			 ,(*it)->_num_reg_rb    [i]
			 ,(*it)->_read_rc       [i]
			 ,(*it)->_num_reg_rc    [i]
			 ,(*it)->_write_rd      [i]
			 ,(*it)->_num_reg_rd    [i]
			 ,(*it)->_write_re      [i]
			 ,(*it)->_num_reg_re    [i]
			 ,(*it)->_exception_use [i]
			 ,(*it)->_exception     [i]
			 );
	    else
	      log_printf(TRACE,Decod_queue,FUNCTION,"    * [%.4d][%.4d] %d"
			 ,x
                         ,i
			 ,(*it)->_val           [i]
			 );

	  }
	x++;
      }
#endif
    
#ifdef STATISTICS
    if (usage_is_set(_usage,USE_STATISTICS))
      {	
        *(_stat_use_queue) += reg_QUEUE->size();
        for (uint32_t i=0; i<_param->_nb_context; i++)
          *(_stat_nb_inst [i]) += reg_NB_INST [i];
      }
#endif

    log_end(Decod_queue,FUNCTION);
  };

}; // end namespace decod_queue
}; // end namespace decod_unit
}; // end namespace front_end
}; // end namespace multi_front_end
}; // end namespace core

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