#ifdef VHDL
/*
 * $Id: Queue_vhdl_body.cpp 103 2009-01-16 16:55:32Z moulu $
 *
 * [ Description ]
 * 
 */

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

namespace morpheo                    {
namespace behavioural {
namespace generic {
namespace queue {


#undef  FUNCTION
#define FUNCTION "Queue::vhdl_body"
  void Queue::vhdl_body (Vhdl * & vhdl)
  {
    log_printf(FUNC,Queue,FUNCTION,"Begin");
    vhdl->set_comment(0,"---------------------------------------------------------------------------");
    vhdl->set_comment(0," Output");
    vhdl->set_comment(0,"---------------------------------------------------------------------------");
    vhdl->set_body   (0,"out_INSERT_ACK        <= not signal_FULL;");
    vhdl->set_body   (0,"out_RETIRE_VAL        <= not signal_EMPTY;");
        
    if (_param->_size_queue > 1)
    vhdl->set_body   (0,"out_RETIRE_DATA       <= reg_DATA(conv_integer(signal_PTR_READ));");
    else
    vhdl->set_body   (0,"out_RETIRE_DATA       <= reg_DATA(0);");

    vhdl->set_body   (0,"");
    vhdl->set_comment(0,"---------------------------------------------------------------------------");
    vhdl->set_comment(0," Slot");
    vhdl->set_comment(0,"---------------------------------------------------------------------------");
    vhdl->set_body   (0,"");
    if (_param->_nb_port_slot > 1)
      for (uint32_t i=0; i<_param->_nb_port_slot; ++i)
        if (i==0)
          vhdl->set_body   (0,"signal_SLOT_0           <= signal_PTR_READ;");
        else
          {
            if (is_power2(_param->_size_queue))
              vhdl->set_body   (0,"signal_SLOT_"+toString(i)+"           <= signal_PTR_READ+"+std_logic_cst(log2(_param->_size_queue),i)+";");
            else
              vhdl->set_body   (0,"signal_SLOT_"+toString(i)+"           <= const_PTR_INIT when signal_SLOT_"+toString(i-1)+" = const_PTR_MAX else signal_SLOT_"+toString(i-1)+"+'1';");

          }
        
    for (uint32_t i=0; i<_param->_nb_port_slot; ++i)
      {
        if (_param->_nb_port_slot > 1)
          vhdl->set_body   (0,"signal_SLOT_"+toString(i)+"_VAL     <= '1' when reg_NB_ELT > "+std_logic_cst(log2(_param->_size_queue+1),i)+" else '0';");
        else
          vhdl->set_body   (0,"signal_SLOT_"+toString(i)+"_VAL     <= not signal_EMPTY;");
        
        vhdl->set_body   (0,"out_SLOT_"+toString(i)+"_VAL        <= signal_SLOT_"+toString(i)+"_VAL;");
        
#ifdef SYSTEMC_VHDL_COMPATIBILITY
        std::string str_val_disable=std_logic_cst(_param->_size_data,0)+" when signal_SLOT_"+toString(i)+"_VAL='0' else";
#endif
        if (_param->_nb_port_slot > 1)
          {
            vhdl->set_body   (0,"out_SLOT_"+toString(i)+"_DATA       <= ");
#ifdef SYSTEMC_VHDL_COMPATIBILITY
            vhdl->set_body   (1,str_val_disable);
#endif
            vhdl->set_body   (1,"reg_DATA(conv_integer(signal_SLOT_"+toString(i)+"));");
          }
        else
          if (_param->_size_queue > 1)
            {
              vhdl->set_body   (0,"out_SLOT_"+toString(i)+"_DATA       <=");
#ifdef SYSTEMC_VHDL_COMPATIBILITY
              vhdl->set_body   (1,str_val_disable);
#endif
              vhdl->set_body   (1,"reg_DATA(conv_integer(signal_PTR_READ));");
            }
          else
            {
              vhdl->set_body   (0,"out_SLOT_"+toString(i)+"_DATA       <=");
#ifdef SYSTEMC_VHDL_COMPATIBILITY
              vhdl->set_body   (1,str_val_disable);
#endif
              vhdl->set_body   (1,"reg_DATA(conv_integer(0));");
            }
      }

    if (_param->_have_port_ptr)
      {
    vhdl->set_body   (0,"");
    vhdl->set_comment(0,"---------------------------------------------------------------------------");
    vhdl->set_comment(0," Slot");
    vhdl->set_comment(0,"---------------------------------------------------------------------------");
    vhdl->set_body   (0,"");
    if (_param->_have_port_ptr_write)
    vhdl->set_body   (0,"out_PTR_WRITE         <= signal_PTR_WRITE;");
    if (_param->_have_port_ptr_read)
    vhdl->set_body   (0,"out_PTR_READ          <= signal_PTR_READ;");
      }

    vhdl->set_body   (0,"");
    vhdl->set_comment(0,"---------------------------------------------------------------------------");
    vhdl->set_comment(0," Signal");
    vhdl->set_comment(0,"---------------------------------------------------------------------------");
    vhdl->set_body   (0,"");
    vhdl->set_body   (0,"signal_READ           <= (not signal_EMPTY) and in_RETIRE_ACK;");
    vhdl->set_body   (0,"signal_WRITE          <= (not signal_FULL ) and in_INSERT_VAL;");
    vhdl->set_body   (0,"");
    if (_param->_nb_port_slot>1)
      {
        vhdl->set_body   (0,"signal_EMPTY          <= '1' when reg_NB_ELT = "+std_logic_cst(log2(_param->_size_queue+1),0)+" else '0';");
    if (is_power2(_param->_size_queue))
    vhdl->set_body   (0,"signal_FULL           <= reg_NB_ELT "+std_logic_range(log2(_param->_size_queue),log2(_param->_size_queue))+";");
    else
      vhdl->set_body   (0,"signal_FULL           <= '1' when reg_NB_ELT = "+std_logic_cst(log2(_param->_size_queue+1),_param->_size_queue)+" else '0';");
      }
    else
      {
    vhdl->set_body   (0,"signal_EMPTY          <= reg_EMPTY;");
    vhdl->set_body   (0,"signal_FULL           <= reg_FULL ;");
      }
    vhdl->set_body   (0,"");
    if (_param->_size_queue > 1)
      {
    vhdl->set_body   (0,"signal_PTR_READ       <= reg_PTR_READ;");
    if (_param->_nb_port_slot>1)
      {
        if (is_power2(_param->_size_queue))
          vhdl->set_body   (0,"signal_PTR_WRITE      <= reg_PTR_READ + reg_NB_ELT"+std_logic_range(log2(_param->_size_queue))+";");
        else
          vhdl->set_body   (0,"signal_PTR_WRITE      <= reg_PTR_READ + reg_NB_ELT"+std_logic_range(log2(_param->_size_queue))+" when reg_PTR_READ + reg_NB_ELT"+std_logic_range(log2(_param->_size_queue)) +" <= const_PTR_MAX else reg_PTR_READ + reg_NB_ELT"+std_logic_range(log2(_param->_size_queue))+" - const_PTR_MAX-'1';");
      }
    else
    vhdl->set_body   (0,"signal_PTR_WRITE      <= reg_PTR_WRITE;");
      }
    vhdl->set_body   (0,"");

    if (_param->_nb_port_slot>1)
      {
    vhdl->set_body   (0,"");
    vhdl->set_comment(0," nb_elt");
    if (_param->_size_queue > 1)
      {  
    vhdl->set_body   (0,"signal_NEXT_NB_ELT  <= ");
    vhdl->set_body   (1,"reg_NB_ELT   when (signal_READ xor signal_WRITE) = '0' else");
    if (_param->_size_queue > 2)
      {
    vhdl->set_body   (1,"reg_NB_ELT +'1' when signal_WRITE='1' else");
    vhdl->set_body   (1,"reg_NB_ELT -'1';");
      }
    else
    vhdl->set_body   (1,"not reg_NB_ELT;");
      }
      }
    else
      {
    vhdl->set_body   (0,"signal_PTR_EQUAL      <=");
    if (_param->_size_queue > 1)
      {
    vhdl->set_body   (1,"'1' when signal_NEXT_PTR_READ = signal_NEXT_PTR_WRITE else");
    vhdl->set_body   (1,"'0';");
      }
    else
    vhdl->set_body   (1,"'1';");
    vhdl->set_body   (0,"signal_NEXT_FULL      <=");
    vhdl->set_body   (1,"'1' when signal_WRITE='1' and signal_PTR_EQUAL='1' else");
    vhdl->set_body   (1,"'0' when signal_READ ='1'                          else");
    vhdl->set_body   (1,"reg_FULL ;");
    vhdl->set_body   (0,"signal_NEXT_EMPTY     <=");
    vhdl->set_body   (1,"'1' when signal_READ ='1' and signal_PTR_EQUAL='1' else");
    vhdl->set_body   (1,"'0' when signal_WRITE='1'                          else");
    vhdl->set_body   (1,"reg_EMPTY;");
    vhdl->set_body   (0,"");

    vhdl->set_comment(0," write");
    if (_param->_size_queue > 1)
      {
    vhdl->set_body   (0,"signal_NEXT_PTR_WRITE <= ");
    vhdl->set_body   (1,"reg_PTR_WRITE  when signal_WRITE='0' else");
    if (is_log2(_param->_size_queue) == false)
    vhdl->set_body   (1,"const_PTR_INIT when reg_PTR_WRITE = const_PTR_MAX else");
    if (_param->_size_queue > 2)
    vhdl->set_body   (1,"reg_PTR_WRITE+'1';");
    else
    vhdl->set_body   (1,"not reg_PTR_WRITE;");
      }
      }

    vhdl->set_body   (0,"");
    vhdl->set_comment(0," read");
    if (_param->_size_queue > 1)
      {  
    vhdl->set_body   (0,"signal_NEXT_PTR_READ  <= ");
    vhdl->set_body   (1,"reg_PTR_READ   when signal_READ='0' else");
    if (is_log2(_param->_size_queue) == false)
    vhdl->set_body   (1,"const_PTR_INIT when reg_PTR_READ  = const_PTR_MAX else");

    if (_param->_size_queue > 2)
    vhdl->set_body   (1,"reg_PTR_READ +'1';");
    else
    vhdl->set_body   (1,"not reg_PTR_READ;");
      }
    vhdl->set_body   (0,"");

    vhdl->set_comment(0,"---------------------------------------------------------------------------");
    vhdl->set_comment(0," Registers");
    vhdl->set_comment(0,"---------------------------------------------------------------------------");
    vhdl->set_body   (0,"");
    vhdl->set_body   (0,"queue_write: process (in_CLOCK)");
    vhdl->set_body   (0,"begin  -- process queue_write");
    vhdl->set_body   (1,"if in_CLOCK'event and in_CLOCK = '1' then");
    vhdl->set_body   (0,"");
    vhdl->set_body   (2,"if (in_NRESET = '0') then");    
    if (_param->_size_queue > 1)
      {
        vhdl->set_body   (3,"reg_PTR_READ  <= const_PTR_INIT;");
        if (_param->_nb_port_slot>1)
        vhdl->set_body   (3,"reg_NB_ELT    <= "+std_logic_cst(log2(_param->_size_queue+1),0)+";");
        else
        vhdl->set_body   (3,"reg_PTR_WRITE <= const_PTR_INIT;");
      }
    if (_param->_nb_port_slot<=1)
      {
    vhdl->set_body   (3,"reg_FULL      <= '0';");
    vhdl->set_body   (3,"reg_EMPTY     <= '1';");
      }
    vhdl->set_body   (2,"else");
    if (_param->_size_queue > 1)
      {
        vhdl->set_body   (3,"reg_PTR_READ  <= signal_NEXT_PTR_READ ;");
        if (_param->_nb_port_slot>1)
        vhdl->set_body   (3,"reg_NB_ELT    <= signal_NEXT_NB_ELT   ;");
        else
        vhdl->set_body   (3,"reg_PTR_WRITE <= signal_NEXT_PTR_WRITE;");
      }
    if (_param->_nb_port_slot<=1)
      {
    vhdl->set_body   (3,"reg_FULL      <= signal_NEXT_FULL ;");
    vhdl->set_body   (3,"reg_EMPTY     <= signal_NEXT_EMPTY;");
      }
    vhdl->set_body   (0,"");
    vhdl->set_body   (3,"if (signal_WRITE = '1') then");    
    if (_param->_size_queue > 1)
      vhdl->set_body   (3,"\treg_DATA(conv_integer(signal_PTR_WRITE)) <= in_INSERT_DATA;");
    else
      vhdl->set_body   (3,"\treg_DATA(0) <= in_INSERT_DATA;");
    vhdl->set_body   (3,"end if;");
    vhdl->set_body   (2,"end if;");
    vhdl->set_body   (0,"");
    vhdl->set_body   (1,"end if;");
    vhdl->set_body   (0,"end process queue_write;");

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

}; // end namespace queue
}; // end namespace generic

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