{
File name CommonSubs.mc
Last edited by Jim August 20, 1981 2:20 PM: Fix for new assembler.
Last edited: Johnsson, January 20, 1981 10:22 AM
Last edited: Charnley, October 8, 1980 9:23 AM
Last edited: Garner, April 11, 1980 4:52 PM
Description: Emulator Subroutines
Author: don charnley
Created: March 28, 1980
}
{codes used for L0
indicate where to return from fixing the map flags
return is relative to RMapFixCaller
}
{codes used for L1
indicate how to reset state if page fault encountered
return is relative to RFixForTrap
}
{codes used for L1
indicate return from CycleMask
}
{codes used for L2
indicate where to return from remapping a Local or Global
return is relative to LGRemapCaller
}
{codes used for L3
indicate where virtual address is
}
{——————————————————————————————————————————————————————
Read Map Update Subroutines
——————————————————————————————————————————————————————}
{Timing: 4 cycles}
{Enter at cycle 3, returns to cycle1}
{returns thru L0 if map fixed ok}
{returns thru L1 if wants to trap}
{uses L3 to distinguish where virtual address is}
RLMapFix:Xbus ← Rx LRot0,XwdDisp, L3 ← L3.rhTT.Q,c3;
RLMapFixx:Map ← [rhTT,Q], DISP2[RFixRFlags],c1;
RMapFix:Xbus ← Rx LRot0,XwdDisp, L3 ← L3.rhMDS.Q,c3;
Map ← [rhMDS,Q], DISP2[RFixRFlags],c1;
RFixRFlags:MDR ← Rx or 10, L0Disp, GOTO[ReRead],c2, at[0,4];
MDR ← Rx or 10, L0Disp, GOTO[ReRead],c2, at[1,4,RFixRFlags];
MDR ← Rx or 10, L0Disp, GOTO[ReRead],,c2, at[2,4,RFixRFlags];
IBEmptyTrap:T ← qPageFault, L1Disp, GOTO[RTrap],c2, at[3,4,RFixRFlags];
ReRead:Xbus ← 1, XDisp, RET[RMapFixCaller],c3;
RTrap:push, RET[RFixForTrap],c3;
{——————————————————————————————————————————————————————
Local and Global Remap Subroutines
——————————————————————————————————————————————————————}
{Timing: 9 cycles (3 clicks), + 2 clicks if flags need fixing }
{Enter at cycle 1, returns to cycle1}
{returns thru L2 if all ok, thru LGRemapCaller}
{returns thru L1 {from RLMapFix} if wants to trap, thru FixForTrap}
{assumes caller executed "TT ← UvL/UvG"}
{ USES TT, Rx, rhRx, rhMDS, and Q}
LGRemap:TT ← TT + 0FF + 1,c1;
Noop,c2;
Noop,c3;
Map ← [rhMDS,TT],c1;
Noop,c2;
Rx ← rhRx ← MD, XRefBr,c3;
LGRefetch:MAR ← [rhRx,Q + 0], BRANCH[LGMapUD,$],c1;
L2Disp,c2;
rhTT ← TT ← MD, RET[LGRemapCaller],c3;
LGMapUD:Noop {code duplicated to protect L0},c2;
Xbus ← Rx LRot0,XwdDisp, L3 ← L3.rhMDS.TT,c3;
Map ← [rhMDS,TT], DISP2[LGFixRFlags],c1;
LGFixRFlags:MDR ← Rx or 10, GOTO[LGReRead],c2, at[0,4];
MDR ← Rx or 10, GOTO[LGReRead],c2, at[1,4,LGFixRFlags];
MDR ← Rx or 10, GOTO[LGReRead],,c2, at[2,4,LGFixRFlags];
T ← qPageFault, L1Disp, GOTO[RTrap],c2, at[3,4,LGFixRFlags];
LGReRead:Xbus ← 1, XDisp, GOTO[LGRefetch],c3;
{——————————————————————————————————————————————————————
Write Map Update Subroutines
——————————————————————————————————————————————————————}
{Timing: 4 cycles}
{Enter at cycle 3, returns to cycle1}
{returns thru L0 if map fixed ok}
{returns thru L1 if wants to trap}
WLMapFix:Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhTT.Q,c3;
Map ← [rhTT, Q], DISP2[FixWFlags],c1;
WMapFix:Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhMDS.Q,c3;
Map ← [rhMDS, Q], DISP2[FixWFlags],c1;
FixWFlags:MDR ← Rx or 0B0, L0Disp, GOTO[ReWrite],c2, at[0,4];
MDR ← Rx or 0B0, L0Disp, GOTO[ReWrite],c2, at[1,4,FixWFlags];
T ← qWriteProtect, L1Disp, GOTO[WTrap],,c2, at[2,4,FixWFlags];
T ← qPageFault, L1Disp, GOTO[WTrap],c2, at[3,4,FixWFlags];
ReWrite:Xbus ← 2, XDisp, RET[WMapFixCaller],c3;
WTrap:push, RET[WFixForTrap],c3;
{——————————————————————————————————————————————————————
Read Map Update Subroutines
——————————————————————————————————————————————————————}
{Timing: 4 cycles}
{Enter at cycle 3, returns to cycle1}
{returns thru L0 if map fixed ok}
{returns thru L1 if wants to trap}
{uses L3 to distinguish where virtual address is}
{LGxMapFix must be at[1,2]. See EMapUD in Refill.mc}
RLxMapFix:Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhTT.Q,c3;
Map ← [rhTT, Q], DISP2[RxFixRFlags],c1;
RxMapFix:Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhMDS.Q,c3;
Map ← [rhMDS,Q], DISP2[RxFixRFlags],c1;
LGxMapFix:Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhTT.TT,c3, at[1,2];
Map ← [rhTT,TT], DISP2[RxFixRFlags],c1;
RxFixRFlags:MDR ← Rx or 10, L0Disp, GOTO[RexRead],c2, at[0,4];
MDR ← Rx or 10, L0Disp, GOTO[RexRead],c2, at[1,4,RxFixRFlags];
MDR ← Rx or 10, L0Disp, GOTO[RexRead],,c2, at[2,4,RxFixRFlags];
T ← qPageFault, L1Disp, GOTO[RTrap],c2, at[3,4,RxFixRFlags];
RexRead:Xbus ← 1, XDisp, RET[RxMapFixCaller],c3;
{——————————————————————————————————————————————————————
Write Map Update Subroutines
——————————————————————————————————————————————————————}
{Timing: 4 cycles}
{Enter at cycle 3, returns to cycle1}
{returns thru L0 if map fixed ok}
{returns thru L1 if wants to trap}
WLxMapFix:Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhTT.Q,c3;
Map ← [rhTT, Q], DISP2[FixWxFlags],c1;
WxMapFix:Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhMDS.Q,c3;
Map ← [rhMDS, Q], DISP2[FixWxFlags],c1;
FixWxFlags:MDR ← Rx or 0B0, L0Disp, GOTO[RexWrite],c2, at[0,4];
MDR ← Rx or 0B0, L0Disp, GOTO[RexWrite],c2, at[1,4,FixWxFlags];
T ← qWriteProtect, L1Disp, GOTO[WTrap],,c2, at[2,4,FixWxFlags];
T ← qPageFault, L1Disp, GOTO[WTrap],c2, at[3,4,FixWxFlags];
RexWrite:Xbus ← 2, XDisp, RET[WxMapFixCaller],c3;
{——————————————————————————————————————————————————————
Read Map Update Subroutines
——————————————————————————————————————————————————————}
{Timing: 4 cycles}
{Enter at cycle 3, returns to cycle1}
{returns thru L0 if map fixed ok}
{returns thru L1 if wants to trap}
{uses L3 to distinguish where virtual address is}
RLyMapFix:Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhTT.Q,c3;
Map ← [rhTT, Q], DISP2[RyFixRFlags],c1;
RyMapFix:Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhMDS.Q,c3;
Map ← [rhMDS,Q], DISP2[RyFixRFlags],c1;
RyFixRFlags:MDR ← Rx or 10, L0Disp, GOTO[ReyRead],c2, at[0,4];
MDR ← Rx or 10, L0Disp, GOTO[ReyRead],c2, at[1,4,RyFixRFlags];
MDR ← Rx or 10, L0Disp, GOTO[ReyRead],,c2, at[2,4,RyFixRFlags];
T ← qPageFault, L1Disp, GOTO[RTrap],c2, at[3,4,RyFixRFlags];
ReyRead:Xbus ← 1, XDisp, RET[RyMap],c3;
{——————————————————————————————————————————————————————
Write Map Update Subroutines
——————————————————————————————————————————————————————}
{Timing: 4 cycles}
{Enter at cycle 3, returns to cycle1}
{returns thru L0 if map fixed ok}
{returns thru L1 if wants to trap}
WyMapFix:Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhMDS.Q,c3;
Map ← [rhMDS, Q], DISP2[FixWyFlags],c1;
FixWyFlags:MDR ← Rx or 0B0, L0Disp, GOTO[ReyWrite],c2, at[0,4];
MDR ← Rx or 0B0, L0Disp, GOTO[ReyWrite],c2, at[1,4,FixWyFlags];
T ← qWriteProtect, L1Disp, GOTO[WTrap],,c2, at[2,4,FixWyFlags];
T ← qPageFault, L1Disp, GOTO[WTrap],c2, at[3,4,FixWyFlags];
ReyWrite:Xbus ← 2, XDisp, RET[WyMap],c3;
{——————————————————————————————————————————————————————
RFixForTrap
——————————————————————————————————————————————————————}
NoFixes:Noop, GOTO[NoMoreFix],c1, at[L1r.NoFixes,10,RFixForTrap];
PC ← PC - PC16, GOTO[NoMoreFix],c1, at[L1r.DecOnly,10,RFixForTrap];
PopOnlyFix:pop, GOTO[NoMoreFix],c1, at[L1r.PopOnly,10,RFixForTrap];
push, GOTO[PushFix],c1, at[L1r.Push2Only,10,RFixForTrap];
PC ← PC - PC16, push, GOTO[NoMoreFix],c1, at[L1r.PushDec,10,RFixForTrap];
push, GOTO[NoMoreFix],c1, at[L1r.PushOnly,10,RFixForTrap];
PC ← PC - 1, push, GOTO[NoMoreFix],c1, at[L1r.PushDecDec,10,RFixForTrap];
PC ← PC - 1, pop, GOTO[NoMoreFix],c1, at[L1r.PopDecDec,10,RFixForTrap];
PC ← PC - PC16, pop, GOTO[NoMoreFix],c1, at[L1r.PopDec,10,RFixForTrap];
PC ← PC - 1, push, GOTO[PushFix],c1, at[L1r.Push2DecDec,10,RFixForTrap];
PC ← PC - 1, pop, GOTO[PopFix],c1, at[L1r.Pop2DecDec,10,RFixForTrap];
PC ← PC - 1, GOTO[NoMoreFix],c1, at[L1r.DecDec,10,RFixForTrap];
{——————————————————————————————————————————————————————
WFixForTrap fixups
——————————————————————————————————————————————————————}
Noop, GOTO[NoMoreFix],c1, at[L1w.NoFixes,10,WFixForTrap];
PC ← PC - PC16, GOTO[NoMoreFix],c1, at[L1w.DecOnly,10,WFixForTrap];
push, GOTO[PushFix],c1, at[L1w.Push2Only,10,WFixForTrap];
PC ← PC - PC16, push, GOTO[PushFix],c1, at[L1w.Push2Dec,10,WFixForTrap];
PC ← PC - PC16, push, GOTO[NoMoreFix],c1, at[L1w.PushDec,10,WFixForTrap];
push, GOTO[NoMoreFix],c1, at[L1w.PushOnly,10,WFixForTrap];
push, GOTO[Push3Fix],c1, at[L1w.Push3Only,10,WFixForTrap];
PC ← PC - 1, GOTO[NoMoreFix],c1, at[L1w.DecDec,10,WFixForTrap];
PC ← PC - 1, push, GOTO[NoMoreFix],c1, at[L1w.PushDecDec,10,WFixForTrap];
PC ← PC - PC16, pop, GOTO[NoMoreFix],c1, at[L1w.PopDec,10,WFixForTrap];
PC ← PC - 1, push, GOTO[PushFix],c1, at[L1w.Push2DecDec,10,WFixForTrap];
pop, GOTO[NoMoreFix],c1, at[L1w.PopOnly,10,WFixForTrap];
{——————————————————————————————————————————————————————
Trap Handling
——————————————————————————————————————————————————————}
NoMoreFix:L3Disp, GOTO[TrapFixDone],c2;
PushFix:push, L3Disp, GOTO[TrapFixDone],c2;
PopFix:pop, L3Disp, GOTO[TrapFixDone],c2;
Push3Fix:push, L3Disp, GOTO[TrapFixPush3],c2;
TrapFixDone:DISP3[FormVA],c3;
TrapFixPush3:push, DISP3[FormVA],c3;
FormVA:uFaultParm0 ← Q, GOTO[VArhTT],c1, at[L3.rhTT.Q,8,FormVA];
uFaultParm0 ← TT, GOTO[VArhTT],c1, at[L3.rhTT.TT,8,FormVA];
uFaultParm0 ← Q, GOTO[VAMDS],c1, at[L3.rhMDS.Q,8,FormVA];
VAMDS:Q ← rhMDS, GOTO[Faultc3],c2;
VArhTT:Q ← rhTT, GOTO[Faultc3],c2;
{At Faultc3, uFaultParm0 stored, Q has uFaultPram1, T has FaultQueuePointer}
Faultc3:uFaultParm1 ← Q,c3;
Faultc1:Rx ← pFault, STK ← TOS, pop, GOTO[SaveRegs],c1;
{At Trapc1, TT holds the trap parmater, T has the sSDIndex}
Trapc3:GOTO[Trapc1],c3;
Trapc1:UTrapParm ← TT, L2 ← L2.TRAPStashr,c1;
Trapc2:TT ← UvPCpage, L1←0, GOTO[StashPC0] {in Xfer.mc},c2;
{——————————————————————————————————————————————————————
CycleMask
——————————————————————————————————————————————————————}
{Timing:1 click}
{Used by: SHIFT, RF, WF, BITBLT instructions}
{Entry:T = data to be rotated & masked,
TT = pre-rotated version of T
a DISP4 pending which determines rotation:
0 => no rotation
1 => left rotate 1
:
0F => left rotate 15;
a INIA.11 branch is pending to determine if shift should be abandoned.
rhT = value to be dispatched on to determine mask
0 => 1
1 => 3
:
0F => 0FFFF
Exit:TT holds the mask,
TOS holds the rotated data,
T does not contain the original data, rhT is untouched}
CycleMask:[] ← rhT, XDisp, BRANCH[ShiftOut0, ShiftOK0],c*, at[0,10,CycleMask];
T ← TT, [] ← rhT, XDisp, BRANCH[ShiftOut0, ShiftOK0],c*, at[1,10,CycleMask];
T ← LRot1 TT, [] ← rhT, XDisp, BRANCH[ShiftOut0, ShiftOK0],c*, at[2,10,CycleMask];
T ← RRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut4, ShiftOK4],c*, at[3,10,CycleMask];
[] ← rhT, XDisp, BRANCH[ShiftOut4, ShiftOK4],c*, at[4,10,CycleMask];
T ← LRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut4, ShiftOK4],c*, at[5,10,CycleMask];
T ← LRot1 TT, [] ← rhT, XDisp, BRANCH[ShiftOut4, ShiftOK4],c*, at[6,10,CycleMask];
T ← RRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut8, ShiftOK8],c*, at[7,10,CycleMask];
[] ← rhT, XDisp, BRANCH[ShiftOut8, ShiftOK8],c*, at[8,10,CycleMask];
T ← LRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut8, ShiftOK8],c*, at[9,10,CycleMask];
T ← LRot1 TT, [] ← rhT, XDisp, BRANCH[ShiftOut8, ShiftOK8],c*, at[0A,10,CycleMask];
T ← RRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut12, ShiftOK12],c*, at[0B,10,CycleMask];
[] ← rhT, XDisp, BRANCH[ShiftOut12, ShiftOK12],c*, at[0C,10,CycleMask];
T ← LRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut12, ShiftOK12],c*, at[0D,10,CycleMask];
T ← LRot1 TT, [] ← rhT, XDisp, BRANCH[ShiftOut12, ShiftOK12],c*, at[0E,10,CycleMask];
T ← RRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut0, ShiftOK0],c*, at[0F,10,CycleMask];
ShiftOK0:TOS ← T, pRet2, DISP4[MaskTbl],c*;
ShiftOK4:TOS ← T LRot4, pRet2, DISP4[MaskTbl],c*;
ShiftOK8:TOS ← T LRot8, pRet2, DISP4[MaskTbl],c*;
ShiftOK12:TOS ← T LRot12, pRet2, DISP4[MaskTbl],c*;
{Here if no pending branch on entry to CycleMask (magnitude of shift count greater than 15). stackP has already been decremented--check for underflow at NegIB.}
ShiftOut0:CANCELBR[ShiftOut, 0F],c3;
ShiftOut4:CANCELBR[ShiftOut, 0F],c3;
ShiftOut8:CANCELBR[ShiftOut, 0F],c3;
ShiftOut12:CANCELBR[ShiftOut, 0F],c3;
ShiftOut:TOS ← 0, GOTO[NegIB],c1;
{——————————————————————————————————————————————————————
MaskTbl SUBROUTINE
first cycle = c* , one cycle long
This subroutine generates a right justified mask. of n ones given n (n = 1 gives 1, n = 8 gives 00FF and n = 16 gives FFFF). The subroutine may also be used to generate a left justified mask.
REGISTERS
Rnnumber of 1 bits desired in mask (0 means 16)
maskwhere the mask is generated
CALLING SEQUENCES
For a right justified mask
[] ← Rn - 1, YDisp,c1;
[] ← retnum, XDisp, DISP4[MaskTbl],c2;
{rtn here}Noop,c1, at[retnum,10,MaskRet];
For a left justified mask
[] ← 0 - Rn, YDisp,c2;
[] ← retnum, XDisp, DISP4[MaskTbl],c3;
{rtn here}mask ← RShift1 ~mask, SE ← 1,c2, at[retnum,10,MaskRet];
RETURNS THRU
MaskRet
——————————————————————————————————————————————————————}
MaskTbl:TT ← 1, RET[MaskRet],c*, at[0,10,MaskTbl];
TT ← 3, RET[MaskRet],c*, at[1,10,MaskTbl];
TT ← 7, RET[MaskRet],c*, at[2,10,MaskTbl];
TT ← 0F, RET[MaskRet],c*, at[3,10,MaskTbl];
TT ← 1F, RET[MaskRet],c*, at[4,10,MaskTbl];
TT ← 3F, RET[MaskRet],c*, at[5,10,MaskTbl];
TT ← 7F, RET[MaskRet],c*, at[6,10,MaskTbl];
TT ← 0FF, RET[MaskRet],c*, at[7,10,MaskTbl];
TT ← LShift1 0FF, SE←1, RET[MaskRet] {TT ← 1FF},c*, at[8,10,MaskTbl];
TT ← RShift1 u7FF, RET[MaskRet] {TT ← 3FF},c*, at[9,10,MaskTbl];
TT ← u7FF, RET[MaskRet] {TT ← 7FF},c*, at[0A,10,MaskTbl];
TT ← RShift1 u1FFF, RET[MaskRet] {TT ← FFF},c*, at[0B,10,MaskTbl];
TT ← u1FFF, RET[MaskRet] {TT ← 1FFF},c*, at[0C,10,MaskTbl];
TT ← u3FFF, RET[MaskRet] {TT ← 3FFF},c*, at[0D,10,MaskTbl];
TT ← RShift1 (~TT xor TT), RET[MaskRet] {TT ← 7FFF},c*, at[0E,10,MaskTbl];
TT ← ~TT xor TT, RET[MaskRet] {TT ← FFFF},c*, at[0F,10,MaskTbl];