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

#include "Behavioural/Generic/RegisterFile/RegisterFile_Multi_Banked/include/RegisterFile_Multi_Banked.h"
#include "Behavioural/Generic/RegisterFile/RegisterFile_Monolithic/include/RegisterFile_Monolithic.h"
#include "Behavioural/Generic/Select/Select_Priority_Fixed/include/Select_Priority_Fixed.h"
#include "Behavioural/include/Vhdl.h"

namespace morpheo                    {
namespace behavioural {
namespace generic {
namespace registerfile {
namespace registerfile_multi_banked {

  void RegisterFile_Multi_Banked::vhdl (void)
  {
    log_printf(FUNC,RegisterFile_Multi_Banked,"vhdl","Begin");
    
    //===================================
    //===== Component               =====
    //===================================

    //----- RegisterFile_Monolithic -----

    morpheo::behavioural::generic::registerfile::registerfile_monolithic::Parameters * param_bank;
    morpheo::behavioural::generic::registerfile::registerfile_monolithic::RegisterFile_Monolithic * bank;
    
    // Create all bank. All bank is identical
    param_bank = new morpheo::behavioural::generic::registerfile::registerfile_monolithic::Parameters
      (_param->_nb_port_read_by_bank
       ,_param->_nb_port_write_by_bank
       ,0 // mixte port
       ,_param->_nb_word/_param->_nb_bank
       ,_param->_size_word);
    
    std::string bank_name = _name + "_bank";
    bank = new morpheo::behavioural::generic::registerfile::registerfile_monolithic::RegisterFile_Monolithic 
      (bank_name.c_str()
#ifdef STATISTICS
       ,NULL
#endif
       ,param_bank
       ,USE_VHDL);
    
    _component->set_component(bank->_component
#ifdef POSITION
			      , 0, 0, 0, 0
#endif
			      , INSTANCE_LIBRARY
			      );
    

    //----- Select_Priority_Fixed -----

    // Create all select_unit :
    //  * 4 units : to the read port, "quotient" ports and "rest" ports. Idem to the write port.
    //  * for a FULL_CROSSBAR, there are no "rest" ports
    uint32_t nb_select_port_1 ;
    uint32_t nb_select_port_2 ;
    uint32_t nb_select_port_3 ;
    uint32_t nb_select_port_4 ;
      
    if (_param->_crossbar == FULL_CROSSBAR)
      {
	nb_select_port_1 = _param->_nb_port_read ;
	nb_select_port_3 = _param->_nb_port_write;
	nb_select_port_2 = nb_select_port_4 = 0;
      }
    else
      {
	nb_select_port_2=(_param->_nb_port_read                  )/_param->_nb_port_read_by_bank;
	nb_select_port_1=((_param->_nb_port_read%_param->_nb_port_read_by_bank)==0)?0:(nb_select_port_2+1);
	nb_select_port_4=(_param->_nb_port_write                 )/_param->_nb_port_write_by_bank;
	nb_select_port_3=((_param->_nb_port_write%_param->_nb_port_write_by_bank)==0)?0:(nb_select_port_4+1);
      }
      
//     cout << "nb_select_port_1 : " << nb_select_port_1 << endl;
//     cout << "nb_select_port_2 : " << nb_select_port_2 << endl;
//     cout << "nb_select_port_3 : " << nb_select_port_3 << endl;
//     cout << "nb_select_port_4 : " << nb_select_port_4 << endl;
    
    morpheo::behavioural::generic::select::select_priority_fixed::Parameters *param_select1 = NULL;
    morpheo::behavioural::generic::select::select_priority_fixed::Parameters *param_select2 = NULL;
    morpheo::behavioural::generic::select::select_priority_fixed::Parameters *param_select3 = NULL;
    morpheo::behavioural::generic::select::select_priority_fixed::Parameters *param_select4 = NULL;

    morpheo::behavioural::generic::select::select_priority_fixed::Select_Priority_Fixed *select1 = NULL;
    morpheo::behavioural::generic::select::select_priority_fixed::Select_Priority_Fixed *select2 = NULL;
    morpheo::behavioural::generic::select::select_priority_fixed::Select_Priority_Fixed *select3 = NULL;
    morpheo::behavioural::generic::select::select_priority_fixed::Select_Priority_Fixed *select4 = NULL;

    bool have_select1 = ((nb_select_port_1 != 0               ));
    bool have_select2 = ((nb_select_port_2 != 0               ) and
			 (nb_select_port_2 != nb_select_port_1)); 
    bool have_select3 = ((nb_select_port_3 != 0               ) and
			 (nb_select_port_3 != nb_select_port_2) and
			 (nb_select_port_3 != nb_select_port_1));
    bool have_select4 = ((nb_select_port_4 != 0               ) and
			 (nb_select_port_4 != nb_select_port_3) and
			 (nb_select_port_4 != nb_select_port_2) and
			 (nb_select_port_4 != nb_select_port_1) );

    std::string select_name1;
    std::string select_name2;
    std::string select_name3;
    std::string select_name4;
    
    if (have_select1)
      {
	select_name1  = _name+"_select_"+toString(nb_select_port_1)+"_ports";
	param_select1 = new morpheo::behavioural::generic::select::select_priority_fixed::Parameters (nb_select_port_1,true, false);
	select1       = new morpheo::behavioural::generic::select::select_priority_fixed::Select_Priority_Fixed 
	  (select_name1.c_str()
#ifdef STATISTICS
	   ,NULL
#endif
	   ,param_select1
	   ,USE_VHDL);

	_component->set_component(select1->_component
#ifdef POSITION
				  , 0, 0, 0, 0
#endif
				  , INSTANCE_LIBRARY
				  );
      }

    if (have_select2)
      {
	select_name2  = _name+"_select_"+toString(nb_select_port_2)+"_ports";
	
	param_select2 = new morpheo::behavioural::generic::select::select_priority_fixed::Parameters (nb_select_port_2,true, false);
	select2       = new morpheo::behavioural::generic::select::select_priority_fixed::Select_Priority_Fixed 
	  (select_name2.c_str()
#ifdef STATISTICS
	   ,NULL
#endif
	   ,param_select2
	   ,USE_VHDL);
      
	_component->set_component(select2->_component
#ifdef POSITION
				  , 0, 0, 0, 0
#endif
				  , INSTANCE_LIBRARY
				  );
      }

    if (have_select3)
      {
	select_name3  = _name+"_select_"+toString(nb_select_port_3)+"_ports";
	
	param_select3 = new morpheo::behavioural::generic::select::select_priority_fixed::Parameters (nb_select_port_3,true, false);
	select3       = new morpheo::behavioural::generic::select::select_priority_fixed::Select_Priority_Fixed 
	  (select_name3.c_str()
#ifdef STATISTICS
	   ,NULL
#endif
	   ,param_select3
	   ,USE_VHDL);

	_component->set_component(select3->_component
#ifdef POSITION
				  , 0, 0, 0, 0
#endif
				  , INSTANCE_LIBRARY
				  );
      }
    
    if (have_select4)
      {
	select_name4  = _name+"_select_"+toString(nb_select_port_4)+"_ports";
	
	param_select4 = new morpheo::behavioural::generic::select::select_priority_fixed::Parameters (nb_select_port_4,true, false);
	select4       = new morpheo::behavioural::generic::select::select_priority_fixed::Select_Priority_Fixed 
	  (select_name4.c_str()
#ifdef STATISTICS
	   ,NULL
#endif
	   ,param_select4
	   ,USE_VHDL);
      
      	_component->set_component(select4->_component
#ifdef POSITION
				  , 0, 0, 0, 0
#endif
				  , INSTANCE_LIBRARY
				  );
      }
    
    Vhdl * vhdl = new Vhdl (_name);

    _interfaces->set_port(vhdl);
    _component->vhdl_instance(vhdl);

    vhdl_declaration (vhdl);
    vhdl_body        (vhdl);

    vhdl->generate_file();

    delete vhdl;
    delete bank;
    delete param_bank;
    if (have_select1)
      {
	delete select1;
	delete param_select1;
      }
    if (have_select2)
      {
	delete select2;
	delete param_select2;
      }
    if (have_select3)
      {
	delete select3;
	delete param_select3;
      }
    if (have_select4)
      {
	delete select4;
	delete param_select4;
      }

    log_printf(FUNC,RegisterFile_Multi_Banked,"vhdl","End");
  };

}; // end namespace registerfile_multi_banked
}; // end namespace registerfile
}; // end namespace generic

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