:TITLE[Ustats.0mc, October 23, 1983  4:48 PM, van Melle];

:IF[StatsMode];

mc[FVStartStatEventR, 375];
mc[FVExitStatEvent, lshift[376,10]];

onpage[pgFrame3];
FNStat:		* Come here on function call when lspStatsPtr is on
	lspL2 ← T, loadpage[pgStats];		* Nargs
	lspL2 ← (lspL2) or (300c), call[EmitFnStats];
	T ← lspNargs, goto[FNStatDone];		* Restore state we entered in

onpage[pgJump];		* Tail of return is on pgJump for ifu refill
ReturnStat:		* Come here when we are about to return to someone
			* returnstat is just like fncall, but Nargs = 77
	loadpage[pgStats];
	lspL2 ← (377c), call[EmitFnStats];	* Nargs = all ones
	goto[ReturnStatDone];

onpage[pgLisp0];
SubrStat:		* Come here on subrcall.  Subr# in ac2, Nargs in ac3
	T ← (AC3) or (300c);		* Nargs
	lspL2 ← T, loadpage[pgStats];
	lspL2 ← lsh[lspL2, 10], call[SubrStat1];
	T ← (StatsPointerLocation);
	PStore1[MDS, lspStatsPtr], goto[SubrStatDone];
		* Make stats pointer up to date, since going to bcpl now


onpage[pgJump];
CheckStatOvfl:				* have we overflowed?
	lu ← (lspStatsPtr) - (StatsBufferBoundary), goto[nxiLBL, R<0];
	goto[StatsPunt, alu>=0];
	  goto[nxiLBL];


:IF[FvarStatsMode];
onpage[pgFVar];
FvStartStat:
	FVarReturnAddress ← T, loadpage[pgStats];	* save return link
	lspL2 ← (FVStartStatEventR), call[EmitFnStats];
	goto[NewFrame];

FVExitStat:
	T ← rsh[FVarBindingHi, 10];		* Hiloc of binding pointer
	lspL2 ← T;
	T ← FVarName, loadpage[pgStats];	* Name we looked up
	lspL2 ← (lspL2) or (FVExitStatEvent), call[EmitStatsCommon];
	APC&APCTask ← FVarReturnAddress, goto[FVLookupExit];
:ENDIF;


onpage[pgStats];

SubrStat1:
	T ← AC2, goto[EmitStatsCommon];		* "fn header" lo = punt#

EmitFnStats:	* Come here with L2 = desired hi byte.  rh[L2] and L3
		* will be filled from IfuBr/Hi to produce a 4-word stat
	T ← rhmask[lspIfuBrHi];		* hiloc of fnheader
	lspL2 ← (lsh[lspL2, 10]) or T;	* Nargs in left half
	T ← lspIfuBr;			* fnheader lo
EmitStatsCommon:
	lspL3 ← T, UseCTask;
	T ← APCTask&APC;		* return link
	lspL5 ← T;			* save it
	T ← lspStatsPtr, goto[Emit2, R Even];
	  PStore1[MDS, RZero];		* filler word; even placement
	  T ← lspStatsPtr ← (lspStatsPtr) + 1;	* Doubleword align pointer
Emit2:	PStore2[MDS, lspL2];	* Store nargs,,fnheader hi,, Fnheader lo
	call[GetTime];			* Get time in L2,3
	T ← lspStatsPtr ← (lspStatsPtr) + (2c);
	PStore2[MDS, lspL2];		* store time
	APCTask&APC ← lspL5;		* restore link & return
	lspStatsPtr ← (lspStatsPtr) + (2c), return;


:ENDIF;


onpage[pgStats];

* RCLK subroutine.  Returns time left justified in L2, L3

GetTime:
	T ← (R400) + (30c);		* Alto RTC
	PFetch1[MDS, lspL2];		* Fetch high half of clock
	lspL3 ← IP[RTCLow]c;
	T ← (SStkP&NStkp) xor (377c);
	Stkp ← lspL3, lspL3 ← T, NoRegILockOK;
	T ← (Stack) and not (77c);	* fetch most of low clock
	Stkp ← lspL3, lspL3 ← T, NoRegILockOK, return;

*
* If we absolutely place one instruction in Timer.mc, we could
* get the time instead by doing (saving net 5 instructions)
*
*	loadpageExternal[XMiscPage];
*	T ← (R400) + (30c), callExternal[MXRclkLoc];
*


* RCLK -- store 32-bit processor clock @TOS

@RCLK:	loadpage[pgSetBase], opcode[167];
	call[lspSetBase];		* Setup lspGenBr for store
	loadpage[pgStats];
	call[GetTime];			* Get clock in L2,3
	PStore2[lspGenBr, lspL2, 0], goto[nxiLBL];	* Store it


:END[Ustats];