#ifdef SYSTEMC
/*
 * $Id: Commit_unit_genMealy_retire.cpp 100 2009-01-08 13:06:27Z 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::genMealy_retire"
  void Commit_unit::genMealy_retire (void)
  {
    log_begin(Commit_unit,FUNCTION);
    log_function(Commit_unit,FUNCTION,_name.c_str());

    Tcontrol_t retire_val          [_param->_nb_rename_unit][_param->_max_nb_inst_retire];
    uint32_t   num_inst_retire     [_param->_nb_rename_unit];
    bool       can_retire          [_param->_nb_rename_unit];

    Tcontrol_t spr_write_val       [_param->_nb_front_end][_param->_max_nb_context];
    Tcontrol_t spr_write_sr_f_val  [_param->_nb_front_end][_param->_max_nb_context];
    Tcontrol_t spr_write_sr_f      [_param->_nb_front_end][_param->_max_nb_context];
    Tcontrol_t spr_write_sr_cy_val [_param->_nb_front_end][_param->_max_nb_context];
    Tcontrol_t spr_write_sr_cy     [_param->_nb_front_end][_param->_max_nb_context];
    Tcontrol_t spr_write_sr_ov_val [_param->_nb_front_end][_param->_max_nb_context];
    Tcontrol_t spr_write_sr_ov     [_param->_nb_front_end][_param->_max_nb_context];


    // Initialisation
    for (uint32_t i=0; i<_param->_nb_bank; i++)
      internal_BANK_RETIRE_VAL  [i] = false;

    for (uint32_t i=0; i<_param->_nb_rename_unit; i++)
      {
	num_inst_retire [i] = 0;
	can_retire      [i] = true ;
	for (uint32_t j=0; j<_param->_nb_inst_retire[i]; j++)
	  retire_val [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)
        {
          spr_write_val [i][j] = 0;
          spr_write_sr_f_val  [i][j] = 0;
          spr_write_sr_cy_val [i][j] = 0;
          spr_write_sr_ov_val [i][j] = 0;

        }
    // Scan Top of each bank
    for (uint32_t i=0; i<_param->_nb_bank; i++)
      {
	uint32_t num_bank = (reg_NUM_BANK_HEAD+i)%_param->_nb_bank;

	if (not _rob[num_bank].empty())
	  {
	    // Scan all instruction in windows and test if instruction is speculative
	    entry_t  * entry = _rob [num_bank].front();
	    uint32_t   x     = entry->rename_unit_id;
	    uint32_t   y     = num_inst_retire [x];
	
            // test if :
            //  * can retire (all previous instruction is retired)
            //  * all structure is ok (not busy)
	    if (can_retire [x] and // in-order
		(y < _param->_nb_inst_retire [x]) and
		PORT_READ(in_RETIRE_ACK [x][y])) // not busy
	      {
		rob_state_t state = entry->state;
		
		if ((state == ROB_END_OK         ) or 
		    (state == ROB_END_KO         ) or 
		    (state == ROB_END_BRANCH_MISS) or 
		    (state == ROB_END_MISS       )//  or 
// 		    (state == ROB_END_EXCEPTION)
		    )
		  {
		    Tcontext_t         front_end_id   = entry->front_end_id;
		    Tcontext_t         context_id     = entry->context_id;  
		    Tcontrol_t         write_re       = entry->write_re;
		    Tspecial_address_t num_reg_re_log = entry->num_reg_re_log;

		    // if state is ok, when write flags in the SR regsiters
		    bool spr_write_ack = true;

                    // Write in SR the good flag
		    if ((state == ROB_END_OK  ) and write_re)
                      // ROB_END_BRANCH_MISS is a valid branch instruction but don't modify RE
		      {
			spr_write_ack = PORT_READ(in_SPR_WRITE_ACK [front_end_id][context_id]);

			// retire_ack is set !!!
			spr_write_val       [front_end_id][context_id] = 1;

			Tspecial_data_t flags = entry->flags;

			switch (num_reg_re_log)
			  {
			  case SPR_LOGIC_SR_F     : 
			    {
			      spr_write_sr_f_val  [front_end_id][context_id] = 1;
			      spr_write_sr_f      [front_end_id][context_id] = (flags & FLAG_F )!=0;

			      break;
			    }
			  case SPR_LOGIC_SR_CY_OV :
			    {
			      spr_write_sr_cy_val [front_end_id][context_id] = 1;
			      spr_write_sr_ov_val [front_end_id][context_id] = 1;	
			      spr_write_sr_cy     [front_end_id][context_id] = (flags & FLAG_CY)!=0;
			      spr_write_sr_ov     [front_end_id][context_id] = (flags & FLAG_OV)!=0;
			
			      break;
			    }
			  default : 
			    {
#ifdef DEBUG_TEST
			      throw ERRORMORPHEO(FUNCTION,_("Invalid num_reg_re_log.\n"));
#endif
			    }
			  }
		      }

		    // find an instruction can be retire, and in order

		    if (spr_write_ack)
		      {
			retire_val [x][y] = 1;
			num_inst_retire [x] ++;
			internal_BANK_RETIRE_VAL [num_bank] = true;
		      }

		    internal_BANK_RETIRE_NUM_RENAME_UNIT [num_bank] = x;
		    internal_BANK_RETIRE_NUM_INST        [num_bank] = y;

		    if (_param->_have_port_front_end_id)
		    PORT_WRITE(out_RETIRE_FRONT_END_ID          [x][y], front_end_id                );
		    if (_param->_have_port_context_id)
		    PORT_WRITE(out_RETIRE_CONTEXT_ID            [x][y], context_id                  );
// 		    PORT_WRITE(out_RETIRE_RENAME_UNIT_ID        [x][y], entry->rename_unit_id       );
		    PORT_WRITE(out_RETIRE_EVENT_STATE           [x][y], reg_EVENT_STATE[front_end_id][context_id]);
		    PORT_WRITE(out_RETIRE_USE_STORE_QUEUE       [x][y], entry->use_store_queue      );
		    PORT_WRITE(out_RETIRE_USE_LOAD_QUEUE        [x][y], entry->use_load_queue       );
		    PORT_WRITE(out_RETIRE_STORE_QUEUE_PTR_WRITE [x][y], entry->store_queue_ptr_write);
		    if (_param->_have_port_load_queue_ptr)
		    PORT_WRITE(out_RETIRE_LOAD_QUEUE_PTR_WRITE  [x][y], entry->load_queue_ptr_write );
		    PORT_WRITE(out_RETIRE_READ_RA               [x][y], entry->read_ra              );
		    PORT_WRITE(out_RETIRE_NUM_REG_RA_PHY        [x][y], entry->num_reg_ra_phy       );
		    PORT_WRITE(out_RETIRE_READ_RB               [x][y], entry->read_rb              );
		    PORT_WRITE(out_RETIRE_NUM_REG_RB_PHY        [x][y], entry->num_reg_rb_phy       );
		    PORT_WRITE(out_RETIRE_READ_RC               [x][y], entry->read_rc              );
		    PORT_WRITE(out_RETIRE_NUM_REG_RC_PHY        [x][y], entry->num_reg_rc_phy       );
		    PORT_WRITE(out_RETIRE_WRITE_RD              [x][y], entry->write_rd             );
		    PORT_WRITE(out_RETIRE_NUM_REG_RD_LOG        [x][y], entry->num_reg_rd_log       );
		    PORT_WRITE(out_RETIRE_NUM_REG_RD_PHY_OLD    [x][y], entry->num_reg_rd_phy_old   );
		    PORT_WRITE(out_RETIRE_NUM_REG_RD_PHY_NEW    [x][y], entry->num_reg_rd_phy_new   );
		    PORT_WRITE(out_RETIRE_WRITE_RE              [x][y], write_re                    );
		    PORT_WRITE(out_RETIRE_NUM_REG_RE_LOG        [x][y], num_reg_re_log              );
		    PORT_WRITE(out_RETIRE_NUM_REG_RE_PHY_OLD    [x][y], entry->num_reg_re_phy_old   );
		    PORT_WRITE(out_RETIRE_NUM_REG_RE_PHY_NEW    [x][y], entry->num_reg_re_phy_new   );
		  }
	      }

	    // Retire "in-order"
	    can_retire [x] &= retire_val [x][y];
	  }
      }
    
    for (uint32_t i=0; i<_param->_nb_rename_unit; i++)
      for (uint32_t j=0; j<_param->_nb_inst_retire[i]; j++)
	PORT_WRITE(out_RETIRE_VAL [i][j],retire_val [i][j]);

    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_SPR_WRITE_VAL       [i][j], spr_write_val       [i][j]);
	  PORT_WRITE(out_SPR_WRITE_SR_F_VAL  [i][j], spr_write_sr_f_val  [i][j]);
	  PORT_WRITE(out_SPR_WRITE_SR_F      [i][j], spr_write_sr_f      [i][j]);
	  PORT_WRITE(out_SPR_WRITE_SR_CY_VAL [i][j], spr_write_sr_cy_val [i][j]);
	  PORT_WRITE(out_SPR_WRITE_SR_CY     [i][j], spr_write_sr_cy     [i][j]);
	  PORT_WRITE(out_SPR_WRITE_SR_OV_VAL [i][j], spr_write_sr_ov_val [i][j]);
	  PORT_WRITE(out_SPR_WRITE_SR_OV     [i][j], spr_write_sr_ov     [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
