*-----------------------------------------------------------
Title[InitialSubrs...August 28, 1985  3:23 PM...Willie-Sue];
* Subroutines to assist in memory system initialization.
*-----------------------------------------------------------

% *-----------------------------------------------------------
Subroutines in this File,
by Order of Appearance in Listing
	SetMCR		Set MCR w/ T
	LongWait	Wait T cycles, excluding cost of Call and Return.
	ClearCacheFlags	Clear all the flags of the cache.
	PresetMap	Initialize map to Map[i]← i
	SetTestSyn	Set test syndrome.
	SetBRForPage	Set BR so that VA=0 will point to indicated page.
	WriteMap	Map[BR]← RScr,,RScr2
	ResetTags	Initialize the tags for the current task.
	WaitForMapBuf	Wait for MapBuf to be not busy
% *-----------------------------------------------------------


M[PushReturn, TopLevel[] ILC[(Stack&+1← Link)]];
M[ReturnP, (StkP-1, Branch[DoReturn])];

* Cache configuration -- must change when 4K cache data chips are installed.
	MC[highestCol, 3];	* maximum column index
	MC[highestRow, 77];	* maximum row index
	Set[CABitsInPipe1, 6];	* CacheA data bits that appear in Pipe1
	Set[cacheShift, 4];	* Position of cache row in VA
	Set[nBitsInRow, 6];

* Map configuration
* Pretend map is 16K, and simply do not touch map entries beyond that.
* Emulators do a more thorough initialization and discover the truth about the hardware.
* Unfortunately, if there is more real memory than the "map" covers,
*   the intialization gets very confused and leaves at least some of the map
*   initialized to vacant.
*  Hence, the nPagesInMap has been set to 64K (almost)

	Set[logWordsPerPage, 10];
	MC[nPagesInMap, 177400];

TopLevel;

*-----------------------------------------------------------
DoReturn:	* Branched to by ReturnP macro
*-----------------------------------------------------------
	Link← Stack, Branch[Retn];


