inline void MOESI_protocol::do_snoop_M (Mreq *request)
{
  switch (request->msg)
  {
    case GETS:
      /** Someone needs the cache line to read which we have.
          We should provide that data.
      */
      set_shared_line();
      send_DATA_on_bus(request->addr,request->src_mid);
    	state = MOESI_CACHE_O;
    	break;

    case GETM:
      /** Someone needs the cache line to read which we have.
          We should provide that data.
      */
      set_shared_line();
      send_DATA_on_bus(request->addr,request->src_mid);
    	state = MOESI_CACHE_I;
    	break;


    case DATA:
       /** Someone else needed the cache line data which is available to that processer.
          We should just ignore it.
      */
    	break;

    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: I state shouldn't see this message\n");
  }
}
inline void MSI_protocol::do_snoop_M (Mreq *request)
{
	switch (request->msg) {
    case GETS:
		set_shared_line();
    	send_DATA_on_bus(request->addr,request->src_mid);
    	state = MSI_CACHE_S;
    	break;
    case GETM:
    	/**
    	 * Another cache wants the data so we send it to them and transition to
    	 * Invalid since they will be transitioning to M.  When we send the DATA
    	 * it will go on the bus the next cycle and the memory will see it and cancel
    	 * its lookup for the DATA.
    	 */
    	/**
    	 * We use set_shared_line() here to demonstrate its use.  Since we had a copy
    	 * of the line being requested, we should indicate that the data is shared on
    	 * chip.  (This will be essential to understand in order to implement MESI/
    	 * MOSI/MOESI)
    	 */
    	set_shared_line();
    	send_DATA_on_bus(request->addr,request->src_mid);
    	state = MSI_CACHE_I;
    	break;
    case DATA:
    	fatal_error ("Should not see data for this line!  I have the line!");
    	break;
    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: M state shouldn't see this message\n");
    }
}
inline void MOESI_protocol::do_snoop_OM (Mreq *request){
	switch (request->msg){
	case GETS:send_DATA_on_bus(request->addr,request->src_mid);			//SEND DATA ON BUS SINCE I'M IN INTERMEDIATE STATE BETWEEN O AND M
				break;
	case GETM:send_DATA_on_bus(request->addr,request->src_mid);			//SEND DATA ON BUS SINCE I'M IN INTERMEDIATE STATE BETWEEN O AND M AND INVALIDATE SELF
			  state = MOESI_CACHE_IM;
		break;
	case DATA:
	
	break;
	default:
		request->print_msg (my_table->moduleID, "ERROR");
		fatal_error ("Client: IM state shouldn't see this message\n");
	}
}
inline void MOESI_protocol::do_snoop_SM (Mreq *request)
{
  switch (request->msg)
  {
    case GETS:
      set_shared_line();
      if(-1!=Owner_nodeID)
      {
        //give data
        send_DATA_on_bus(request->addr,request->src_mid);
      }
      break;

    case GETM:
      if( (-1!=Owner_nodeID) && (false==get_shared_line()) )
      {
        //give data
        set_shared_line();
        send_DATA_on_bus(request->addr,request->src_mid);
      }
      if (request->src_mid.nodeID != Owner_nodeID)
      {
         //Change state
        state = MOESI_CACHE_IM;
        Owner_nodeID = -1;
      }
      break;

    case DATA:
      Owner_nodeID = -1;

      //Get data
      send_DATA_to_proc(request->addr);

      //Change to modify state
      state = MOESI_CACHE_M;
      break;

    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: State shouldn't see this message\n");
    }
}
inline void MOESI_protocol::do_snoop_OM_Intermediate (Mreq *request)
{
	switch (request->msg) {
	case GETS:
		set_shared_line();
		send_DATA_on_bus(request->addr,request->src_mid);
		break;
	case GETM:
		send_DATA_on_bus(request->addr,request->src_mid);
		state = MOESI_CACHE_IM_Intermediate;
		break;
	case DATA:
		state = MOESI_CACHE_M;
		break;
	default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: I state shouldn't see this message\n");
    }
}
inline void MSI_protocol::do_snoop_M (Mreq *request){
	switch (request->msg){
	case GETS:
		
		send_DATA_on_bus(request->addr,request->src_mid);				//SUPPLY THE DATA
		state = MSI_CACHE_S;
		break;
	case GETM:
		
		send_DATA_on_bus(request->addr,request->src_mid);				//SUPPLY THE DATA AND INVALIDATE SELF
		state = MSI_CACHE_I;
		break;
	case DATA:
		fatal_error ("Should not see data for this line!  I have the line!");
		break;
	default: request->print_msg (my_table->moduleID, "ERROR");
		fatal_error ("Client: M state shouldn't see this message\n");
	}
}
inline void MOESI_protocol::do_snoop_O (Mreq *request)
{
	switch (request->msg) {
		case GETS:
			set_shared_line();
			send_DATA_on_bus(request->addr,request->src_mid);
			break;
		case GETM:
			state = MOESI_CACHE_I;
			set_shared_line();
			send_DATA_on_bus(request->addr,request->src_mid);
			break;
		case DATA:
			fatal_error ("Should not see data for this line!  I have the line!");
    		break;
		default:
		    request->print_msg (my_table->moduleID, "ERROR");
		    fatal_error ("Client: O state shouldn't see this message\n");
    }
}
inline void MOESIF_protocol::do_snoop_FM (Mreq *request)
{
	switch (request->msg) {
	case GETS:
		set_shared_line(); // Set shared line to prevent other nodes going to E
		send_DATA_on_bus(request->addr,request->src_mid);
		break;
	case GETM:
		set_shared_line(); // Set shared line to prevent other nodes going to E
		send_DATA_on_bus(request->addr,request->src_mid);
		break;
	case DATA:
		send_DATA_to_proc(request->addr);
		state = MOESIF_CACHE_M;
		break;
	default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: IM state shouldn't see this message\n");
	}
}
inline void MESI_protocol::do_snoop_E (Mreq *request)
{
    switch (request->msg) {
        case GETS:
            // Send the data, set the shared line and downgrade to S
            send_DATA_on_bus(request->addr, request->src_mid);
            set_shared_line(true);
            state = MESI_CACHE_S;
            break;
        case GETM:
            send_DATA_on_bus(request->addr, request->src_mid);
            state = MESI_CACHE_I; // Go to the invalid state
            break;
        case DATA:
            break;
        default:
            request->print_msg (my_table->moduleID, "ERROR");
            fatal_error ("Client SnoopE state shouldn't see this message\n");
    }
}
inline void MOESIF_protocol::do_snoop_F (Mreq *request)
{
	switch (request->msg) {
	case GETS:
		/* In the F state, we can provide data to other nodes requesting the data
		since we have a copy.
		*/
		set_shared_line(); 
		send_DATA_on_bus(request->addr,request->src_mid);
		break;
	case GETM:
		set_shared_line();
		send_DATA_on_bus(request->addr,request->src_mid);
		state = MOESIF_CACHE_I; /* Downgrade to I if other node requesting M */
		break;
	case DATA:
		break;
	default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: S state shouldn't see this message\n");
	}
}
inline void MSI_protocol::do_snoop_M (Mreq *request)
{
    switch (request->msg) {
    case GETS:
    	//since I have the most updated data, I should supply it!
        set_shared_line();
        send_DATA_on_bus(request->addr,request->src_mid);
        state = MSI_CACHE_S;
        break;
    case GETM:
    	//since someone else is modifying the data, I should abort and invalidate myself
        set_shared_line();
        send_DATA_on_bus(request->addr,request->src_mid);
        state = MSI_CACHE_I;
        break;
    case DATA: break;
    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: I state shouldn't see this message\n");
    }

}
inline void MOSI_protocol::do_snoop_OM (Mreq *request){
	switch (request->msg) {
		case GETS:
			set_shared_line();
			send_DATA_on_bus(request->addr,request->src_mid);
			break;
		case GETM:
			state = MOSI_CACHE_IM;
			set_shared_line();
			send_DATA_on_bus(request->addr,request->src_mid);
			Sim->cache_misses++;
			break;
		case DATA:
			send_DATA_to_proc(request->addr);		
			state = MOSI_CACHE_M;
			if (get_shared_line()){}
			break;
		default:
		    request->print_msg (my_table->moduleID, "ERROR");
		    fatal_error ("Client: OM state shouldn't see this message\n");
	}
}
inline void MOESI_protocol::do_snoop_M (Mreq *request)
{
switch (request->msg){
	case GETS:
		
		send_DATA_on_bus(request->addr,request->src_mid);				//SUPPLY THE DATA SINCE I HAVE THE UPDATED VERSION
		state = MOESI_CACHE_O;											//I SUPPLY THE DIRTY DATA TO EVERYONE
		set_shared_line();
		break;
	case GETM:
		
		send_DATA_on_bus(request->addr,request->src_mid);				//SUPPLY DATA
		state = MOESI_CACHE_I;											//INVALIDATE
		set_shared_line();
		break;
	case DATA:
		fatal_error ("Should not see data for this line!  I have the line!");
		break;
	default: request->print_msg (my_table->moduleID, "ERROR");
		fatal_error ("Client: M state shouldn't see this message\n");
	}

}
inline void MESI_protocol::do_snoop_M (Mreq *request)
{
    switch (request->msg) {
        case GETS:
            // Send the data and go to S
            send_DATA_on_bus(request->addr, request->src_mid);
            set_shared_line(true);
            state = MESI_CACHE_S;
            break;
        case GETM:
            // Send the data and go to I
            send_DATA_on_bus(request->addr, request->src_mid);
            state = MESI_CACHE_I;
            break;
        case DATA:
            request->print_msg (my_table->moduleID, "ERROR");
            fatal_error("SnoopM should not see data for this line! I have the line!\n");
            break;
        default:
            request->print_msg (my_table->moduleID, "ERROR");
            fatal_error ("Client SnoopM state shouldn't see this message\n");
    }
}
inline void TYPE(_protocol)::do_snoop_M (Mreq *request)
{
	switch (request->msg) {
	/*
	  See cache function 
	  with same state for 
	  description of this state
	*/
	case GETM:// See E state 
		state = TYPE(_CACHE_I);
		set_shared_line();
		send_DATA_on_bus(request->addr,request->src_mid);
		break;
	case GETS:
		state = TYPE(_CACHE_S);
		set_shared_line();
		send_DATA_on_bus(request->addr,request->src_mid);
		break;
	case DATA:
	default:
		request->print_msg (my_table->moduleID, "ERROR");
		fatal_error ("Client: M state shouldn't see this message\n");
	}
}
inline void TYPE(_protocol)::do_snoop_FM (Mreq *request)
{
	switch (request->msg) {
	/*
	  See cache function 
	  with same state for 
	  description of this state
	*/
	case GETM: // if someone writes to the dataz, then invalidate
		state = TYPE(_CACHE_IM);
	case GETS://technically in F , so give the dataz to the other guy
		send_DATA_on_bus(request->addr,request->src_mid);
		set_shared_line();
		break;
	case DATA: // can haz dataz
		send_DATA_to_proc(request->addr);
		state = TYPE(_CACHE_M);
		break;
	default:
		request->print_msg (my_table->moduleID, "ERROR");
		fatal_error ("Client: FM state shouldn't see this message\n");
	}
}