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

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

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

  void Two_Level_Branch_Predictor::allocation (void)
  {
    log_printf(FUNC,Two_Level_Branch_Predictor,"allocation","Begin");

    _component   = new Component ();

    Entity * entity = _component->set_entity (_name                 
					     ,"Two_Level_Branch_Predictor"
#ifdef POSITION
					     ,MIXTE
#endif
					      );
    
    _interfaces = entity->set_interfaces();

    // ~~~~~[ Interface : "" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    {
      Interface * interface = _interfaces->set_interface(""
#ifdef POSITION
							 , IN  
							 , SOUTH
							 , "Generalist interface"
#endif
							 );
      
      in_CLOCK              = interface->set_signal_clk              ("clock" ,1);
      in_NRESET             = interface->set_signal_in  <Tcontrol_t> ("nreset",1,RESET_VHDL_YES);
    }
    
    // ~~~~~[ Interface : "predict" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     in_PREDICT_VAL                 = new SC_IN (Tcontrol_t)     * [_param._nb_prediction     ];
    out_PREDICT_ACK                 = new SC_OUT(Tcontrol_t)     * [_param._nb_prediction     ];
     in_PREDICT_ADDRESS             = new SC_IN (Taddress_t)     * [_param._nb_prediction     ];
    if (_param._have_bht)
    out_PREDICT_BHT_HISTORY         = new SC_OUT(Tbht_history_t) * [_param._nb_prediction     ];
    if (_param._have_pht)
    out_PREDICT_PHT_HISTORY         = new SC_OUT(Tpht_history_t) * [_param._nb_prediction     ];

    for (uint32_t i=0; i<_param._nb_prediction; i++)
      {
	Interface_fifo * interface = _interfaces->set_interface("predict_"+toString(i)
#ifdef POSITION
								, IN  
								, WEST
								, "Interface Predict"
#endif
								);

	 in_PREDICT_VAL                 [i] = interface->set_signal_valack_in            ("val"    , VAL);
	out_PREDICT_ACK                 [i] = interface->set_signal_valack_out           ("ack"    , ACK);
	 in_PREDICT_ADDRESS             [i] = interface->set_signal_in  <Taddress_t>     ("address", _param._size_address);
	if (_param._have_bht)
	out_PREDICT_BHT_HISTORY         [i] = interface->set_signal_out <Tbht_history_t> ("bht_history", _param._bht_size_shifter);
	if (_param._have_pht)
	out_PREDICT_PHT_HISTORY         [i] = interface->set_signal_out <Tpht_history_t> ("pht_history", _param._pht_size_counter);
      }

    // ~~~~~[ Interface : "branch_complete" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     in_BRANCH_COMPLETE_VAL         = new SC_IN (Tcontrol_t)     * [_param._nb_branch_complete];
    out_BRANCH_COMPLETE_ACK         = new SC_OUT(Tcontrol_t)     * [_param._nb_branch_complete];
     in_BRANCH_COMPLETE_ADDRESS     = new SC_IN (Taddress_t)     * [_param._nb_branch_complete];
    if (_param._have_bht)
     in_BRANCH_COMPLETE_BHT_HISTORY = new SC_IN (Tbht_history_t) * [_param._nb_branch_complete];
    if (_param._have_pht)
     in_BRANCH_COMPLETE_PHT_HISTORY = new SC_IN (Tpht_history_t) * [_param._nb_branch_complete];
     in_BRANCH_COMPLETE_DIRECTION   = new SC_IN (Tcontrol_t)     * [_param._nb_branch_complete];

    for (uint32_t i=0; i<_param._nb_branch_complete; i++)
      {
	Interface_fifo * interface = _interfaces->set_interface("branch_complete_"+toString(i)
#ifdef POSITION
								, IN  
								, EAST
								, "Interface branch complete"
#endif
								);

	 in_BRANCH_COMPLETE_VAL         [i] = interface->set_signal_valack_in            ("val"        , VAL);		   
	out_BRANCH_COMPLETE_ACK         [i] = interface->set_signal_valack_out           ("ack"        , ACK);		   
	 in_BRANCH_COMPLETE_ADDRESS     [i] = interface->set_signal_in  <Taddress_t    > ("address"    , _param._size_address);
	if (_param._have_bht)
	 in_BRANCH_COMPLETE_BHT_HISTORY [i] = interface->set_signal_in  <Tbht_history_t> ("bht_history", _param._bht_size_shifter);
	if (_param._have_pht)
	 in_BRANCH_COMPLETE_PHT_HISTORY [i] = interface->set_signal_in  <Tpht_history_t> ("pht_history", _param._pht_size_counter);
	 in_BRANCH_COMPLETE_DIRECTION   [i] = interface->set_signal_in  <Tcontrol_t    > ("direction"  , 1);
      }

    // ~~~~~[ Component ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    
    string name_component;

    // =====[ component_Branch_History_Table ]============================    
    if (_param._have_bht)
      {
	name_component = _name+"_Branch_History_Table";
	
	component_Branch_History_Table = new morpheo::behavioural::stage_1_ifetch::predictor::meta_predictor::two_level_branch_predictor::branch_history_table ::Branch_History_Table (name_component.c_str()
#ifdef STATISTICS
																						       ,_param_statistics
#endif
																						       ,*(_param._param_branch_history_table));
	
	_component->set_component (component_Branch_History_Table->_component
#ifdef POSITION
				   , 75
				   , 25
				   , 10
				   , 10
#endif
				   );
      }
    
    // =====[ component_Pattern_History_Table ]===========================    
    if (_param._have_pht)
      {
	name_component = _name+"_Pattern_History_Table";
	
	component_Pattern_History_Table = new morpheo::behavioural::stage_1_ifetch::predictor::meta_predictor::two_level_branch_predictor::pattern_history_table ::Pattern_History_Table (name_component.c_str()
#ifdef STATISTICS
																							  ,_param_statistics
#endif
																							  ,*(_param._param_pattern_history_table));
	
	_component->set_component (component_Pattern_History_Table->_component
#ifdef POSITION
				   , 75
				   , 75
				   , 10
				   , 10
#endif
				   );
      }

    // =====[ component_Two_Level_Branch_Predictor_Glue ]=================

    name_component = _name+"_Two_Level_Branch_Predictor_Glue";

    component_Two_Level_Branch_Predictor_Glue = new morpheo::behavioural::stage_1_ifetch::predictor::meta_predictor::two_level_branch_predictor::two_level_branch_predictor_glue::Two_Level_Branch_Predictor_Glue (name_component.c_str()
#ifdef STATISTICS
																										   ,_param_statistics
#endif
																										   ,*(_param._param_two_level_branch_predictor_glue));
    
    _component->set_component (component_Two_Level_Branch_Predictor_Glue->_component
#ifdef POSITION
			       , 50
			       , 75
			       , 10
			       , 10
#endif
			       );
    
    // ~~~~~[ Component - Instanciation ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    // =====[ component_Branch_History_Table - Instanciation ]============
    if (_param._have_bht)
      {
#ifdef POSITION
	_component->interface_map (_name+"_Branch_History_Table","",
				   _name                        ,"");
#endif
	
	_component->port_map(_name+"_Branch_History_Table", "in_CLOCK" , _name,"in_CLOCK" );
	_component->port_map(_name+"_Branch_History_Table", "in_NRESET", _name,"in_NRESET");

	for (uint32_t i=0; i<_param._nb_prediction; i++)
	  {
#ifdef POSITION
	    _component->interface_map (_name+"_Branch_History_Table","predict_"+toString(i),
				       _name                        ,"predict_"+toString(i));
#endif
	    _component->port_map(_name+"_Branch_History_Table", "in_PREDICT_"+toString(i)+"_VAL"    , _name                                   , "in_PREDICT_"+toString(i)+"_VAL"        );
	    _component->port_map(_name+"_Branch_History_Table","out_PREDICT_"+toString(i)+"_ACK"    , _name+"_Two_Level_Branch_Predictor_Glue", "in_PREDICT_"+toString(i)+"_BHT_ACK"    );
	    _component->port_map(_name+"_Branch_History_Table", "in_PREDICT_"+toString(i)+"_ADDRESS", _name+"_Two_Level_Branch_Predictor_Glue","out_PREDICT_"+toString(i)+"_BHT_ADDRESS");
	    _component->port_map(_name+"_Branch_History_Table","out_PREDICT_"+toString(i)+"_HISTORY", _name                                   ,"out_PREDICT_"+toString(i)+"_BHT_HISTORY");
	  }
	
	for (uint32_t i=0; i<_param._nb_branch_complete; i++)
	  {
#ifdef POSITION
	    _component->interface_map (_name+"_Branch_History_Table","branch_complete_"+toString(i),
				       _name                        ,"branch_complete_"+toString(i));
#endif
	    _component->port_map(_name+"_Branch_History_Table", "in_BRANCH_COMPLETE_"+toString(i)+"_VAL"      , _name                                   , "in_BRANCH_COMPLETE_"+toString(i)+"_VAL"          );
	    _component->port_map(_name+"_Branch_History_Table","out_BRANCH_COMPLETE_"+toString(i)+"_ACK"      , _name+"_Two_Level_Branch_Predictor_Glue", "in_BRANCH_COMPLETE_"+toString(i)+"_BHT_ACK"      );
	    _component->port_map(_name+"_Branch_History_Table", "in_BRANCH_COMPLETE_"+toString(i)+"_ADDRESS"  , _name+"_Two_Level_Branch_Predictor_Glue","out_BRANCH_COMPLETE_"+toString(i)+"_BHT_ADDRESS"  );
	    _component->port_map(_name+"_Branch_History_Table", "in_BRANCH_COMPLETE_"+toString(i)+"_HISTORY"  , _name                                   , "in_BRANCH_COMPLETE_"+toString(i)+"_BHT_HISTORY"  );
	    _component->port_map(_name+"_Branch_History_Table", "in_BRANCH_COMPLETE_"+toString(i)+"_DIRECTION", _name                                   , "in_BRANCH_COMPLETE_"+toString(i)+"_DIRECTION"    );
	  }
      }
    
    // =====[ component_Pattern_History_Table - Instanciation ]===========
    if (_param._have_pht)
      {
#ifdef POSITION
	_component->interface_map (_name+"_Pattern_History_Table","",
				   _name                         ,"");
#endif
	
	_component->port_map(_name+"_Pattern_History_Table", "in_CLOCK" , _name,"in_CLOCK" );
	_component->port_map(_name+"_Pattern_History_Table", "in_NRESET", _name,"in_NRESET");

	for (uint32_t i=0; i<_param._nb_prediction; i++)
	  {
#ifdef POSITION
	    _component->interface_map (_name+"_Pattern_History_Table","predict_"+toString(i),
				       _name                         ,"predict_"+toString(i));
#endif
	    _component->port_map(_name+"_Pattern_History_Table", "in_PREDICT_"+toString(i)+"_VAL"    , _name                                   , "in_PREDICT_"+toString(i)+"_VAL"        );
	    _component->port_map(_name+"_Pattern_History_Table","out_PREDICT_"+toString(i)+"_ACK"    , _name+"_Two_Level_Branch_Predictor_Glue", "in_PREDICT_"+toString(i)+"_PHT_ACK"    );
	    _component->port_map(_name+"_Pattern_History_Table", "in_PREDICT_"+toString(i)+"_ADDRESS", _name+"_Two_Level_Branch_Predictor_Glue","out_PREDICT_"+toString(i)+"_PHT_ADDRESS");
	    _component->port_map(_name+"_Pattern_History_Table","out_PREDICT_"+toString(i)+"_HISTORY", _name                                   ,"out_PREDICT_"+toString(i)+"_PHT_HISTORY");
	  }

	for (uint32_t i=0; i<_param._nb_branch_complete; i++)
	  {
#ifdef POSITION
	    _component->interface_map (_name+"_Pattern_History_Table","branch_complete_"+toString(i),
				       _name                        ,"branch_complete_"+toString(i));
#endif
	    _component->port_map(_name+"_Pattern_History_Table", "in_BRANCH_COMPLETE_"+toString(i)+"_VAL"      , _name                                   , "in_BRANCH_COMPLETE_"+toString(i)+"_VAL"          );
	    _component->port_map(_name+"_Pattern_History_Table","out_BRANCH_COMPLETE_"+toString(i)+"_ACK"      , _name+"_Two_Level_Branch_Predictor_Glue", "in_BRANCH_COMPLETE_"+toString(i)+"_PHT_ACK"      );
	    _component->port_map(_name+"_Pattern_History_Table", "in_BRANCH_COMPLETE_"+toString(i)+"_ADDRESS"  , _name+"_Two_Level_Branch_Predictor_Glue","out_BRANCH_COMPLETE_"+toString(i)+"_PHT_ADDRESS"  );
	    _component->port_map(_name+"_Pattern_History_Table", "in_BRANCH_COMPLETE_"+toString(i)+"_HISTORY"  , _name                                   , "in_BRANCH_COMPLETE_"+toString(i)+"_PHT_HISTORY"  );
	    _component->port_map(_name+"_Pattern_History_Table", "in_BRANCH_COMPLETE_"+toString(i)+"_DIRECTION", _name                                   , "in_BRANCH_COMPLETE_"+toString(i)+"_DIRECTION"    );
	  }
      }

    // =====[ component_Two_Level_Branch_Predictor_Glue - Instanciation ]=
