{
 SwapGerm.mc
 30-Oct-87 23:08:11
 
 Copyright 1987 by Xerox Corporation.  All rights reserved.

 Code to move the germ from where Pilot leaves it to where Cedar wants it.
}


{** this stuff is specific to PrincOps version! **}

Set[mapRealAddrHigh,	4];
Set[mapRealAddrLow,	0];

Set[germPageHigh,	0];
Set[germPageLow,	0];

Set[cedarGermPageHigh,	3E];
Set[cedarGermPageLow,	2];

Set[globalFrameTableHigh,	2];
Set[globalFrameTableLow,	0];

Set[germPageCount,	30];	{should get this value from Opie}
Set[topPageHighByte,	1B];	{		"		}
Set[topPageLowByte,	80];	{		"		}

MacroDef[RtnBLT, at[#1,10,subrRet]];

Set[L0.gftExch,		0];
Set[L0.germExch,	1];
Set[L0.vswap,		2];

{++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

	Well, We've got a problem here.

	PrincOps 3.0 expects the germ at .mv 3E0200 and
	PrincOps 4.0 expects the germ at .mv 100.

	We can move the germ in virtual space by moving map entries; we don't have
	to move anything in physical address space.

	transferCount contains the number of virtual pages we have to move
	from .map 1 to .map 3E02

	CoreInitial sets up map and leaves next available virtual page in topPage.

	Since everybody's been nice enough so far to move things around and play the
	game according the the PrincOps 4.0 rules (like Bermuda),
	how about if we just swap the approprite map entries
	and leave everything as it already is?

	Well, that leaves a funny hole in VM at .mv 100,
	
	So...

	So we do an even cuter swap
	put the germ where it belongs: .mv 3E0200 <==> .mv 100
	move some real pages back under .vm 100 to be *nice*
	.map topPage-transferCount <==> .map 1

	On top of that, MDS relief required moving one other page in the germ that we
	have to fix up to get the global frame table back in the right place.

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
}

setSwapConstants:
		rB ← germPageCount,				c1;
		transferCount ← rB,	 			c2;
		rE ← topPageHighByte,				c3;

		rE ← rE LRot8,					c1;
		rE ← rE or topPageLowByte,			c2;
		topPage ← rE,					c3;

{
	Bermuda can break here to modify topPage or transferCount.
}

constantsOK:
		rC ← transferCount, {number of pages in germ}	c1;
		rErh ← mapRealAddrHigh,				c2;
		rBrh ← mapRealAddrHigh,				c3;

{
	Swap the gft (at .map 200) back where it belongs (.map 0)
}

swapGft:
		rB ← germPageHigh,				c1;
		rB ← rB LRot8,					c2;
		rB ← rB or germPageLow, {vp of 4.0 germ}	c3;

		rE ← globalFrameTableHigh,			c1;
		rE ← rE LRot8,					c2;
		rE ← rE or globalFrameTableLow,			c3;

		Noop,						c1;
		L0 ← L0.gftExch,				c2;
		CALL[memSwap],					c3;

		rE ← cedarGermPageHigh,				c1, RtnBLT[L0.gftExch];
		rE ← rE LRot8,					c2;
		rE ← rE or cedarGermPageLow, {vp of 3.0 germ}	c3;

{
	Swap map entries at .map 0 (Pilot germ location) with those vacant entries at .map 3E02 (Cedar germ location).
}

looper:
		Noop,						c1;
		L0 ← L0.germExch,				c2;
		CALL[memSwap],					c3;

		rB ← rB + 1,					c1, RtnBLT[L0.germExch];
		rC ← rC - 1, ZeroBr,				c2;
		rE ← rE + 1, BRANCH[looper, swipe],		c3;

{
	Now swap the map entries for the last physical memory pages *present* in vm
	with those at .map 0 to fill in the hole in vm.
}

swipe:
		rB ← germPageHigh,				c1;
		rB ← rB LRot8,					c2;
		rB ← rB or germPageLow, {vp of 4.0 germ}	c3;

		rC ← transferCount, {number of pages in germ}	c1;
		rE ← topPage,					c2;
		rE ← rE - rC, {vp of real memory block}		c3;

looper2:
		Noop,						c1; 
		L0 ← L0.vswap,					c2;
		CALL[memSwap],					c3;

		rB ← rB + 1,					c1, RtnBLT[L0.vswap];
		rC ← rC - 1, ZeroBr,				c2;
		rE ← rE + 1, BRANCH[looper2, vswapdone],	c3;

vswapdone:
		Noop,						c1;
		Noop,						c2;
		GOTO[Germ],					c3;



{
	Swaps two locations in memory, takes addresses in $rE and $rB, clobbers acR and rD.
}

memSwap:
		MAR ← [rErh, rE+0],				c1;
		Noop,						c2;
		acR ← MD,					c3;

		MAR ← [rBrh, rB+0],				c1;
		Noop,						c2;
		rD ← MD,					c3;

		MAR ← [rErh, rE+0],				c1;
		MDR ← rD,					c2;
		Noop,						c3;

		MAR ← [rBrh, rB+0],				c1;
		MDR ← acR, pRet0,				c2;
		RET[subrRet],					c3;