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

#include "Behavioural/Core/Multi_Execute_loop/Execute_loop/Multi_Read_unit/Read_unit/Reservation_station/include/Reservation_station.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_execute_loop {
namespace execute_loop {
namespace multi_read_unit {
namespace read_unit {
namespace reservation_station {

#undef  FUNCTION
#define FUNCTION "Reservation_station::vhdl_body"
  void Reservation_station::vhdl_body (Vhdl * & vhdl)
  {
    std::string range_retire, range_insert;

    if (_param->_size_queue == 1)
      range_insert = "(0)";
    else
      range_insert = "(conv_integer(internal_INSERT_SLOT"+std_logic_range(log2(_param->_size_queue))+"))";

    log_printf(FUNC,Reservation_station,FUNCTION,"Begin");

    vhdl->set_body ("-----------------------------------");
    vhdl->set_body ("-- interface 'INSERT'");
    vhdl->set_body ("-----------------------------------");
    vhdl->set_body ("");
    vhdl->set_body ("     out_INSERT_ACK          <= not internal_FULL;");
    vhdl->set_body ("internal_INSERT_TRANSACTION  <= not internal_FULL and in_INSERT_VAL;");
    
    vhdl->set_body ("internal_INSERT_SLOT         <=");
    for (uint32_t i=0; i<_param->_size_queue; i++)
      {
	vhdl->set_body ("\t"+std_logic_conv(log2(_param->_size_queue+1),i)+" when reg_VAL("+toString(i)+")='0' else");
      }
    vhdl->set_body ("\t"+std_logic_conv(log2(_param->_size_queue+1),_param->_size_queue)+";");

    vhdl->set_body ("");
    vhdl->set_body ("-----------------------------------");
    vhdl->set_body ("-- interface 'RETIRE'");
    vhdl->set_body ("-----------------------------------");
    vhdl->set_body ("");
    for (uint32_t i=0; i<_param->_nb_inst_retire; i++)
      vhdl->set_body ("internal_RETIRE_TRANSACTION_"+toString(i)+"<= not internal_RETIRE_SLOT_"+toString(i)+std_logic_range(log2(_param->_size_queue)+1,log2(_param->_size_queue),log2(_param->_size_queue))+" and in_RETIRE_"+toString(i)+"_ACK;");
    vhdl->set_body ("");

    uint32_t nb_slot_scan = _param->_size_queue-_param->_nb_inst_retire+1;
    for (uint32_t i=0; i<_param->_nb_inst_retire; i++)
      {
	vhdl->set_body ("internal_RETIRE_SLOT_"+toString(i)+"       <= ");
	for (uint32_t j=i; j<nb_slot_scan+i; j++)
	  {
	    vhdl->set_body ("\t"+std_logic_conv(log2(_param->_size_queue+1),j)+" when");
	    for (uint32_t k=0; k<i; k++)
	      {
		vhdl->set_body ("\t\tnot (internal_RETIRE_SLOT_"+toString(k)+std_logic_range(log2(_param->_size_queue)+1,log2(_param->_size_queue)-1,0)+" = "+std_logic_conv(log2(_param->_size_queue),j)+std_logic_range(log2(_param->_size_queue))+") and");
	      }
	    vhdl->set_body ("\t\t(reg_VAL        ("+toString(j)+")='1') and");
	    vhdl->set_body ("\t\t(reg_DATA_RA_VAL("+toString(j)+")='1') and");
	    vhdl->set_body ("\t\t(reg_DATA_RB_VAL("+toString(j)+")='1') and");
	    vhdl->set_body ("\t\t(reg_DATA_RC_VAL("+toString(j)+")='1') else");
	  }
	vhdl->set_body ("\t"+std_logic_conv(log2(_param->_size_queue+1),_param->_size_queue)+";");
	vhdl->set_body ("");
      }

    for (uint32_t i=0; i<_param->_nb_inst_retire; i++)
      {
	if (_param->_size_queue == 1)
	  range_retire = "(0)";
	else
	  range_retire = "(conv_integer(internal_RETIRE_SLOT_"+toString(i)+std_logic_range(log2(_param->_size_queue)+1,log2(_param->_size_queue)-1,0)+"))";

	vhdl->set_body ("out_RETIRE_"+toString(i)+"_VAL             <= not internal_RETIRE_SLOT_"+toString(i)+std_logic_range(log2(_param->_size_queue)+1,log2(_param->_size_queue),log2(_param->_size_queue))+";");
	if (_param->_have_port_context_id)			    
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_CONTEXT_ID      <= reg_CONTEXT_ID   "+range_retire+";");
	if (_param->_have_port_front_end_id)			    
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_FRONT_END_ID    <= reg_FRONT_END_ID "+range_retire+";");
	if (_param->_have_port_ooo_engine_id)			    
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_OOO_ENGINE_ID   <= reg_OOO_ENGINE_ID"+range_retire+";");
	if (_param->_have_port_rob_id)				    
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_ROB_ID          <= reg_ROB_ID       "+range_retire+";");
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_OPERATION       <= reg_OPERATION    "+range_retire+";");
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_TYPE            <= reg_TYPE         "+range_retire+";");
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_HAS_IMMEDIAT    <= reg_HAS_IMMEDIAT "+range_retire+";");
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_IMMEDIAT        <= reg_IMMEDIAT     "+range_retire+";");
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_DATA_RA         <= reg_DATA_RA      "+range_retire+";");
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_DATA_RB         <= reg_DATA_RB      "+range_retire+";");
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_DATA_RC         <= reg_DATA_RC      "+range_retire+";");
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_WRITE_RD        <= reg_WRITE_RD     "+range_retire+";");
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_NUM_REG_RD      <= reg_NUM_REG_RD   "+range_retire+";");
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_WRITE_RE        <= reg_WRITE_RE     "+range_retire+";");
	vhdl->set_body ("out_RETIRE_"+toString(i)+"_NUM_REG_RE      <= reg_NUM_REG_RE   "+range_retire+";");
	vhdl->set_body ("");
      }

//     vhdl->set_body ("-----------------------------------");
//     vhdl->set_body ("-- flags");
//     vhdl->set_body ("-----------------------------------");
//     vhdl->set_body ("");
//     vhdl->set_body ("internal_EMPTY <=");
//     for (uint32_t i=_param->_size_queue-1; i>0; i--)
//       vhdl->set_body ("\tnot reg_VAL ("+toString(i)+") and");
//     vhdl->set_body ("\tnot reg_VAL (0);");
//     vhdl->set_body ("internal_FULL  <=");
//     for (uint32_t i=_param->_size_queue-1; i>0; i--)
//       vhdl->set_body ("\t    reg_VAL ("+toString(i)+") and");
//     vhdl->set_body ("\t    reg_VAL (0);");

    vhdl->set_body ("");
    vhdl->set_body ("-----------------------------------");
    vhdl->set_body ("-- transition");
    vhdl->set_body ("-----------------------------------");
    vhdl->set_body ("");
    vhdl->set_body ("transition: process (in_CLOCK)");
    vhdl->set_body ("begin  -- process transition");
    vhdl->set_body ("\tif in_CLOCK'event and in_CLOCK = '1' then");
    vhdl->set_body ("");
    vhdl->set_body ("\t\tif (in_NRESET = '0') then");    
    for (uint32_t i=0; i<_param->_size_queue; i++)
      {
	vhdl->set_body ("\t\t\treg_VAL ("+toString(i)+")<= '0';");
      }
    vhdl->set_body ("\t\telse");


    vhdl->set_body ("");
    vhdl->set_body ("\t\t\t-----------------------------------");
    vhdl->set_body ("\t\t\t-- bypass");
    vhdl->set_body ("\t\t\t-----------------------------------");
    vhdl->set_body ("");
    vhdl->set_body ("\t\t\t-- interface : 'GPR_WRITE'");
    for (uint32_t i=0; i<_param->_nb_gpr_write; i++)
      {
	vhdl->set_body ("\t\t\tif (in_GPR_WRITE_"+toString(i)+"_VAL = '1') then");
	vhdl->set_body ("\t\t\t\t-- scan all entry (don't test if entry is valid)");
	for (uint32_t j=0; j<_param->_size_queue; j++)
	  {
	    if (_param->_have_port_ooo_engine_id)
	      vhdl->set_body ("\t\t\t\tif (in_GPR_WRITE_"+toString(i)+"_OOO_ENGINE_ID = reg_OOO_ENGINE_ID ("+toString(j)+")) then");
	    vhdl->set_body ("\t\t\t\t\tif (in_GPR_WRITE_"+toString(i)+"_NUM_REG = reg_NUM_REG_RA ("+toString(j)+")) then");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RA_VAL ("+toString(j)+") <= '1';");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RA     ("+toString(j)+") <= in_GPR_WRITE_"+toString(i)+"_DATA;");
	    vhdl->set_body ("\t\t\t\t\tend if;");    

	    vhdl->set_body ("\t\t\t\t\tif (in_GPR_WRITE_"+toString(i)+"_NUM_REG = reg_NUM_REG_RB ("+toString(j)+")) then");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RB_VAL ("+toString(j)+") <= '1';");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RB     ("+toString(j)+") <= in_GPR_WRITE_"+toString(i)+"_DATA;");
	    vhdl->set_body ("\t\t\t\t\tend if;");    

	    if (_param->_have_port_ooo_engine_id)
	      vhdl->set_body ("\t\t\t\tend if;");    
	  }
	vhdl->set_body ("\t\t\tend if;");    
      }

