#ifdef SYSTEMC
/*
 * $Id: Commit_unit_genMoore.cpp 118 2009-05-20 22:01:32Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_OOO_Engine/OOO_Engine/Commit_unit/include/Commit_unit.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_ooo_engine {
namespace ooo_engine {
namespace commit_unit {


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

    // ===================================================================
    // =====[ REEXECUTE ]=================================================
    // ===================================================================
    {
      log_printf(TRACE,Commit_unit,FUNCTION,"  * REEXECUTE [0]");

      // Store instruction comming Out Of Order in Load Store Unit. 
      // Must be executed in no speculative mode. Also, send a signal when an Store is in head of ROB

      Tcontrol_t val      = false;
      uint32_t   num_bank = reg_NUM_BANK_HEAD;

      if (not _rob[num_bank].empty())
	{
          log_printf(TRACE,Commit_unit,FUNCTION,"    * ROB is not empty");
          log_printf(TRACE,Commit_unit,FUNCTION,"    * num_bank      : %d",num_bank);

          entry_t    * entry = _rob [num_bank].front();
	  rob_state_t  state = entry->state;

          // Test state
	  val   = ((state == ROB_STORE_HEAD_OK) or
		   (state == ROB_STORE_HEAD_KO));

          log_printf(TRACE,Commit_unit,FUNCTION,"    * val           : %d",val);
	  if (val)
	    {
              Tpacket_t packet_id = ((entry->ptr << _param->_shift_num_slot) | num_bank);

              log_printf(TRACE,Commit_unit,FUNCTION,"    * packet_id     : %d",packet_id);
	  
              // Reexecute store
	      if (_param->_have_port_context_id)
  	      PORT_WRITE(out_REEXECUTE_CONTEXT_ID            [0], entry->context_id           );
	      if (_param->_have_port_front_end_id)
  	      PORT_WRITE(out_REEXECUTE_FRONT_END_ID          [0], entry->front_end_id         );
	      if (_param->_have_port_rob_ptr  )
  	      PORT_WRITE(out_REEXECUTE_PACKET_ID             [0], packet_id                   );
	      PORT_WRITE(out_REEXECUTE_TYPE                  [0], entry->type                 );
	      PORT_WRITE(out_REEXECUTE_STORE_QUEUE_PTR_WRITE [0], entry->store_queue_ptr_write);
	      PORT_WRITE(out_REEXECUTE_OPERATION             [0], (state == ROB_STORE_HEAD_OK)?OPERATION_MEMORY_STORE_HEAD_OK:OPERATION_MEMORY_STORE_HEAD_KO);
	    }
	}
 
      internal_REEXECUTE_VAL      [0] = val;
      internal_REEXECUTE_NUM_BANK [0] = num_bank;
      
      PORT_WRITE(out_REEXECUTE_VAL[0], internal_REEXECUTE_VAL [0]);
    }

    // ===================================================================
    // =====[ BRANCH_COMPLETE ]===========================================
    // ===================================================================
    {
      // Branchement must be send at the prediction unit
      uint32_t nb_scan_bank = 0;

      // for each port, find a valid branchement.
      for (uint32_t i=0; i<_param->_nb_inst_branch_complete; i++)
	{
	  Tcontrol_t  val  = false;
	  
	  for (uint32_t j=nb_scan_bank; j<_param->_nb_bank; j++)
	    {
	      nb_scan_bank ++;

              // translate bank number
	      uint32_t num_bank = (reg_NUM_BANK_HEAD+j)%_param->_nb_bank;
	      
	      if (not _rob [num_bank].empty())
		{
		  entry_t    * entry    = _rob [num_bank].front();
		  rob_state_t  state    = entry->state;
		  
		  if (state == ROB_BRANCH_COMPLETE)
		    {
		      val = true;
		      
		      internal_BRANCH_COMPLETE_NUM_BANK           [i] = num_bank;
		      
		      if (_param->_have_port_context_id)
		      PORT_WRITE(out_BRANCH_COMPLETE_CONTEXT_ID   [i], entry->context_id      );
		      if (_param->_have_port_front_end_id)
		      PORT_WRITE(out_BRANCH_COMPLETE_FRONT_END_ID [i], entry->front_end_id    );
		      if (_param->_have_port_depth)
		      PORT_WRITE(out_BRANCH_COMPLETE_DEPTH        [i], entry->depth           );
		      PORT_WRITE(out_BRANCH_COMPLETE_ADDRESS      [i], entry->address_next    );
// 		      PORT_WRITE(out_BRANCH_COMPLETE_FLAG         [i],(entry->flags&FLAG_F)!=0);
		      PORT_WRITE(out_BRANCH_COMPLETE_NO_SEQUENCE  [i], entry->no_sequence     );
		      
		      break;
		    }
		}
	    }

	  internal_BRANCH_COMPLETE_VAL [i] = val;
	  PORT_WRITE(out_BRANCH_COMPLETE_VAL [i], internal_BRANCH_COMPLETE_VAL [i]);
	}
    }

    // ===================================================================
    // =====[ UPDATE ]====================================================
    // ===================================================================
    {
      internal_UPDATE_VAL = 0;
      internal_UPDATE_NUM_BANK = reg_NUM_BANK_HEAD;

      if (not _rob[internal_UPDATE_NUM_BANK].empty())
	{
          log_printf(TRACE,Commit_unit,FUNCTION,"  * UPDATE");
          log_printf(TRACE,Commit_unit,FUNCTION,"    * num_bank : %d",internal_UPDATE_NUM_BANK);

	  entry_t * entry = _rob [internal_UPDATE_NUM_BANK].front();

          switch (entry->state)
            {
            case ROB_END_EXCEPTION_UPDATE :
              {
                internal_UPDATE_VAL = 1;
                throw ERRORMORPHEO(FUNCTION,_("Moore : exception is not yet supported (Coming Soon).\n"));
                break;
              }
            case ROB_END_LOAD_MISS_UPDATE :
              {
                log_printf(TRACE,Commit_unit,FUNCTION,"    * ROB_END_LOAD_MISS_UPDATE");

                internal_UPDATE_VAL = 1;

                Tcontext_t front_end_id = entry->front_end_id;
                Tcontext_t context_id   = entry->context_id  ;

                log_printf(TRACE,Commit_unit,FUNCTION,"      * front_end_id : %d",front_end_id);
                log_printf(TRACE,Commit_unit,FUNCTION,"      * context_id   : %d",context_id  );

                if (_param->_have_port_front_end_id)
                PORT_WRITE(out_UPDATE_FRONT_END_ID    ,front_end_id);
                if (_param->_have_port_context_id)
                PORT_WRITE(out_UPDATE_CONTEXT_ID      ,context_id  );
                if (_param->_have_port_depth)
                PORT_WRITE(out_UPDATE_DEPTH           ,entry->depth);
                PORT_WRITE(out_UPDATE_TYPE            ,EVENT_TYPE_LOAD_MISS_SPECULATION);
//                 PORT_WRITE(out_UPDATE_IS_DELAY_SLOT   ,reg_PC_CURRENT_IS_DS      [front_end_id][context_id]);
//                 PORT_WRITE(out_UPDATE_ADDRESS         ,reg_PC_CURRENT            [front_end_id][context_id]);
//                 PORT_WRITE(out_UPDATE_ADDRESS_EPCR_VAL,reg_PC_CURRENT_IS_DS_TAKE [front_end_id][context_id]);
//                 PORT_WRITE(out_UPDATE_ADDRESS_EPCR    ,reg_PC_NEXT               [front_end_id][context_id]);
//                 PORT_WRITE(out_UPDATE_ADDRESS_EEAR_VAL,0);
// //              PORT_WRITE(out_UPDATE_ADDRESS_EEAR    ,);

                PORT_WRITE(out_UPDATE_IS_DELAY_SLOT   ,0);
                PORT_WRITE(out_UPDATE_ADDRESS         ,reg_PC_NEXT [front_end_id][context_id]);
                PORT_WRITE(out_UPDATE_ADDRESS_EPCR_VAL,0);
//              PORT_WRITE(out_UPDATE_ADDRESS_EPCR    ,);
                PORT_WRITE(out_UPDATE_ADDRESS_EEAR_VAL,0);
//              PORT_WRITE(out_UPDATE_ADDRESS_EEAR    ,);

                break;
              }
            default :
              {
//                 internal_UPDATE_VAL = 0; 
              }
            }
	}
      
      PORT_WRITE(out_UPDATE_VAL, internal_UPDATE_VAL);

      log_printf(TRACE,Commit_unit,FUNCTION,"  * UPDATE (end)");
    }
 
    // ===================================================================
    // =====[ NB_INST ]===================================================
    // ===================================================================
    for (uint32_t i=0; i<_param->_nb_front_end; i++)
      for (uint32_t j=0; j<_param->_nb_context [i]; j++)
	{
	  PORT_WRITE(out_NB_INST_COMMIT_ALL [i][j], reg_NB_INST_COMMIT_ALL [i][j]);
	  PORT_WRITE(out_NB_INST_COMMIT_MEM [i][j], reg_NB_INST_COMMIT_MEM [i][j]);
	}

    // ===================================================================
    // =====[ RETIRE_EVENT ]==============================================
    // ===================================================================
    for (uint32_t i=0; i<_param->_nb_front_end; i++)
      for (uint32_t j=0; j<_param->_nb_context [i]; j++)
        PORT_WRITE(out_RETIRE_EVENT_STATE [i][j], reg_EVENT_STATE[i][j]);

    log_end(Commit_unit,FUNCTION);
  };

}; // end namespace commit_unit
}; // end namespace ooo_engine
}; // end namespace multi_ooo_engine
}; // end namespace core
}; // end namespace behavioural
}; // end namespace morpheo              
#endif
