#ifdef SYSTEMC
/*
 * $Id: Issue_queue_function_out_of_order_genMoore.cpp 138 2010-05-12 17:34:01Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_OOO_Engine/OOO_Engine/Issue_queue/include/Issue_queue.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_ooo_engine {
namespace ooo_engine {
namespace issue_queue {


#undef  FUNCTION
#define FUNCTION "Issue_queue::function_out_of_order_genMoore"
  void Issue_queue::function_out_of_order_genMoore (void)
  {
    log_begin(Issue_queue,FUNCTION);
    log_function(Issue_queue,FUNCTION,_name.c_str());

    if (PORT_READ(in_NRESET))
      {
    // ===================================================================
    // =====[ REEXECUTE_UNIT ]============================================
    // ===================================================================
    // Same implementation in in-order and out-of-order

    // ===================================================================
    // =====[ ISSUE_IN ]==================================================
    // ===================================================================
    {
      Tcontrol_t ack [_param->_nb_rename_unit][_param->_max_nb_inst_rename];

      // Initialisation
      for (uint32_t i=0; i<_param->_nb_bank; i++)
        internal_BANK_IN_ACK  [i] = false;
    
      for (uint32_t i=0; i<_param->_nb_rename_unit; i++)
        for (uint32_t j=0; j<_param->_nb_inst_rename[i]; j++)
          ack [i][j] = false;
    
      // std::list<generic::priority::select_t> * select_reg = _priority_reg->select(); // same select for all issue
      
      // issue_in interface
      std::list<generic::priority::select_t> * select_in = _priority_in ->select(); // same select for all issue
      for (std::list<generic::priority::select_t>::iterator it=select_in ->begin();
           it!=select_in ->end();
           it++)
        {
          // Get num interface
          uint32_t num_rename_unit = it->grp;
          uint32_t num_inst_rename = it->elt;

          log_printf(TRACE,Issue_queue,FUNCTION,"  * ISSUE_IN [%d][%d]",num_rename_unit,num_inst_rename);
          
          // scan all bank
          // for (std::list<generic::priority::select_t>::iterator it=select_reg->begin();
          //      it!=select_reg->end();
          //      it++)
          for (uint32_t num_bank=0;
               num_bank<_param->_nb_bank;
               ++num_bank)
            {
              // uint32_t num_bank  = it->grp;

              log_printf(TRACE,Issue_queue,FUNCTION,"    * BANK [%d]",num_bank);
          
              // test if bank is not busy (full or previous access)
              if (not internal_BANK_IN_ACK [num_bank] and (_issue_queue[num_bank].size() < _param->_size_bank))
                {
                  log_printf(TRACE,Issue_queue,FUNCTION,"    * find");

                  // find
                  ack [num_rename_unit][num_inst_rename] = true;
                  internal_BANK_IN_ACK             [num_bank] = true;
                  internal_BANK_IN_NUM_RENAME_UNIT [num_bank] = num_rename_unit;
                  internal_BANK_IN_NUM_INST        [num_bank] = num_inst_rename;
		  
                  break; // Stop scan
                }
              else
                log_printf(TRACE,Issue_queue,FUNCTION,"    * not find");
            }
        }
    
      for (uint32_t i=0; i<_param->_nb_rename_unit; i++)
        for (uint32_t j=0; j<_param->_nb_inst_rename[i]; j++)
          PORT_WRITE(out_ISSUE_IN_ACK [i][j],ack [i][j]);
    }

    // ===================================================================
    // =====[ ISSUE_OUT ]=================================================
    // ===================================================================
    {
      Tcontrol_t val [_param->_nb_inst_issue];

      for (uint32_t i=0; i<_param->_nb_inst_issue; i++)
        val [i] = 0;

      // From Reexecute_queue

//       uint32_t num_reexecute_entry = 0;
      for (std::list<entry_t*>::iterator it=_reexecute_queue.begin();
           it!=_reexecute_queue.end();
           ++it)
        {
          entry_t* entry = (*it);

          for (uint32_t i=0; i<_param->_nb_inst_issue; i++)
            // test if no previous transaction and can accept this type
            if ((val[i] == 0)
//                 and _param->_table_issue_type [i][entry->_type]
                )
              {
                // find a issue port
                val [i] = 1;
	    
                if (_param->_have_port_context_id)
	        PORT_WRITE(out_ISSUE_OUT_CONTEXT_ID            [i], entry->_context_id           );
	        if (_param->_have_port_front_end_id)
	        PORT_WRITE(out_ISSUE_OUT_FRONT_END_ID          [i], entry->_front_end_id         );
	        if (_param->_have_port_rob_ptr  )
	        PORT_WRITE(out_ISSUE_OUT_PACKET_ID             [i], entry->_packet_id            );
	        PORT_WRITE(out_ISSUE_OUT_OPERATION             [i], entry->_operation            );
	        PORT_WRITE(out_ISSUE_OUT_TYPE                  [i], entry->_type                 );
	        PORT_WRITE(out_ISSUE_OUT_CANCEL                [i], 0                            );
	        PORT_WRITE(out_ISSUE_OUT_STORE_QUEUE_PTR_WRITE [i], entry->_store_queue_ptr_write);
	        PORT_WRITE(out_ISSUE_OUT_STORE_QUEUE_PTR_READ  [i], entry->_store_queue_ptr_read );
	        PORT_WRITE(out_ISSUE_OUT_STORE_QUEUE_EMPTY     [i], entry->_store_queue_empty    );
	        if (_param->_have_port_load_queue_ptr)
	        PORT_WRITE(out_ISSUE_OUT_LOAD_QUEUE_PTR_WRITE  [i], entry->_load_queue_ptr_write );
	        PORT_WRITE(out_ISSUE_OUT_HAS_IMMEDIAT          [i], entry->_has_immediat         );
	        PORT_WRITE(out_ISSUE_OUT_IMMEDIAT              [i], entry->_immediat             );
	        PORT_WRITE(out_ISSUE_OUT_READ_RA               [i], entry->_read_ra              );
	        PORT_WRITE(out_ISSUE_OUT_NUM_REG_RA            [i], entry->_num_reg_ra           );
	        PORT_WRITE(out_ISSUE_OUT_READ_RB               [i], entry->_read_rb              );
	        PORT_WRITE(out_ISSUE_OUT_NUM_REG_RB            [i], entry->_num_reg_rb           );
	        PORT_WRITE(out_ISSUE_OUT_READ_RC               [i], entry->_read_rc              );
	        PORT_WRITE(out_ISSUE_OUT_NUM_REG_RC            [i], entry->_num_reg_rc           );
	        PORT_WRITE(out_ISSUE_OUT_WRITE_RD              [i], entry->_write_rd             );
	        PORT_WRITE(out_ISSUE_OUT_NUM_REG_RD            [i], entry->_num_reg_rd           );
	        PORT_WRITE(out_ISSUE_OUT_WRITE_RE              [i], entry->_write_re             );
	        PORT_WRITE(out_ISSUE_OUT_NUM_REG_RE            [i], entry->_num_reg_re           );

                internal_ISSUE_OUT_FROM_REEXECUTE [i] = true;
//              internal_ISSUE_OUT_NUM_BANK       [i] = num_reexecute_entry;
                internal_ISSUE_OUT_ENTRY          [i] = entry;

                break; // stop scan
              }
//           num_reexecute_entry ++;
        }

      // From Issue_queue

      std::list<generic::priority::select_t> * select = _priority_out->select(); // same select for all issue

      for (std::list<generic::priority::select_t>::iterator it=select->begin();
           it!=select->end();
           it++)
        {
          uint32_t num_bank=it->grp;

//        log_printf(TRACE,Issue_queue,Issue_queue,FUNCTION,"    * Bank [%d]",num_bank);

          // Have instruction ?
          if (not _issue_queue [num_bank].empty())
            {
// 	      log_printf(TRACE,Issue_queue,Issue_queue,FUNCTION,"      * Not Empty !!!");

              entry_t* entry = _issue_queue [num_bank].front();
              
              for (uint32_t i=0; i<_param->_nb_inst_issue; i++)
                // test if no previous transaction and can accept this type
                if ((val[i] == 0)
//                     and _param->_table_issue_type [i][entry->_type]
                    )
                  {
                    // find a issue port
                    val [i] = 1;

                    if (_param->_have_port_context_id)
	            PORT_WRITE(out_ISSUE_OUT_CONTEXT_ID            [i], entry->_context_id           );
	            if (_param->_have_port_front_end_id)
	            PORT_WRITE(out_ISSUE_OUT_FRONT_END_ID          [i], entry->_front_end_id         );
	            if (_param->_have_port_rob_ptr  )
	            PORT_WRITE(out_ISSUE_OUT_PACKET_ID             [i], entry->_packet_id            );
	            PORT_WRITE(out_ISSUE_OUT_OPERATION             [i], entry->_operation            );
	            PORT_WRITE(out_ISSUE_OUT_TYPE                  [i], entry->_type                 );
	            PORT_WRITE(out_ISSUE_OUT_CANCEL                [i], 0                            );
	            PORT_WRITE(out_ISSUE_OUT_STORE_QUEUE_PTR_WRITE [i], entry->_store_queue_ptr_write);
	            PORT_WRITE(out_ISSUE_OUT_STORE_QUEUE_PTR_READ  [i], entry->_store_queue_ptr_read );
	            PORT_WRITE(out_ISSUE_OUT_STORE_QUEUE_EMPTY     [i], entry->_store_queue_empty    );
	            if (_param->_have_port_load_queue_ptr)
	            PORT_WRITE(out_ISSUE_OUT_LOAD_QUEUE_PTR_WRITE  [i], entry->_load_queue_ptr_write );
	            PORT_WRITE(out_ISSUE_OUT_HAS_IMMEDIAT          [i], entry->_has_immediat         );
	            PORT_WRITE(out_ISSUE_OUT_IMMEDIAT              [i], entry->_immediat             );
	            PORT_WRITE(out_ISSUE_OUT_READ_RA               [i], entry->_read_ra              );
	            PORT_WRITE(out_ISSUE_OUT_NUM_REG_RA            [i], entry->_num_reg_ra           );
	            PORT_WRITE(out_ISSUE_OUT_READ_RB               [i], entry->_read_rb              );
	            PORT_WRITE(out_ISSUE_OUT_NUM_REG_RB            [i], entry->_num_reg_rb           );
	            PORT_WRITE(out_ISSUE_OUT_READ_RC               [i], entry->_read_rc              );
	            PORT_WRITE(out_ISSUE_OUT_NUM_REG_RC            [i], entry->_num_reg_rc           );
	            PORT_WRITE(out_ISSUE_OUT_WRITE_RD              [i], entry->_write_rd             );
	            PORT_WRITE(out_ISSUE_OUT_NUM_REG_RD            [i], entry->_num_reg_rd           );
	            PORT_WRITE(out_ISSUE_OUT_WRITE_RE              [i], entry->_write_re             );
	            PORT_WRITE(out_ISSUE_OUT_NUM_REG_RE            [i], entry->_num_reg_re           );
                    
                    internal_ISSUE_OUT_FROM_REEXECUTE [i] = false;
                    internal_ISSUE_OUT_NUM_BANK       [i] = num_bank;
                    internal_ISSUE_OUT_ENTRY          [i] = entry;

                    break; // stop scan
                  }
            }
        }

      for (uint32_t i=0; i<_param->_nb_inst_issue; i++)
        {
          internal_ISSUE_OUT_VAL [i] = val [i];
        }
    }
      }
    else
      {
        // Reset
        for (uint32_t i=0; i<_param->_nb_bank; i++)
          {
            internal_BANK_IN_ACK  [i] = 0;
//             internal_BANK_IN_NUM_RENAME_UNIT [num_bank] = num_rename_unit;
//             internal_BANK_IN_NUM_INST        [num_bank] = num_inst_rename;
          }
        for (uint32_t i=0; i<_param->_nb_rename_unit; i++)
          for (uint32_t j=0; j<_param->_nb_inst_rename[i]; j++)
            PORT_WRITE(out_ISSUE_IN_ACK [i][j],0);

          for (uint32_t i=0; i<_param->_nb_inst_issue; i++)
            {
              internal_ISSUE_OUT_VAL [i] = 0;
//            internal_ISSUE_OUT_FROM_REEXECUTE [i] = true;
//            internal_ISSUE_OUT_NUM_BANK       [i] = num_bank;
//            internal_ISSUE_OUT_ENTRY          [i] = entry;
            }
      }

    // Write output
      for (uint32_t i=0; i<_param->_nb_inst_issue; i++)
        {
          PORT_WRITE(out_ISSUE_OUT_VAL [i], internal_ISSUE_OUT_VAL [i]);
        }

    log_end(Issue_queue,FUNCTION);
  };

}; // end namespace issue_queue
}; // end namespace ooo_engine
}; // end namespace multi_ooo_engine
}; // end namespace core

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