#ifdef SYSTEMC
/*
 * $Id: Decod_genMealy.cpp 110 2009-02-19 16:31:47Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_Front_end/Front_end/Decod_unit/Decod/include/Decod.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_front_end {
namespace front_end {
namespace decod_unit {
namespace decod {


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

    //-----------------------------------
    // Initialization
    //-----------------------------------
    Tcontrol_t context_event_val = false;
    Tcontrol_t ifetch_ack [_param->_nb_context][_param->_max_nb_inst_fetch];
    for (uint32_t i=0; i<_param->_nb_context; i++)
      for (uint32_t j=0; j<_param->_nb_inst_fetch[i]; j++)
	ifetch_ack [i][j] = false;

    Tcontrol_t predict_val [_param->_nb_inst_decod];
    Tcontrol_t decod_val   [_param->_nb_inst_decod];
    for (uint32_t i=0; i<_param->_nb_inst_decod; i++)
      {
	decod_val   [i] = false;
	predict_val [i] = false;
      }

    Tcontrol_t can_continue      [_param->_nb_context];
    Tcontrol_t have_decod_branch [_param->_nb_context];

    for (uint32_t i=0; i<_param->_nb_context; i++)
      {
	internal_CONTEXT_HAVE_TRANSACTION [i] = false;
	internal_CONTEXT_ADDRESS_PREVIOUS [i] = reg_CONTEXT_ADDRESS_PREVIOUS [i];
	internal_CONTEXT_IS_DELAY_SLOT    [i] = reg_CONTEXT_IS_DELAY_SLOT    [i];
	
	can_continue                      [i] = PORT_READ(in_CONTEXT_DECOD_ENABLE [i]);
        have_decod_branch                 [i] = false;
      }
    
    //-----------------------------------
    // Loop of decod
    //-----------------------------------
    // scan all decod "slot_out"
    std::list<generic::priority::select_t> * select = _priority->select();
    std::list<generic::priority::select_t>::iterator it=select->begin();
    for (uint32_t i=0; i<_param->_nb_inst_decod; i++)
      {
	while ((it != select->end())    and  // have a no scanned "slot_in" ?
	       (decod_val [i] == false) and  // have not a previous selected entry?
	       (context_event_val == false)) // Have not a context_event (spr_access, exception, ...)
	  {
// 	    predict_val [i] = false;

	    Tcontext_t x = it->grp;
	    uint32_t   y = it->elt;

	    // Test if this instruction is valid
	    if ((PORT_READ(in_IFETCH_VAL [x][y]) == 1) and // entry is valid
		(can_continue [x]                == 1))    // context can decod instruction (have not a previous event)
	      {
                log_printf(TRACE,Decod,FUNCTION,"  * IFETCH [%d][%d]",x,y);    
                log_printf(TRACE,Decod,FUNCTION,"    * decod_ack [%d] : %d",i,PORT_READ(in_DECOD_ACK [i]));

		decod_val  [i]    = true;                        // fetch_val and decod_enable 
		ifetch_ack [x][y] = PORT_READ(in_DECOD_ACK [i]); // fetch_val and decod_enable and decod_ack

		Tgeneral_data_t addr = PORT_READ(in_IFETCH_ADDRESS [x])+y;

		_decod_instruction->_instruction      = PORT_READ(in_IFETCH_INSTRUCTION [x][y]);
		_decod_instruction->_context_id       = x;
		_decod_instruction->_address_previous = internal_CONTEXT_ADDRESS_PREVIOUS [x];
		_decod_instruction->_address          = addr; //Compute the current address
		_decod_instruction->_address_next     = addr+1;
		_decod_instruction->_is_delay_slot    = internal_CONTEXT_IS_DELAY_SLOT [x];

                // Test IFetch exception
                Texception_t ifetch_exception = PORT_READ(in_IFETCH_EXCEPTION [x]);

                if (ifetch_exception == EXCEPTION_IFETCH_NONE)
                  {
                    // Decod !
                    log_printf(TRACE,Decod,FUNCTION,"  * DECOD [%d]",i);
                    log_printf(TRACE,Decod,FUNCTION,"    * context       : %d",x);
                    log_printf(TRACE,Decod,FUNCTION,"    * fetch         : %d",y);
                    log_printf(TRACE,Decod,FUNCTION,"    * address       : %.8x (%.8x)",addr,(addr<<2));
                    log_printf(TRACE,Decod,FUNCTION,"    * is_delay_slot : %d",internal_CONTEXT_IS_DELAY_SLOT [x]);
                    
                    instruction_decod (_decod_instruction, _decod_param[x]);

                    log_printf(TRACE,Decod,FUNCTION,"    * address_next  : %.8x (%.8x)",_decod_instruction->_address_next,(_decod_instruction->_address_next<<2));
                  }
                else
                  {
                    // No decod : nop
                    instruction_l_nop (_decod_instruction, _decod_param[x]);

                    _decod_instruction->_exception_use = EXCEPTION_USE_NONE;
                    _decod_instruction->_exception     = exception_ifetch_to_exception_decod(ifetch_exception);
                    
                    // INSTRUCTION_TLB  
                    // INSTRUCTION_PAGE 
                    // BUS_ERROR        
                    if (_decod_instruction->_is_delay_slot)
                      _decod_instruction->_address_next       = _decod_instruction->_address_previous;
                    else
                      _decod_instruction->_address_next       = _decod_instruction->_address;
                    
                    _decod_instruction->_event_type         = EVENT_TYPE_EXCEPTION;
                  }

		Ttype_t      type      = _decod_instruction->_type;
                // Depth current. If have decod a branch and i can continue : depth = depth_next
                Tdepth_t     depth     = (_param->_have_port_depth)?PORT_READ(in_CONTEXT_DEPTH [x]):0;

                if ((_param->_nb_branch_speculated[x] > 0) and have_decod_branch [x])
                  depth = (depth+1)%_param->_nb_branch_speculated[x];
                
		if (_param->_have_port_context_id)
		PORT_WRITE(out_DECOD_CONTEXT_ID    [i], x);
		if (_param->_have_port_depth)
                PORT_WRITE(out_DECOD_DEPTH         [i], depth);
		PORT_WRITE(out_DECOD_TYPE          [i], type);
		PORT_WRITE(out_DECOD_OPERATION     [i], _decod_instruction->_operation     );
 		PORT_WRITE(out_DECOD_NO_EXECUTE    [i], _decod_instruction->_no_execute    );
		PORT_WRITE(out_DECOD_IS_DELAY_SLOT [i], _decod_instruction->_is_delay_slot );
#ifdef DEBUG
 		PORT_WRITE(out_DECOD_ADDRESS       [i], addr);
#endif
//                 if ((type == TYPE_BRANCH) and
//                     ((_decod_instruction->_branch_condition = BRANCH_CONDITION_FLAG_SET) or
//                      (_decod_instruction->_branch_condition = BRANCH_CONDITION_FLAG_UNSET)))
//                 PORT_WRITE(out_DECOD_ADDRESS_NEXT  [i], _decod_instruction->_address+2);
//                 else
                PORT_WRITE(out_DECOD_ADDRESS_NEXT  [i], _decod_instruction->_address_next  );
		PORT_WRITE(out_DECOD_HAS_IMMEDIAT  [i], _decod_instruction->_has_immediat  );
		PORT_WRITE(out_DECOD_IMMEDIAT      [i], _decod_instruction->_immediat      );
		PORT_WRITE(out_DECOD_READ_RA       [i], _decod_instruction->_read_ra       );
		PORT_WRITE(out_DECOD_NUM_REG_RA    [i], _decod_instruction->_num_reg_ra    );
		PORT_WRITE(out_DECOD_READ_RB       [i], _decod_instruction->_read_rb       );
		PORT_WRITE(out_DECOD_NUM_REG_RB    [i], _decod_instruction->_num_reg_rb    );
		PORT_WRITE(out_DECOD_READ_RC       [i], _decod_instruction->_read_rc       );
		PORT_WRITE(out_DECOD_NUM_REG_RC    [i], _decod_instruction->_num_reg_rc    );
		PORT_WRITE(out_DECOD_WRITE_RD      [i],(_decod_instruction->_num_reg_rd!=0)?_decod_instruction->_write_rd:0);
		PORT_WRITE(out_DECOD_NUM_REG_RD    [i], _decod_instruction->_num_reg_rd    );
		PORT_WRITE(out_DECOD_WRITE_RE      [i], _decod_instruction->_write_re      );
		PORT_WRITE(out_DECOD_NUM_REG_RE    [i], _decod_instruction->_num_reg_re    );
		PORT_WRITE(out_DECOD_EXCEPTION_USE [i], _decod_instruction->_exception_use );
// 		PORT_WRITE(out_DECOD_EXCEPTION     [i], _decod_instruction->_exception     );

                // Branch predictor can accept : the depth is valid
                log_printf(TRACE,Decod,FUNCTION,"    * context_depth_val : %d",PORT_READ(in_CONTEXT_DEPTH_VAL [x]));
                decod_val   [i]    &= PORT_READ(in_CONTEXT_DEPTH_VAL [x]);
                ifetch_ack  [x][y] &= PORT_READ(in_CONTEXT_DEPTH_VAL [x]);

		if (type == TYPE_BRANCH)
		  {
		    log_printf(TRACE,Decod,FUNCTION,"    * type is branch");
                    log_printf(TRACE,Decod,FUNCTION,"      * predict_val  : %d",ifetch_ack [x][y]);
                    log_printf(TRACE,Decod,FUNCTION,"      * predict_ack  : %d",PORT_READ(in_PREDICT_ACK [i]));

		    log_printf(TRACE,Decod,FUNCTION,"      * address src  : %.8x (%.8x)",_decod_instruction->_address     ,_decod_instruction->_address     <<2);
		    log_printf(TRACE,Decod,FUNCTION,"      * address dest : %.8x (%.8x)",_decod_instruction->_address_next,_decod_instruction->_address_next<<2);
                    
                    // test if have already decod an branch : one branch per context
		    predict_val [i]     = not have_decod_branch [x] and ifetch_ack  [x][y] // and decod_val [i]
		      ;
                    decod_val   [i]    &= not have_decod_branch [x] and PORT_READ(in_PREDICT_ACK [i]);// predict_ack and fetch_val and decod_enable 		    
                    ifetch_ack  [x][y] &= not have_decod_branch [x] and PORT_READ(in_PREDICT_ACK [i]);// predict_ack and fetch_val and decod_enable and decod_ack
                
		    if (_param->_have_port_context_id)
		    PORT_WRITE(out_PREDICT_CONTEXT_ID                  [i],x);
		    PORT_WRITE(out_PREDICT_MATCH_INST_IFETCH_PTR       [i],y == ((_param->_have_port_inst_ifetch_ptr)?PORT_READ(in_IFETCH_INST_IFETCH_PTR [x]):0));
		    PORT_WRITE(out_PREDICT_BRANCH_STATE                [i],PORT_READ(in_IFETCH_BRANCH_STATE                [x]));
		    if (_param->_have_port_depth)
                    PORT_WRITE(out_PREDICT_BRANCH_UPDATE_PREDICTION_ID [i],PORT_READ(in_IFETCH_BRANCH_UPDATE_PREDICTION_ID [x]));
		    PORT_WRITE(out_PREDICT_BRANCH_CONDITION            [i],_decod_instruction->_branch_condition  );
// 		    PORT_WRITE(out_PREDICT_BRANCH_STACK_WRITE          [i],_decod_instruction->_branch_stack_write);
		    PORT_WRITE(out_PREDICT_BRANCH_DIRECTION            [i],_decod_instruction->_branch_direction  );
		    PORT_WRITE(out_PREDICT_ADDRESS_SRC                 [i],_decod_instruction->_address           );
		    PORT_WRITE(out_PREDICT_ADDRESS_DEST                [i],_decod_instruction->_address_next      );
		
                    // can continue is set if direction is "not take" (also, continue is sequential order)

//   		    can_continue [x] = false; // one branch per context, the DS don't execute
  		    can_continue [x]&= PORT_READ(in_PREDICT_CAN_CONTINUE [i]); // one branch per context, the DS don't execute
                    have_decod_branch [x] = true;
		  }

		Tevent_type_t event_type = _decod_instruction->_event_type;
		if (event_type != EVENT_TYPE_NONE)
		  {
		    // speculative jump at the exception handler
		    // if type = TYPE_BRANCH, also event_type == EVENT_TYPE_NONE
		    context_event_val   = ifetch_ack  [x][y] // and decod_val [i]
		      ;
		    decod_val   [i]    &= PORT_READ(in_CONTEXT_EVENT_ACK);// context_event_ack and fetch_val and decod_enable 		  
		    ifetch_ack  [x][y] &= PORT_READ(in_CONTEXT_EVENT_ACK);// context_event_ack and fetch_val and decod_enable and decod_ack

		    if (_param->_have_port_context_id)
		    PORT_WRITE(out_CONTEXT_EVENT_CONTEXT_ID   , x);
                    if (_param->_have_port_depth)
		    PORT_WRITE(out_CONTEXT_EVENT_DEPTH        , depth);
		    PORT_WRITE(out_CONTEXT_EVENT_TYPE         , _decod_instruction->_event_type    );
		    PORT_WRITE(out_CONTEXT_EVENT_IS_DELAY_SLOT, _decod_instruction->_is_delay_slot );
		    PORT_WRITE(out_CONTEXT_EVENT_ADDRESS      , _decod_instruction->_address       );
		    PORT_WRITE(out_CONTEXT_EVENT_ADDRESS_EPCR , _decod_instruction->_address_next  );
		  }

		// fetch_ack = 
		//   ((event_type == EVENT_TYPE_NONE) or ((event_type != EVENT_TYPE_NONE) and context_event_ack)) and
		//   ((type       == TYPE_BRANCH    ) or ((type       != TYPE_BRANCH    ) and predict_ack      )) and
		//   fetch_val and decod_ack and decod_enable and true (is decod_val)

		// To compute the "next previous" address
		Tcontrol_t have_transaction = ifetch_ack [x][y];

		internal_CONTEXT_HAVE_TRANSACTION [x] |= have_transaction;
		if (have_transaction)
		  {
		    internal_CONTEXT_ADDRESS_PREVIOUS [x] = addr;
		    internal_CONTEXT_IS_DELAY_SLOT    [x] = (type == TYPE_BRANCH); // next is a delay slot if current have branch type
		  }

		can_continue [x] &= have_transaction; // to have a in order decod !!! if a previous instruction can decod, also next instruction can't decod.
	      }

	    log_printf(TRACE,Decod,FUNCTION,"    - num_(decod, context, fetch) : %d %d %d",i, x, y);
	    log_printf(TRACE,Decod,FUNCTION,"      - ifetch_ack        : %d",ifetch_ack  [x][y]);
	    log_printf(TRACE,Decod,FUNCTION,"      - context_event_val : %d",context_event_val );
	    log_printf(TRACE,Decod,FUNCTION,"      - predict_val       : %d",predict_val [i]   );
	    log_printf(TRACE,Decod,FUNCTION,"      - decod_val         : %d",decod_val   [i]   );
	    
	    it ++;
	  }
      }
    //-----------------------------------
    // Write output
    //-----------------------------------

    for (uint32_t i=0; i<_param->_nb_context; i++)
      for (uint32_t j=0; j<_param->_nb_inst_fetch[i]; j++)
	PORT_WRITE(out_IFETCH_ACK [i][j], ifetch_ack [i][j]);

    PORT_WRITE(out_CONTEXT_EVENT_VAL, context_event_val);

    for (uint32_t i=0; i<_param->_nb_inst_decod; i++)
      {
	PORT_WRITE(out_PREDICT_VAL [i], predict_val [i]);
	PORT_WRITE(out_DECOD_VAL   [i], decod_val   [i]);
        
#ifdef STATISTICS
        internal_DECOD_VAL [i] = decod_val [i];
#endif
      }

    log_end(Decod,FUNCTION);
  };

}; // end namespace decod
}; // end namespace decod_unit
}; // end namespace front_end
}; // end namespace multi_front_end
}; // end namespace core

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