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

#include "Behavioural/Stage_1_Ifetch/Predictor/Meta_Predictor/Two_Level_Branch_Predictor/Two_Level_Branch_Predictor_Glue/include/Two_Level_Branch_Predictor_Glue.h"

namespace morpheo                    {
namespace behavioural {
namespace stage_1_ifetch {
namespace predictor {
namespace meta_predictor {
namespace two_level_branch_predictor {
namespace two_level_branch_predictor_glue {


  void Two_Level_Branch_Predictor_Glue::vhdl_body (Vhdl & vhdl)
  {
    log_printf(FUNC,Two_Level_Branch_Predictor_Glue,"vhdl_body","Begin");

    vhdl.set_body ("-- ack output");
    for (uint32_t i=0; i<_param._nb_prediction; i++)
      {
	string bht_ack, pht_ack;

	if (_param._have_bht)
	  bht_ack = "in_PREDICT_BHT_ACK_"+toString(i);
	else
	  bht_ack = "'1'";

	if (_param._have_pht)
	  pht_ack = "in_PREDICT_PHT_ACK_"+toString(i);
	else
	  pht_ack = "'1'";

	vhdl.set_body ("out_PREDICT_ACK_"+toString(i)+"         <= "+bht_ack+" and "+pht_ack+";");
      }

    for (uint32_t i=0; i<_param._nb_branch_complete; i++)
      {
	string bht_ack, pht_ack;

	if (_param._have_bht)
	  bht_ack = "in_BRANCH_COMPLETE_BHT_ACK_"+toString(i);
	else
	  bht_ack = "'1'";

	if (_param._have_pht)
	  pht_ack = "in_BRANCH_COMPLETE_PHT_ACK_"+toString(i);
	else
	  pht_ack = "'1'";

	vhdl.set_body ("out_BRANCH_COMPLETE_ACK_"+toString(i)+" <= "+bht_ack+" and "+pht_ack+";");
      }
    
    vhdl.set_body ("");
    vhdl.set_body ("-- address output");

    for (uint32_t i=0; i<_param._nb_prediction; i++)
      {
	// The address is higher than the address size of bht
	if (_param._have_bht)
	  vhdl.set_body ("out_PREDICT_BHT_ADDRESS_"+toString(i)+" <= in_PREDICT_ADDRESS_"+toString(i)+std_logic_range(_param._bht_size_address)+";");

	if (_param._have_pht)
	  {
	    // For pht : 2 cases
	    if (_param._have_bht)
	      {
		uint32_t min = 0;
		uint32_t max = _param._pht_size_address;

		// A lot of case :
		//
		//      pht_size_addr
		// addr             bht_history
		//
		// ---------] |
		//            |[---------
		//
		// -----------|----]               share
		//            |  [-------
		//
		// -----------|----]            no share
		//            |     [-----
		//
		
		// Test if address is share 
		if (_param._pht_size_address_shift > 0)
		  {
		    min = _param._pht_size_address_shift;
		    vhdl.set_body ("out_PREDICT_PHT_ADDRESS_"+toString(i)+std_logic_range(min) + " <=  in_PREDICT_BHT_HISTORY_"+toString(i)+std_logic_range(min)+";");
		  }

		if (_param._bht_size_history < _param._pht_size_address)
		  {
		    max = _param._bht_size_history;
		    vhdl.set_body ("out_PREDICT_PHT_ADDRESS_"+toString(i)+std_logic_range(_param._pht_size_address-1,max) + " <=  in_PREDICT_ADDRESS_"+toString(i)+std_logic_range(_param._pht_size_address-1-_param._pht_size_address_shift, _param._pht_size_address_share)+";");
		  }
		
		// intersection
		if (_param._pht_size_address_share > 0)
		  vhdl.set_body ("out_PREDICT_PHT_ADDRESS_"+toString(i)+std_logic_range(max-1,min) + " <=  in_PREDICT_ADDRESS_"+toString(i)+std_logic_range(_param._pht_size_address_share-1,0)+" xor in_PREDICT_BHT_HISTORY_"+toString(i)+std_logic_range(max-1,min)+";");
	      }
	    else
	      vhdl.set_body ("out_PREDICT_PHT_ADDRESS_"+toString(i)+" <=  in_PREDICT_ADDRESS_"+toString(i)+std_logic_range(_param._pht_size_address)+";");
	  }
      }

    for (uint32_t i=0; i<_param._nb_branch_complete; i++)
      {
	// The address is higher than the address size of bht
	if (_param._have_bht)
	  vhdl.set_body ("out_BRANCH_COMPLETE_BHT_ADDRESS_"+toString(i)+" <= in_BRANCH_COMPLETE_ADDRESS_"+toString(i)+std_logic_range(_param._bht_size_address)+";");

	if (_param._have_pht)
	  {
	    // For pht : 2 cases
	    if (_param._have_bht)
	      {
		uint32_t min = 0;
		uint32_t max = _param._pht_size_address;

		// Test if address is share 
		if (_param._pht_size_address_shift > 0)
		  {
		    min = _param._pht_size_address_shift;
		    vhdl.set_body ("out_BRANCH_COMPLETE_PHT_ADDRESS_"+toString(i)+std_logic_range(min) + " <=  in_BRANCH_COMPLETE_BHT_HISTORY_"+toString(i)+std_logic_range(min)+";");
		  }

		if (_param._bht_size_history < _param._pht_size_address)
		  {
		    max = _param._bht_size_history;
		    vhdl.set_body ("out_BRANCH_COMPLETE_PHT_ADDRESS_"+toString(i)+std_logic_range(_param._pht_size_address-1,max) + " <=  in_BRANCH_COMPLETE_ADDRESS_"+toString(i)+std_logic_range(_param._pht_size_address-1-_param._pht_size_address_shift, _param._pht_size_address_share)+";");
		  }
		
		// intersection
		if (_param._pht_size_address_share > 0)
		  vhdl.set_body ("out_BRANCH_COMPLETE_PHT_ADDRESS_"+toString(i)+std_logic_range(max-1,min) + " <=  in_BRANCH_COMPLETE_ADDRESS_"+toString(i)+std_logic_range(_param._pht_size_address_share-1,0)+" xor in_BRANCH_COMPLETE_BHT_HISTORY_"+toString(i)+std_logic_range(max-1,min)+";");
	      }
	    else
	      vhdl.set_body ("out_BRANCH_COMPLETE_PHT_ADDRESS_"+toString(i)+" <=  in_BRANCH_COMPLETE_ADDRESS_"+toString(i)+std_logic_range(_param._pht_size_address)+";");
	  }
      }

    log_printf(FUNC,Two_Level_Branch_Predictor_Glue,"vhdl_body","End");
  };

}; // end namespace two_level_branch_predictor_glue
}; // end namespace two_level_branch_predictor
}; // end namespace meta_predictor
}; // end namespace predictor
}; // end namespace stage_1_ifetch

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