/*
 * Copyright (c) 1996 by Satish Chandra, Brad Richards, Mark D. Hill, 
 * James R. Larus, and David A. Wood.
 *
 * Teapot is distributed under the following conditions:
 * 
 *     You may make copies of Teapot for your own use and modify those copies.
 * 
 *     All copies of Teapot must retain our names and copyright notice.
 * 
 *     You may not sell Teapot or distributed Teapot in conjunction with a
 *     commercial product or service without the expressed written consent of
 *     the copyright holders.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 * 
 */


Procedure AccChg(id:ID; tag_chg: TAG_CHG);
Begin
	Alias me: Nodes[cur_node] Do
		Switch tag_chg
			Case TPPI_Blk_Invalidate:
				Assert (me.AccCtrl[id] != Blk_Invalid) "invalidating already inv";
				me.AccCtrl[id] := Blk_Invalid;
			Case TPPI_Blk_Validate_RW:
---ryw.del			Assert (me.AccCtrl[id] = Blk_Invalid) "validating non invalid";
				me.AccCtrl[id] := Blk_Writable;
			Case TPPI_Blk_Downgrade_RO:
				Assert (me.AccCtrl[id] = Blk_Writable) "downgrading non wr";
				me.AccCtrl[id] := Blk_ReadOnly;
			Case TPPI_Blk_Upgrade_RW:
				Assert (me.AccCtrl[id] = Blk_ReadOnly) "upgrading non RO";
				me.AccCtrl[id] := Blk_Writable;
			Case TPPI_Blk_No_Tag_Change:
		End;
	End;
End;

Procedure Send(dest: NODE; msg: MSG; id: ID; orig_client: NODE);
Begin
	Assert (!Isundefined(dest)) "all Send must have dest defined";
	Assert (!Isundefined(msg)) "all Send must have msg defined";
	Assert (!Isundefined(id)) "all Send must have id defined";
	Assert (!Isundefined(orig_client)) "all Send must have orig_client defined";
	NW_Send(dest, msg, id, cur_node, orig_client);
End;

Procedure Send2(dest: NODE; msg: MSG; id: ID; orig_client: NODE;
		handType: XpotHandleType_t);
Begin
	Send (dest, msg, id, orig_client);
End;

Procedure SendData(dest: NODE; msg: MSG; id: ID; post_tag_chg: TAG_CHG; orig_client: NODE);
Begin
	Alias me: Nodes[cur_node] Do
---ryw.del	Assert (me.AccCtrl[id] != Blk_Invalid) "attempt to read inv while send";
		Assert (!Isundefined(orig_client)) "all SendData must have orig_client defined";
		NW_SendData(dest, msg, id, cur_node, me.Dram[id].Data, orig_client);
		AccChg(id, post_tag_chg);
	End
End;

Procedure SendData2(dest: NODE; msg: MSG; id: ID; post_tag_chg: TAG_CHG; orig_client: NODE; handType: XpotHandleType_t);
Begin
	SendData (dest, msg, id, post_tag_chg, orig_client);
End;

Procedure RecvData(id: ID; pre_tag_chg: TAG_CHG; post_tag_chg: TAG_CHG);
Begin
	AccChg(id, pre_tag_chg);
	Alias me : Nodes[cur_node] Do
		Assert (me.AccCtrl[id] = Blk_Writable) "attempt to write unwrit at recv";
		NW_RecvData(id, cur_msg, cur_node);
--		Undefine cur_msg;
	End;
	AccChg(id, post_tag_chg);
End;


Procedure RecvData2(id: ID; pre_tag_chg: TAG_CHG; post_tag_chg: TAG_CHG; 
		    xt: XpotThread_t; rep: XpotRep_t);
Begin
	AccChg(id, pre_tag_chg);
	Alias me : Nodes[cur_node] Do
		Assert (me.AccCtrl[id] = Blk_Writable) "attempt to write unwrit at recv";
		NW_RecvData(id, cur_msg, cur_node);
