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 MESI_protocol::do_snoop_SM (Mreq *request)
{
	switch (request->msg) {
	case GETS: 
                set_shared_line();  
                break;
	case GETM:
                set_shared_line();  
		break;
	case DATA:
		/** SM state meant that the block had sent the GET and was waiting on DATA.
		 * Now that Data is received we can send the DATA to the processor and finish
		 * the transition to M.
		 */
		/**
		 * Note we use get_shared_line() here to demonstrate its use.
		 * (Hint) The shared line indicates when another cache has a copy and is useful
		 * for knowing when to go to the E/S state.
		 * Since we only have I and M state in the MI protocol, what the shared line
		 * means here is whether a cache sent the data or the memory controller.
		 */
		send_DATA_to_proc(request->addr);
		state = MESI_CACHE_M;
		break;
	default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: I state shouldn't see this message\n");
	}
}
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 MOESI_protocol::do_snoop_S (Mreq *request)
{
  switch (request->msg)
  {
    case GETS:
      /** Someone else needs the cache line which will be provided by memory.
          We should just ignore it.
      */
      set_shared_line();
      break;

    case GETM:
      /** Someone is going to modify the cache line. We should move to Invalid state
       */
      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 MESI_protocol::do_snoop_SM (Mreq *request) {
    switch (request->msg) {
        case GETS:
            set_shared_line(true); // Set line to shared because others are getting the data
            break;
        case GETM:
            break;
        case DATA:
            // Send the data up, set shared=false since we have the data
            send_DATA_to_proc(request->addr);
            state = MESI_CACHE_M;
            set_shared_line(false);
            break;
        default:
            request->print_msg (my_table->moduleID, "ERROR");
            fatal_error ("Client SnoopSM state shouldn't see this message\n");
    }
}
inline void MOESI_protocol::do_snoop_S (Mreq *request)
{
	switch (request->msg) {
		case GETS:
			set_shared_line();
    		break;
		case GETM:
			set_shared_line();
    		state = MOESI_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: S state shouldn't see this message\n");
    }
}
inline void MOESI_protocol::do_snoop_M (Mreq *request)
{
    switch (request->msg) {
    case GETS:
        set_shared_line();
        send_DATA_on_bus(request->addr,request->src_mid);
        state = MOESI_CACHE_O;
        break;
    case GETM:
        set_shared_line();
        send_DATA_on_bus(request->addr,request->src_mid);
        state = MOESI_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 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 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 MOESI_protocol::do_snoop_O (Mreq *request)
{
switch (request->msg){
	case GETS:
		set_shared_line();
		send_DATA_on_bus(request->addr,request->src_mid);				// BEING THE OWNER I SUPPLY THE DATA
		
		break;
	case GETM:
		set_shared_line();
		send_DATA_on_bus(request->addr,request->src_mid);				// BEING THE OWNER I SUPPLY THE DATA AND INVALIDATE SELF
		state = MOESI_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: O 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 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 MESI_protocol::do_snoop_IM (Mreq *request) {
    switch (request->msg) {
        case GETS:
        case GETM:
            break;
        case DATA:
            // send the data up, set the shared line to false, only we have the data
            send_DATA_to_proc(request->addr);
            set_shared_line(false);
            state = MESI_CACHE_M; // Send the data and transition
            break;
        default:
            request->print_msg (my_table->moduleID, "ERROR");
            fatal_error ("Client SnoopIM state shouldn't see this message\n");
    }
}
inline void MOESI_protocol::do_snoop_SM (Mreq *request){
	switch (request->msg){
	case GETS:set_shared_line();										//INDICATION OF DATA SHARING
				break;
	case GETM:
		break;
	case DATA:
		send_DATA_to_proc(request->addr);								//JUST SEND REQUIRED DATA TO PROCESSOR
		state = MOESI_CACHE_M;
	
	break;
	default:
		request->print_msg (my_table->moduleID, "ERROR");
		fatal_error ("Client: IM state shouldn't see this message\n");
	}
}
inline void MOESIF_protocol::do_snoop_S (Mreq *request)
{
	switch (request->msg) {
	case GETS:
		set_shared_line(); // Set shared line to prevent other nodes going to E
		break;
	case GETM:
		state = MOESIF_CACHE_I;	
		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 MESI_protocol::do_snoop_S (Mreq *request)
{
    switch (request->msg) {
        case GETS:
            set_shared_line(true); // Set the shared line
            break;
        case GETM:
            state = MESI_CACHE_I; // go to invalid, someone else wants to write
            break;
        case DATA:
            request->print_msg (my_table->moduleID, "ERROR");
            fatal_error ("SnoopS should not see data for this line! I have the line!\n");
            break;
        default:
            request->print_msg (my_table->moduleID, "ERROR");
            fatal_error ("Client SnoopS state shouldn't see this message\n");
    }
}
inline void MOESIF_protocol::do_snoop_SM (Mreq *request)
{
	switch (request->msg) {
	case GETS:
		set_shared_line();
		break;
	case GETM:
		break;
	case DATA:
		send_DATA_to_proc(request->addr);
		state = MOESIF_CACHE_M;
		break;
		break;
	default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: IS 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 TYPE(_protocol)::do_snoop_S (Mreq *request)
{
	switch (request->msg) {
	/*
	  See cache function 
	  with same state for 
	  description of this state
	*/
	case GETM:// I can haz invalidated
		state = TYPE(_CACHE_I);
	case GETS:
		// I can haz dataz, so let those 
		//jerks know they are ruining 
		//everything, and can not haz E state
		set_shared_line();
		break;
	case DATA:
	default:
		request->print_msg (my_table->moduleID, "ERROR");
		fatal_error ("Client: S state shouldn't see this message\n");
	}
}
inline void MESI_protocol::do_snoop_IS (Mreq *request) {
    switch (request->msg) {
        case GETS:
        case GETM:
            break;
        case DATA:
            // Send the data up
            send_DATA_to_proc(request->addr);
            // Check if there are other copies in other processors. If so
            // then we go to the shared state, otherwise go to exclusive
            if (get_shared_line())
                state = MESI_CACHE_S;
            else {
                state = MESI_CACHE_E;
                set_shared_line(false);
            }
            break;
        default:
            request->print_msg (my_table->moduleID, "ERROR");
            fatal_error ("Client SnoopIS 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");
	}
}
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_SM (Mreq *request)
{
	switch (request->msg) {
	/*
	  See cache function 
	  with same state for 
	  description of this state
	*/
	case GETM://if we see someones GETM we invalidate our dataz,
		// so it is like we were in invalid before the CPU 
		// asked for the memories
		state = TYPE(_CACHE_IM);
	case GETS://those jerks are reading whil im trying to write 
		set_shared_line();
		break;
	case DATA://YAY! we can finaly haz dataz
		send_DATA_to_proc(request->addr);
		state = TYPE(_CACHE_M);
		break;
	default:
		request->print_msg (my_table->moduleID, "ERROR");
		fatal_error ("Client: SM state shouldn't see this message\n");
	}
}