#ifdef SYSTEMC
/*
 * $Id$
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_Front_end/Front_end/Prediction_unit/Update_Prediction_Table/include/Update_Prediction_Table.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_front_end {
namespace front_end {
namespace prediction_unit {
namespace update_prediction_table {


#undef  FUNCTION
#define FUNCTION "Update_Prediction_Table::genMealy_branch_complete"
  void Update_Prediction_Table::genMealy_branch_complete (void)
  {
    log_begin(Update_Prediction_Table,FUNCTION);
    log_function(Update_Prediction_Table,FUNCTION,_name.c_str());
    
    for (uint32_t i=0; i<_param->_nb_inst_branch_complete; i++)
#ifdef DEBUG_TEST
      // just to don't have exception in not transaction
      if (PORT_READ(in_BRANCH_COMPLETE_VAL [i]))
#endif
      {
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * BRANCH_COMPLETE [%d]",i);

	Tcontext_t          context   = (_param->_have_port_context_id)?PORT_READ(in_BRANCH_COMPLETE_CONTEXT_ID [i]):0;
	Tdepth_t            depth     = (_param->_have_port_depth     )?PORT_READ(in_BRANCH_COMPLETE_DEPTH      [i]):0;
	Tcontrol_t          miss      = false;
	Tcontrol_t          take      = reg_UPDATE_PREDICTION_TABLE [context][depth]._last_take   ;
	Taddress_t          addr_dest = reg_UPDATE_PREDICTION_TABLE [context][depth]._address_dest;
	Tbranch_condition_t condition = reg_UPDATE_PREDICTION_TABLE [context][depth]._condition   ;

        Tcontrol_t          no_sequence = PORT_READ(in_BRANCH_COMPLETE_NO_SEQUENCE [i]);
        Taddress_t          addr_good = PORT_READ(in_BRANCH_COMPLETE_ADDRESS [i]);

        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * context        : %d",context);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * depth          : %d",depth  );
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * condition      : %s",toString(condition).c_str());
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * no_sequence    : %d",no_sequence);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * address_good   : %.8x",addr_good);

        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * (before)");
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * miss         : %d",miss);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * take         : %d",take);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * address_dest : %.8x",addr_dest);

	switch (condition)
	  {
	  case BRANCH_CONDITION_NONE_WITHOUT_WRITE_STACK          : // l.j
	  case BRANCH_CONDITION_NONE_WITH_WRITE_STACK             : // l.jal
	    {
	      //miss      : always hit
	      //addr_dest : compute in decod stage
              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * BRANCH_CONDITION_NONE_WITHOUT_WRITE_STACK");
              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * BRANCH_CONDITION_NONE_WITH_WRITE_STACK   ");

#ifdef DEBUG_TEST
              if (take != 1)
                throw ERRORMORPHEO(FUNCTION,toString("Branch_complete[%d] (condition %s) : bad direction.",i,toString(condition).c_str()));
//               if (addr_dest != addr_good)
//                 throw ERRORMORPHEO(FUNCTION,toString("Branch_complete[%d] (condition %s) : bad destination address.",i,toString(condition).c_str()));
#endif

	      break;
	    }
	  case BRANCH_CONDITION_FLAG_UNSET                        : // l.bnf
	  case BRANCH_CONDITION_FLAG_SET                          : // l.bf
	    {
	      //addr_dest : compute in decod stage
              //miss if the direction is bad
              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * BRANCH_CONDITION_FLAG");

//               Tcontrol_t take_good = not flag; // flag set = not take
//               Tcontrol_t take_good = flag; // flag set = take
              Tcontrol_t take_good = no_sequence;

	      miss = (take != take_good);
	      take = take_good;

#ifdef DEBUG_TEST
//               if (addr_dest != addr_good)
//                 throw ERRORMORPHEO(FUNCTION,toString("Branch_complete[%d] (condition %s) : bad destination address.",i,toString(condition).c_str()));
#endif

	      break;
	    }
	  case BRANCH_CONDITION_READ_REGISTER_WITHOUT_WRITE_STACK : // l.jr (rb!=r9)
	  case BRANCH_CONDITION_READ_REGISTER_WITH_WRITE_STACK    : // l.jalr
	  case BRANCH_CONDITION_READ_STACK                        : // l.jr (rb==r9)
	    {
              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * BRANCH_CONDITION_READ_REGISTER_WITHOUT_WRITE_STACK");
              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * BRANCH_CONDITION_READ_REGISTER_WITH_WRITE_STACK   ");
              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * BRANCH_CONDITION_READ_STACK                       ");

              // miss if destination address is bad
	      miss      = (addr_dest != addr_good);
	      addr_dest = addr_good;

#ifdef DEBUG_TEST
              if (take != 1)
                throw ERRORMORPHEO(FUNCTION,toString("Branch_complete[%d] (condition %s) : bad direction.",i,toString(condition).c_str()));
#endif
              
	      break;
	    }
	  }

        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * (after)");
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * miss         : %d",miss);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * take         : %d",take);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * address_dest : %.8x",addr_dest);
        
	internal_BRANCH_COMPLETE_MISS_PREDICTION [i] = miss     ;
	internal_BRANCH_COMPLETE_TAKE            [i] = take     ;
	internal_BRANCH_COMPLETE_ADDRESS_DEST    [i] = addr_dest;
        
	PORT_WRITE(out_BRANCH_COMPLETE_MISS_PREDICTION [i], internal_BRANCH_COMPLETE_MISS_PREDICTION [i]);
// 	PORT_WRITE(out_BRANCH_COMPLETE_TAKE            [i], internal_BRANCH_COMPLETE_TAKE            [i]);
// 	PORT_WRITE(out_BRANCH_COMPLETE_ADDRESS_SRC     [i], reg_UPDATE_PREDICTION_TABLE [context][depth]._address_src);
// 	PORT_WRITE(out_BRANCH_COMPLETE_ADDRESS_DEST    [i], internal_BRANCH_COMPLETE_ADDRESS_DEST    [i]);
      }

    log_end(Update_Prediction_Table,FUNCTION);
  };

}; // end namespace update_prediction_table
}; // end namespace prediction_unit
}; // end namespace front_end
}; // end namespace multi_front_end
}; // end namespace core

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