--		Undefine cur_msg;
	End;
	AccChg(id, post_tag_chg);
End;


Function IsAMRply(msg : MSG):BOOLEAN;
Begin
	Switch(msg)
	Case WR_RO_FAULT:
		return false;
	Case WR_FAULT:
		return false;
	Case WR_Done:
		return false;
	Case INV_Done:
		return false;
	Case INV_Start:
		return false;
	Case OW_FAULT:
		return false;
	Case RD_FAULT:
		return false;
	Case CC_SUPPLY_DATA_RO:
		return false;
--	Case CC_SUPPLY_DATA_RO_AMRPLY:
--		return true;
	Case CC_SUPPLY_DATA_RW:
		return false;
--	Case CC_SUPPLY_DATA_RW_AMRPLY:
--		return true;
	Case CC_GRANT_OW:
		return false;
	Case SS_SUPPLY_DATA_RO:
		return false;
--	Case SS_SUPPLY_DATA_RO_AMRPLY:
--		return true;
	Case SS_SUPPLY_DATA_RW:
		return false;
--	Case SS_SUPPLY_DATA_RW_AMRPLY:
--		return true;
	Case UPGRADE_DONE:
		return false;
	Case UPGRADE_DONE_AMRPLY:
		return true;
	Case UPGRADE_DONE_NACK_AMRPLY:
		return true;

	Case REVOKE_READ_TOKEN:
		return false;
	Case REVOKE_READ_TOKEN_AMRPLY:
		return true;
 	Case REVOKE_RW_TOKEN2:
		return false;
	Case REVOKE_RW_TOKEN2_AMRPLY:
		return true;
--	Case REVOKE_RW_TOKEN:
--		return false;
--	Case REVOKE_RW_TOKEN_AMRPLY:
--		return true;
	Case CC_DATA_REQ_RO:
		return false;
	Case CC_DATA_REQ_RO_AMRPLY:
		return true;
	Case CC_DATA_REQ_RO_NACK_AMRPLY:
		return true;
	Case CC_DATA_REQ_RW:
		return false;
	Case CC_DATA_REQ_RW_AMRPLY:
		return true;
	Case CC_DATA_REQ_RW_NACK_AMRPLY:
		return true;

	Case RELEASE_RW_TOKEN:
		return false;
	Case RELEASE_RD_TOKEN:
		return false;
--	Case RELEASE_RW_TOKEN_AMRPLY:
--		return true;
--	Case RELEASE_RD_TOKEN_AMRPLY:
--		return true;
	Case GET_RO_REQ:
		return false;
--	Case GET_RO_REQ_AMRPLY:
--		return true;
	Case GET_RW_REQ:
		return false;
--	Case GET_RW_REQ_AMRPLY:
--		return true;
	case GET_OW_REQ:
		return false;
--	Case GET_OW_REQ_AMRPLY:
--		return true;
	Case UPGRADE_REQ:
		return false;
--	Case UPGRADE_REQ_AMRPLY:
--		return true;
	Case WRITE_BACK_DATA_DONE:
		return false; 
--	Case WRITE_BACK_DATA_DONE_AMRPLY:
--		return true; 
	Case SS_DATA_REQ_RO:
		return false;
	Case SS_DATA_REQ_RO_AMRPLY:
		return true;
	Case SS_DATA_REQ_RW:
		return false;
	Case SS_DATA_REQ_RW_AMRPLY:
		return true;
	Case WRITE_BACK_DATA:
		return false; 
	Case WRITE_BACK_DATA_AMRPLY:
		return true; 
	Else
		Assert(false) "Bad case in transfer.m: IsAMRepl()";
	End;
End;

Function IsNotAMRply(msg : MSG):BOOLEAN;
Begin
	If (IsAMRply(msg))
	Then
		Return false;
	Else
		Return true;
	Endif;
End;

