{
file: <CoPilot>DLion>CedarB0.mc
Created by H. Sturgis; major rewrite by E. Fiala
Edited by Trow	 9-Dec-87 23:44:53 

Copyright (C) 1983, 1984, 1985, 1986, 1987 by Xerox Corporation.  All rights reserved.

This bank 0 code continues opcode implementations begun in CedarB1.mc.  Opcodes defined
here are as follows:
	CRefType

	EnableMicrocode
	DisableMicrocode
	AssignRef
	CreateRef
	ReclaimedRef
	ReclaimableRef
	AllocateObject
	FreeObject
The performance critical opcodes are AssignRef and CRefType.  Other automatic storage
management opcodes are a factor of 10 less frequently executed than AssignRef and CRefType.
The opcodes from EnableMicrocode down are associated with Cedar automatic storage management
and are implemented as specified by Cedar's RCMicrocodeImpl.mesa; any of these may be
trapped and the software procedure used instead except EnableMicrocode, DisableMicrocode,
and GCSetup must be implemented if any others are implemented.

Subroutines in this file are also used by BlockB0.mc.

Notes:
1) C. Black reported that refCount=0 in the target of a Ref for which AssignRef
was decrementing the refCount; the ref pointed at a 64k boundary.  This was using 16 July 85
microcode.
2) Save 1 click in FOSLookup if separate U registers are used to make a pointer to
the FOSTable in EnableMicrocode.
3) Find out whether or not FOSTable can be in a separate 64k bank from ZCT.
4) Find out whether it is ok to page fault or get ZCT overflow after writing the header and
type words of a block in Allocate; if ok, then replace the useless read of the header by a
write of these two words.
5) The last entry instruction in CedarB1 and the first 4 entry instructions in CedarB0 can
be combined for AllocateObject and ReclaimedRef.
}


{****This stack error code has not been checked out****
CS Parity, stack, memory double-bit, and VM out-of-range errors jump to location 0 in bank 0,
or maybe to location 0 in the bank where the stack error occurs; this is synchronized so that
the trap begins on c1.  Code here transfers control to the error handler in Refill.mc.}

ErrLoc:
{db}	Bank ← MSBank1, CANCELBR[$, 0F],					c1, at[0];
{db}	rInt ← ErrnIBInt, ClrIntErr, GOTOABS[BxErrLoc]				c2;
{db}	GOTOABS[B1ErrInBank0] {In Refill.mc},					c3, at[BxErrLoc];

{Address of Bank1OpTable must match OpTable entry in Refill.mc; this mi is useless, but
it is addressed in DISPNI which is about to cross to the other bank.}
Bank1OpTable:
	GOTO[Bank1OpTable],					c*, at[500];


{*************************************************************************
aCRefType
   on entry
	TOS contains high order bits of a REF
	STK contains low order bits of a REF
   on exit
	stack is popped once
	TOS contains ref type
   Can page fault, but no traps are possible.  Preceding bank 1 instructions have been:
 	Bank ← MSBank0, L0 ← L0.CRefT2,				c1;
{db}	TT ← STK, L2 ← L2.CRefT1, GOTOABS[BxCRefType],		c2;
{db}	[] ← TOS or STK, ZeroBr, GOTOABS[B0CRefType],		c3, at[BxCRefType];
**************************************************************************}
{db}	[] ← TOS or STK, ZeroBr, GOTOABS[B0CRefType],		c3, at[BxCRefType];

CRefT0:	TT ← TT - 1, CarryBr, BRANCH[$, CRefTNil],		c1, at[B0CRefType];
	rhTT ← TOS LRot0, BRANCH[$, CRefT1],			c2;
	  Q ← TOS - 1, CALL[BankFix],				c3;
CRefT1:	TOS ← u3FFF, CALL[NcRdOne],				c3, at[L2.CRefT1, 10, BankFixRets];
	{returns to CRefT2}

CRefTNil:
	CANCELBR[$],						c2;
	TOS ← 0, pop, GOTO[CRefT6],				c3;

{now strip off top two bits}
CRefT2:	Bank ← MSBank1, pop,					c1, at[L0.CRefT2, 10, NcRdOneRets];
{db}	TOS ← TOS and T, IBDisp, GOTOABS[BxDISPNI2],		c2;
	
ReadMBusExit:
WriteMBusExit:
Enable4:
Disable2:
ALC17:
RAR5:
Free5:
Free14:
CRefT6:	Bank ← MSBank1,						c1, at[L0.Disable2, 10, NcWrDblRets];
CSDon6:
RR9:
{db}	IBDisp, GOTOABS[BxDISPNI2],				c2;
RAR6:
ALC18:
CRefT7:
{db}	PC ← PC + 1, DISPNI[Bank1OpTable],			c3, at[BxDISPNI2];
{next instruction will be in bank 1}


{*************************************************************************
aEnableMicrocode
	on entry
		TOS = high half of pointer to ZeroCountTable (ZCT)
		STK = low half of pointer to ZCT
	on exit
		stack is popped once
		TOS = ucVersion
		uMicrocodeDisabled = FALSE (= 0)
		uZctHigh = original TOS
		uZctLow = original STK
		<uWpHigh, uWpLow>, uMarkingDecrements, and uFOSResidueMask set from the ZCT
Can't fault or trap.  Previous bank 1 instructions have been:
	Bank ← MSBank0,						c1;
{db}	uZctHigh ← TOS, GOTOABS[BxEnable],			c2;
{db}	TT ← STK, GOTOABS[B0Enable],				c3, at[BxEnable];
*************************************************************************}
{db}	TT ← STK, GOTOABS[B0Enable],				c3, at[BxEnable];

Enable0:
	uZctLow ← TT, L0 ← L0.Enable2,				c1, at[B0Enable];
	uMicrocodeDisabled ← 0,					c2;
	rhTT ← uZctHigh, CALL[NcRdDbl] {read zct.wp},		c3;

Enable2:
	uWpHigh ← Q,						c1, at[L0.Enable2, 10, NcRdDblRets];
	uWpLow ← T, L0 ← L0.Enable3,				c2;
{TT still equals uZctLow because no page boundary was crossed by the previous NcRdDbl.}
	TT ← TT + NcMarkingDecsOffset, CALL[NcRdDbl],		c3;

Enable3:
	T ← RRot1 (T and 1),					c1, at[L0.Enable3, 10, NcRdDblRets];
	T ← RRot1 T,						c2;
	uMarkingDecrements ← T,					c3;
	
	uFOSResidueMask ← Q, pop,				c1;
	TOS ← 4,						c2;
	{noop} GOTO[Enable4],					c3;
	


{*************************************************************************
aDisableMicrocode
	on entry
		TOS = high half of pointer to ZCT
		STK = low half of pointer to ZCT
	on exit
		stack is popped twice
		TOS ← previous STK-1
		uMicrocodeDisabled ← TRUE (= -1)
		also, any modified cached ZCT info has been returned to ZCT (i.e., wP)
Previous bank 1 instructions have been:
	Bank ← MSBank0,						c1;
{db}	GOTOABS[BxDisable],					c2;
{db}	GOTOABS[B0Disable],					c3, at[BxDisable];
*************************************************************************}
{db}	GOTOABS[B0Disable],					c3, at[BxDisable];

Disable0:
	rhTT ← TOS LRot0,					c1, at[B0Disable];
	TT ← STK, pop,						c2;
	TOS ← STK, pop,						c3;
	
