#ifdef SYSTEMC
/*
 * $Id$
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_Front_end/Front_end/Ifetch_unit/Ifetch_queue/include/Ifetch_queue.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_front_end {
namespace front_end {
namespace ifetch_unit {
namespace ifetch_queue {


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

    if (PORT_READ(in_NRESET) == 0)
      {
	reg_PTR_READ  = 0;
	reg_PTR_WRITE = 0;

	for (uint32_t i=0; i<_param->_size_queue; i++)
	  _queue [i]->_state = IFETCH_QUEUE_STATE_EMPTY;
      }
    else
      {
	// ==========================================================
	// =====[ ADDRESS ]==========================================
	// ==========================================================
	if (PORT_READ(in_ADDRESS_VAL) and internal_ADDRESS_ACK)
	  {
	    // New slot in ifetch_queue is allocated
	    
	    _queue[reg_PTR_WRITE]->_state                       = IFETCH_QUEUE_STATE_WAIT_RSP;
	      
#ifdef STATISTICS
	    (*_sum_transaction_address) ++;
#endif

	    for (uint32_t i=0; i<_param->_nb_instruction; i++)
	      {
		Tcontrol_t enable = PORT_READ(in_ADDRESS_INSTRUCTION_ENABLE [i]);
#ifdef STATISTICS
		(*_sum_inst_enable) += enable;
#endif
		_queue[reg_PTR_WRITE]->_instruction_enable [i]      = enable;
	      }
	    _queue[reg_PTR_WRITE]->_address                     = PORT_READ(in_ADDRESS_INSTRUCTION_ADDRESS        );
	    _queue[reg_PTR_WRITE]->_inst_ifetch_ptr             = (_param->_have_port_instruction_ptr)?PORT_READ(in_ADDRESS_INST_IFETCH_PTR            ):0;
	    _queue[reg_PTR_WRITE]->_branch_state                = PORT_READ(in_ADDRESS_BRANCH_STATE               );
	    _queue[reg_PTR_WRITE]->_branch_update_prediction_id = (_param->_have_port_branch_update_prediction_id)?PORT_READ(in_ADDRESS_BRANCH_UPDATE_PREDICTION_ID):0;
	    
	    reg_PTR_WRITE = (reg_PTR_WRITE+1)%_param->_size_queue;
	  }

	// ==========================================================
	// =====[ DECOD ]============================================
	// ==========================================================
	bool have_instruction_decod  = false;
	bool have_instruction_enable = false;
	for (uint32_t i=0; i<_param->_nb_instruction; i++)
	  {
	    if (internal_DECOD_VAL [i] and PORT_READ(in_DECOD_ACK[i]))
	      {
		have_instruction_decod = true;
		_queue[reg_PTR_READ]->_instruction_enable [i] = false;
	      }
	    have_instruction_enable |= _queue[reg_PTR_READ]->_instruction_enable [i];
	  }

	// Test if all is decoded
	if (have_instruction_decod and not have_instruction_enable)
	  {
	    // all is decod
	    _queue[reg_PTR_READ]->_state = IFETCH_QUEUE_STATE_EMPTY;
	    reg_PTR_READ = (reg_PTR_READ+1)%_param->_size_queue;
	  }
	  
	// ==========================================================
	// =====[ ICACHE_RSP ]=======================================
	// ==========================================================
	if (PORT_READ(in_ICACHE_RSP_VAL) and internal_ICACHE_RSP_ACK)
	  {
	    Tpacket_t ptr = (_param->_have_port_queue_ptr)?PORT_READ(in_ICACHE_RSP_PACKET_ID):0;
	    
	    for (uint32_t i=0; i<_param->_nb_instruction; i++)
	      _queue[ptr]->_instruction [i]      = PORT_READ(in_ICACHE_RSP_INSTRUCTION [i]);
	    
	    switch (PORT_READ(in_ICACHE_RSP_ERROR))
	      {
	      case ICACHE_ERROR_NONE      : _queue[ptr]->_exception = EXCEPTION_IFETCH_NONE     ; break;
	      case ICACHE_ERROR_BUS_ERROR : _queue[ptr]->_exception = EXCEPTION_IFETCH_BUS_ERROR; break;
	      default : ERRORMORPHEO(FUNCTION,"icache_rsp_error : unknow value.");
	      }

	    switch (_queue[ptr]->_state)
	      {
	      case IFETCH_QUEUE_STATE_WAIT_RSP       : _queue[ptr]->_state = IFETCH_QUEUE_STATE_HAVE_RSP; break;
	      case IFETCH_QUEUE_STATE_ERROR_WAIT_RSP : _queue[ptr]->_state = IFETCH_QUEUE_STATE_EMPTY   ; break;
	      default : ERRORMORPHEO(FUNCTION,"icache_rsp : invalid ifetch_queue state.");
	      }
	  }

	// ==========================================================
	// =====[ EVENT_RESET ]======================================
	// ==========================================================
	if (PORT_READ(in_EVENT_RESET_VAL) and internal_EVENT_RESET_ACK)
	  {
	    // Scan all entry of queue and test the status
	    for (uint32_t i=0; i<_param->_size_queue; i++)
	      switch (_queue[i]->_state)
	      {
	      case IFETCH_QUEUE_STATE_ERROR_WAIT_RSP :                                                        break;
	      case IFETCH_QUEUE_STATE_WAIT_RSP       : _queue[i]->_state = IFETCH_QUEUE_STATE_ERROR_WAIT_RSP; break;
	      default                                : _queue[i]->_state = IFETCH_QUEUE_STATE_EMPTY         ; break;
	      }

	    // all entry is empty (or wait respons to flush)
	    // reset ptr
	    //   1) reg_PTR_READ = reg_PTR_WRITE =  = 0
	    //   2) reg_PTR_READ = reg_PTR_WRITE
	    // In method 1), the probalitie than the entry pointed by reg_PTR_WRITE is a slot with state "error_wait_rsp" is more importate that the method 2)
	    reg_PTR_READ = reg_PTR_WRITE;
	  }

// 	log_printf(TRACE,Ifetch_queue,FUNCTION,"reg_PTR_WRITE : %d",reg_PTR_WRITE);
// 	log_printf(TRACE,Ifetch_queue,FUNCTION,"reg_PTR_READ  : %d",reg_PTR_READ );
// 	for (uint32_t i=0; i<_param->_size_queue; i++)
// 	  {
// 	    log_printf(TRACE,Ifetch_queue,FUNCTION,"[%d] %d %.8x %d - %d %d %d", i, _queue [i]->_state, _queue [i]->_address,_queue [i]->_inst_ifetch_ptr,_queue [i]->_branch_state,_queue [i]->_branch_update_prediction_id,_queue [i]->_exception);

// 	    for (uint32_t j=0; j<_param->_nb_instruction; j++)
// 	      log_printf(TRACE,Ifetch_queue,FUNCTION,"  * %d %.8x", _queue [i]->_instruction_enable[i], _queue [i]->_instruction[i]);
// 	  }

#ifdef STATISTICS
	for (uint32_t i=0; i<_param->_size_queue; i++)
	  switch (_queue[i]->_state)
	    {
	    case IFETCH_QUEUE_STATE_EMPTY          : break;
	    case IFETCH_QUEUE_STATE_WAIT_RSP       : (*_sum_use_queue_wait_rsp      ) ++; break;
	    case IFETCH_QUEUE_STATE_HAVE_RSP       : (*_sum_use_queue_have_rsp      ) ++; break;
	    case IFETCH_QUEUE_STATE_ERROR_WAIT_RSP : (*_sum_use_queue_error_wait_rsp) ++; break;
	    default : break;
	    }
#endif
      }

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

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

}; // end namespace ifetch_queue
}; // end namespace ifetch_unit
}; // end namespace front_end
}; // end namespace multi_front_end
}; // end namespace core

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