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

#include "Behavioural/Generic/Shifter/include/Shifter.h"

namespace morpheo                    {
namespace behavioural {
namespace generic {
namespace shifter {


  void Shifter::vhdl_body (Vhdl & vhdl)
  {
    //uint32_t log2_size_data = static_cast<uint32_t>(ceil(log2(_param._size_data)));

    vhdl.set_body ("-- Compute all case of shift");

    for (uint32_t i=0; i<_param._nb_port; i++)
      {
	//-----[ Shift logic Left ]--------------------------------------------
	if (_param._have_shift_logic_left)
	  vhdl.set_body ("shift_logic_left_"+toString(i)+"        <= TO_STDLOGICVECTOR(TO_BITVECTOR(in_SHIFTER_DATA_"+toString(i)+") sll CONV_INTEGER(shift_"+toString(i)+"));");
	//-----[ Shift logic Right ]-------------------------------------------
	if (_param._have_shift_logic_right)
	  vhdl.set_body ("shift_logic_right_"+toString(i)+"       <= TO_STDLOGICVECTOR(TO_BITVECTOR(in_SHIFTER_DATA_"+toString(i)+") srl CONV_INTEGER(shift_"+toString(i)+"));");
	//-----[ Shift arithmetic Left ]---------------------------------------
	if (_param._have_shift_arithmetic_left)
	  vhdl.set_body ("shift_arithmetic_left_"+toString(i)+"   <= TO_STDLOGICVECTOR(TO_BITVECTOR(in_SHIFTER_DATA_"+toString(i)+") sla CONV_INTEGER(shift_"+toString(i)+"));");
	//-----[ Shift arithmetic Right ]--------------------------------------
	if (_param._have_shift_arithmetic_right)
	  vhdl.set_body ("shift_arithmetic_right_"+toString(i)+"  <= TO_STDLOGICVECTOR(TO_BITVECTOR(in_SHIFTER_DATA_"+toString(i)+") sra CONV_INTEGER(shift_"+toString(i)+"));");
	//-----[ Rotate Left ]-------------------------------------------------
	if (_param._have_rotate_left)
	  vhdl.set_body ("rotate_left_"+toString(i)+"             <= TO_STDLOGICVECTOR(TO_BITVECTOR(in_SHIFTER_DATA_"+toString(i)+") rol CONV_INTEGER(shift_"+toString(i)+"));");
	//-----[ Rotate Right ]------------------------------------------------
	if (_param._have_rotate_right)
	  vhdl.set_body ("rotate_right_"+toString(i)+"            <= TO_STDLOGICVECTOR(TO_BITVECTOR(in_SHIFTER_DATA_"+toString(i)+") ror CONV_INTEGER(shift_"+toString(i)+"));");
      }

    if (_param._size_data_completion > 0)
      {
	vhdl.set_body ("");
	vhdl.set_body ("-- Mask");

	for (uint32_t i=0; i<_param._nb_port; i++)
	  {
	    string print_shifter_completion;
	    
	    if (_param._type_completion_bool == true)
	      print_shifter_completion = "in_SHIFTER_CARRY_IN";
	    else
	      print_shifter_completion = "in_SHIFTER_COMPLETION";

	    if (_param._size_data == _param._size_data_completion)
	      {
		vhdl.set_body ("shifter_completion_left_"+toString(i)+"  <= "+print_shifter_completion+"_"+toString(i)+";");
		vhdl.set_body ("shifter_completion_right_"+toString(i)+" <= "+print_shifter_completion+"_"+toString(i)+";");
	      }
	    else
	      {
		vhdl.set_body ("shifter_completion_left_"+toString(i)+std_logic_range(_param._size_data-1,_param._size_data_completion)+"  <= "+std_logic_others(_param._size_data-_param._size_data_completion,0)+";");
		vhdl.set_body ("shifter_completion_left_"+toString(i)+std_logic_range(_param._size_data_completion                    )+"  <= "+print_shifter_completion+"_"+toString(i)+";");

		vhdl.set_body ("shifter_completion_right_"+toString(i)+std_logic_range(_param._size_data-1,_param._size_data-_param._size_data_completion)+" <= "+print_shifter_completion+"_"+toString(i)+";");
		vhdl.set_body ("shifter_completion_right_"+toString(i)+std_logic_range(_param._size_data-_param._size_data_completion                    )+" <= "+std_logic_others(_param._size_data-_param._size_data_completion,0)+";");
	      }
	    
 	    vhdl.set_body ("mask_completion_left_"+toString(i)+"     <= TO_STDLOGICVECTOR(TO_BITVECTOR(cst_completion) sll CONV_INTEGER(shift_"+toString(i)+"));");
 	    vhdl.set_body ("mask_completion_right_"+toString(i)+"    <= TO_STDLOGICVECTOR(TO_BITVECTOR(cst_completion) srl CONV_INTEGER(shift_"+toString(i)+"));");
	  }
      }
	      

    vhdl.set_body ("");
    vhdl.set_body ("-- Multiplexor");

    for (uint32_t i=0; i<_param._nb_port; i++)
      {
	vhdl.set_body ("out_SHIFTER_DATA_"+toString(i)+"       <=");
	string print_else = "    ";

	//-----[ Shift arithmetic Left ]---------------------------------------
	if (_param._have_shift_arithmetic_left)
	  {
	    bool   have_when  = false;
	    string print_when = "";
	    string print_and  = "";
	    
	    if (_param._direction   == external_direction)
	      {
		have_when = true;
		print_when += " in_SHIFTER_DIRECTION_"+toString(i)+" = cst_is_direction_left ";
		print_and = " and ";
	      }
	    if (_param._rotate      == external_rotate)
	      {
		have_when = true;
		print_when += print_and+" in_SHIFTER_TYPE_"+toString(i)+" = cst_is_type_shift ";
		print_and = " and ";
	      }
	    if (_param._carry       == external_carry)
	      {
		have_when = true;
		print_when += print_and+" in_SHIFTER_CARRY_"+toString(i)+" = cst_is_carry_arithmetic";
	      }

	    if (have_when)
	      print_when = "when " + print_when;

	    vhdl.set_body ("\t"+print_else+" shift_arithmetic_left_"+toString(i)+"   "+print_when);
	    print_else = "else";
	  }
	//-----[ Shift arithmetic Right ]--------------------------------------
	if (_param._have_shift_arithmetic_right)
	  {
	    bool   have_when  = false;
	    string print_when = "";
	    string print_and  = "";
	    
	    if (_param._direction   == external_direction)
	      {
		have_when = true;
		print_when += " in_SHIFTER_DIRECTION_"+toString(i)+" = cst_is_direction_right";
		print_and = " and ";
	      }
	    if (_param._rotate      == external_rotate)
	      {
		have_when = true;
		print_when += print_and+" in_SHIFTER_TYPE_"+toString(i)+" = cst_is_type_shift ";
		print_and = " and ";
	      }
	    if (_param._carry       == external_carry)
	      {
		have_when = true;
		print_when += print_and+" in_SHIFTER_CARRY_"+toString(i)+" = cst_is_carry_arithmetic";
	      }

	    if (have_when)
	      print_when = "when " + print_when;

	    vhdl.set_body ("\t"+print_else+" shift_arithmetic_right_"+toString(i)+"  "+print_when);
	    print_else = "else";
	  }
	//-----[ Shift logic Left ]--------------------------------------------
	if (_param._have_shift_logic_left)
	  {
	    bool   have_when  = false;
	    string print_when = "";
	    string print_and  = "";
	    
	    if (_param._direction   == external_direction)
	      {
		have_when = true;
		print_when += " in_SHIFTER_DIRECTION_"+toString(i)+" = cst_is_direction_left ";
		print_and = " and ";
	      }
	    if (_param._rotate      == external_rotate)
	      {
		have_when = true;
		print_when += print_and+" in_SHIFTER_TYPE_"+toString(i)+" = cst_is_type_shift ";
		print_and = " and ";
	      }
	    if (_param._carry       == external_carry)
	      {
		have_when = true;
		print_when += print_and+" in_SHIFTER_CARRY_"+toString(i)+" = cst_is_carry_logic     ";
	      }

	    if (have_when)
	      print_when = "when " + print_when;

	    string print_expr_completion;

	    if (_param._size_data_completion == 0)
	      print_expr_completion = "shift_logic_left_"+toString(i)+" ";
	    else
	      print_expr_completion = "(shift_logic_left_"+toString(i)+"  and mask_completion_left_"+toString(i)+" ) or ( shifter_completion_left_"+toString(i)+"  and not mask_completion_left_"+toString(i)+" )";

	    vhdl.set_body ("\t"+print_else+" "+print_expr_completion+"        "+print_when);
	    print_else = "else";
	  }
	//-----[ Shift logic Right ]-------------------------------------------
	if (_param._have_shift_logic_right)
	  {
	    bool   have_when  = false;
	    string print_when = "";
	    string print_and  = "";
	    
	    if (_param._direction   == external_direction)
	      {
		have_when = true;
		print_when += " in_SHIFTER_DIRECTION_"+toString(i)+" = cst_is_direction_right";
		print_and = " and ";
	      }
	    if (_param._rotate      == external_rotate)
	      {
		have_when = true;
		print_when += print_and+" in_SHIFTER_TYPE_"+toString(i)+" = cst_is_type_shift ";
		print_and = " and ";
	      }
	    if (_param._carry       == external_carry)
	      {
		have_when = true;
		print_when += print_and+" in_SHIFTER_CARRY_"+toString(i)+" = cst_is_carry_logic     ";
	      }

	    if (have_when)
	      print_when = "when " + print_when;

	    string print_expr_completion;

	    if (_param._size_data_completion == 0)
	      print_expr_completion = "shift_logic_right_"+toString(i);
	    else
	      print_expr_completion = "(shift_logic_right_"+toString(i)+" and mask_completion_right_"+toString(i)+") or ( shifter_completion_right_"+toString(i)+" and not mask_completion_right_"+toString(i)+")";

	    vhdl.set_body ("\t"+print_else+" "+print_expr_completion+"        "+print_when);
	    print_else = "else";
	  }
	//-----[ Rotate Left ]-------------------------------------------------
	if (_param._have_rotate_left)
	  {
	    bool   have_when  = false;
	    string print_when = "";
	    string print_and  = "";
	    
	    if (_param._direction   == external_direction)
	      {
		have_when = true;
		print_when += " in_SHIFTER_DIRECTION_"+toString(i)+" = cst_is_direction_left ";
		print_and = " and ";
	      }
	    if (_param._rotate      == external_rotate)
	      {
		have_when = true;
		print_when += print_and+" in_SHIFTER_TYPE_"+toString(i)+" = cst_is_type_rotate";
		print_and = " and ";
	      }

	    if (have_when)
	      print_when = "when " + print_when;

	    vhdl.set_body ("\t"+print_else+" rotate_left_"+toString(i)+"             "+print_when);
	    print_else = "else";
	  }
	//-----[ Rotate Right ]------------------------------------------------
	if (_param._have_rotate_right)
	  {
	    bool   have_when  = false;
	    string print_when = "";
	    string print_and  = "";
	    
	    if (_param._direction   == external_direction)
	      {
		have_when = true;
		print_when += " in_SHIFTER_DIRECTION_"+toString(i)+" = cst_is_direction_right";
		print_and = " and ";
	      }
	    if (_param._rotate      == external_rotate)
	      {
		have_when = true;
		print_when += print_and+" in_SHIFTER_TYPE_"+toString(i)+" = cst_is_type_rotate";
		print_and = " and ";
	      }

	    if (have_when)
	      print_when = "when " + print_when;

	    vhdl.set_body ("\t"+print_else+" rotate_right_"+toString(i)+"            "+print_when);
	    print_else = "else";
	  }
	vhdl.set_body (";");
      }
    
  };
  /*
  //-----[ Shift logic Left ]--------------------------------------------
  if (_param._have_shift_logic_left)
    {

    }

  //-----[ Shift logic Right ]-------------------------------------------
  if (_param._have_shift_logic_right)
    {
      
    }

  //-----[ Shift arithmetic Left ]---------------------------------------
  if (_param._have_shift_arithmetic_left)
    {

    }

  //-----[ Shift arithmetic Right ]--------------------------------------
  if (_param._have_shift_arithmetic_right)
    {
      
    }
  
  //-----[ Rotate Left ]-------------------------------------------------
  if (_param._have_rotate_left)
    {
      
    }
  
  //-----[ Rotate Right ]------------------------------------------------
  if (_param._have_rotate_right)
    {
      
    }
  */
}; // end namespace shifter
}; // end namespace generic
}; // end namespace behavioural
}; // end namespace morpheo              
#endif
