/*
 * $Id: Meta_Predictor_allocation.cpp 112 2009-03-18 22:36:26Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_Front_end/Front_end/Prediction_unit/Direction/Meta_Predictor/include/Meta_Predictor.h"
#include "Behavioural/include/Allocation.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_front_end {
namespace front_end {
namespace prediction_unit {
namespace direction {
namespace meta_predictor {

#undef  FUNCTION
#define FUNCTION "Meta_Predictor::allocation"
  void Meta_Predictor::allocation 
  (
#ifdef STATISTICS
   morpheo::behavioural::Parameters_Statistics * param_statistics
#else
   void
#endif
   )
  {
    log_begin(Meta_Predictor,FUNCTION);

    _component   = new Component (_usage);

    Entity * entity = _component->set_entity (_name       
					      ,"Meta_Predictor"
#ifdef POSITION
					      ,COMBINATORY 
#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, CLOCK_VHDL_YES);
      in_NRESET       = interface->set_signal_in  <Tcontrol_t> ("nreset",1, RESET_VHDL_YES);
    }

    // ~~~~~[ Interface : "predict" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    {
      ALLOC1_INTERFACE_BEGIN("predict",IN,WEST,_("Predict direction interface"),_param->_nb_inst_predict);

      ALLOC1_VALACK_IN ( in_PREDICT_VAL          ,VAL);
      ALLOC1_VALACK_OUT(out_PREDICT_ACK          ,ACK);
      ALLOC1_SIGNAL_IN ( in_PREDICT_ADDRESS      ,"ADDRESS"      ,Taddress_t,_param->_size_address);
      ALLOC1_SIGNAL_OUT(out_PREDICT_DIRECTION    ,"DIRECTION"    ,Tcontrol_t,1                    );
      ALLOC1_SIGNAL_OUT(out_PREDICT_HISTORY      ,"HISTORY"      ,Thistory_t,_param->_size_history);

      ALLOC1_INTERFACE_END(_param->_nb_inst_predict);
    }

    // ~~~~~[ Interface : "update" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    {
      ALLOC1_INTERFACE_BEGIN("update",IN,WEST,_("Update direction interface"),_param->_nb_inst_update);

      ALLOC1_VALACK_IN ( in_UPDATE_VAL           ,VAL);
      ALLOC1_VALACK_OUT(out_UPDATE_ACK           ,ACK);
      ALLOC1_SIGNAL_IN ( in_UPDATE_ADDRESS       ,"ADDRESS"      ,Taddress_t,_param->_size_address);
      ALLOC1_SIGNAL_IN ( in_UPDATE_HISTORY       ,"HISTORY"      ,Thistory_t,_param->_size_history);
      ALLOC1_SIGNAL_IN ( in_UPDATE_HISTORY_VAL   ,"HISTORY_VAL"  ,Tcontrol_t,1                    );
      ALLOC1_SIGNAL_IN ( in_UPDATE_DIRECTION     ,"DIRECTION"    ,Tcontrol_t,1                    );

      ALLOC1_INTERFACE_END(_param->_nb_inst_update);
    }
    
    // ~~~~~[ Component ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    std::string name;

    
    {
      _component_two_level_branch_predictor = new morpheo::behavioural::core::multi_front_end::front_end::prediction_unit::direction::meta_predictor::two_level_branch_predictor::Two_Level_Branch_Predictor * [_param->_nb_predictor];

      for (uint32_t i=0; i<_param->_nb_predictor; ++i)
        {
          name = _name+"_two_level_branch_predictor_"+toString(i);
          log_printf(INFO,Meta_Predictor,FUNCTION,_("Create   : %s"),name.c_str());
          
          _component_two_level_branch_predictor [i] = new morpheo::behavioural::core::multi_front_end::front_end::prediction_unit::direction::meta_predictor::two_level_branch_predictor::Two_Level_Branch_Predictor
            (name.c_str()
#ifdef STATISTICS
             ,param_statistics
#endif
             ,_param->_param_two_level_branch_predictor[i]
             ,_usage);
          
          _component->set_component (_component_two_level_branch_predictor[i]->_component
#ifdef POSITION
                                     , 50, 50, 10, 10
#endif
                                     );
        }
    }
    
    {
      name = _name+"_glue";
      log_printf(INFO,Meta_Predictor,FUNCTION,_("Create   : %s"),name.c_str());
      
      _component_glue = new morpheo::behavioural::core::multi_front_end::front_end::prediction_unit::direction::meta_predictor::meta_predictor_glue::Meta_Predictor_Glue
        (name.c_str()
#ifdef STATISTICS
         ,param_statistics
#endif
         ,_param->_param_glue
         ,_usage);
      
      _component->set_component (_component_glue->_component
#ifdef POSITION
                                 , 50, 50, 10, 10
#endif
                                 );
    }
    
    // ~~~~~[ Instanciation ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    
    std::string src,dest;

    // ===================================================================
    // =====[ Two_Level_Branch_Predictor ]================================
    // ===================================================================
    
    for (uint32_t i=0; i<_param->_nb_predictor; ++i)
    {
      src = _name+"_two_level_branch_predictor_"+toString(i);
      log_printf(INFO,Prediction_unit,FUNCTION,_("Instance : %s"),src.c_str());
      
      {
        dest = _name;
#ifdef POSITION
        _component->interface_map (src ,"",
                                   dest,"");
#endif

        PORT_MAP(_component,src , "in_CLOCK" ,dest, "in_CLOCK");
        PORT_MAP(_component,src , "in_NRESET",dest, "in_NRESET");
      }

      // ~~~~~[ Interface : "predict" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      for (uint32_t j=0; j<_param->_nb_inst_predict; ++j)
        {
          dest = _name;

#ifdef POSITION
          _component->interface_map (src ,"predict_"+toString(j),
                                     dest,"predict_"+toString(j));
#endif

          PORT_MAP(_component,src , "in_PREDICT_"+toString(j)+"_ADDRESS"      ,
                              dest, "in_PREDICT_"+toString(j)+"_ADDRESS"      );

          dest = _name+"_glue";

#ifdef POSITION
          _component->interface_map (src ,"predict_"+toString(j),
                                     dest,"predict_predictor_"+toString(i)+"_"+toString(j));
#endif

          COMPONENT_MAP(_component,src , "in_PREDICT_"                          +toString(j)+"_VAL"          ,
                                   dest,"out_PREDICT_PREDICTOR_"+toString(i)+"_"+toString(j)+"_VAL"          );
          COMPONENT_MAP(_component,src ,"out_PREDICT_"                          +toString(j)+"_ACK"          ,
                                   dest, "in_PREDICT_PREDICTOR_"+toString(i)+"_"+toString(j)+"_ACK"          );
//        COMPONENT_MAP(_component,src , "in_PREDICT_"                          +toString(j)+"_ADDRESS"      ,
//                                 dest,"out_PREDICT_PREDICTOR_"+toString(i)+"_"+toString(j)+"_ADDRESS"      );
          COMPONENT_MAP(_component,src ,"out_PREDICT_"                          +toString(j)+"_DIRECTION"    ,
                                   dest, "in_PREDICT_PREDICTOR_"+toString(i)+"_"+toString(j)+"_DIRECTION"    );
          COMPONENT_MAP(_component,src ,"out_PREDICT_"                          +toString(j)+"_HISTORY"      ,
                                   dest, "in_PREDICT_PREDICTOR_"+toString(i)+"_"+toString(j)+"_HISTORY"      );
          if (_param->_predictor_update_on_prediction [i])
            {
          COMPONENT_MAP(_component,src , "in_PREDICT_"                          +toString(j)+"_DIRECTION_VAL",
                                   dest,"out_PREDICT_PREDICTOR_"+toString(i)+"_"+toString(j)+"_DIRECTION_VAL");
          COMPONENT_MAP(_component,src , "in_PREDICT_"                          +toString(j)+"_DIRECTION"    ,
                                   dest,"out_PREDICT_PREDICTOR_"+toString(i)+"_"+toString(j)+"_DIRECTION"    );
            }
        }

      // ~~~~~[ Interface : "update" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      for (uint32_t j=0; j<_param->_nb_inst_update; ++j)
        {
          dest = _name;

#ifdef POSITION
          _component->interface_map (src ,"update_"+toString(j),
                                     dest,"update_"+toString(j));
#endif

          PORT_MAP(_component,src , "in_UPDATE_"+toString(j)+"_ADDRESS"      ,
                              dest, "in_UPDATE_"+toString(j)+"_ADDRESS"      );

          dest = _name+"_glue";

#ifdef POSITION
          _component->interface_map (src ,"update_"+toString(j),
                                     dest,"update_predictor_"+toString(i)+"_"+toString(j));
#endif

          COMPONENT_MAP(_component,src , "in_UPDATE_"                          +toString(j)+"_VAL"          ,
                                   dest,"out_UPDATE_PREDICTOR_"+toString(i)+"_"+toString(j)+"_VAL"          );
          COMPONENT_MAP(_component,src ,"out_UPDATE_"                          +toString(j)+"_ACK"          ,
                                   dest, "in_UPDATE_PREDICTOR_"+toString(i)+"_"+toString(j)+"_ACK"          );
//        COMPONENT_MAP(_component,src , "in_UPDATE_"                          +toString(j)+"_ADDRESS"      ,
//                                 dest,"out_UPDATE_PREDICTOR_"+toString(i)+"_"+toString(j)+"_ADDRESS"      );
          COMPONENT_MAP(_component,src , "in_UPDATE_"                          +toString(j)+"_DIRECTION"    ,
                                   dest,"out_UPDATE_PREDICTOR_"+toString(i)+"_"+toString(j)+"_DIRECTION"    );
          COMPONENT_MAP(_component,src , "in_UPDATE_"                          +toString(j)+"_HISTORY"      ,
                                   dest,"out_UPDATE_PREDICTOR_"+toString(i)+"_"+toString(j)+"_HISTORY"      );
          COMPONENT_MAP(_component,src , "in_UPDATE_"                          +toString(j)+"_HISTORY_VAL"  ,
                                   dest,"out_UPDATE_PREDICTOR_"+toString(i)+"_"+toString(j)+"_HISTORY_VAL"  );
          if (_param->_predictor_update_on_prediction [i])
          COMPONENT_MAP(_component,src , "in_UPDATE_"                          +toString(j)+"_MISS"         ,
                                   dest,"out_UPDATE_PREDICTOR_"+toString(i)+"_"+toString(j)+"_MISS"         );
        }
//     // ~~~~~[ Interface : "update" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//   public    : SC_IN (Tcontrol_t)           **  in_UPDATE_VAL           ;//[nb_inst_update]
//   public    : SC_OUT(Tcontrol_t)           ** out_UPDATE_ACK           ;//[nb_inst_update]
//   public    : SC_IN (Taddress_t)           **  in_UPDATE_ADDRESS       ;//[nb_inst_update]
//   public    : SC_IN (Thistory_t)           **  in_UPDATE_HISTORY       ;//[nb_inst_update]
//   public    : SC_IN (Tcontrol_t)           **  in_UPDATE_DIRECTION     ;//[nb_inst_update]
//   public    : SC_IN (Tcontrol_t)           **  in_UPDATE_MISS          ;//[nb_inst_update] // if update_on_prediction

    }
      
    // ===================================================================    
    // =====[ Glue ]======================================================    
    // ===================================================================    

    {
      src = _name+"_glue";
      log_printf(INFO,Prediction_unit,FUNCTION,_("Instance : %s"),src.c_str());
      
      {
        dest = _name;
#ifdef POSITION
        _component->interface_map (src ,"",
                                   dest,"");
#endif

        PORT_MAP(_component,src , "in_CLOCK" ,dest, "in_CLOCK");
        PORT_MAP(_component,src , "in_NRESET",dest, "in_NRESET");
      }

      // ~~~~~[ Interface : "predict" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      for (uint32_t i=0; i<_param->_nb_inst_predict; ++i)
        {
          dest = _name;
#ifdef POSITION
          _component->interface_map (src ,"predict_"+toString(i),
                                     dest,"predict_"+toString(i));
#endif
           
          PORT_MAP(_component,src , "in_PREDICT_"+toString(i)+"_VAL"      ,
                              dest, "in_PREDICT_"+toString(i)+"_VAL"      );
          PORT_MAP(_component,src ,"out_PREDICT_"+toString(i)+"_ACK"      ,
                              dest,"out_PREDICT_"+toString(i)+"_ACK"      );
          PORT_MAP(_component,src ,"out_PREDICT_"+toString(i)+"_HISTORY"  ,
                              dest,"out_PREDICT_"+toString(i)+"_HISTORY"  );
          PORT_MAP(_component,src ,"out_PREDICT_"+toString(i)+"_DIRECTION",
                              dest,"out_PREDICT_"+toString(i)+"_DIRECTION");
        }

      //  out_PREDICT_PREDICTOR_VAL           -> two_level_branch_predictor. in_PREDICT_PREDICTOR_VAL          
      //   in_PREDICT_PREDICTOR_ACK           -> two_level_branch_predictor.out_PREDICT_PREDICTOR_ACK          
      //   in_PREDICT_PREDICTOR_HISTORY       -> two_level_branch_predictor.out_PREDICT_PREDICTOR_HISTORY      
      //   in_PREDICT_PREDICTOR_DIRECTION     -> two_level_branch_predictor.out_PREDICT_PREDICTOR_DIRECTION    
      //  out_PREDICT_PREDICTOR_DIRECTION_VAL -> two_level_branch_predictor. in_PREDICT_PREDICTOR_DIRECTION_VAL
      //  out_PREDICT_PREDICTOR_DIRECTION     -> two_level_branch_predictor. in_PREDICT_PREDICTOR_DIRECTION    

      // ~~~~~[ Interface : "update" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      for (uint32_t i=0; i<_param->_nb_inst_update; ++i)
        {
          dest = _name;
#ifdef POSITION
          _component->interface_map (src ,"update_"+toString(i),
                                     dest,"update_"+toString(i));
#endif

          PORT_MAP(_component,src , "in_UPDATE_"+toString(i)+"_VAL"        ,
                              dest, "in_UPDATE_"+toString(i)+"_VAL"        );
          PORT_MAP(_component,src ,"out_UPDATE_"+toString(i)+"_ACK"        ,
                              dest,"out_UPDATE_"+toString(i)+"_ACK"        );
          PORT_MAP(_component,src , "in_UPDATE_"+toString(i)+"_HISTORY"    ,
                              dest, "in_UPDATE_"+toString(i)+"_HISTORY"    );
          PORT_MAP(_component,src , "in_UPDATE_"+toString(i)+"_HISTORY_VAL",
                              dest, "in_UPDATE_"+toString(i)+"_HISTORY_VAL");
          PORT_MAP(_component,src , "in_UPDATE_"+toString(i)+"_DIRECTION"  ,
                              dest, "in_UPDATE_"+toString(i)+"_DIRECTION"  );
        }
      
      //  out_UPDATE_PREDICTOR_VAL        -> two_level_branch_predictor. in_UPDATE_PREDICTOR_VAL      
      //   in_UPDATE_PREDICTOR_ACK        -> two_level_branch_predictor.out_UPDATE_PREDICTOR_ACK      
      //  out_UPDATE_PREDICTOR_HISTORY    -> two_level_branch_predictor. in_UPDATE_PREDICTOR_HISTORY  
      //  out_UPDATE_PREDICTOR_HISTORY_VAL-> two_level_branch_predictor. in_UPDATE_PREDICTOR_HISTORY  
      //  out_UPDATE_PREDICTOR_DIRECTION  -> two_level_branch_predictor. in_UPDATE_PREDICTOR_DIRECTION
      //  out_UPDATE_PREDICTOR_MISS       -> two_level_branch_predictor. in_UPDATE_PREDICTOR_MISS     

    }

    // ~~~~~[ Others ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     if (DEBUG_Meta_Predictor == true)
       _component->test_map();

#ifdef POSITION
     if (usage_is_set(_usage,USE_POSITION))
       _component->generate_file();
#endif

     log_end(Meta_Predictor,FUNCTION);
  };

}; // end namespace meta_predictor
}; // end namespace direction
}; // end namespace prediction_unit
}; // end namespace front_end
}; // end namespace multi_front_end
}; // end namespace core

}; // end namespace behavioural
}; // end namespace morpheo              
