#ifdef SYSTEMC
/*
 * $Id: Load_Store_pointer_unit_transition.cpp 122 2009-06-03 08:15:51Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_OOO_Engine/OOO_Engine/Rename_unit/Load_Store_pointer_unit/include/Load_Store_pointer_unit.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_ooo_engine {
namespace ooo_engine {
namespace rename_unit {
namespace load_store_pointer_unit {


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

    if (PORT_READ(in_NRESET) == 0)
      {
	for (uint32_t i=0; i<_param->_nb_load_store_queue; i++)
	  {
	    reg_STORE_QUEUE_PTR_WRITE [i] = 0;
	    reg_STORE_QUEUE_NB_USE    [i] = 0;
	    reg_LOAD_QUEUE_PTR_WRITE  [i] = 0;
	    
	    for (uint32_t j=0; j<_param->_size_store_queue[i]; j++)
	      reg_STORE_QUEUE_USE [i][j] = false;
	    for (uint32_t j=0; j<_param->_size_load_queue[i]; j++)
	      reg_LOAD_QUEUE_USE  [i][j] = false;
	  }
        for (uint32_t i=0; i<_param->_nb_front_end; ++i)
          for (uint32_t j=0; j<_param->_nb_context[i]; ++j)
            {
              reg_STORE_QUEUE_PTR_READ  [i][j] = 0;
              reg_STORE_QUEUE_EMPTY     [i][j] = true;
            }
      }
    else
      {
	// =====================================================
	// =====[ INSERT ]======================================
	// =====================================================
	
	for (uint32_t i=0; i<_param->_nb_inst_insert; i++)
	  if (PORT_READ(in_INSERT_VAL [i]) and internal_INSERT_ACK [i])
	    {
 	      log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"  * INSERT [%d]",i);
	      
	      switch (internal_INSERT_OPERATION_USE [i])
		{
		case OPERATION_USE_STORE_QUEUE :
		  {
 		    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * use STORE_QUEUE");

		    Tcontext_t front_end_id = (_param->_have_port_front_end_id)?PORT_READ(in_INSERT_FRONT_END_ID [i]):0;
		    Tcontext_t context_id   = (_param->_have_port_context_id  )?PORT_READ(in_INSERT_CONTEXT_ID   [i]):0;
		    uint32_t   lsq = internal_INSERT_LSQ [i];
		    Tlsq_ptr_t ptr = internal_INSERT_PTR [i];

 		    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * lsq : %d",lsq);
 		    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * ptr : %d",ptr);

		    reg_STORE_QUEUE_EMPTY     [front_end_id][context_id] = false; // new element
		    reg_STORE_QUEUE_PTR_WRITE [lsq]      = (ptr+1)%_param->_size_store_queue[lsq];
		    reg_STORE_QUEUE_NB_USE    [lsq]      ++;
		    reg_STORE_QUEUE_USE       [lsq][ptr] = true;

		    break;
		  }
		case OPERATION_USE_LOAD_QUEUE :
		  {
 		    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * use LOAD_QUEUE");

		    uint32_t   lsq = internal_INSERT_LSQ [i];
		    Tlsq_ptr_t ptr = internal_INSERT_PTR [i];
		    
 		    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * lsq : %d",lsq);
 		    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * ptr : %d",ptr);

		    reg_LOAD_QUEUE_PTR_WRITE [lsq]      = (ptr+1)%_param->_size_load_queue[lsq];
		    reg_LOAD_QUEUE_USE       [lsq][ptr] = true;

		    break;
		  }
		default :
		  {
		    break;
		  }
		}
	    }
		
	// =====================================================
	// =====[ RETIRE ]======================================
	// =====================================================
	for (uint32_t i=0; i<_param->_nb_inst_retire; i++)
	  if (PORT_READ(in_RETIRE_VAL [i]) and internal_RETIRE_ACK [i])
	    {
 	      log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"  * RETIRE [%d]",i);

	      switch (internal_RETIRE_OPERATION_USE [i])
		{
		case OPERATION_USE_STORE_QUEUE :
		  {
 		    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * use STORE_QUEUE");

		    uint32_t   lsq = internal_RETIRE_LSQ [i];
		    Tlsq_ptr_t ptr = internal_RETIRE_PTR [i];

 		    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * lsq : %d",lsq);
 		    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * ptr : %d",ptr);
	
                    // TODO : if ROB retire ooo context, can retire store ooo.

// 		    reg_STORE_QUEUE_PTR_WRITE [lsq]      = ((ptr==0)?_param->_size_store_queue[lsq]:ptr)-1;
		    reg_STORE_QUEUE_NB_USE    [lsq]      --;
		    reg_STORE_QUEUE_USE       [lsq][ptr] = false;

		    break;
		  }
		case OPERATION_USE_LOAD_QUEUE :
		  {
 		    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * use LOAD_QUEUE");

		    uint32_t   lsq = internal_RETIRE_LSQ [i];
		    Tlsq_ptr_t ptr = internal_RETIRE_PTR [i];
		    
 		    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * lsq : %d",lsq);
 		    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * ptr : %d",ptr);
		    
// 		    reg_LOAD_QUEUE_PTR_WRITE [lsq]      = ((ptr==0)?_param->_size_load_queue[lsq]:ptr)-1;
		    reg_LOAD_QUEUE_USE       [lsq][ptr] = false;
		    
		    break;
		  }
		default :
		  {
		    break;
		  }
		}	
	    }
        
        for (uint32_t i=0; i<_param->_nb_front_end; ++i)
          for (uint32_t j=0; j<_param->_nb_context[i]; ++j)
            {
              uint32_t lsq = _param->_link_load_store_unit_with_thread[i][j];
                    
              if (PORT_READ(in_RETIRE_EVENT_STATE [i][j]) == EVENT_STATE_NO_EVENT)
                {
                  uint32_t ptr_old =  reg_STORE_QUEUE_PTR_READ[i][j];
                  uint32_t ptr_new = (reg_STORE_QUEUE_PTR_READ[i][j]+1)%_param->_size_store_queue[lsq];

                  if ((reg_STORE_QUEUE_USE [lsq][ptr_old] == false) and
		      (reg_STORE_QUEUE_EMPTY    [i][j] == false))
                    {
                      reg_STORE_QUEUE_PTR_READ [i][j] = ptr_new;
                      if (ptr_new == reg_STORE_QUEUE_PTR_WRITE [lsq])
                      reg_STORE_QUEUE_EMPTY    [i][j] = true;
                    }
                }
              
              if (PORT_READ(in_RETIRE_EVENT_VAL[i][j]) and internal_RETIRE_EVENT_ACK [i][j])
                if (PORT_READ(in_RETIRE_EVENT_STATE [i][j]) == EVENT_STATE_EVENT)
                  {
		    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"  * EVENT [%d][%d]",i,j);

                    // reset ptr_read
                    reg_STORE_QUEUE_PTR_READ [i][j] = reg_STORE_QUEUE_PTR_WRITE [lsq];
                    reg_STORE_QUEUE_EMPTY    [i][j] = true;
                  }
            }
      }
    
    // ===================================================================
    // =====[ OTHER ]=====================================================
    // ===================================================================

#if (DEBUG >= DEBUG_TRACE) and (DEBUG_Commit_unit == true)
    {
      log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"  * Dump Load_Store_pointer Unit");
      
      for (uint32_t i=0; i<_param->_nb_load_store_queue; ++i)
        {
          log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * Load_Store_unit [%d]",i);
          log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"      * reg_LOAD_QUEUE_PTR_WRITE  : %d", reg_LOAD_QUEUE_PTR_WRITE [i]);
          log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"      * reg_LOAD_QUEUE_USE        :");
          for (uint32_t j=0; j<_param->_size_load_queue [i]; ++j)
          log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"        [%d] %d",j,reg_LOAD_QUEUE_USE [i][j]);
          log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"      * reg_STORE_QUEUE_NB_USE    : %d", reg_STORE_QUEUE_NB_USE   [i]);
          log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"      * reg_STORE_QUEUE_PTR_WRITE : %d", reg_STORE_QUEUE_PTR_WRITE[i]);
          log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"      * reg_STORE_QUEUE_USE       :");
          for (uint32_t j=0; j<_param->_size_store_queue [i]; ++j)
          log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"        [%d] %d",j,reg_STORE_QUEUE_USE [i][j]);
        }
      for (uint32_t i=0; i<_param->_nb_front_end; ++i)
        for (uint32_t j=0; j<_param->_nb_context[i]; ++j)
          {
          log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"      * reg_STORE_QUEUE_PTR_READ [%d][%d] : %d",i,j,reg_STORE_QUEUE_PTR_READ [i][j]);
          log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"      * reg_STORE_QUEUE_EMPTY    [%d][%d] : %d",i,j,reg_STORE_QUEUE_EMPTY    [i][j]);
          }
    }
#endif

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

    log_end(Load_Store_pointer_unit,FUNCTION);
  };

}; // end namespace load_store_pointer_unit
}; // end namespace rename_unit
}; // end namespace ooo_engine
}; // end namespace multi_ooo_engine
}; // end namespace core

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