/*
 *------------------------------------------------------------------
 *
 * SendGenericAMRplyIfNeeded --
 *
 *     Send an AM_REPLY to the message if one hasn't been sent 
 *     already (checks cur_msg.am_reply_done).
 *     This routine can only be used for messages for which
 *     AM_REPLY always means, roughly, "OK, I'm working on it"
 *     It doesn't know what to do if the AMREPLY is really
 *     supposed to have content (e.g. ACK/NACK). Use other
 *     routines for those replies.
 *
 *     The point of putting (almost) all replies in this routine
 *     is so that we can reply when a message is handled or when
 *     it is queued, but not both.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *------------------------------------------------------------------
 */
Procedure SendGenericAMRplyIfNeeded(id: ID; msgType : MSG; src : NODE; orig_client : NODE; 
	token : OPAQUE_AM_TOKEN);
Begin
	If (cur_msg.am_reply_done = true)
	Then
		-- Reply was already sent when message was queued
		Return;
	Endif;

	Assert(IsAMRply(msgType) = false) "transfer.m: SendGenericAMRplyIfNeeded: Cant reply to reply";


#if 0
--	/*
--	 * This is where we send AM_REPLIES to messages that
--	 * whose replies have a null handler.
--	 * XXX No longer send meaningless replies over net
--	 * to reduce the state space of the simulator.
--	 */
--	Switch(msgType)
--	Case RD_FAULT:
--		/* ignore -- no reply needed */
--		cur_msg.am_reply_done := true;
--	Case WR_FAULT:
--		/* ignore -- no reply needed */
--		cur_msg.am_reply_done := true;
--	Case WR_RO_FAULT:
--		/* ignore -- no reply needed */
--		cur_msg.am_reply_done := true;
--	Case CC_SUPPLY_DATA_RO:
--		Send(src, CC_SUPPLY_DATA_RO_AMRPLY, id, orig_client);
--		cur_msg.am_reply_done := true;
--	Case CC_SUPPLY_DATA_RW:
--		Send(src, CC_SUPPLY_DATA_RW_AMRPLY, id, orig_client);
--		cur_msg.am_reply_done := true;
--	Case MGR_SUPPLY_DATA_RO:
--		Send(src, MGR_SUPPLY_DATA_RO_AMRPLY, id, orig_client);
--		cur_msg.am_reply_done := true;
--	Case MGR_SUPPLY_DATA_RW:
--		Send(src, MGR_SUPPLY_DATA_RW_AMRPLY, id, orig_client);
--		cur_msg.am_reply_done := true;
--
--	Case REVOKE_READ_TOKEN:
--		Send(src, REVOKE_READ_TOKEN_AMRPLY, id, orig_client);
--		cur_msg.am_reply_done := true;
--	Case REVOKE_RW_TOKEN:
--		Send(src, REVOKE_RW_TOKEN_AMRPLY, id, orig_client);
--		cur_msg.am_reply_done := true;
--
--	Case RELEASE_RW_TOKEN:
--		Send(src, RELEASE_RW_TOKEN_AMRPLY, id, orig_client);
--		cur_msg.am_reply_done := true;
--	Case RELEASE_RD_TOKEN:
--		Send(src, RELEASE_RD_TOKEN_AMRPLY, id, orig_client);
--		cur_msg.am_reply_done := true;
--	Case GET_RO_REQ:
--		Send(src, GET_RO_REQ_AMRPLY, id, orig_client);
--		cur_msg.am_reply_done := true;
--	Case GET_RW_REQ:
--		Send(src, GET_RW_REQ_AMRPLY, id, orig_client);
--		cur_msg.am_reply_done := true;
--	Case UPGRADE_REQ:
--		Send(src, UPGRADE_REQ_AMRPLY, id, orig_client);
--		cur_msg.am_reply_done := true;
--	Case WRITE_BACK_DATA:
--		Send(src, WRITE_BACK_DATA_AMRPLY, id, orig_client);
--		cur_msg.am_reply_done := true; 
--
--
--
--	Case CC_DATA_REQ_RO:
--		Error "transfer.m: Cant use generic reply for CC_DATA_REQ_RO (is it nack or ack?)";
--	Case CC_DATA_REQ_RW:
--		Error "transfer.m: Cant use generic reply for CC_DATA_REQ_RW (is it nack or ack?)";
--	Case UPGRADE_DONE:
--		Error "transfer.m: Cant use generic reply for UPGRADE_DONE (is it nack or ack?)";
--	Else
--		Error "Bad case in transfer.m: SendGenericAMRplyIfNeeded()";
--	End;
#else
	/*
         * Current simulator implementation does not send replies
	 * if to the NULL handler.
	 */
	Switch(msgType)
	Case REVOKE_RW_TOKEN2:
		Send (src, REVOKE_RW_TOKEN2_AMRPLY, id, orig_client);
		cur_msg.am_reply_done := true;