    vhdl->set_body ("\t\t\t-- interface : 'SPR_WRITE'");
    for (uint32_t i=0; i<_param->_nb_spr_write; i++)
      {
	vhdl->set_body ("\t\t\tif (in_SPR_WRITE_"+toString(i)+"_VAL = '1') then");
	vhdl->set_body ("\t\t\t\t-- scan all entry (don't test if entry is valid)");
	for (uint32_t j=0; j<_param->_size_queue; j++)
	  {
	    if (_param->_have_port_ooo_engine_id)
	      vhdl->set_body ("\t\t\t\tif (in_SPR_WRITE_"+toString(i)+"_OOO_ENGINE_ID = reg_OOO_ENGINE_ID ("+toString(j)+")) then");
	    vhdl->set_body ("\t\t\t\t\tif (in_SPR_WRITE_"+toString(i)+"_NUM_REG = reg_NUM_REG_RC ("+toString(j)+")) then");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RC_VAL ("+toString(j)+") <= '1';");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RC     ("+toString(j)+") <= in_SPR_WRITE_"+toString(i)+"_DATA;");
	    vhdl->set_body ("\t\t\t\t\tend if;");    

	    if (_param->_have_port_ooo_engine_id)
	      vhdl->set_body ("\t\t\t\tend if;");    
	  }
	vhdl->set_body ("\t\t\tend if;");    
      }

