:TITLE[LoadRAM];
%
Edit by Fiala 25 March 1981: Bummed 10b mi and improved speed 20 percent;
	changed FFault value for Alto mode exit; use yBuf-yBuf1 instead of
	xBuf-xBuf3 to overwrite less of Initialize's device table during
	CSLKeyboard overlay load; make ExchStkP and SetStkP available as
	subroutines.
Edit by Johnsson, January 28, 1980  12:14 PM
%
%Verify consistency of parameters among all implementations; only Initial
should contain this file directly--other programs should use LoadRAMOccupied.
GlobalDefs will normally define all entry locations.
%
IDF[LRJStart,IFE[LRJStart,300,,ER[Incompatible.value.for.LRJStart]],
	Set[LRJStart,300]];
IDF[LRJContinue,IFE[LRJContinue,300,,ER[Incompatible.value.for.LRJContinue]]];
IDF[ExchStkPLoc,IFE[ExchStkPLoc,330,,ER[Incompatible.value.for.ExchStkPLoc]],
	Set[ExchStkPLoc,330]];
IDF[SetStkPLoc,IFE[SetStkPLoc,331,,ER[Incompatible.value.for.SetStkPLoc]],
	Set[SetStkPLoc,331]];

%This code will load control store with mi from an array of items in the form:
	word 0	(addr lsh 4) or (cs bits 32d-35d)
	word 1	cs bits 0-15d
	word 2	bits 16d-31d
The last item has addr=7777b.  In the last item, word 1 is the start address
of the code just loaded and word 2 is a checksum.  The checksum should be
checked by other software since detection of errors after loading the control
store is of marginal interest.  The code below does not check checksums.

Entry conditions (at LRJenter):
	FFault even to crash on MC1 or stack errors
	LP,,LPhi has base pointer to array-1 in MakeLoaderFile form.
	xfTemp1 = 0 for inline refresh without tasking
		= 1 for normal tasking
	RTemp1 is even iff start address is to be believed
	RTemp1 < 0 if resume Alto emulator, >=0 if resume Mesa

Reentry conditions to load next overlay (also at LRJenter):
	LP,,LPhi untouched
	xfTemp1 and RTemp1 as above

Smashes yBuf, yBuf1, and yBuf2 (= RTemp).

Timing ~ 40 cycles/mi + [28 cycles if overlay started else 38 or 39 cycles]
+ 4 cycles/mi for inline refresh.  Fastest possible loop would be about
26 cycles/mi with lots more code and RM registers.
%

*To avoid "APCTask&APC← illegal with return" error message...
Macro[LRJAPCTask&APC←,FF1@[7] FF2@[10] A←];

LRJenter:
	LU ← LP, GoTo[.+3,R Odd], At[LRJStart];
	  PFetch1[LP,yBuf,1], At[LRJStart,2];
	  PFetch2[LP,yBuf1,2], OddOK, GoTo[.+3], At[LRJStart,1];
	PFetch2[LP,yBuf,1], At[LRJStart,3];
	PFetch1[LP,yBuf2,3], At[LRJStart,4];
	LP ← (LP) + (3C), Call[LRJ1], At[LRJStart,5];
*LRJ1 returns here if tasking permitted, else jumps here.
LRJ2:	LU ← yBuf1, UseCTask, Call[LRJadr], At[LRJStart,6];
	WriteCS0&2, LU ← yBuf2, At[LRJStart,7];
	APCTask&APC ← yBuf1, At[LRJStart,10];
	WriteCS1, GoTo[LRJenter], At[LRJStart,11];

LRJ1:	T ← (yBuf) + (20C), Skip[Carry'], At[LRJStart,12];
	  LPhi ← (LPhi) + (400C) + 1, GoTo[.-1], At[LRJStart,15];
	yBuf ← Rsh[yBuf,4], GoTo[RamLoaded,Carry], At[LRJStart,14];
	xfTemp1 ← (xfTemp1) + (20C), Skip[R Odd], At[LRJStart,16];
	  Refresh[xfTemp1], GoTo[LRJ2], At[LRJStart,20];
*It is ok to do APCTask&APC← with Return here because, if an io task runs
*next, it is not permitted to task (i.e., to have a Return) in its 1st mi;
*the emulator needs the APCTask&APC← for the call here from LRJ2--other
*emulator routes to this mi are unaffected.
LRJadr:	LRJAPCTask&APC ← yBuf1, Return, At[LRJStart,21];

RamLoaded:
	RTemp1, Skip[R Odd], At[LRJStart,17];	*odd if no jump
*Note that any task can be started.
	  LU ← APCTask&APC ← yBuf1, Call[LRJadr], At[LRJStart,22];
*Some started overlays may return here (NOTE that IP[RTemp] .eq. IP[yBuf2]).
	RTemp ← IP[FFault]C, Call[ExchStkP], At[LRJStart,23];
	RTemp1, T ← 1C, NoRegILockOK, GoTo[.+3,R>=0], At[LRJStart,24];
	  T ← PCB, LoadPageExternal[nePage], At[LRJStart,27];
	  GoToExternal[JmpFinLoc], At[LRJStart,13];
*Setting FFault odd causes MC1 and Stack errors to be handled by notifying
*the emulator rather than by crashing.
	Stack ← (Stack) or T, LoadPageExternal[opPage3], At[LRJStart,26];
	StkP ← RTemp, GoToExternal[P7TailLoc], At[LRJStart,25];

*Useful subroutines
ExchStkP:
	T ← (SStkP&NStkP) xor (377C), At[ExchStkPLoc];
SetStkP:
	StkP ← RTemp, RTemp ← T, NoRegILockOK, Return, At[SetStkPLoc];

:END[LoadRam];