---ryw.new
	Case WRITE_BACK_DATA:
		Send(src, WRITE_BACK_DATA_AMRPLY, id, orig_client);
		cur_msg.am_reply_done := true; 

---ryw.oldCase WRITE_BACK_DATA_DONE:
--- 		Send(src, WRITE_BACK_DATA_DONE_AMRPLY, id, orig_client);
---ryw.end	cur_msg.am_reply_done := true;

	Case CC_DATA_REQ_RO:
		Error "transfer.m: Cant use generic reply for CC_DATA_REQ_RO (is it nack or ack?)";
	Case CC_DATA_REQ_RW:
		Error "transfer.m: Cant use generic reply for CC_DATA_REQ_RW (is it nack or ack?)";
	Case UPGRADE_DONE:
		Error "transfer.m: Cant use generic reply for UPGRADE_DONE (is it nack or ack?)";
	Else
		cur_msg.am_reply_done := true;
	End;
#endif
End;






/*
 *------------------------------------------------------------------
 *
 * SendNackAMRply --
 *      For those replies that actually mean something...
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *------------------------------------------------------------------
 */
Procedure SendNackAMRply(id: ID; msgType : MSG; src : NODE; orig_client : NODE;
	token : OPAQUE_AM_TOKEN);
Begin
	Assert (!(cur_msg.am_reply_done = true)) "transfer.m: Send NackAmRply: already replied";

	Switch(msgType)
	Case CC_DATA_REQ_RO:
		Send(src, CC_DATA_REQ_RO_NACK_AMRPLY, id, orig_client);
		cur_msg.am_reply_done := true; 
	Case CC_DATA_REQ_RW:
		Send(src, CC_DATA_REQ_RW_NACK_AMRPLY, id, orig_client);
		cur_msg.am_reply_done := true; 
	Case UPGRADE_DONE:
		Send(src, UPGRADE_DONE_NACK_AMRPLY, id, orig_client);
		cur_msg.am_reply_done := true; 
	Else
		Assert(false) "Bad case in transfer.m: SendNackAMRply()";
	End;
End;



/*
 *------------------------------------------------------------------
 *
 * SendAckAMRply --
 *      For those replies that actually mean something...
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *------------------------------------------------------------------
 */
Procedure SendAckAMRply(id: ID; msgType : MSG; src : NODE; orig_client : NODE;
	token : OPAQUE_AM_TOKEN);
Begin
	If (cur_msg.am_reply_done = true)
	Then
		-- Reply was already sent when message was queued
		Return;
	Endif;

	Switch(msgType)
	Case CC_DATA_REQ_RO:
		Send(src, CC_DATA_REQ_RO_AMRPLY, id, orig_client);
		cur_msg.am_reply_done := true; 
	Case CC_DATA_REQ_RW:
		Send(src, CC_DATA_REQ_RW_AMRPLY, id, orig_client);
		cur_msg.am_reply_done := true; 
	Case UPGRADE_DONE:
		Send(src, UPGRADE_DONE_AMRPLY, id, orig_client);
		cur_msg.am_reply_done := true; 
	Else
		Assert(false) "Bad case in transfer.m: SendAckAMRply()";
	End;
End;


Function ReqFailed (req: XpotReqP_t):BOOLEAN;
Begin
	return false;
End;
