{ 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. }