{db}	uMicrocodeDisabled ← ~rInt xor rInt,			c1;
	T ← uWpLow, L0 ← L0.Disable2,				c2;
	Rx ← uWpHigh, CALL[NcWrDbl] {write back zct.wp},	c3;
{Returns to Disable2 in CRefType.}


	
{*************************************************************************
AssignRef
   on entry
	TOS contains high order bits of a Long Pointer
	STK contains low order bits of the Long Pointer
	STK-1 contains high order bits of a Ref
	STK-2 contains low order bits of the Ref
	alpha byte contains the offset from <TOS, STK>
   on normal exit
	nominal semantics
		RefCount[theRefAt[TOS, STK] + offset] has been decremented
		RefCount[theRef[STK-1, STK-2]] has been incremented
		theRef[STK-1, STK-2] has been placed at [TOS, STK] + offset.
	all arguments popped from stack
   Can cause page fault or trap.  Preceding bank 1 instructions were as follows:
 	Q  ← ib, push,						c1;
	STK ← TOS, pop, Rx ← TOS + 1,				c2;
	T ← 76'b,						c3;

	Bank ← MSBank0,						c1;
{db}	uNcTrapOffset ← T, GOTOABS[BxAssignRef],		c2;
{db}	[] ← uMicrocodeDisabled, ZeroBr, GOTOABS[B0AssignRef],	c3, at[BxAssignRef];
*************************************************************************}
{db}	[] ← uMicrocodeDisabled, ZeroBr, GOTOABS[B0AssignRef],	c3, at[BxAssignRef];

AR0:	TT ← STK, pop, BRANCH[$, AR0a],				c1, at[B0AssignRef];
	  TT ← NcDisabledTrap, push, GOTO[NcTrapC3],		c2;
AR0a:	TT ← TT + Q {Q = ib}, CarryBr, pop,			c2;
	uARefLhsLow ← TT,  pop, BRANCH[AR1a, AR1b],		c3;

{no effect on stackP, trap if stackP = 0; note that TT will hold uARefLhsLow
until subsequent call on NcRdDbl}
AR1a:	uARefLhsHigh ← TOS, fXpop, push, GOTO[AR1c],		c1;
AR1b:	uARefLhsHigh ← Rx, fXpop, push,				c1;
AR1c:	rhTT ← uARefLhsHigh, push,				c2;
	Q ← STK, {STK - 2} push,				c3;

	T ← STK, {STK - 1} push,				c1;
{Stack pointer is now ok for page faults, etc., and stack overflow has occurred, if its going to happen.}
{**Maybe combine this mi with AR5c below somehow.}
	uARefRhsNil ← T or Q, L0 ← L0.AR4,			c2;
{compute the NHP for the rhs}	
	Q ← Q - 2 {prefix size}, CarryBr,			c3;

	uARefRhpLow ← Q, BRANCH[AR3a, AR3b],			c1;
AR3a:	Q ← T - 1, GOTO[AR3c],					c2;
AR3b:	Q ← T, GOTO[AR3c],					c2;
AR3c:	uARefRhpHigh ← Q, CALL[NcRdDbl] {read the lhs ref},	c3;
	{note: <rhTT, TT> is still holding <uARefLhsHigh, uARefLhsLow>}

{test for nil old ref (lhs)}	
AR4:	uARefLhsRefNil ← T or Q,				c1, at[L0.AR4, 10, NcRdDblRets];
{compute the pointer to the header word for the lhs}	
	T ← T - 2, CarryBr,					c2;
	uARefLhpLow ← T, BRANCH[AR5a, AR5b],			c3;

AR5a:	Q ← Q - 1, GOTO[AR5c],					c1;
AR5b:	Q ← Q - 0, GOTO[AR5c],					c1;

{if rhs non nil, then read and process the rhs header word}
AR5c:	[] ← uARefRhsNil, ZeroBr, L0 ← L0.AR7,			c2;
	uARefLhpHigh ← Q, BRANCH[$, AR8a],			c3;
		
	[] ← uARefRhpHigh xor Q, NZeroBr, rhTT ← uARefRhpHigh,	c1;	
	[] ← uARefRhpLow xor T {uARefLhpLow}, NZeroBr, BRANCH[$, AR6a],	c2;
{read the new (rhs) header word}
{also, if lhs = rhs, then return (x←x)}	
	TT ← uARefRhpLow, BRANCH[AR15, NcRdOne],		c3;

AR6a:	TT ← uARefRhpLow, CANCELBR[NcRdOne],			c3;
 
AR7:	Rx ← T + 2, {add 1 to rhs refCount field}		c1, at[L0.AR7, 10, NcRdOneRets];
	Q ← Rx and 176'b {extract refCount field},		c2;
{uARefRhsW must have maybeOnStack set to false before it is written.}
	uARefRhsW ← Rx, Rx ← Rx and Q, ZeroBr {test for overflow},	c3;
	
{branch if rhs refCount = last[]}
{rhs nil comes here}
{now process lhs ref; first, if non nil, read the header word}
AR8a:	[] ← uARefLhsRefNil, ZeroBr, L0 ← L0.CheckForUnderflow, BRANCH[$, AR18],	c1;
	TT ← uARefLhpLow, L3 ← L3.AR10, BRANCH[$, AR12a],	c2;
	rhTT ← uARefLhpHigh, CALL[NcRdOne],			c3;
{NcRdOne returns to CheckForUnderflow which checks for underflow and
subtracts 1 from refCount if no underflow occurs}

AR10:	Rx ← RRot1 u8000 {maybeOnStack bit},			c2, at[L3.AR10, 10, CheckForUnderflowRets];
{maybeOnStack ← markingDecrements}	
	T ← T and ~Rx,						c3;