    vhdl->set_body ("\t\t\t-- interface : 'BYPASS_WRITE_GPR'");
    for (uint32_t i=0; i<_param->_nb_bypass_write; i++)
      {
	vhdl->set_body ("\t\t\tif (in_BYPASS_WRITE_"+toString(i)+"_GPR_VAL = '1') then");
	vhdl->set_body ("\t\t\t\t-- scan all entry (don't test if entry is valid)");
	for (uint32_t j=0; j<_param->_size_queue; j++)
	  {
	    if (_param->_have_port_ooo_engine_id)
	      vhdl->set_body ("\t\t\t\tif (in_BYPASS_WRITE_"+toString(i)+"_OOO_ENGINE_ID = reg_OOO_ENGINE_ID ("+toString(j)+")) then");
	    vhdl->set_body ("\t\t\t\t\tif (in_BYPASS_WRITE_"+toString(i)+"_GPR_NUM_REG = reg_NUM_REG_RA ("+toString(j)+")) then");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RA_VAL ("+toString(j)+") <= '1';");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RA     ("+toString(j)+") <= in_BYPASS_WRITE_"+toString(i)+"_GPR_DATA;");
	    vhdl->set_body ("\t\t\t\t\tend if;");    

	    vhdl->set_body ("\t\t\t\t\tif (in_BYPASS_WRITE_"+toString(i)+"_GPR_NUM_REG = reg_NUM_REG_RB ("+toString(j)+")) then");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RB_VAL ("+toString(j)+") <= '1';");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RB     ("+toString(j)+") <= in_BYPASS_WRITE_"+toString(i)+"_GPR_DATA;");
	    vhdl->set_body ("\t\t\t\t\tend if;");    

