#ifdef SYSTEMC
/*
 * $Id: Reexecute_unit_genMealy_commit.cpp 123 2009-06-08 20:43:30Z rosiere $
 *
 * [ Description ]
 * 
 */

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

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_ooo_engine {
namespace ooo_engine {
namespace reexecute_unit {

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

    if (PORT_READ(in_NRESET))
      {
    // Initialisation
    Tcontrol_t execute_loop_ack [_param->_nb_execute_loop][_param->_max_nb_inst_execute];

    for (uint32_t i=0; i<_param->_nb_execute_loop; ++i)
      for (uint32_t j=0; j<_param->_nb_inst_execute [i]; ++j)
	execute_loop_ack [i][j] = false;

    for (uint32_t i=0; i<_param->_nb_bank; i++)
      internal_QUEUE_PUSH [i] = 0;

    // execute_loop interface
    std::list<generic::priority::select_t> * select_queue_in        = _priority_queue_in ->select();
    std::list<generic::priority::select_t>::iterator it_queue_in    = select_queue_in    ->begin();

    std::list<generic::priority::select_t> * select_execute_loop    = _priority_execute_loop ->select();
    std::list<generic::priority::select_t>::iterator it_execute_loop= select_execute_loop ->begin();
  
    // For each nb_inst
    for (uint32_t i=0; i<_param->_nb_inst_commit; ++i)
      {
	Tcontrol_t commit_val = false;

	// find a executed instruction
	for (;
	     (it_execute_loop!=select_execute_loop->end()) and (commit_val == false);
	     ++it_execute_loop)
	  {
	    // take num_execute_loop and num_inst_execute
	    uint32_t x = it_execute_loop->grp;
	    uint32_t y = it_execute_loop->elt;

	    // test id instruction is valid
	    if (PORT_READ(in_EXECUTE_LOOP_VAL [x][y]))
	      {
		// Need spr_acces / reexecute ?
		Texception_t    exception  = PORT_READ(in_EXECUTE_LOOP_EXCEPTION [x][y]);
		Taddress_t      address    = PORT_READ(in_EXECUTE_LOOP_ADDRESS   [x][y]);
		Tcontrol_t      spr_access = ((exception ==  EXCEPTION_ALU_SPR_ACCESS_MUST_READ ) or
					      (exception ==  EXCEPTION_ALU_SPR_ACCESS_MUST_WRITE));
		if (spr_access)
		  {
		    // find a not full bank
		    bool find = false;
		    for (;
			 (it_queue_in!=select_queue_in->end()) and (find == false);
			 ++it_queue_in)
		      {
			uint32_t num_bank = it_queue_in->grp;
			if (_reexecute_queue [num_bank].size() < _param->_size_queue)
			  {
			    find = true;
			    
			    // this instruction don't need spr access. send at the re order buffer
			    commit_val              = 1; // in_EXECUTE_LOOP_VAL = 1
			    execute_loop_ack [x][y] = PORT_READ(in_COMMIT_ACK [i]);
			    
			    internal_QUEUE_PUSH                [num_bank] = execute_loop_ack [x][y]; // in_EXECUTE_LOOP_VAL = 1
			    internal_QUEUE_NUM_EXECUTE_LOOP    [num_bank] = x;
			    internal_QUEUE_NUM_INST_EXECUTE    [num_bank] = y;
			    internal_QUEUE_NUM_INST_COMMIT     [num_bank] = i;
			    internal_QUEUE_INFO                [num_bank].spr_wen = (exception ==  EXCEPTION_ALU_SPR_ACCESS_MUST_WRITE);
			    
			    // if reexecute, don't commit, just read instruction information (num_reg_rd)
			    PORT_WRITE(out_COMMIT_WEN          [i], not must_reexecute(address & 0xffff, internal_QUEUE_INFO[num_bank]));
			  }
		      }
		  }
		else
		  {
		    // this instruction don't need spr access. send at the re order buffer
		    commit_val              = 1; // in_EXECUTE_LOOP_VAL = 1
		    execute_loop_ack [x][y] = PORT_READ(in_COMMIT_ACK [i]);

		    PORT_WRITE(out_COMMIT_WEN          [i], 1);
		  }
		
		if (commit_val)
		  {
// 		    if (_param->_have_port_context_id)
// 		    PORT_WRITE(out_COMMIT_CONTEXT_ID   [i], PORT_READ(in_EXECUTE_LOOP_CONTEXT_ID   [x][y]));
// 		    if (_param->_have_port_front_end_id)
// 		    PORT_WRITE(out_COMMIT_FRONT_END_ID [i], PORT_READ(in_EXECUTE_LOOP_FRONT_END_ID [x][y]));
		    if (_param->_have_port_rob_ptr  )
		    PORT_WRITE(out_COMMIT_PACKET_ID    [i], PORT_READ(in_EXECUTE_LOOP_PACKET_ID    [x][y]));
		  //PORT_WRITE(out_COMMIT_OPERATION    [i], PORT_READ(in_EXECUTE_LOOP_OPERATION    [x][y]));
		  //PORT_WRITE(out_COMMIT_TYPE         [i], PORT_READ(in_EXECUTE_LOOP_TYPE         [x][y]));
		    PORT_WRITE(out_COMMIT_FLAGS        [i], PORT_READ(in_EXECUTE_LOOP_FLAGS        [x][y]));
		    PORT_WRITE(out_COMMIT_EXCEPTION    [i], exception);
		    PORT_WRITE(out_COMMIT_NO_SEQUENCE  [i], PORT_READ(in_EXECUTE_LOOP_NO_SEQUENCE  [x][y]));
		    PORT_WRITE(out_COMMIT_ADDRESS      [i], address);
		  }
	      }
	  }
	
#ifdef STATISTICS
	internal_COMMIT_VAL [i] = commit_val;
#endif
	PORT_WRITE(out_COMMIT_VAL [i], commit_val);
      }

    for (uint32_t i=0; i<_param->_nb_execute_loop; ++i)
      for (uint32_t j=0; j<_param->_nb_inst_execute [i]; ++j)
	PORT_WRITE(out_EXECUTE_LOOP_ACK [i][j], execute_loop_ack [i][j]);
      }
    else
      {
#ifdef STATISTICS
        for (uint32_t i=0; i<_param->_nb_inst_commit; ++i)
          internal_COMMIT_VAL [i] = 0;
#endif
        for (uint32_t i=0; i<_param->_nb_execute_loop; ++i)
          for (uint32_t j=0; j<_param->_nb_inst_execute [i]; ++j)
            PORT_WRITE(out_EXECUTE_LOOP_ACK [i][j], 0);
      }

    log_end(Reexecute_unit,FUNCTION);
  };
  
}; // end namespace reexecute_unit
}; // end namespace ooo_engine
}; // end namespace multi_ooo_engine
}; // end namespace core

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


