*-----------------------------------------------------------
Title[Junk.mc...November 23, 1982  9:36 AM...Taft];
*** Pilot-only version ***
* Junk task and related subroutines.
*-----------------------------------------------------------

%
This code maintains the real time clock and event counters,
and optionally samples the emulator task's PC and keeps a histogram.

The main loop does the following:
1. Acknowledge junk wakeup.
2. Maintain the real time clock (ITHi,,ITLo).
3. Call UpdateCounters every EventUpdateInterval times (about once/ms).
4. Samples the emulator's PC, if sampling is enabled.

Caution: the ITLo cell must be updated once and only once per wakeup
of the Junk task.  This is because the real time clock is used for timing
by the Ethernet output task, which is higher-priority than Junk.
%

* Interval between calls to UpdateCounters
MC[EventUpdateInterval, 37];	* Times 32 us = ~1 ms.

Set[XTask, IP[JNK]];


*-----------------------------------------------------------
* Junk task
*-----------------------------------------------------------

Subroutine;
JNKInitPC: T← JNK, CoReturn;
TopLevel;
	T← A0, RBase← RBase[Events];
	ITDeltaLo← T+(TIOA← T)+1;	* ITLo← 1
	EventUpdateTimer← T-T-1, Branch[JunkTaskLoop];

* Main loop consumes 4 cycles per wakeup in the normal case
* (no counter update or PC sampling).
* ITDeltaLo normally contains 1 (required for AckJunkTW←).
* ITDeltaLo=0 => PC sampling enabled.
JunkUpdateCounters:
	Call[UpdateCounters];
JunkTaskLoop:
	T← ITDeltaLo, Branch[SamplePC, R even];
JunkTaskCont:
	ITLo← (ITLo)+(AckJunkTW← T);
	ITHi← A← ITHi, XorSavedCarry;
	EventUpdateTimer← (EventUpdateTimer)+1, Block,
		DblBranch[JunkUpdateCounters, JunkTaskLoop, R>=0];

* Here to sample the emulator's PC and maintain a histogram.
* Histogram format is an array of LONG CARDINALs pointed to by PCHistBR.
SamplePC:
	T← A0, TaskingOff;
	RdTPC← T, TaskingOn;
	T← NOT (Link);			* TPC data is inverted
	T← T+T, MemBase← PCHistBR;	* 2 words per histogram slot
	Fetch← T;			* Increment histogram entry for PC
	JunkTemp← MD+1;
	T← (Store← T)+1, DBuf← JunkTemp, Branch[.-2, Carry];
	T← (ITDeltaLo)+1, Branch[JunkTaskCont];

*-----------------------------------------------------------
UpdateCounters:
* Subroutine to update RM shadow of event counters.
* Called from Junk and Emulator tasks.  Emulator must call with TaskingOff.
* Entry: RBase=RBase[Events]
* Exit: Event*Lo, EventHi1, EventHi0 updated; T clobbered.
* Event*Prev remembers the previous value of EventCnt*', a non-resettable
* register.  Event*Lo maintains the count since the last restart.
*-----------------------------------------------------------
Subroutine;
KnowRBase[Events];

* Update event count A.
	T← (EventAPrev)-(EventCntA');
	EventALo← (EventALo)+T;
	EventAPrev← (EventAPrev)-T, Branch[.+3, Carry'];
	EventAHi1← (EventAHi1)+1;
	EventAHi0← A← EventAHi0, XorSavedCarry;

* Update event count B.
	T← (EventBPrev)-(EventCntB');
	EventBLo← (EventBLo)+T;
	EventBPrev← (EventBPrev)-T, Branch[.+3, Carry'];
	EventBHi1← (EventBHi1)+1;
	EventBHi0← A← EventBHi0, XorSavedCarry;

* Reset the timer for Junk task calls.
	EventUpdateTimer← NOT (EventUpdateInterval), Return;



* Subroutines called only from the Emulator.
Set[XTask, IP[EMU]];

*-----------------------------------------------------------
SetPCHistAddr:
* Subroutine to set the PC histogram address and enable/disable
* sampling of the emulator task's PC.
* Entry: T,,Q = LONG POINTER to table (or 0,,0 to disable)
*	RBase=Events
* Exit: RBase=Events
*	MemBase=PCHistBR
* Table is ARRAY [0..4095] OF LONG CARDINAL.
* The emulator's PC is used as an index into the array, and the appropriate
* word is incremented every 32 microseconds.
*-----------------------------------------------------------
Subroutine;
KnowRBase[Events];

	ITDeltaLo← (ITDeltaLo) OR (1C);	* Disable sampling
	EventTemp0← Q, MemBase← PCHistBR;
	PD← (BRLo← EventTemp0) OR T;
	BRHi← T, Branch[.+2, ALU=0];
	ITDeltaLo← (ITDeltaLo)-1;	* Enable sampling
JunkRet:
	TaskingOn, Return;

*-----------------------------------------------------------
StartCounters:
* Subroutine to enable event counters and reset them to zero.
* Entry: T=event counter enable word (for InsSetOrEvent←), RBase=Events.
* Exit: event counters zeroed, T unchaged, RBase=Events.
*-----------------------------------------------------------
Subroutine;

* Enable hardware counters as specified in the call.
	InsSetOrEvent← T;

* Now reset the software counters.  Must do this with TaskingOff to prevent
* interference from the junk task, and must not read event counters until
* at least 3 cycles after InsSetOrEvent← or we might read trash.
	EventALo← A0, TaskingOff;
	EventAHi1← A0;
	EventAHi0← A0;
	EventAPrev← EventCntA';

	EventBLo← A0;
	EventBHi1← A0;
	EventBHi0← A0, TaskingOn;
	EventBPrev← EventCntB', Return;

*-----------------------------------------------------------
ReadCounters:
* Subroutine to read current values of counters into memory.
* Entry: T=pointer to CounterValues record, RBase=Events.
*  CounterValues: TYPE = MACHINE DEPENDENT RECORD [
*	eventALo, eventAHi1, eventAHi0: CARDINAL,	-- event counterA
*	eventBLo, eventBHi1, eventBHi0: CARDINAL];	-- event counterB
* Exit: T, Q, and EventTemp0 clobbered.
*-----------------------------------------------------------
Subroutine;

	Fetch← T, Q← T;			* Minimize waiting while TaskingOff
	T← MD, EventTemp0← Link;
TopLevel;
	TaskingOff, Call[UpdateCounters]; * Capture up-to-date state
	T← (Store← Q)+1, DBuf← EventALo;
	T← (Store← T)+1, DBuf← EventAHi1;
	T← (Store← T)+1, DBuf← EventAHi0;
	T← (Store← T)+1, DBuf← EventBLo;
	T← (Store← T)+1, DBuf← EventBHi1;
	T← (Store← T)+1, DBuf← EventBHi0;
	Link← EventTemp0, Branch[JunkRet];