{Check the LHS refCount field and overflow bit simultaneously; call OnZ if both of these
are 0 or if uMarkingDecrements # 0.}
	TOS ← 177'b,						c1;
	[] ← T and TOS, ZeroBr,					c2;
	TOS ← uMarkingDecrements, NZeroBr, BRANCH[$, AR10d],	c3;

	TOS ← T or TOS, BRANCH[AR11b, AR10e],			c1;
AR10d:	TOS ← T or TOS, CANCELBR[$]				c1;
AR10e:	T ← uARefLhpLow, L3 ← L3.AR11b,				c2;
	Rx ← uARefLhpHigh, CALL[OnZ],				c3;
	
{now write back the left side header word}
AR11b:	TT ← uARefLhpLow, L0 ← L0.AR12b,			c2, at[L3.AR11b, 10, OnZRets];
	rhTT ← uARefLhpHigh, CALL[NcWrOne],			c3;

AR12a: {lhs = nil jumps here}
	{noop}							c3;
	
{write back the rhs header word, if rhs # nil}	
AR12b:	[] ← uARefRhsNil, ZeroBr,				c1, at[L0.AR12b, 10, NcWrOneRets];
	Rx ← RRot1 u8000 {maybeOnStack}, BRANCH[$, AR13],	c2;
	T ← uARefRhsW,						c3;

	rhTT ← uARefRhpHigh,					c1;
	TT ← uARefRhpLow, L0 ← L0.AR14,				c2;
	T ← T and ~Rx, CALL[NcWrOne],				c3;
					
AR14:	{noop}							c1, at[L0.AR14, 10, NcWrOneRets];
	{noop}							c2;
{finally, do lhs↑ ← rhs}
AR13:	TT ← uARefLhsLow, pop,					c3;
	Rx ← STK {rhs high}, pop, L0 ← L0.AR16,			c1;
	T ← STK {rhs low},					c2;
	rhTT ← uARefLhsHigh, CALL[NcWrDbl],			c3;

AR16:	Bank ← MSBank1, GOTO[AR19],				c1, at[L0.AR16, 10, NcWrDblRets];

{x←x comes here}
AR15:	pop,							c1;
	pop,							c2;
	{noop}							c3;

CR3:	Bank ← MSBank1,						c1, at[L0.CR3, 10, NcWrOneRets];
LBZ7:
AR19:
{db}	PC ← PC + 1, pop, IBDisp, GOTOABS[BxDISPNI],		c2;
{db}	TOS ← STK, pop,	DISPNI[Bank1OpTable],			c3, at[BxDISPNI];

{rhs refCount overflow trap}
AR18:	TT ← NcRCOverflowTrap, CANCELBR[NcTrapC3],		c2;



{*************************************************************************
CreateRef
   on entry
	<TOS, STK> contain an NHP (pointer to a header word)
   on normal exit
	NHP entered into ZCT
	header word modified
	all arguments popped from stack
   Can cause Page Fault.  Previous bank 1 instructions have been:
 	Bank ← MSBank0, L0 ← L0.CR1,				c1;
{db}	T ← Rx + 377'b + 1, GOTOABS[BxCreateRef],		c2;
{db}	[] ← uMicrocodeDisabled, ZeroBr, GOTOABS[B0CreateRef],	c3, at[BxCreateRef];
*************************************************************************}
{db}	[] ← uMicrocodeDisabled, ZeroBr, GOTOABS[B0CreateRef],	c3, at[BxCreateRef];

ReclaimableRef0:
CreateRef0:
	uNcTrapOffset ← T, BRANCH[$, CR0a],			c1, at[B0CreateRef];
	  TT ← NcDisabledTrap, GOTO[NcTrapC3],			c2;
CR0a:	TT ← STK, {fXpop, fZpop,}				c2;
	rhTT ← TOS LRot0, {push,} CALL[NcRdOne],		c3;
	
CR1:	TT ← 177'b, {refCount field u 1},			c1, at[L0.CR1, 10, NcRdOneRets];
	[] ← TT and T, NZeroBr,					c2;
{Assume existing value of maybeOnStack = 0 and set it to 1 if marking decrements.}
	Rx ← TOS, BRANCH[$, CR4],				c3;

	TOS ← uMarkingDecrements,				c1;
	TOS ← T or TOS, L3 ← L3.CR2,				c2;
	T ← STK, CALL[OnZ],					c3; 

CR2:	TT ← STK, L0 ← L0.CR3, push,				c2, at[L3.CR2, 10, OnZRets];
	rhTT ← STK, pop, CALL[NcWrOne],				c3;
{next instruction at the end of AssignRef}

CR4:	TT ← NcCedarDisasterTrap, GOTO[NcTrapC2],		c1;


{*************************************************************************
ReclaimableRef
  on entry
	<TOS, STK> contain an NHP.
  results
	If refCount # 0 or RCOverflow or inZCT = 1 then return "continue";
	else if maybeOnStack = 1 or FoundInFOSTable then OnZ & return "continue";
	else if f = 1 then return "finalizeIt";
	else return "reclaimIt".
  Can page fault; only traps are microcode disabled and ZCT overflow.
  Previous bank 1 instructions have been:
 	Bank ← MSBank0, L0 ← L0.RAR1,				c1;
{db}	T ← Rx + 377'b + 1, GOTOABS[BxCreateRef],		c2;
{db}	[] ← uMicrocodeDisabled, ZeroBr, GOTOABS[B0CreateRef],	c3, at[BxCreateRef];
*************************************************************************}

RAR1:	Rx ← RRot1 377'b,					c1, at[L0.RAR1, 10, NcRdOneRets];
	[] ← T and Rx, NZeroBr, {inZCT, refCount # 0 or RCOverflow?}	c2;
	uHdrSave ← T, Rx ← LRot1 T, BRANCH[$, RARCont1],	c3;

{Not in ZCT, refCount = 0, and RCOverflow = 0}
	[] ← Rx, NegBr {maybeOnStack?},				c1;
	uHdrHigh ← TOS, BRANCH[$, RAROnZ1],			c2;
	L3 ← L3.RAR2,						c3;

	TOS ← TOS and 377'b, CALL[FOSLookUp],			c1;

RAR2:	T ← 200'b {f}, BRANCH[$, RAROnZ2],			c3, at[L3.RAR2, 10, NcFOSLURets];

	[] ← uHdrSave and T {f}, ZeroBr,			c1;
	BRANCH[$, RAR4],					c2;
{RAR5 is at the end of CRefType}
	TOS ← 2 {finalizeIt}, pop, GOTO[RAR5],			c3;
RAR4:	TOS ← 1 {reclaimIt}, pop, GOTO[RAR5],			c3;

RAROnZ5:
RARCont1: {Rare inZCT = 1 race case, refCount # 0, or RCOverflow}
	Bank ← MSBank1, pop,					c1, at[L0.RAROnZ5, 10, NcWrOneRets];
{db}	TOS ← 0 {continue = 0}, IBDisp, GOTOABS[BxDISPNI2],	c2;

RAROnZ1: {maybeOnStack => OnZ and "continue"}
	uHdrSave ← T,						c3;
RAROnZ2: {Found in FOSTable => OnZ and "continue"}
	Rx ← uHdrHigh {NHPHigh},				c1;
RAROnZ3:
	TOS ← uHdrSave {header}, L3 ← L3.RAROnZ4,		c2;
	T ← STK {NHPLow}, CALL[OnZ],				c3;

RAROnZ4:
	TT ← STK, L0 ← L0.RAROnZ5,				c2, at[L3.RAROnZ4, 10, OnZRets];
	rhTT ← uHdrHigh, CALL[NcWrOne],				c3;



{*************************************************************************
ReclaimedRef
  on entry
	<TOS, STK> contain a Ref already checked for non-NIL and plausibility.
  results
	trap on underflow, else
	return NIL if no further action is necessary, or
	return the Ref, if it should be reclaimed or has finalization.
  NIL is returned if Ref-2 is already in the ZCT or if refCount > 1.
  If refCount = 1 but maybeOnStack=1, then the Ref is put in ZCT and NIL is returned.
  If Ref-2 or the WildCard is found in the FOSTable, then NIL is returned.
  Can Trap or cause Page Fault.  Previous bank 1 instructions have been:
 	Bank ← MSBank0,						c1;
{db}	T ← Rx + 377'b + 1, GOTOABS[BxReclaimedRef],		c2;
{db}	[] ← uMicrocodeDisabled, ZeroBr, GOTOABS[B0ReclaimedRef],	c3, at[BxReclaimedRef];
*************************************************************************}
{db}	[] ← uMicrocodeDisabled, ZeroBr, GOTOABS[B0ReclaimedRef],	c3, at[BxReclaimedRef];

ReclaimedRef0:
	uNcTrapOffset ← T, BRANCH[$, RR0a],			c1, at[B0ReclaimedRef];
	  TT ← NcDisabledTrap, GOTO[NcTrapC3],			c2;
RR0a:	TT ← STK, L0 ← L0.CheckForUnderflow,			c2;
	TT ← TT - 2, CarryBr,					c3;

	uHdrLow ← TT, BRANCH[$, RR2],				c1;
	TOS ← TOS - 1, L3 ← L3.RR3, GOTO[RR2a],			c2;
RR2:	TOS ← TOS, L3 ← L3.RR3,					c2;
RR2a:	rhTT ← TOS LRot0, CALL[NcRdOne] {fetch the header},	c3;
{NcRdOne returns to CheckForUnderflow with the header in T;
CheckForUnderflow traps on underflow, else subtracts 1 from refCount and returns.}

RR3:	Rx ← RRot1 377'b,					c2, at[L3.RR3, 10, CheckForUnderflowRets];
	[] ← T and Rx, NZeroBr {inZCT, refCount # 0 or RCOverflow?},	c3;

	uHdrSave ← T, Rx ← T LRot1, BRANCH[$, RR6],		c1;
	[] ← Rx, NegBr {Test maybeOnStack}, L3 ← L3.RR4, 	c2;
	uHdrHigh ← TOS, BRANCH[$, RR7],				c3;

	TOS ← TOS and 377'b, CALL[FOSLookUp],			c1;

RR4:	T ← uHdrSave, BRANCH[$, RR11],				c3, at[L3.RR4, 10, NcFOSLURets];

{No match in FOSTable.  Check for finalization.}
	TOS ← 200'b,						c1;
	[] ← T and TOS, ZeroBr {f}, push,			c2;
	TOS ← STK, pop, BRANCH[RR12, $],			c3;
	
{Reclaim is indicated.  Write the header in T and return the Ref as the result.}
	rhTT ← uHdrHigh, 					c1;
	TT ← uHdrLow, L0 ← L0.RR8, GOTO[RR13],			c2;

{finalization trap}
RR12:	TT ← RCFinalizeTrap, GOTO[NcTrapC2],			c1;

{refCount = 0 and not in ZCT, but maybeOnStack = 1, so put the Ref in ZCT}
RR7:	Rx ← uHdrHigh, GOTO[RR5],				c1;
	
{FOS match => enter in ZCT}	
RR11:	Rx ← uHdrHigh,						c1;
RR5:	T ← uHdrLow, L3 ← L3.RR10,				c2;
	TOS ← uHdrSave, CALL[OnZ],				c3;

RR10:	TT ← uHdrLow,						c2, at[L3.RR10, 10, OnZRets];
	rhTT ← uHdrHigh,					c3;

	{noop}							c1;
{Decremented refCount # 0 or nhp already in ZCT}
RR6:	STK ← TOS ← 0, L0 ← L0.RR8,				c2;
RR13:	CALL[NcWrOne] {Write back the header},			c3;
	
RR8:	Bank ← MSBank1, GOTO[RR9] {In CRefType},			c1, at[L0.RR8, 10, NcWrOneRets];


{*************************************************************************
AllocateObject
  on entry
	TOS	type
	STK	requested size EXCLUDING the two NHP words
  results
	TOS	high part of a Ref to the allocated block
	STK	low part of the Ref
  Return NIL if size > Allocator.maxSmallBlockSize (= 1076'b).  Otherwise,
  extract the 8-bit BSI (Block Size Index) from ZCT.sizeToBSI.  Finally, fetch
  the pointer to the free list for objects of this BSI from ZCT.BSItoFreeList.
  Trap if the free list pointer is NIL; otherwise, it points at the NHP of a
  block, and the Ref returned will be NHP + 2.  Fetch the long pointer to the
  next free list object from [NHP+2]↑, store it into the free list header, and
  zero the two words which contained that long pointer (leaving the object entirely zero).
  
  The maybeOnStack, F, refCount, RCOverflowed fields of a free list object
  are known to contain 0, and the body of the object is zero except for the
  two-word link to the next free list object; F cannot be initialized to 1 here
  when the Ref will have finalization because the Ref must be put in other data
  structures first.
  
  Can page fault; traps are microcode disabled, ZCT full, and NormalFreeListEmpty.
  Previous bank 1 instructions have been:
 	Bank ← MSBank0,						c1;
{db}	T ← Rx + 377'b + 1, GOTOABS[BxAllocateObject],		c2;
{db}	[] ← uMicrocodeDisabled, ZeroBr, GOTOABS[B0AllocateObject],	c3, at[BxAllocateObject];
*************************************************************************}
{db}	[] ← uMicrocodeDisabled, ZeroBr, GOTOABS[B0AllocateObject],	c3, at[BxAllocateObject];

@AllocateObject0:
	uNcTrapOffset ← T, BRANCH[$, ALC1],			c1, at[B0AllocateObject];
	  TT ← NcDisabledTrap, GOTO[NcTrapC3],			c2;
{Size > maxSmallBlockSize (= 1076'b)  =>  return NIL.}
ALC1:	TT ← STK {size},					c2;
	Rx ← LShift1(377'b), SE ← 1 {777'b},			c3;

	Rx ← Rx + 77'b {1076'b},				c1;
	[] ← TT - Rx - 1, CarryBr, L0 ← L0.ALC3,		c2;
	TT ← RShift1(STK), SE ← 0, BRANCH[$, ALCNil],		c3;

{ZCT.sizeToBSI is packed two items per word beginning at ZCT word 1400'b}
	Rx ← Rx + 302'b {1400'b},				c1;
{Check for stack underflow, no change to StkP.}
	TT ← TT + Rx, fXpop, fZpop, push,			c2;
	TOS ← RRot1(STK), CALL[RdZCTTT],			c3;

ALC3:	[] ← TOS, NegBr {even or odd byte?}, L0 ← L0.ALC8,	c1, at[L0.ALC3, 10, NcRdOneRets];
	Rx ← T LRot8, BRANCH[$, ALC4],				c2;
{Even displacements => bits 0..7, odd displacements => bits 8..15'd in the word.}
	T ← LShift1(Rx and 377'b), SE ← 0, GOTO[ALC5],		c3;
ALC4:	T ← LShift1(T and 377'b), SE ← 0,			c3;

ALC5:	TT ← T + 377'b + 1 {400'b = displacement of BSItoFreeList table}, CALL[RdDblZCTTT],	c1;

ALC8:	[] ← T or Q, ZeroBr {free list = NIL?}, L0 ← L0.ALC9,	c1, at[L0.ALC8, 10, NcRdDblRets];
	TT ← uNHPLow ← T, BRANCH[$, ALCEmpty],			c2;

{Since the header and first two data words of the block may be on different pages and get
page faults, both must be referenced before calling OnZ.
  [NHP + 0]	header word (OR'ed with markingDecrements and inZCT)
  [NHP + 1]	type word (set from argument originally in TOS)
  [NHP + 2]	low part of link to next free block
  [NHP + 3]	high part of link to next free block
}
	rhTT ← Q LRot0, CALL[NcRdOne] {Read the header},	c3;

ALC9:	Q ← rhTT,						c1, at[L0.ALC9, 10, NcRdOneRets];
	uNHPHigh ← Q,						c2;
	TOS ← uMarkingDecrements, L2 ← L2.ALC10,		c3;

	TT ← TT + 2, CarryBr, L0 ← L0.ALC11,			c1;
	TOS ← T or TOS, BRANCH[ALC10, $],			c2;
	  Q ← Q + 1, CALL[BankFix],				c3;
ALC10:	uRefHi ← Q, CALL[NcRdDbl],				c3, at[L2.ALC10, 10, BankFixRets];

ALC11:	uNextFLLow ← T,						c1, at[L0.ALC11, 10, NcRdDblRets];
	uNextFLHigh ← Q,					c2;
{Start making the header word; all fields are 0 except markingDecrements and inZCT.}
	T ← uNHPLow, L3 ← L3.ALC12,				c3;

	Rx ← uNHPHigh,						c1;
	{noop}							c2;
	{noop} CALL[OnZ],					c3;

{Have header word in T now; write header and type}
ALC12:	TT ← uNHPLow, push, L0 ← L0.ALC13,			c2, at[L3.ALC12, 10, OnZRets];
	rhTT ← uNHPHigh,					c3;

	Rx ← STK {type}, pop,					c1;
	{noop}							c2;
	{noop} CALL[NcWrDbl],					c3;

{TT was not smashed by NcWrDbl because the header address is even.}
ALC13:	TT ← TT + 2,						c1, at[L0.ALC13, 10, NcWrDblRets];
	rhTT ← uRefHi,						c2;
	T ← 0, L0 ← L0.ALC16,					c3;

	Rx ← 0,							c1;
	STK ← TT {Low part of returned Ref}, 			c2;
{Write NIL into first two words of block.}
	TOS ← uRefHi {High part of returned Ref}, CALL[NcWrDbl],	c3;

ALC16:	T ← uNextFLLow,						c1, at[L0.ALC16, 10, NcWrDblRets];
	Rx ← uNextFLHigh,					c2;
	TT ← uFLLow, L0 ← L0.ALC17,				c3;

	rhTT ← uFLHigh,						c1;
	{noop}							c2;
	{noop} CALL[NcWrDbl] {Advance the free list},		c3;
{L0.ALC17 is the same location as L0.Disable2 which is in CRefType.}

{Free list empty => return NIL.}
ALCNil:	Bank ← MSBank1,						c1;
{db}	TOS ← STK ← 0 {NIL}, IBDisp, GOTOABS[BxDISPNI2],	c2;

ALCEmpty:
	TT ← NormalFreeListEmpty, GOTO[NcTrapC1],		c3;



{*************************************************************************
FreeObject
  At original entry:
	TOS	high part of NHP
	STK	low part of NHP
  At subsequent entry following interrupts or page faults, there is an extra
  word on the stack, and it is known that BSI # BSIEscape:
  	TOS	Count of words left to zero
	STK	high part of NHP
	STK-1	low part of NHP
  results
	TOS	1 if successful, 0 if unsuccessful
  Trap with parameter 2 if microcode is disabled; otherwise, fetch the header
  word to obtain the BSI.  Return false if BSI = 77'b (BSIEscape).  In all other
  cases, the object size (INCLUDING the 2 header words) is obtained from the
  BSItoSize table in the ZCT, and the object is zeroed except for the first
  header word.  Finally, the current free list pointer for the object's BSI is
  fetched from the ZCT and stored in words 2 and 3 of the object; finally, the
  NHP is stored in the free list cell.
  
  Since the object may be as large as 1100'b words, it is necessary to retain
  state during block zeroing for restart from page faults and interrupts.
  Since other processes might run and change the free list before FreeObject
  completes, the free list update must be atomic, must be done only once, and
  must be done after block zeroing to prevent a race with AllocateObject.  An
  extra word containing a count of words remaining to be zeroed is pushed onto
  the stack; restarting the opcode after a page fault or interrupt can be
  distinguished from the first start because the opcode is minimal stack, so the
  stack pointer is unique in each case.
  
  Can page fault or be interrupted; only trap is microcode disabled.

  Previous instructions in Bank 1 have been:
	Bank ← MSBank0,						c1;
{db}	T ← Rx + 377'b + 1, GOTOABS[BxFreeObject],		c2;
{db}	uNcTrapOffset ← T, GOTOABS[B0FreeObject],		c3, at[BxFreeObject];
*************************************************************************}
{db}	uNcTrapOffset ← T, GOTOABS[B0FreeObject],		c3, at[BxFreeObject];

@FreeObjecta:
	Rx ← ErrnIBnStkp, L0 ← L0.Free3,			c1, at[B0FreeObject];
	Rx ← Rx and 17'b {~StkP},				c2;
{StkP = 0 when the stack is empty, 1 when a single item is in TOS, etc.  So
on the original call stackp = 2 here, and stackp = 3 when resuming from an
interrupt with the block-zeroing count already pushed onto the stack.}
	[] ← Rx xor 15'b, ZeroBr {StkP = 2)?},			c3;

	[] ← uMicrocodeDisabled, NZeroBr, BRANCH[$, Free1],	c1;
	[] ← Rx xor 14'b, ZeroBr {StkP = 3?}, BRANCH[$, FreeDisabled0],	c2;
	rhTT ← STK, pop, BRANCH[$, Free2],			c3;
	  TT ← NcCedarDisasterTrap, GOTO[NcTrapC2] {Stack too big on minimal stack opcode},	c1;
{The opcode restarted from page fault or interrupt with count word on the stack.
The header must still be read to determine the BSI.}
Free2:	TT ← STK, push, L0 ← L0.Free2a,				c1;
	{noop}							c2;
	CALL[NcRdOne] {Read the header},			c3;

Free2a:	Q ← 77'b,						c1, at[L0.Free2a, 10, NcRdOneRets];
	T ← (T LRot8) and Q {BSI}, L1 ← L1.Free9,		c2;
{Note that TT and rhTT are still equal to the NHP.}
	uBSISave ← T, GOTO[Free7],				c3;

{Original call => initialize count word on the stack.}
Free1:	rhTT ← TOS LRot0 {high part of NHP}, BRANCH[$, FreeDisabled1],	c2;
	TT ← STK {low part of NHP}, CALL[NcRdOne] {Read the header},	c3;

Free3:	Q ← 77'b,						c1, at[L0.Free3, 10, NcRdOneRets];
	T ← (T LRot8) and Q {BSI},				c2;
	[] ← T xor Q, ZeroBr,					c3;

{1000'b + BSI = displacement to word containing size of block.}
	TT ← LShift1(377'b), SE ← 1, BRANCH[Free4, $],		c1;
	  {BSI = BSIEscape => return false.}
	  TOS ← 0, pop,						c2;
	  GOTO[Free5] {In CRefType},				c3;
Free4:	TT ← TT + T + 1, L0 ← L0.Free6,				c2;
	uBSISave ← T, CALL[RdZCTTT],				c3;

{The block size includes the two header words; zero the second header word and
all data words in the block, and then store the old free list pointer into the
first two data words of the block.  The number of words to zero is the block
size (including 2 header words) - 1.  The pointer to the last word in the block
is NHP + block size - 1.}
Free6:	TT ← STK, push {low part of NHP},			c1, at[L0.Free6, 10, NcRdOneRets];
	TOS ← T - 1, L1 ← L1.Free9,				c2;
	{noop}							c3;

Free7:	TT ← TT + TOS, CarryBr, L2 ← L2.Free8,			c1;
	Q ← rhTT ← STK, BRANCH[Free8, $],			c2;
	  Q ← Q + 1, CALL[BankFix],				c3;
{Now have no. words to zero in TOS, pointer to last word in <rhTT, TT>.}
Free8:	{noop} CALL[BZero1],					c3, at[L2.Free8, 10, BankFixRets];

{The block has now been zeroed except for the first header word, and TOS contains 0.
Also, TT ← LShift1(uBSISave), SE ← 0 has been done on the RET from the BZero subroutine.
It is possible that the type word (2nd header word) and first two data words are on
different pages, and that the page containing the first two data words has been
swapped out since it was zeroed; in this case, a page fault would occur when writing the
old free list pointer into the first two data words of the block.

The displacement from the beginning of the ZCT to the free list pointer = 400'b + 2*BSI.}
Free9:	TT ← TT + 377'b + 1, L0 ← L0.Free11, CALL[RdDblZCTTT],	c1, at[L1.Free9, 10, BZRets];

{Write free list pointer in <Q, T> into (NHP + 2)↑.  Note that <rhTT, TT> did not change
during NcRdDbl because the address was even.}
Free11:	Rx ← Q, pop,						c1, at[L0.Free11, 10, NcRdDblRets];
	TT ← STK, push, L0 ← L0.Free13,				c2;
	TT ← TT + 2, CarryBr, L2 ← L2.Free12,			c3;

	Q ← rhTT ← STK, BRANCH[Free12, $],			c1;
	  Q ← Q + 1, CALL[BankFix],				c2;
Free12:	Noop,							c2, at[L2.Free12, 10, BankFixRets];
	{noop} CALL[NcWrDbl],					c3;

{Write the NHP into the free list--can't page fault.}
Free13:	TT ← uFLLow,						c1, at[L0.Free13, 10, NcWrDblRets];
	rhTT ← uFLHigh,						c2;
	Rx ← STK, pop,						c3;

	T ← STK, pop, L0 ← L0.Free14,				c1;
	TOS ← 1,						c2;
	CALL[NcWrDbl] {Returns to CRefType},			c3;

{If microcode is disabled after block zeroing commenced (and the opcode
was interrupted or page faulted), then work so far accomplished is abandoned,
the stack is reset to its value at the original onset of the opcode, and the
disabled trap is given.}
FreeDisabled0:
	pop, BRANCH[$, FreeDisabled2],				c3;
	TT ← NcCedarDisasterTrap, GOTO[NcTrapC2],		c1;
FreeDisabled2:
	TT ← NcDisabledTrap, GOTO[NcTrapC2],			c1;

FreeDisabled1:
	TT ← NcDisabledTrap, GOTO[NcTrapC1],			c3;



{*************************************************************************
CheckForUnderflow
  At entry:
	L3	return link
	T	header word
  Disaster trap if refCount = 0 and RCoverflow = 0;
  Underflow trap if refCount = 0 and RCoverflow = 1;
  Otherwise:
	T	original value with refCount field decremented.
	Rx	176'b
*************************************************************************}
CheckForUnderflow:
	Rx ← 176'b,						c1, at[L0.CheckForUnderflow, 10, NcRdOneRets];
	[] ← T and Rx, ZeroBr,					c2;
	L3Disp, BRANCH[$, CheckForUnderflow1],			c3;
	T ← T - 2, RET[CheckForUnderflowRets],			c1;

{refCount = 0}	
CheckForUnderflow1:
	[] ← T and 1, {rcOverflowed} ZeroBr, CANCELBR[$, 0F],	c1;
	BRANCH[CheckForUnderflow2, CheckForUnderflow3],		c2;

CheckForUnderflow2: {refCount=0 and rcOverflow so trap}
	TT ← NcUnderflowOccured, GOTO[NcTrapC1],		c3;

CheckForUnderflow3: {refCount=0 and not rcOverflow so error}
	TT ← NcCedarDisasterTrap, GOTO[NcTrapC1],		c3;
	

{*************************************************************************
OnZ
  At entry:
  	L3 return link
	Rx = NHPHigh
	T = NHPLow
	TOS = header
  At exit:
  	<NHPHigh, NHPLow> has been put in the ZCT.
	T = the header with the inZCT bit set (but it has not been stored)
	Smashes TT, rhTT, Q, Rx, rhRx, TOS, L2, L0
  It is the callers responsibility to store the header in T.
*************************************************************************}
OnZ:	[] ← TOS, NegBr {test inZCT bit}, L0 ← L0.OnZ1,		c1;
	TT ← uWpLow, BRANCH[$, OnZDone],			c2;
{Store <NHPHigh, NHPLow> = <Rx, T> in ZCT at the location pointed at by <uWpHigh, uWpLow>}
	rhTT ← uWpHigh, CALL[NcWrDbl],				c3;

{ref now in memory; try to advance wp.  When the low-order block address bits for the
double-word just written are 3774'b, then the next double-word (at <3776'b, 3777'b>)
is the link to the next block.  <uWpHigh, uWpLow> are still in <rhTT, TT> because TT
being even implies that no page boundary was crossed when writing the double-word.}
{OnZ1:	Q ← TT and u7FF {3777'b}, L0 ← L0.OnZ2,			c1, at[L0.OnZ1, 10, NcWrDblRets];
	Q ← Q + 3,						c2;
	[] ← Q xor u7FF, ZeroBr {end of block?},		c3;

	TT ← TT + 2, BRANCH[OnZ.BlockNotFull, $],		c1;
{Block full; this read of the block link can't fault because the preceding 2 words
on the same page were just written.}
	Rx ← RRot1 1,						c2;
	TOS ← Rx or TOS {Set inZCT = 1}, CALL[NcRdDbl],		c3;}

OnZ1:	Q ← TT + 4, L0 ← L0.OnZ2,				c1, at[L0.OnZ1, 10, NcWrDblRets];
	[] ← Q and u7FF, ZeroBr {end of block?},		c2;
	TT ← TT + 2, BRANCH[OnZ.BlockNotFull, $],		c3;

{Block full; this read of the block link can't fault because the preceding 2 words
on the same page were just written.}
	Map ← Q ← [rhTT, TT], GOTO[NcRdDbl0],			c1;

	
OnZ2:	[] ← T or Q, ZeroBr,					c1, at[L0.OnZ2, 10, NcRdDblRets];
	BRANCH[$, OnZ.NilLink],					c2;
	uWpLow ← T,						c3;
	
	uWpHigh ← Q,						c1;
	GOTO[OnZDone],						c2;

OnZ.BlockNotFull:
 	Noop,							c1;
	uWpLow ← TT,						c2;
OnZDone: {Sign bit = 1 indicating already in ZCT}
	T ← RRot1 1, L3Disp,					c3;
	T ← T or TOS {set inZCT = 1}, RET[OnZRets],		c1;

OnZ.NilLink:
	TT ← NcZctFullTrap, GOTO[NcTrapC1],			c3;


{*************************************************************************
FOSLookUp
  On entry:
	L0	return displacement in NcRdOne dispatch
	TT	low-order bits of NHP
	TOS	high-order bits of NHP unmasked (***Should mask to 8 bits)
  On return:
  	TT, rhTT Rx, Q smashed.
	T	FOSTable entry for the NHP.
	TOS	residue R.
The 32-bit NHP is hashed as follows:
  the least significant bit is not used (because NHP's are even so this bit = 0);
  the next 12 low-order bits are the quantity X used in the hash;
  the next 11 bits are R (bits [0..7] of the NHP are assumed 0);
  hash displacement ← X xor (R & ResidueMask);
The FOSTable entry matches a particular R if the entry and'ed with R = R.

*************************************************************************}
FOSLookUp:
	Rx ← TT LRot4,						c2;
	Rx ← Rx and 16'b,					c3;

	TOS ← TOS LRot4,					c1;
{Note that R has been masked to 11 bits, accommodating a 24-bit VM or 64k pages.}
	TOS ← RRot1(TOS or Rx),					c2;
	Q ← TOS,						c3;

	Q ← uFOSResidueMask and Q,				c1;
	TT ← RShift1(TT and u1FFF), SE ← 0,			c2;
	TT ← TT xor Q {hash table index},			c3;

	Rx ← 5,							c1;
	Rx ← Rx LRot8 {2400'b = SIZE[ZCTObject]}, L0 ← L0.FOSLU,	c2;
{preserve R in TOS}
	TT ← TT + Rx {FOS entry displacement}, CALL[RdZCTTT],	c3;

{T holds FOSTable entry, TOS holds residue R}
FOSLU:	T ← T and TOS, L3Disp,					c1, at[L0.FOSLU, 10, NcRdOneRets];
	[] ← T xor TOS, ZeroBr {match?}, RET[NcFOSLURets],	c2;


{*************************************************************************
BankFix stores the VAhi in Q into rhTT and returns via L2.
*************************************************************************}
BankFix:
	L2Disp,							c*;
	rhTT ← Q LRot0, RET[BankFixRets],			c*;


{*************************************************************************
RdZCTTT reads a word from <uZctHigh, uZctLow> + TT into T.
Clobbers Rx, rhRx, Q, L2.  A page fault may occur.
Returns via L0.
*************************************************************************}
RdZCTTT:
	Q ← uZctLow, L2 ← L2.RdOneA,				c1;
	TT ← TT + Q, CarryBr,					c2;
	Q ← rhTT ← uZctHigh, BRANCH[RdOneA, $],			c3;
	  Q ← Q + 1, CALL[BankFix],				c1;
RdOneA:	Map ← Q ← [rhTT, TT], GOTO[NcRdOnex],			c1, at[L2.RdOneA, 10, BankFixRets];


{*************************************************************************
RdZCTTT reads two words from <uZctHigh, uZctLow> + TT into T and Q and
saves the address in <uFLHigh, uFLLow> for AllocateObject and FreeObject.
Clobbers Rx, rhRx, Q, L2.  A page fault may occur.
Returns via L0.
*************************************************************************}
RdDblZCTTT:
	Q ← uZctLow, L2 ← L2.RdDblZCTTT1,			c2;
	TT ← TT + Q, CarryBr,					c3;

	Q ← rhTT ← uZctHigh, BRANCH[RdDblZCTTT1, $],		c1;
	  Q ← Q + 1, CALL[BankFix],				c2;
RdDblZCTTT1:
	uFLLow ← TT,						c2, at[L2.RdDblZCTTT1, 10, BankFixRets];
	uFLHigh ← Q, GOTO[NcRdDbl] {Fetch free list pointer},	c3;


{*************************************************************************
NcRdDbl reads a pair of words from virtual address [rhTT, TT] into [Q, T].
If the pair of words is a long cardinal, then upon return
	Q holds bits [0..15] (the high order bits) (second word)
	T holds bits [16..31]  (the low order bits) (first word)

Smashes Rx, rhRx, L2.
TT is smashed if a page boundary is crossed, and rhTT if a 64k boundary is crossed.
A page fault may occur.
Returns via L0.
*************************************************************************}
NcRdDbl:
	Map ← Q ← [rhTT,TT], 					c1;
NcRdDbl0: {entry here from OnZ}
	L2 ← L2.NcRdDbl1,					c2;
	Rx ← rhRx ← MD, XRefBr,					c3;

NcRdDbl1:
	MAR ← [rhRx,Q + 0], BRANCH[NcRdDblM0,$],		c1, at[L2.NcRdDbl1,10,NcRMapFixRets];
	Noop,							c2;
	T ← MD,							c3;

	MAR ← [rhRx,Q + 1],					c1;
NcRdDblTail:
	L0Disp, BRANCH[$,NcRdDblPgCr,1],			c2;
	Q ← MD, RET[NcRdDblRets],				c3;

NcRdDblPgCr:
	TT ← TT + 1, CarryBr, CANCELBR[$, 0F],			c3;

NcRdDbl4:
	Map ← Q ← [rhTT,TT], BRANCH[NcRdDbl2, $],		c1;
	  {Crossed 64k boundary}
	  Q ← rhTT + 1, LOOPHOLE[byteTiming],			c2;
	  rhTT ← Q LRot0, GOTO[NcRdDbl4],			c3;
NcRdDbl2:
	L2 ← L2.NcRdDbl3, 					c2;
	Rx ← rhRx ← MD, XRefBr,					c3;

NcRdDbl3:
	MAR ← [rhRx,Q + 0], BRANCH[NcRdDblM1,NcRdDblTail],	c1, at[L2.NcRdDbl3,10,NcRMapFixRets];

NcRdDblM0:
	CALL[NcRMapFix] {will return via L2 to L2.NcRdDbl1},	c2;

NcRdDblM1:
	CALL[NcRMapFix] {will return via L2 to NcRdDbl3},	c2;


{*************************************************************************
NcRdOne reads a word from virtual address [rhTT, TT] into T using Rx and rhRX
for the real address.  Clobbers Rx, rhRx, L2, Q.  A page fault may occur.
Returns via L0.
*************************************************************************}
NcRdOne:
	Map ← Q ← [rhTT, TT], 					c1;
NcRdOnex:
	L2 ← L2.NcRdOne1,					c2;
	Rx ← rhRx ← MD, XRefBr,					c3;

NcRdOne1:
	MAR ← [rhRx, Q + 0], BRANCH[NcRdOneM0,$],		c1, at[L2.NcRdOne1, 10, NcRMapFixRets];
	L0Disp,							c2;
	T ← MD, RET[NcRdOneRets],				c3;

NcRdOneM0:
	CALL[NcRMapFix] {will return via L2 to NcRdOne1},	c2;


{*************************************************************************
NcWrOne writes a word from T to virtual address [rhTT, TT].
[rhTT, TT] are left undisturbed; clobbers Q, Rx, rhRx, L2.
A page or write protect fault may occur.
Returns via L0.
*************************************************************************}
NcWrOne:
	Map ← Q ← [rhTT, TT], 					c1;
NcWrOneE2: {Entry for LongBlkZ}
	L2 ← L2.NcWrOne1,					c2;
	Rx ← rhRx ← MD, XdwDisp,				c3;

NcWrOne1:
	MAR ← [rhRx, Q + 0], DISP2[NcWrOneM0],			c1, at[L2.NcWrOne1, 10, NcWMapFixRets];
NcWrOneM0:
	CALL[NcWMapFix] {will return via L2 to NcWrOne1},	c2, at[0, 4, NcWrOneM0];
{db}	CALL[NcWMapFix] {WP fault},				c2, at[1, 4, NcWrOneM0];
	CALL[NcWMapFix] {Page fault},				c2, at[3, 4, NcWrOneM0];
{db}	MDR ← T, L0Disp,					c2, at[2, 4, NcWrOneM0];
	RET[NcWrOneRets],					c3;


{*************************************************************************
NcWrDbl writes a pair of words, to virtual address [rhTT, TT] from [Rx, T],
where
	Rx holds bits [0..15] (the high order bits) (second word)
	T holds bits [16..31] (the low order bits) (first word)
Clobbers Q, Rx, rhRx, L2, uNcQ.
TT is smashed if a page boundary is crossed and rhTT if a 64k boundary is crossed.
A page fault may occur.
Returns via L0.
*************************************************************************}
NcWrDbl:
	Map ← Q ← [rhTT,TT], 					c1;
NcWrDblx:
	uNcQ ← Rx, L2 ← L2.NcWrDbl1,				c2;
	Rx ← rhRx ← MD, XdwDisp,				c3;

NcWrDbl1:
	MAR ← [rhRx,Q + 0], DISP2[NcWrDblM0],			c1, at[L2.NcWrDbl1,10,NcWMapFixRets];
NcWrDblM0:
	CALL[NcWMapFix] {will return via L2 to NcWrDbl1},	c2, at[0, 4, NcWrDblM0];
{db}	CALL[NcWMapFix] {WP fault},				c2, at[1, 4, NcWrDblM0];
	CALL[NcWMapFix] {Page fault},				c2, at[3, 4, NcWrDblM0];
{db}	MDR ← T,						c2, at[2, 4, NcWrDblM0];
	{uNcCleanFlag ← ~PC xor PC,}				c3;

	MAR ← [rhRx,Q + 1],					c1;
NcWrDblTail:
	MDR ← uNcQ, L0Disp, BRANCH[$,NcWrDblPgCr,1],		c2;
NcWrDbl5:
	RET[NcWrDblRets],					c3;

NcWrDblPgCr:
	TT ← TT + 1, CarryBr, CANCELBR[$, 0F],			c3;

NcWrDbl4:
	Map ← Q ← [rhTT,TT], BRANCH[NcWrDbl2,$],		c1;
	  Q ← rhTT + 1, LOOPHOLE[byteTiming],			c2;
	  rhTT ← Q LRot0, GOTO[NcWrDbl4],			c3;
NcWrDbl2:
	L2 ← L2.NcWrDbl3, 					c2;
	Rx ← rhRx ← MD, XdwDisp,				c3;

NcWrDbl3:
	MAR ← [rhRx,Q + 0], DISP2[NcWrDblM1],			c1, at[L2.NcWrDbl3,10,NcWMapFixRets];
NcWrDblM1:
	CALL[NcWMapFix] {will return via L2 to NcWrDbl3},	c2, at[0, 4, NcWrDblM1];
{db}	MDR ← uNcQ, L0Disp, BRANCH[NcWrDbl5,NcWrDblPgCr,1],	c2, at[2, 4, NcWrDblM1];
{db}	CALL[NcWMapFix] {WP fault},				c2, at[1, 4, NcWrDblM1];
	CALL[NcWMapFix] {Page fault},				c2, at[3, 4, NcWrDblM1];


{**********************************************************************
assorted fix up routines for the basic read/write routines
**********************************************************************}
NcRMapFix:
	Xbus ← Rx LRot0, XdwDisp, 				c3;

	Map ← [rhTT, Q], DISP2[NcRMapFixFlags],			c1;

NcRMapFixFlags:
{db}	MDR ← Rx or map.referenced, L2Disp, GOTO[NcFixReRead],	c2, at[0, 4, NcRMapFixFlags];
{db}	MDR ← Rx or map.referenced, L2Disp, GOTO[NcFixReRead],	c2, at[2, 4, NcRMapFixFlags];
{db}	MDR ← Rx or map.referenced, L2Disp, GOTO[NcFixReRead],	c2, at[1, 4, NcRMapFixFlags];
	T ← qPageFault, GOTO[NcRWFault],			c2, at[3, 4, NcRMapFixFlags];

NcFixReRead:
{jt}	Xbus ← rdw.1xx, XDisp, RET[NcRMapFixRets],		c3;

NcWMapFix:
	Xbus ← Rx LRot0, XdwDisp,				c3;

	Map ← [rhTT, Q], DISP2[NcWMapFixFlags],			c1;

NcWMapFixFlags:
{bj}	MDR ← Rx or map.rd, L2Disp, GOTO[NcFixReWrite],		c2, at[0, 4, NcWMapFixFlags];
{db}	MDR ← Rx or map.rd, L2Disp, GOTO[NcFixReWrite],		c2, at[2, 4, NcWMapFixFlags];
{db}	T ← qWriteProtect, GOTO[NcRWFault],			c2, at[1, 4, NcWMapFixFlags];
	T ← qPageFault, GOTO[NcRWFault],			c2, at[3, 4, NcWMapFixFlags];

NcFixReWrite:
{db}	Xbus ← rdw.x10, XDisp, RET[NcWMapFixRets],		c3;

NcRWFault:
	uFaultParm0 ← Q,					c3;

	Bank ← MSBank1,						c1;
{db}	Q ← rhTT, push, GOTOABS[BxCedarFault],			c2;
{db}	TOS ← STK, GOTOABS[B1CedarFault],			c3, at[BxCedarFault];
{next instruction in bank 1}


{********************************************************************
NcTrap
	TrapTable offset in uNcTrapOffset (opcode if non misc, else 400'b + alpha if misc)
	TrapParm in TT
	Restore TOS
	Read the trap's codelink from a table.
********************************************************************}
NcTrapC1:							c1;
NcTrapC2:							c2;
NcTrapC3:
	UTrapParm ← TT, push,					c3;
	Bank ← MSBank1,						c1;
{db}	TOS ← STK, pop, GOTOABS[BxTrapContinue],		c2;
{db}	T ← sNcCedarTrapTable, GOTOABS[B1TrapContinue],		c3, at[BxTrapContinue];
{next executed instruction in bank 1}


{

RTE: 11-Jan-84 11:23:48: Disable writes back certain values, and it was using the current register contents for a poitner to ZCT, this is incorrect at the first, presumaby initialization, call.  So, modified Disable to use the incoming pointer param as the ZCT pointer.
RTE: 11-Jan-84 13:02:13: a CANCELBR following an L0Disp needed a 0F mask, rather than no mask.
RTE: 11-Jan-84 16:08:23: needed an extra pop in Enable.  Showed up as a page fault during a subsequent monitor entry.  UGH.
RTE: 11-Jan-84 16:40:00: AssignRef code, during preliminaries, did 4 pops (to provoke stack errors), followed by 2 pushes, follwed by 2 pops!!!.  must replace the 2 pops by 2 pushes.
RTE: 12-Jan-84 10:42:24: NcCedarOpCodeTrap did not arrange for TOS to get placed into appropriate stack location (not absolutely sure this is needed, but it would explain observed behavior).
RTE: 12-Jan-84 10:42:27: NcCedarOpCodeTrap clobbered TT (via swap regs?) before placint it in UTrapParm.
RTE: 12-Jan-84 11:03:55: CheckForRCUnderflow generated underflow when it should have generated a disaster trap, and conversely.
RTE: 12-Jan-84 16:39:40: (tick = 1 on this and all the above RTEs) wrote back the modified lhs header to the cell holding the REF, rather than to the block that the ref pointed to.
RTE:13-Jan-84  9:44:50: (tick = 1) same bug, missed on place to correct the loading of the address for the store. (several branches lead to the actual store action.)
RTE: 13-Jan-84 10:17:09: Disable clobbered part of an address between reading the contents, and writing back a modifed value.
RTE: 13-Jan-84 10:36:40: (tick = 31) OnZ incorrectly computed wp when storing the ref in the zct (i.e. did not obtain wp from correct registers).
RTE: 14-Jan-84 16:34:34: Disable set the register after conditionalREstore of registers, i.e. after the swap with the test versions.  Thus the test disable set the real disable register.  Examination showed that Enable had the same problem.
LiveRTE: 23-Jan-84 14:15:28: Enable should return a 0, in fact I popped the stack twice, returning nothing.  Not caught by test because I was not comparing microcode Enable and sim Enable, mearly using it.  The machine code procedure for calling it failed to  specify a return parameter.
LiveRTE: 24-Jan-84 13:09:02: Enable should return 3 (see MicrocodeVersion in ?), rather than 0 as does the software implementation.
RTE: 25-Jan-84 17:06:20: (Tick = 8) AssignRef passed wrong item as the ref-2 arg to OnZ.
Created by: Sturgis:  26-Jan-84 12:52:19
RTE: 26-Jan-84 10:23:52: (tick = 276) OnZ, at an end of block with a nil forward pointer, clobbered uWpHigh just before taking the nil branch.  Also, the test for nil used and rather than or.
LiveRTE: 26-Jan-84 12:52:12: the enabled/disabled test for non test op codes got the result reversed.
LiveRTE:  9-Feb-84 10:53:09: no one cleared the uNcCleanFlag.  So, added this to the normal preamble, but had to remove one of the registers from the save list (rhL)
RTE: 25-Feb-84 15:24:04: (tick = 2) forgot to code the error cases for CreateRef.  (Just allowed execution to flow into next op code implementation.)
change:  8-May-84 10:03:03: add privateHesVersion op code.
Change:  8-May-84 17:05:43: modify AssignRef to do an OnZ also if uMarkingDecrements is true.  This is for Cedar 5.2.
change: 12-May-84 12:16:46: modify enable to return a 4, the new ref counting version stamp, rather than 3 as of old.
Fiala 12-Jul-85 14:02:29: Absorbed NewCedarOpsC.mc and NewCedarOpsD.mc
Fiala 15-Jul-85 to 28-Aug-85 12:12:24: Bummed ~157'd mi out of the original code with major
	speed improvements to all opcodes.  Rewrote OnZ to use Rx and T instead of L and G,
	respectively; eliminated register saving and restoring code.  Removed code
	for unimplemented opcodes now handled in CedarB1.mc.  Debugged CreateRef, which
	which hadn't been tested.  Moved AssignRef register definitions into CedarDefs.dfn.
	Coded and debugged ReclaimedRef, ReclaimableRef, AllocateObject, LocalBlkZ, and
	LongBlkZ; coded FreeObject.  Had EnableMicrocode cache the residue mask in uFOSResidueMask.
	Added stack error intercept at abs.loc. 0.
Fiala 15-Nov-85 Fixed bug in AllocateObject for size = 1077'b.
Fiala 9-Apr-86 Fix bug in OnZ at block crossing.
Fiala 17-Apr-86 Bummed the mi at LBZ2+1; removed useless branch in mi at BZ2b; added code for Checksum.
Fiala 21-Apr-86 11:14:17 Added the BankFix subroutine to bum 2 of 3 mi at each 64k boundary crossing;
	altogether saved 12d mi.  Bummed 1 mi at jump to Free7.
Fiala 22-Apr-86 17:37:29 Bummed 1 mi in CSPgO; bummed 1 click at AR7+3 and AR12b+4; bummed 1 click at
	beginning of AssignRef; changed "Add[Bank0, ...]" symbols to be "B0..." symbols; bummed 3 mi
	duplicated at RAROnZ5.
Fiala 22-Apr-86 23:14:01 Bummed 8 instructions by introducing the RdZCTTT subroutine.
Fiala 23-Apr-86 17:55:38 Bummed 1 mi at RR12-1; absorbed Rx  176'b into CheckForUnderflow saving 1 mi;
	bummed 1 mi at AR1a+1.  Saved 6 mi with the RdDblZCTTT subroutine.
Fiala 24-Apr-86 16:53:50 Saved 2 mi and 1 click by moving code back to bank 1 for CRefType; saved 4 mi
	here and 2 mi in CedarB1 by sharing the entry code for CreateRef and ReclaimableRef.
Fiala 30-Apr-86 10:49:04 A crash during full boot at BufferManager.GetInputBuffer seems to occur fairly
	often.  Undoing the removals in Block.mc didn't help.  Undoing the BankFix changes didn't help.
	Tried removing Checksum altogether; seemed to fix problem; put CheckSum changes back in with
	more conservative code at CSPgO1; crash happened again; removed interrupt code from checksum;
	crash still happened.
	Bummed 3 mi and 1 click in OnZ where new ZCT block is fetched.
	During this, got another crash in which the first 10 words at address 2760000B (a page with ropes on it)
	were smashed to all 1's.  Also got a crash at TrapsImpl.StartCM (address fault at 400004B) **Needs fixing**
	Became suspicious that this crash was not microcode.
Fiala 14-May-86 14:53:45 Changed the Map reference sequence in BZ, NcWrOne, and NcWrDbl for new map
	format; also changed NcWMapFix.
Fiala 20-May-86 17:14:09 Replaced Bank ← 1 by Bank ← MSBank1, so that the MS control
	values can be handled properly.
Fiala  8-Jul-86 15:48:08 Forked the non-Cedar opcodes into BlockB0.mc.
Fiala  5-Mar-87 13:37:40 Moved IM reserves for Kernel and multi-bank booting to StartMesa;
	deleted SelfLoop instruction??
Fiala   7-Jul-87  9:24:56 Fixed bug in AllocateObject reported by Hauser; was failing
	when size - 1076'b < 0; changed to allow sizes up to 64k.
Trow	13-Oct-87 14:29:05 Remove reference to EE at Disable0.  Fix bank crossing to accommodate both Dandelions and Daybreaks.  Reverse targets 1 and 2 of XwdDisp.
BJackson 22-Oct-87  3:29:43 use "map.rd" instead of "30".
Trow	22-Oct-87 16:41:31 Change XwdDisp to XdwDisp.
Trow	 9-Dec-87 23:40:43 Change ErrLoc.
}