	    if (_param->_have_port_ooo_engine_id)
	      vhdl->set_body ("\t\t\t\tend if;");    
	  }
	vhdl->set_body ("\t\t\tend if;");    
      }

    vhdl->set_body ("\t\t\t-- interface : 'BYPASS_WRITE_SPR'");
    for (uint32_t i=0; i<_param->_nb_bypass_write; i++)
      {
	vhdl->set_body ("\t\t\tif (in_BYPASS_WRITE_"+toString(i)+"_SPR_VAL = '1') then");
	vhdl->set_body ("\t\t\t\t-- scan all entry (don't test if entry is valid)");
	for (uint32_t j=0; j<_param->_size_queue; j++)
	  {
	    if (_param->_have_port_ooo_engine_id)
	      vhdl->set_body ("\t\t\t\tif (in_BYPASS_WRITE_"+toString(i)+"_OOO_ENGINE_ID = reg_OOO_ENGINE_ID ("+toString(j)+")) then");
	    vhdl->set_body ("\t\t\t\t\tif (in_BYPASS_WRITE_"+toString(i)+"_SPR_NUM_REG = reg_NUM_REG_RC ("+toString(j)+")) then");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RC_VAL ("+toString(j)+") <= '1';");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RC     ("+toString(j)+") <= in_BYPASS_WRITE_"+toString(i)+"_SPR_DATA;");
	    vhdl->set_body ("\t\t\t\t\tend if;");    

	    if (_param->_have_port_ooo_engine_id)
	      vhdl->set_body ("\t\t\t\tend if;");    
	  }
	vhdl->set_body ("\t\t\tend if;");    
      }

    vhdl->set_body ("\t\t\t-- interface : 'BYPASS_MEMORY_GPR'");
    for (uint32_t i=0; i<_param->_nb_bypass_memory; i++)
      {
	vhdl->set_body ("\t\t\tif (in_BYPASS_MEMORY_"+toString(i)+"_VAL = '1') then");
	vhdl->set_body ("\t\t\t\t-- scan all entry (don't test if entry is valid)");
	for (uint32_t j=0; j<_param->_size_queue; j++)
	  {
	    if (_param->_have_port_ooo_engine_id)
	      vhdl->set_body ("\t\t\t\tif (in_BYPASS_MEMORY_"+toString(i)+"_OOO_ENGINE_ID = reg_OOO_ENGINE_ID ("+toString(j)+")) then");
	    vhdl->set_body ("\t\t\t\t\tif (in_BYPASS_MEMORY_"+toString(i)+"_NUM_REG = reg_NUM_REG_RA ("+toString(j)+")) then");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RA_VAL ("+toString(j)+") <= '1';");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RA     ("+toString(j)+") <= in_BYPASS_MEMORY_"+toString(i)+"_DATA;");
	    vhdl->set_body ("\t\t\t\t\tend if;");    

	    vhdl->set_body ("\t\t\t\t\tif (in_BYPASS_MEMORY_"+toString(i)+"_NUM_REG = reg_NUM_REG_RB ("+toString(j)+")) then");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RB_VAL ("+toString(j)+") <= '1';");
	    vhdl->set_body ("\t\t\t\t\t\treg_DATA_RB     ("+toString(j)+") <= in_BYPASS_MEMORY_"+toString(i)+"_DATA;");
	    vhdl->set_body ("\t\t\t\t\tend if;");    

	    if (_param->_have_port_ooo_engine_id)
	      vhdl->set_body ("\t\t\t\tend if;");    
	  }
	vhdl->set_body ("\t\t\tend if;");    
      }

    vhdl->set_body ("");
    vhdl->set_body ("\t\t\t-- interface : 'INSERT'");
    vhdl->set_body ("\t\t\tif (internal_INSERT_TRANSACTION = '1') then");



    vhdl->set_body ("\t\t\t\treg_VAL           "+range_insert+" <= '1';");

    if (_param->_have_port_context_id)
    vhdl->set_body ("\t\t\t\treg_CONTEXT_ID    "+range_insert+" <= in_INSERT_CONTEXT_ID   ;");
    if (_param->_have_port_front_end_id)
    vhdl->set_body ("\t\t\t\treg_FRONT_END_ID  "+range_insert+" <= in_INSERT_FRONT_END_ID ;");
    if (_param->_have_port_ooo_engine_id)
    vhdl->set_body ("\t\t\t\treg_OOO_ENGINE_ID "+range_insert+" <= in_INSERT_OOO_ENGINE_ID;");
    if (_param->_have_port_rob_id)
    vhdl->set_body ("\t\t\t\treg_ROB_ID        "+range_insert+" <= in_INSERT_ROB_ID       ;");
    vhdl->set_body ("\t\t\t\treg_OPERATION     "+range_insert+" <= in_INSERT_OPERATION    ;");
    vhdl->set_body ("\t\t\t\treg_TYPE          "+range_insert+" <= in_INSERT_TYPE         ;");
    vhdl->set_body ("\t\t\t\treg_HAS_IMMEDIAT  "+range_insert+" <= in_INSERT_HAS_IMMEDIAT ;");
    vhdl->set_body ("\t\t\t\treg_IMMEDIAT      "+range_insert+" <= in_INSERT_IMMEDIAT     ;");
    vhdl->set_body ("\t\t\t\treg_NUM_REG_RA    "+range_insert+" <= in_INSERT_NUM_REG_RA   ;");
    vhdl->set_body ("\t\t\t\treg_DATA_RA_VAL   "+range_insert+" <= in_INSERT_DATA_RA_VAL  ;");
    vhdl->set_body ("\t\t\t\treg_DATA_RA       "+range_insert+" <= in_INSERT_DATA_RA      ;");
    vhdl->set_body ("\t\t\t\treg_NUM_REG_RB    "+range_insert+" <= in_INSERT_NUM_REG_RB   ;");
    vhdl->set_body ("\t\t\t\treg_DATA_RB_VAL   "+range_insert+" <= in_INSERT_DATA_RB_VAL  ;");
    vhdl->set_body ("\t\t\t\treg_DATA_RB       "+range_insert+" <= in_INSERT_DATA_RB      ;");
    vhdl->set_body ("\t\t\t\treg_NUM_REG_RC    "+range_insert+" <= in_INSERT_NUM_REG_RC   ;");
    vhdl->set_body ("\t\t\t\treg_DATA_RC_VAL   "+range_insert+" <= in_INSERT_DATA_RC_VAL  ;");
    vhdl->set_body ("\t\t\t\treg_DATA_RC       "+range_insert+" <= in_INSERT_DATA_RC      ;");
    vhdl->set_body ("\t\t\t\treg_WRITE_RD      "+range_insert+" <= in_INSERT_WRITE_RD     ;");
    vhdl->set_body ("\t\t\t\treg_NUM_REG_RD    "+range_insert+" <= in_INSERT_NUM_REG_RD   ;");
    vhdl->set_body ("\t\t\t\treg_WRITE_RE      "+range_insert+" <= in_INSERT_WRITE_RE     ;");
    vhdl->set_body ("\t\t\t\treg_NUM_REG_RE    "+range_insert+" <= in_INSERT_NUM_REG_RE   ;");
    vhdl->set_body ("\t\t\tend if;");    

    vhdl->set_body ("");
    vhdl->set_body ("\t\t\t-- interface : 'RETIRE'");
    for (uint32_t i=0; i<_param->_nb_inst_retire; i++)
      {
	if (_param->_size_queue == 1)
	  range_retire = "(0)";
	else
	  range_retire = "(conv_integer(internal_RETIRE_SLOT_"+toString(i)+std_logic_range(log2(_param->_size_queue)+1,log2(_param->_size_queue)-1,0)+"))";

	vhdl->set_body ("\t\t\tif (internal_RETIRE_TRANSACTION_"+toString(i)+" = '1') then");
	
	vhdl->set_body ("\t\t\t\treg_VAL "+range_retire+" <= '0';");
	vhdl->set_body ("\t\t\tend if;");    
      }

    vhdl->set_body ("");
    vhdl->set_body ("\t\tend if;");
    vhdl->set_body ("");
    vhdl->set_body ("\tend if;");
    vhdl->set_body ("end process transition;");

    log_printf(FUNC,Reservation_station,FUNCTION,"End");
  };

}; // end namespace reservation_station
}; // end namespace read_unit
}; // end namespace multi_read_unit
}; // end namespace execute_loop
}; // end namespace multi_execute_loop
}; // end namespace core

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