{
file: <CoPilot>DLion>BlockB0.mc
Created by E. Fiala 9 July 1986
Edited:
Fiala 19-Nov-86 17:57:33 Removed MBus and PCBus opcodes to MBusB0.mc
Copyright (C) 1984, 1985, 1986 by Xerox Corporation. All rights reserved.
Formerly, all of this code was in CedarB0.mc. Opcodes defined here are as follows:
LocalBlkZ (not debugged and not used at present)
LongBlkZ
Checksum
WriteMBus
ReadMBus
WritePCBus
ReadPCBus
LongBlkZ and Checksum are performance critical. Checksum replaces a slower implementation
formerly in Block.mc.
Notes:
1) Check for occurrences of rhB ← rC LRot0, rB ← rC which does not cause an assembler error
but doesn't work (??).
}
SetTask[0];
{***************************************************************************
aLocalBlkZ
At entry to opcode:
TOS Cardinal count of words to zero.
Preceding Bank 1 code has been:
Bank ← MSBank0, c1;
rhTT ← UvMDS, c2;
TT ← UvL, GOTOABS[B0LocalBlkZ], c3;
At return:
The count word is removed from the stack.
Point <rhTT, TT> at the last word remaining to be zeroed; this word is
at LOCAL + 4 + TOS - 1 since the data part of the local frame begins at
LOCAL + 4. Zero the block in reverse order so that the only state variable
is TOS, decremented after each word is zeroed. There is no 64k boundary
crossing to worry about since the local frame is confined to the MDS.
The block-zeroing subroutine is called and returns to the same exit as LongBlkZ.
Timing = 1 click/word.
****************************************************************************}
@LocalBlkZa:
TT ← TT + 3, c1, at[B0LocalBlkZ];
TT ← TT + TOS, L1 ← L1.LBZ2, c2;
fXpop, push, CALL[BZero1], c3;
{***************************************************************************
aLongBlkZ
At entry to opcode:
TOS Cardinal count of words to zero.
STK High half of long pointer to block.
STK-1 Low half of long pointer to block.
Preceding Bank 1 code has been:
Bank ← MSBank0, L1 ← L1.LBZ2, c1;
Q ← rhTT ← STK, c2;
Rx ← TOS - 1, pop, GOTOABS[B0LongBlkZ], c3;
At return:
The count word is removed from the stack, but the long pointer remains.
The block is zeroed in reverse order to avoid state save and restore. After each
iteration the count in TOS is decremented. Timing = 1 click/word.
****************************************************************************}
@LongBlkZa:
TT ← STK, fXpop, fZpop, push, c1, at[B0LongBlkZ];
TT ← TT + Rx, CarryBr, push, c2;
LBZ0: Q ← Q + 1, BRANCH[LBZ1, $], c3;
rhTT ← Q LRot0, c1;
GOTO[LBZ0], c2;
{<rhTT, TT> points at the last word remaining to be zeroed.
TOS holds the cardinal word count. Call the block-zeroing subroutine.}
LBZ1: Map ← Q ← [rhTT, TT], push, CALL[BZero], c1;
LBZ2: Bank ← MSBank1, push, GOTO[LBZ7] {In AssignRef}, c1, at[L1.LBZ2, 10, BZRets];
{***************************************************************************
BZero block-zeroing subroutine
At entry to BZero1 and on any interrupt or page fault:
TOS Cardinal count of words to zero.
<rhTT, TT> Long pointer to last word of the block.
L1 Return link.
At exit:
TOS, STK + 1 0.
TT, rhTT, Q, Rx, rhRx, L0, L2 smashed
The block is zeroed in reverse order to avoid state save and restore. After each
iteration the count in TOS is decremented. On interrupts and page faults, the
shadow cell for TOS on the stack is also written, and it is important that TOS and
its shadow value in STK+1 = 0 on return for FreeObject.
Timing = 1 click/word + 2 clicks/page.
****************************************************************************}
{Entry from LocalBlkZ and FreeObject}
BZero1: Map ← Q ← [rhTT, TT], push, c1;
{Entry from LongBlkZ}
BZero: [] ← STK ← TOS, ZeroBr, L2 ← L2.BZ1, pop, c2;
Rx ← rhRx ← MD, XwdDisp, BRANCH[$, BZ9], c3;
BZ1: MAR ← [rhRx, Q + 0], DISP2[BZ4], c1, at[L2.BZ1, 10, NcWMapFixRets];
BZ4: CALL[NcWMapFix] {Will return via L2 to BZ1}, c2, at[0, 4, BZ4]; {WP=0, D=0 => set D=1 and proceed}
CALL[NcWMapFix] {WP fault}, c2, at[2, 4, BZ4]; {WP=1, D=0 => WP fault}
CALL[NcWMapFix] {Page fault}, c2, at[3, 4, BZ4]; {WP=1, D=1 => Page fault}
MDR ← 0, MesaIntBr, c2, at[1, 4, BZ4]; {WP=0, D=1 => ok to write}
BZ1a: TOS ← TOS - 1, ZeroBr, BRANCH[$, BZInt], c3;
MAR ← Q ← [rhRx, Q - 1], BRANCH[$, BZ8], c1;
BZ7: MDR ← 0, MesaIntBr, BRANCH[BZ1a, BZ5, 1], c2;
{page cross; no word has been written}
BZ5: Q ← 377'b, CANCELBR[$], c3;
TT ← TT - Q - 1, CarryBr, L2 ← L2.BZ6, c1;
Q ← rhTT, BRANCH[$, BZ6], c2;
Q ← Q - 1, CALL[BankFix], c3;
BZ6: TT ← TT or 377'b, GOTO[BZero1], c3, at[L2.BZ6, 10, BankFixRets];
BZInt: [] ← uWP, ZeroBr {Wakeups pending?}, BRANCH[$, BZ8a], c1;
[] ← uWDC, NZeroBr {Wakeups disabled?}, BRANCH[$, BZ2a], c2;
{ClrIntErr must occur before or in the same click as uWP testing.}
ClrIntErr, BRANCH[$, BZ2b], c3;
Bank ← MSBank1, c1;
push, c2;
STK ← TOS, pop, GOTOABS[B1IntContinue], c3;
{no wakeups}
BZ2a: ClrIntErr, CANCELBR[$], c3;
{wakeups disabled}
BZ2b: MAR ← Q ← [rhRx, Q - 1], GOTO[BZ7], c1;
BZ8a: {Finished} CANCELBR[BZ8b, 3], c2;
BZ8: {Finished} CANCELBR[$, 3], c2;
BZ8b: {noop} c3;
{This code is copied from Block.mc. It sets MesaIntRq true if the next
opcode crosses a page boundary. Discussion of this is in Refill.mc.}
BZ9: Xbus ← uPCCross, XRefBr, push, CANCELBR[$, 3], c1;
STK ← TOS, pop, L1Disp, BRANCH[$, BZSetInt], c2;
{This instruction sets up TT for the FreeObject opcode.}
TT ← LShift1(uBSISave), SE ← 0, RET[BZRets], c3;
BZSetInt:
MesaIntRq, RET[BZRets], c3;
{******************************************************************************
Checksum
TOS = uStack5 = srcHi
STK = uStack4 = srcLo
STK-1 = uStack3 = count
STK-2 = uStack2 = csum
The 16-bit Pup checksum is initialized to zero; each 16-bit word in the block is ones-complement
added to the checksum; following each addition, the checksum is left-cycled 1. A final result
of "minus one" (177777B) is converted to zero. 177777B is specifically defined to mean that
the Pup carries no checksum.
During the inner loop, TOS holds the word count, <rhTT, Q> the current VA, T the checksum,
Rx and rhRx the high part of the real address.
Timing: 2 clicks/word + 5 clicks/page.
Previous instructions in bank 1 have been:
Bank ← MSBank0, L0 ← L0.CSRem2, c1, at[7, 10, Misc0n];
rhTT ← TOS LRot0 {srcHi}, c2;
TT ← uStack4 {srcLo}, GOTOABS[B0CSum], c3;
**********************************************************************************}
Checksum:
TOS ← uStack3 {count}, ZeroBr, c1, at[B0CSum];
BRANCH[$, CSDon0], c2;
CALL[NcRdOne], c3;
CSLp: MAR ← Q ← [rhRx, Q + 1], c1;
CSLp1: MesaIntBr, BRANCH[$, CSPgO, 1], c2;
TT ← MD, BRANCH[$, CSInt], c3;
CSRmLp: T ← T + TT, CarryBr, c1;
CSInt5: TOS ← TOS - 1, ZeroBr, BRANCH[$, CSWrap], c2;
T ← T LRot1, BRANCH[CSLp, CSDone], c3;
CSWrap: T ← (T + 1) LRot1, BRANCH[CSLp, CSDone], c3;
{Finished with final word. If csum is all 1's, change it to 0.}
CSDon0: T ← uStack2 {csum}, c3;
CSDone: [] ← T xor ~0, NZeroBr, pop, c1;
Xbus ← uPCCross, XRefBr, pop, BRANCH[$, CSDon3], c2;
STK ← TOS ← 0, pop, BRANCH[CSDon5, CSDon4], c3;
CSDon3: STK ← TOS ← T, pop, BRANCH[CSDon5, CSDon4], c3;
CSDon4: MesaIntRq, c1;
Noop, c2;
Noop, c3;
CSDon5: Bank ← MSBank1, GOTO[CSDon6] {In CRefType}, c1;
{Interrupt request: Ignore current word and check for done first.
ClrIntErr must occur before or in the same click as uWP testing.}
CSInt: [] ← uWP, ZeroBr {Wakeups pending?}, c1;
[] ← uWDC, NZeroBr {Disabled?}, BRANCH[$, CSInt2], c2;
uStack2 ← T, ClrIntErr, BRANCH[CSInt4, CSInt3], c3;
CSInt2: ClrIntErr, CANCELBR[$], {no wakeups} c3;
CSInt3: T ← T + TT, CarryBr, GOTO[CSInt5], {Wakeups disabled} c1;
{The interrupt will take. Save the state; tricky part is reconstructing the
virtual address from <low 8 bits in Q, high 8 bits in uStack4>; srcHi is
already correct since it is updated on every page overflow.}
CSInt4: TT ← uStack4 {old srcLo}, c1;
TT ← TT and ~0FF, c2;
Q ← Q and 0FF, c3;
TT ← TT or Q, push, c1;
uStack4 ← TT {current srcLo}, c2;
uStack3 ← TOS {count}, c3;
Bank ← MSBank1, c1;
Q ← rhTT, c2;
TOS ← STK ← Q, pop, GOTOABS[B1IntContinue], c3;
{Page crossing: First, update the stack values from the working registers
in preparation for a possible page fault. Then copy the updated source
address into <rhTT, TT> for mapping.
}
CSPgO: TT ← uStack4 {old srcLo}, CANCELBR[$], c3;
{Set VA to the last word of the old page and then add 1.}
TT ← TT or 0FF, push {point stkp at srcHi}, c1;
TT ← TT + 1, CarryBr, c2;
CSPgO1: uStack3 ← TOS {count}, BRANCH[CSRem, $], c3;
Q ← rhTT + 1, LOOPHOLE[byteTiming], c1;
rhTT ← Q LRot0, STK ← Q, GOTO[CSPgO1], c2;
CSRem: Noop, c1;
CSRem1: uStack4 ← TT {srcLo}, L0 ← L0.CSRem2, c2;
uStack2 ← T {csum}, pop, CALL[NcRdOne], c3;
CSRem2: TT ← uStack2 {csum}, c1, at[L0.CSRem2, 10, NcRdOneRets];
Noop, c2;
GOTO[CSRmLp], c3;