{
 GermSwap.mc
 26-Oct-87 16:49:20
 
 Copyright 1987 by Xerox Corporation.  All rights reserved.

 Code we can drive from Bermuda to move the germ.
}


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

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

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

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

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

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

Set[L0.vswap,		0E];
Set[L0.germExch,	0F];

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

	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.

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

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

		rE ← cedarGermPageHigh,				c1;
		rE ← rE LRot8,					c2;
		rE ← rE or cedarGermPageLow, {vp of 3.0 germ}	c3;

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

{
	Swap map entries at .map 1 with those vacant entries at .map 3E02.
}

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

germExch:	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 1 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;

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

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

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

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

vswapdone:	GOTO[vswapdone],				c*;



{
	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;