#ifdef SYSTEMC
/*
 * $Id: Load_Store_pointer_unit_genMealy_insert.cpp 138 2010-05-12 17:34:01Z 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::genMealy_insert"
  void Load_Store_pointer_unit::genMealy_insert (void)
  {
    log_begin(Load_Store_pointer_unit,FUNCTION);
    log_function(Load_Store_pointer_unit,FUNCTION,_name.c_str());

    if (PORT_READ(in_NRESET))
      {
    // TODO : limité à nb_inst_memory le nombre d'accès par lsq !!!

    uint32_t   nb_use_lsq            [_param->_nb_load_store_queue];
    Tlsq_ptr_t STORE_QUEUE_PTR_WRITE [_param->_nb_load_store_queue];
    bool       STORE_QUEUE_USE       [_param->_nb_load_store_queue][_param->_max_size_store_queue];
    Tlsq_ptr_t STORE_QUEUE_NB_USE    [_param->_nb_load_store_queue];
    Tlsq_ptr_t LOAD_QUEUE_PTR_WRITE  [_param->_nb_load_store_queue];
    bool       LOAD_QUEUE_USE        [_param->_nb_load_store_queue][_param->_max_size_load_queue];
    
    for (uint32_t i=0; i<_param->_nb_load_store_queue; i++)
      {
        nb_use_lsq            [i] = _param->_nb_inst_memory[i];

        STORE_QUEUE_PTR_WRITE [i] = reg_STORE_QUEUE_PTR_WRITE [i];
        STORE_QUEUE_NB_USE    [i] = reg_STORE_QUEUE_NB_USE    [i];
        LOAD_QUEUE_PTR_WRITE  [i] = reg_LOAD_QUEUE_PTR_WRITE  [i];
	
        for (uint32_t j=0; j<_param->_size_store_queue[i]; j++)
          STORE_QUEUE_USE [i][j] = reg_STORE_QUEUE_USE [i][j];
        for (uint32_t j=0; j<_param->_size_load_queue[i]; j++)
          LOAD_QUEUE_USE  [i][j] = reg_LOAD_QUEUE_USE  [i][j];
      }

    for (uint32_t i=0; i<_param->_nb_inst_insert; i++)
      {
        log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"  * INSERT [%d]",i);

	Tcontrol_t ack  = false;
        bool       find = false;

	if (PORT_READ(in_INSERT_VAL [i]) == true)
          {
            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          = _param->_link_load_store_unit_with_thread[front_end_id][context_id];
            
            log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * front_end_id : %d",front_end_id);
            log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * context_id   : %d",context_id  );
            log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * lsq          : %d",lsq         );
            
            PORT_WRITE(out_INSERT_STORE_QUEUE_PTR_WRITE [i], STORE_QUEUE_PTR_WRITE [lsq]);
//          PORT_WRITE(out_INSERT_STORE_QUEUE_PTR_READ  [i], ((reg_STORE_QUEUE_PTR_READ  [front_end_id][context_id]+1)%_param->_size_load_queue[lsq]));
            PORT_WRITE(out_INSERT_STORE_QUEUE_PTR_READ  [i], reg_STORE_QUEUE_PTR_READ  [front_end_id][context_id]);
            PORT_WRITE(out_INSERT_STORE_QUEUE_EMPTY     [i], reg_STORE_QUEUE_EMPTY     [front_end_id][context_id]);
            if (_param->_have_port_load_queue_ptr)
            PORT_WRITE(out_INSERT_LOAD_QUEUE_PTR_WRITE  [i], LOAD_QUEUE_PTR_WRITE  [lsq]);

            if (PORT_READ(in_INSERT_TYPE [i]) == TYPE_MEMORY)
              {
                log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * type is memory");
               
                find = true;
                
                // Test if a previous instruction use the same lsq
                // Authorize once memory access by load store unit
                if (nb_use_lsq [lsq] > 0)
                  {
                    nb_use_lsq [lsq] --;
                    
                    uint32_t   ptr;
                    
                    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * sq_ptr_write : %d",STORE_QUEUE_PTR_WRITE [lsq]);
                    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * lq_ptr_write : %d",LOAD_QUEUE_PTR_WRITE [lsq]);
                    
                    // operation became of decod_stage. Also operation is != store_head_ok and store_head_ko
                    if (is_operation_memory_store(PORT_READ(in_INSERT_OPERATION [i])))
                      {
                        log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * USE_STORE_QUEUE");
                        
                        internal_INSERT_OPERATION_USE [i] = OPERATION_USE_STORE_QUEUE;
                        
                        ptr = STORE_QUEUE_PTR_WRITE [lsq];
                        ack = not STORE_QUEUE_USE [lsq][ptr] and (static_cast<uint32_t>(STORE_QUEUE_NB_USE [lsq]+1) < _param->_size_store_queue[lsq]);
                        
                        if (ack)
                          {
                            STORE_QUEUE_PTR_WRITE [lsq]      = (ptr+1)%_param->_size_store_queue[lsq];
                            STORE_QUEUE_NB_USE    [lsq]      ++;
                            STORE_QUEUE_USE       [lsq][ptr] = true;
                          }
                      }
                    else
                      {
                        log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * USE_LOAD_QUEUE");
                        
                        internal_INSERT_OPERATION_USE [i] = OPERATION_USE_LOAD_QUEUE;
                        
                        ptr = LOAD_QUEUE_PTR_WRITE [lsq];
                        ack = (not LOAD_QUEUE_USE [lsq][ptr]);
                        
                        if (ack)
                          {
                            LOAD_QUEUE_PTR_WRITE [lsq]      = (ptr+1)%_param->_size_load_queue[lsq];
                            LOAD_QUEUE_USE       [lsq][ptr] = true;
                          }
                      }
                    
                    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * ptr          : %d",ptr         );
                    log_printf(TRACE,Load_Store_pointer_unit,FUNCTION,"    * ack          : %d",ack         );
                    
                    internal_INSERT_LSQ [i] = lsq;
                    internal_INSERT_PTR [i] = ptr;
                  }
              }
          }

        if (not find)
          {
            ack = true;
            
            internal_INSERT_OPERATION_USE [i] = OPERATION_USE_NONE;
          }


	// Write output
	internal_INSERT_ACK [i] = ack;
      }
      }
    else
      {
        for (uint32_t i=0; i<_param->_nb_inst_insert; i++)
          internal_INSERT_ACK [i] = 0;
      }
    
    for (uint32_t i=0; i<_param->_nb_inst_insert; i++)
      PORT_WRITE(out_INSERT_ACK [i], internal_INSERT_ACK [i]);

    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
