#ifdef SYSTEMC
/*
 * $Id: Decod_queue_function_multi_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_multi_fifo_transition"
  void Decod_queue::function_multi_fifo_transition (void)
  {
    log_begin(Decod_queue,FUNCTION);
    log_function(Decod_queue,FUNCTION,_name.c_str());

    if (PORT_READ(in_NRESET) == 0)
      {
        for (uint32_t i=0; i<_param->_nb_bank; ++i)
          reg_QUEUE[i].clear();

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

        reg_NUM_BANK_HEAD = 0;
        reg_NUM_BANK_TAIL = 0;
      }
    else
      {
	//--------------------------------------------------------------------
	//-----[ DECOD_IN ]---------------------------------------------------
	//--------------------------------------------------------------------	

        {
#ifdef STATISTICS
          bool find = false;
#endif
          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);
                
                // Create entry
                decod_queue_entry_t * entry = new decod_queue_entry_t (1);
                reg_QUEUE[reg_NUM_BANK_TAIL].push_back(entry);
                
#ifdef STATISTICS
                find = true;
                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           [0] = 1;
		entry->_context_id    [0] = context;
		entry->_depth         [0] = (_param->_have_port_depth)?PORT_READ(in_DECOD_IN_DEPTH [i]):0;
		entry->_type          [0] = PORT_READ(in_DECOD_IN_TYPE          [i]);
		entry->_operation     [0] = PORT_READ(in_DECOD_IN_OPERATION     [i]);
		entry->_no_execute    [0] = PORT_READ(in_DECOD_IN_NO_EXECUTE    [i]);
		entry->_is_delay_slot [0] = PORT_READ(in_DECOD_IN_IS_DELAY_SLOT [i]);
#ifdef DEBUG
		entry->_address       [0] = PORT_READ(in_DECOD_IN_ADDRESS       [i]);
#endif
		entry->_address_next  [0] = PORT_READ(in_DECOD_IN_ADDRESS_NEXT  [i]);
		entry->_has_immediat  [0] = PORT_READ(in_DECOD_IN_HAS_IMMEDIAT  [i]);
		entry->_immediat      [0] = PORT_READ(in_DECOD_IN_IMMEDIAT      [i]);
		entry->_read_ra       [0] = PORT_READ(in_DECOD_IN_READ_RA       [i]);
		entry->_num_reg_ra    [0] = PORT_READ(in_DECOD_IN_NUM_REG_RA    [i]);
		entry->_read_rb       [0] = PORT_READ(in_DECOD_IN_READ_RB       [i]);
		entry->_num_reg_rb    [0] = PORT_READ(in_DECOD_IN_NUM_REG_RB    [i]);
		entry->_read_rc       [0] = PORT_READ(in_DECOD_IN_READ_RC       [i]);
		entry->_num_reg_rc    [0] = PORT_READ(in_DECOD_IN_NUM_REG_RC    [i]);
		entry->_write_rd      [0] = PORT_READ(in_DECOD_IN_WRITE_RD      [i]);
		entry->_num_reg_rd    [0] = PORT_READ(in_DECOD_IN_NUM_REG_RD    [i]);
		entry->_write_re      [0] = PORT_READ(in_DECOD_IN_WRITE_RE      [i]);
		entry->_num_reg_re    [0] = PORT_READ(in_DECOD_IN_NUM_REG_RE    [i]);
		entry->_exception_use [0] = PORT_READ(in_DECOD_IN_EXCEPTION_USE [i]);
		entry->_exception     [0] = PORT_READ(in_DECOD_IN_EXCEPTION     [i]);

                // Update pointer
                reg_NUM_BANK_TAIL = (reg_NUM_BANK_TAIL+1)%_param->_nb_bank;
		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"));
	      }

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

	//--------------------------------------------------------------------
	//-----[ DECOD_OUT ]--------------------------------------------------
	//--------------------------------------------------------------------
        {
          for (uint32_t i=0; i<_param->_nb_inst_decod; i++)
            if (internal_DECOD_OUT_VAL [i] and internal_DECOD_OUT_ACK[i])
              {
                log_printf(TRACE,Decod_queue,FUNCTION,_("  * DECOD_OUT [%d]"),i);
		
                uint32_t num_bank = reg_NUM_BANK_HEAD;

                Tcontext_t context = reg_QUEUE[num_bank].front()->_context_id [0];

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

		// Pop the slot
		delete reg_QUEUE[num_bank].front();
		reg_QUEUE[num_bank].pop_front();

                // Update pointer
                reg_NUM_BANK_HEAD = (reg_NUM_BANK_HEAD+1)%_param->_nb_bank;
		reg_NB_INST [context] --;
	      }
        }

	//--------------------------------------------------------------------
	//-----[ OTHERS ]-----------------------------------------------------
	//--------------------------------------------------------------------

#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_NUM_BANK_HEAD : %d",reg_NUM_BANK_HEAD);
    log_printf(TRACE,Decod_queue,FUNCTION,"    * reg_NUM_BANK_TAIL : %d",reg_NUM_BANK_TAIL);
    for (uint32_t i=0; i<_param->_nb_context; i++)
      log_printf(TRACE,Decod_queue,FUNCTION,"    * reg_NB_INST [%d] : %d",i,reg_NB_INST [i]);

    for (uint32_t i=0; i<_param->_nb_bank; ++i)
      {
        uint32_t x=0;
        uint32_t num_bank = (reg_NUM_BANK_HEAD+i)%_param->_nb_bank;
        for (std::list<decod_queue_entry_t*>::iterator it=reg_QUEUE[num_bank].begin();
             it!=reg_QUEUE[num_bank].end();
             it++)
          {
            log_printf(TRACE,Decod_queue,FUNCTION,"    * [%.4d][%.4d] %.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"
                       ,i
                       ,x
                       ,(*it)->_context_id    [0]
                       ,(*it)->_depth         [0]
                       ,(*it)->_type          [0]
                       ,(*it)->_operation     [0]
                       ,(*it)->_no_execute    [0]
                       ,(*it)->_is_delay_slot [0]
                       ,(*it)->_address       [0]
                       ,(*it)->_address       [0]<<2
                       ,(*it)->_has_immediat  [0]
                       ,(*it)->_immediat      [0]
                       ,(*it)->_read_ra       [0]
                       ,(*it)->_num_reg_ra    [0]
                       ,(*it)->_read_rb       [0]
                       ,(*it)->_num_reg_rb    [0]
                       ,(*it)->_read_rc       [0]
                       ,(*it)->_num_reg_rc    [0]
                       ,(*it)->_write_rd      [0]
                       ,(*it)->_num_reg_rd    [0]
                       ,(*it)->_write_re      [0]
                       ,(*it)->_num_reg_re    [0]
                       ,(*it)->_exception_use [0]
                       ,(*it)->_exception     [0]
                       );
            x++;
	  }
      }
#endif
    
#ifdef STATISTICS
    if (usage_is_set(_usage,USE_STATISTICS))
      {	
        for (uint32_t i=0; i<_param->_nb_bank; ++i)
          *(_stat_use_queue) += reg_QUEUE[i].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