*-----------------------------------------------------------
SetMCR:		* Set MCR from T after maximum possible required wait
*-----------------------------------------------------------
Subroutine;
	Cnt← 6S, Global;		* LoadMCR >8 cycles after last mem op
	Branch[., Cnt#0&-1];
	PD← A0, LoadMCR[T, T], Branch[LWRetn]; * wait for MCR to settle down


*-----------------------------------------------------------
LongWait:	* wait (T + 2) cycles, not counting Call or Return
*-----------------------------------------------------------
Subroutine;
	PD← T, Global;
LWRetn:	T← T-1, Branch[., ALU#0];
Retn:	Return;

*-----------------------------------------------------------
ClearCacheFlags:
*-----------------------------------------------------------
Subroutine;
	RowX← highestRow, Global;
	PushReturn;
ClrCacheFRowL:	* loop for all the rows of the cache
	ColX← highestCol;
ClrCacheFColL:	* loop for the columns in this row

* This code performs: CacheA[VA, ColX] ← ColX
	T← LSH[ColX, nBitsInRow];	* T← VA for ColX and RowX
	T← T OR (RowX);
	VA← LSH[T, cacheShift];
	T← A0, Call[SetBRForPage];
Set[wantMCR, Or[mcr.useMCRV!, mcr.disCF!, mcr.disHold!, mcr.noWake!,
  mcr.noRef!, mcr.fdMiss!]];
	T← DPF[ColX, 2, mcr.MCRVShift];	* Use ColX as victim; position for MCR
	T← T OR (HighByte[wantMCR]);
	T← T OR (LowByte[wantMCR]), Call[SetMCR];
	Store← VA, DBuf← 0C;
	T← 12C, Call[LongWait];
	Store← VA, DBuf← 0C;
	T← 12C, Call[LongWait];

* This code performs: CFlags[VA, ColX] ← Vacant
Set[wantMCR, Or[mcr.fdMiss!, mcr.noRefHold!, mcr.noWake!, mcr.useMCRV!]];
	T← DPF[ColX, 2, mcr.MCRVShift];	* T← MCR value for ColX as victim
	T← T OR (HighByte[wantMCR]);
	T← T OR (LowByte[wantMCR]), Call[SetMCR];
	T← Xor[cFlags.Vacant!, cFlags.mask!]C; * CFlags← A wants flags inverted
	VA← (VA)-T;			* Set BR← (VA-flags)
	RScr← T-T-1, XorSavedCarry;
	BRLo← VA;
	BRHi← RScr;
* Must put flags on MAR during cycle before CFlags←
	DummyRef← T;			* Really DummyRef← VA
	CFlags← T;			* Put flags in last referenced entry

* Repeat for all columns and all rows
	ColX← (ColX)-1;
	PD← (RowX)-1, Branch[ClrCacheFColL, ALU>=0];
	RowX← (RowX)-1, Branch[ClrCacheFRowL, ALU>=0];
	ReturnP;

*-----------------------------------------------------------
PresetMap:
* Reset and initialize the map hardware from an arbitrary state.
* Initialize entire map to establish a one-to-one correspondence between
* virtual and real memory.
*-----------------------------------------------------------
Subroutine;
	PushReturn;

Set[wantMCR, Or[mcr.fdMiss!,mcr.disHold!,mcr.disCF!,mcr.disBR!,mcr.noWake!]];
	T← HighByte[wantMCR];
	T← T OR (LowByte[wantMCR]), Call[SetMCR];

* When the machine powers up, the map may be in an arbitrary state. 
* Kick-start the automata by performing two fetches. Cope with "tag" bit by
* performing a reference that hits and then punch on the map 8 times
* to wake it up.
	Fetch← RM0, T← 40C, Call[LongWait]; * do two fetches, separated by waits
	Fetch← RM0, T← 40C, Call[LongWait];

	RScr← A0, Cnt← 10S, Call[ResetTags]; * reset our tag bit. use VA=0

ResetMapL:
	RScr← A0;
	RScr2← A0, Call[WriteMap];
	T← mcr.disHold, Branch[ResetMapL, Cnt#0&-1];

					* reset MCR for further map testing:
	T← T OR (mcr.noWake), Call[SetMCR]; * use disHold, noWake
	B← FaultInfo',			* clear any pending wakeups
		Call[ClearCacheFlags];	* assure beingLoaded not set in cache
	T← mcr.noWake, Call[SetMCR];	* clear MCR

* Read the storage configuration, and set these registers:
*  PgsPerMod = number of pages per module
*  ModMask = bit mask of modules present (B0=1 => module 0 present, etc.)
	ModMask← NOT (Config');
	T← LDF[ModMask, 2, 2];		* Storage chip size = 2↑(12 + 2*T)
	T← DPF[T, 2, 11];		* ShC count ← 2*T
	MPageX← T-(ShC← T)-1;
	PgsPerMod← 400C;		* 4K chips give 400B pages/module
	PgsPerMod← ShiftNoMask[PgsPerMod]; * LCY[R, R, 2*n]
	ModMask← LSH[ModMask, 10];	* Left-justify the module-present bits
	ModMask← (ModMask) AND (170000C);
	RScr2← T-T-1, Branch[NoStorage, ALU=0];
	Nop;				* Placement

* MPageX maintains the virtual page minus 1, RScr2 the real page minus 1.
FindModule:
	ModMask← (ModMask) LSH 1, Branch[MapModule, R<0];
	T← PgsPerMod, Branch[EndOfStorage, ALU=0];
	RScr2← (RScr2)+T, Branch[FindModule]; * Skip nonexistent real pages

* PresetMap (cont'd)

MapModule:
	Cnt← PgsPerMod, Branch[PresetMapE];
PresetMapL:
	RScr2← (RScr2)+1;
	MPageX← T← (MPageX)+1, Call[SetBRForPage]; * expects T = virtual page
	RScr← A0, Call[WriteMap];	* Write map entry; WP and Dirty = 0
PresetMapE:
	DblBranch[PresetMapL, FindModule, Cnt#0&-1];

* Exhausted all real storage.  Fill remainder of map with Vacant entries.
EndOfStorage:
	T← nPagesInMap;
	T← T-(MPageX)-1;
	RScr2← T-T-1, Cnt← T, Branch[PresetVacantE];
PresetVacantL:
	Nop;				* Placement
	MPageX← T← (MPageX)+1, Call[SetBRForPage];
	RScr← 140000C, Call[WriteMap];	* WP=1, Dirty=1, real page = -1
PresetVacantE:
	Branch[PresetVacantL, Cnt#0&-1];

	ReturnP;

* No storage modules are present.
NoStorage:
	Branch[.], Breakpoint;


*-----------------------------------------------------------
SetTestSyn:	* Load the TestSyndrome register from RScr2
*-----------------------------------------------------------
Subroutine;
	PushReturn;
	T← 62C, Call[LongWait];
	T← mcr.noWake, Call[SetMCR];
	T← A0, Call[SetBRForPage];	* Zero the current BR
	Store← T, DBuf← RScr2;		* DBuf← data
	LoadTestSyndrome;		* TestSyndrome← DBuf
	T← 62C, Call[LongWait];
ResetFaultInfo:
	B← FaultInfo', ReturnP;

*-----------------------------------------------------------
SetBRForPage:	* Set BR such that a reference to address 0 will generate
* 		a VA referencing the specified page.
* Enter: T = virtual page number
* Clobbers RScr.
*-----------------------------------------------------------
Subroutine;
	RScr← LSH[T, logWordsPerPage];
	BRLo← RScr;
	RScr← RSH[T, Sub[20, logWordsPerPage]];
	BRHi← RScr, Return;


*-----------------------------------------------------------
WriteMap:	 * Write map entry
* Enter: RScr = WP and Dirty bits, left-justified
*	RScr2 = real page number
*	Current BR contains VA for map entry to be written
*-----------------------------------------------------------
Subroutine;
	PushReturn;
	TIOA← RScr, Call[WaitForMapBuf];
	Map← 0S, MapBuf← RScr2, Call[WaitForMapBuf];
	ReturnP;


*-----------------------------------------------------------
WaitForMapBuf:
*-----------------------------------------------------------
Subroutine;
	PD← T-T-1;
	PD← PRef, Branch[., ALU<0];	* MapBufBusy is sign bit
	Return;


*-----------------------------------------------------------
ResetTags:	* kick start the tag bit for our task.
* RScr = address to reference.
* Note: Initial calls ResetTags in all tasks simultaneously, with the same
* RBase value.  However, that's ok because the return PC and argument
* (RScr2 and RScr) are the same for all calls.
*-----------------------------------------------------------
Set[XTask, 1];
Subroutine;
	RScr2← Link;			* Can't use PushReturn in I/O task!!
TopLevel;

Set[wantMCR, Or[mcr.noRef!,mcr.disHold!,mcr.disCF!,mcr.disBR!,mcr.noWake!]];
	T← HighByte[wantMCR];
	T← T OR (LowByte[wantMCR]), Call[SetMCR];

	Store← RScr, DBuf← RScr;	* write and read to cause a hit
	T← 10C, Call[LongWait];
	Link← RScr2;
Subroutine;
	Fetch← RScr, Return;

TopLevel;