#ifdef POSITION
	_component->interface_map (_name+"_Two_Level_Branch_Predictor_Glue","",
				   _name                                   ,"");
#endif
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue", "in_CLOCK" , _name,"in_CLOCK" );
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue", "in_NRESET", _name,"in_NRESET");

	for (uint32_t i=0; i<_param._nb_prediction; i++)
	  {
	if (_param._have_bht)
	  {
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue",  "in_PREDICT_"+toString(i)+"_BHT_ACK"    , _name+"_Branch_History_Table" , "out_PREDICT_"+toString(i)+"_ACK"    );
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue", "out_PREDICT_"+toString(i)+"_BHT_ADDRESS", _name+"_Branch_History_Table" ,  "in_PREDICT_"+toString(i)+"_ADDRESS");
	  }
	if (_param._have_pht)
	  {
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue",  "in_PREDICT_"+toString(i)+"_PHT_ACK"    , _name+"_Pattern_History_Table", "out_PREDICT_"+toString(i)+"_ACK"    );
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue", "out_PREDICT_"+toString(i)+"_PHT_ADDRESS", _name+"_Pattern_History_Table",  "in_PREDICT_"+toString(i)+"_ADDRESS");
	  }
	if (_param._have_bht and _param._have_pht)
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue", "in_PREDICT_"+toString(i)+"_BHT_HISTORY" , _name+"_Branch_History_Table" ,"out_PREDICT_"+toString(i)+"_HISTORY");
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue","out_PREDICT_"+toString(i)+"_ACK"         , _name                         ,"out_PREDICT_"+toString(i)+"_ACK");
        _component->port_map(_name+"_Two_Level_Branch_Predictor_Glue", "in_PREDICT_"+toString(i)+"_ADDRESS"     , _name                         , "in_PREDICT_"+toString(i)+"_ADDRESS");
	  }
    
    for (uint32_t i=0; i<_param._nb_branch_complete; i++)
      {
	if (_param._have_bht)
	  {
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue",  "in_BRANCH_COMPLETE_"+toString(i)+"_BHT_ACK"    , _name+"_Branch_History_Table" , "out_BRANCH_COMPLETE_"+toString(i)+"_ACK"    );
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue", "out_BRANCH_COMPLETE_"+toString(i)+"_BHT_ADDRESS", _name+"_Branch_History_Table" ,  "in_BRANCH_COMPLETE_"+toString(i)+"_ADDRESS");
	  }
	if (_param._have_pht)
	  {
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue",  "in_BRANCH_COMPLETE_"+toString(i)+"_PHT_ACK"    , _name+"_Pattern_History_Table", "out_BRANCH_COMPLETE_"+toString(i)+"_ACK"    );
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue", "out_BRANCH_COMPLETE_"+toString(i)+"_PHT_ADDRESS", _name+"_Pattern_History_Table",  "in_BRANCH_COMPLETE_"+toString(i)+"_ADDRESS");
	  }
	if (_param._have_bht and _param._have_pht)
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue", "in_BRANCH_COMPLETE_"+toString(i)+"_BHT_HISTORY" , _name                         , "in_BRANCH_COMPLETE_"+toString(i)+"_BHT_HISTORY");
	_component->port_map(_name+"_Two_Level_Branch_Predictor_Glue","out_BRANCH_COMPLETE_"+toString(i)+"_ACK"         , _name                         ,"out_BRANCH_COMPLETE_"+toString(i)+"_ACK");
        _component->port_map(_name+"_Two_Level_Branch_Predictor_Glue", "in_BRANCH_COMPLETE_"+toString(i)+"_ADDRESS"     , _name                         , "in_BRANCH_COMPLETE_"+toString(i)+"_ADDRESS");
      }
#ifdef POSITION
    _component->generate_file();
#endif

    log_printf(FUNC,Two_Level_Branch_Predictor,"allocation","End");
  };
  
}; // 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
