{File name: FixedDisplay.mc
Description: Dandelion Display Microcode: "Do not attempt to adjust your set. We control the vertical, we control the horizontal."
Last edited by Jim August 20, 1981 2:20 PM: Fix for new assembler.
Last Edited: Jim Frandeen, July 28, 1981 9:22 AM: make the bottom border one less and make end vertical sync one more to fix the border collision problem.
Last Edited: Sturgis, 5-Aug-83 13:50:39: fix left and top edge problems
Last Edited: DDavies, June 24, 1981 3:33 PM
Last Edited: Sandman, November 10, 1980 5:26 PM
Last Edited: Olmstead, November 3, 1980 3:16 PM
Last Edited: R. Garner, March 26, 1981 1:27 AM
Author: R. Garner (based on previous version by Ron Crane, Pitts Jarvis)
Created: April 15 1980,
}
{The display bit map occupies the first 202’d pages. The next 4 pages (16 scan lines) hold the cursor bit map buffer (uCurBufAddr). Thus there are 50 unused display-bank pages, or 12.8 K words.
The number of refreshes per scan line required is
(128 Refreshes/2 mSec)(28.8 uSec/Line) = 1.8 Refreshes/Line
This code assumes a total of 897 (381’x) Lines per Frame:
2End Vertical Sync
13Top Border
404Even Field
12Bottom Border
18Start Odd Vertical Sync
2End Vertical Sync
13Top Border
404Odd Field
12Bottom Border
17Start Even Vertical Sync
}
{ REGISTER USAGE
uClockBits counts lines. It is incremented by 2 each time we call Sleep. It is set to 1 or 0 at the end of each frame, depending on even or odd frame. It is initially set to zero.
uCopyCount set to 7 at EndVSync. Used to copy 8 lines to CursorBuf
uCurBufAddr is set to the word address of the first location of the cursor in the CursorBuffer: uInitPicLength*wordsPerLine + (CursorX RShift4).
uCurMapAddr is set to point to the first line of the cursor map to be displayed. This is word 5 of the DCB + (1 If (CursorY is even, and this is an odd field) or (CursorY is odd, and this is an even field))
uCursorDiff set at top border to the number of lines to display before the cursor is displayed (uInitPicLength - uDoCursor).
uCursorStop is set to uDoCursor + 14’d at top border.
uCurVisAddr is set to uDoCursor in the high 10 bits and 0 in the low 6 bits at top border. This is uDoCursor*wordsPerLine. The cursor word address (CursorRShift4) is ored into the low 10 bits.
uDoCursor loaded from CursorY in DCB at end vertical sync. This is the line where the cursor is to be displayed. If CursorY is even, and this is an odd field, add 1 to uDoCursor. If CursorY is odd, and this is an even field, add 1 to uDoCursor at top border.
uDWakeup loaded from WakeupMask in DCB at end vertical sync
uExitLength: the line on which a wakeup is caused. It is loaded from scan interrupt in DCB at end vertical sync. It is forced to be even. It is then ored with OddField at top border. If greater than uPicLength, it is set to uPicLength at top border.
uInitCurBufAddr = word address of cursor buffor (follows bit map in low 64K).
uInitCurMapAddr points to word 5 of the DCB.
uInitPicLength = 328’x = 808’d
uNoPic loaded from inverted bit of control bits in DCB at end vertical sync. Inv bit = 0 => uNoPic = NoPic = 41; Inv bit = 1 => uNoPic = NoInvPic = 49.
uPicLength set to 808’d + oddField at top border.
uStartPic loaded from Off bit and Inv bit of control bits in DCB at end vertical sync. 4 bit means display on. Off bit = 0, Inv bit = 0 => uStartPic = Pic = 45; Off bit = 0, Inv bit = 1 => uStartPic = NoPic = 41; Off bit = 1, Inv bit = 0 => uStartPic = InvPic = 4D; Off bit = 1, Inv bit = 1 => uStartPic = NoInvPic = 49.
}
SetTask[1];
StartAddress[DisplayStart];
Set[StartVSync, 23];
Set[EndVSync, 3];
Set[Blank, 43];
Set[Pic, 45];
Set[InvPic, 4D];
Set[NoPic, 41];
Set[NoInvPic, 49];
Set[PicLenShifted, 0CA]; {PicLength = 328’x = 808’d. PicLenShifted = RShift2 PicLength}
{values relative to HibernateRet}
Set[VSyncTime, 17’d]; {odd frame is 18’d}
Set[BotBordTime, 12’d]; {top border is 13’d}
Set[BlankTime, 2];
Set[OffTime, 10’d]; {must be even: see CopyDone}
{values relative to FieldRet}
Set[L5.FieldStart, 1]; {control goes to "FieldStart" from RET[FieldRet]}
Set[L5.Field, 0]; {control goes to "Field" from RET[FieldRet]}
{values relative to SleepRet & DCycleRet}
Set[L5.DCycle6, 0];
Set[L5.DCycleA, 1];
Set[L5.DCycle, 2];
Set[L5.evs2, 3];
Set[L5.tb1, 4];
Set[L5.tb2, 5];
Set[L5.tb5, 6];
Set[L5.Hibernate, 7];
Set[L5.DCycleAx, 8];
{Format of Display Control Block}
Set[IOPageHigh, 1];
Set[IOPage, 40];
Set[DCBLoc, 0EB];
Set[WakeupLoc, 0];{140EB}
Set[DBitsLoc, 1];{140EC} {[0]=Off, [4]=Inv, [6-15]=scan interrupt}
Set[BorderLoc, 2];{140ED}
Set[cursorXLoc, 3];{140EE}
Set[cursorYLoc, 4];{140EF}
Set[cursorMapLoc, 5];{140F0-140FF}
{——————————————————————————————————————————————————————
End Vertical Sync
——————————————————————————————————————————————————————}
{1st line of "End Vertical Sync" (4 clicks): Init uCopyCount and fetch cursorY and WakeupMask.}
DisplayStart:
EndVSync:dX ← 7, Refresh, CANCELBR[$,0F],,c1, at[And[VSyncTime, 0F],10,HibernateRet];
uCopyCount ← dX, L5 ← L5.evs2,c2;
dY ← uDCBLoc,c3;
MAR ← [rhdY, dY + cursorYLoc],c1;
DCtl ← EndVSync, CANCELBR[$, 0],c2;
dX ← MD{cursorY},c3;
MAR ← [rhdY, dY + WakeupLoc],c1;
uDoCursor ← dX, CANCELBR[$, 0],c2;
dX ← MD{WakeupMask}, CALL[Sleep],c3;
{2nd line of "End Vertical Sync" (4 clicks): Fetch scan line wakeup and control bits. Load the border pattern register. Format of control bits:
0: 1=> off,
4: 1=> Invert,
5: 1=> disconnect (presently ignored),
6-15: scan line wake count}
MAR ← [rhdY, dY + BorderLoc], L5 ← L5.tb1,c1, at[L5.evs2,10,SleepRet];
uDWakeup ← dX, CANCELBR[$, 0],c2;
dX ← MD{BorderPattern},c3;
MAR ← [rhdY, dY + DBitsLoc], {DCtl ← EndVSync,},c1;
DBorder ← dX, dY ← ~1, CANCELBR[$, 0],c2;
dX ← MD and dY{ScanLineWakeup and ~1}, XHDisp,c3;
uExitLength ← dX, Refresh, DISP2[NormOn],c1;
NormOn:dX ← Pic, GOTO[DisplayNorm],c2, at[0,4,NormOn];
NormOff:dX ← NoPic, GOTO[DisplayNorm],c2, at[1,4,NormOn];
InvOn:dX ← InvPic, GOTO[DisplayInv],c2, at[2,4,NormOn];
InvOff:dX ← NoInvPic, GOTO[DisplayInv],c2, at[3,4,NormOn];
DisplayNorm:dY ← NoPic, CALL[Sleep],c3;
DisplayInv:dY ← NoInvPic, CALL[Sleep],c3;
{——————————————————————————————————————————————————————
Top Border
——————————————————————————————————————————————————————}
{Border work involves initializing cursor related registers and copying the lines of the visible area within which the cursor appears into the Cursor Buffer. The following values are computed:
The Line number on which the visible region stops:
uPicLength ← uInitPicLength or oddField
The Line number on which a wakeup is caused.:
uExitLength ← MIN[(ScanLineWakeup AND ~1) + 2 OR oddField, uPicLength]
The Line number on which the cursor begins (If CursorY is greater than uPicLength, then no cursor will be displayed):
uDoCursor ← CursorY + ((CursorY xor oddField) and 1)
The Line number on which the cursor stops:
uCursorStop ← uDoCursor + 14’d
The word address of the first word of the cursor bit map in the DCB:
uCurMapAddr ← uInitCurMapAddr + ((CursorY xor oddField) and 1)
The word address of the first location of cursor in the Visible Region:
uCurVisAddr ← uDoCursor*wordsPerLine + (CursorX RShift4)
The word address of the first location of the cursor in the Cursor Buffer:
uCurBufAddr ← uInitPicLength*wordsPerLine + (CursorX RShift4)
The Fifo entries for a cursor line where the cursor is in the middle:
uCursorFifo0 ← [(CursorX RShift4) - 1,,0]
uCursorFifo1 ← [(CursorX RShift4) + 1,,(uInitPicLength-uDoCursor)]
uCursorFifo2 ← [63,,0]
The Fifo entries for a cursor line where the cursor is at an edge:
LeftEdge = (CursorX RShift4)=0,
RightEdge = (CursorX RShift4)=62 or 63
uCursorFifo0’ ← IF LeftEdge THEN uCursorFifo1 ELSE [1,,0]
uCursorFifo1’ ← IF RightEdge THEN uCursorFifo0 ELSE [62,,0]
uCursorFifo2’ ← IF RightEdge THEN [63,,(uInitPicLength-uDoCursor)] ELSE uCursorFifo2
Sturgis: The Fifo entrys for the cursor just off left edge are
uCursorFifo0 ← [0,,(uInitPicLength-uDoCursor)]
uCursorFifo1 ← [62,,0]
uCursorFifo2 ← [63,,0]
The Fifo entry for a line without a cursor is [63,,0].
The mask & shift required to OR the cursor into the visible region are also computed.}
{Sturgis: 5-Aug-83 13:55:52: some work was done (not cleanly) to handle cursors whose upper left corner is slightly above the top edge, or slightly left of left edge. The fixes to handle a high cursor are at the end of "2nd line of "TopBorder"" and add 1 click for a normal cursor (havn’t modified the earlier comments) and additional for high cursors. The fix allows painting the bottom few lines of the cursor buffer at the very top of the screen when needed. These lines just happen to contain the right stuff. The fix for a very left cursor are more complicated. First the case is detected (during "3rd line"), at PossiblyNoCur. ONce detected, the uCursorMaskIsInverted, and L5 is adjusted so that during the 4’th line, special code is invoked to set paint exactly the first word of each line of the cursor buffer. This gets exactly the right bits. Modifying L5 requuired fixing up a return from DCycle that used the same value. I have not computed the added cost of these changes.}
{1st line of "Top Border" (6 clicks): Load uStartPic & uNoPic and compute uPicLength & uDoCursor.}
TopBorder:uStartPic ← dX, Refresh, L5 ← L5.tb2,c1, at[L5.tb1,10,SleepRet];
uNoPic ← dY,c2;
dY ← Line and 1,c3;
dX ← uInitPicLength or dY{oddField},c1;
dY ← uExitLength or dY{oddField},c2;
dY ← dY + 2,c3;
dY ← dY and u3FF,c1;
[] ← dX - dY, CarryBr,c2;
uPicLength ← dX, BRANCH[BadExitLen, ExitLenOK],c3;
BadExitLen:uExitLength ← dX, GOTO[PicLen] ,c1;
ExitLenOK:uExitLength ← dY ,c1;
PicLen:dY ← uDoCursor {cursorY},c2;
dX ← dY xor uClockBits {cursorY xor oddField},c3;
dX ← dX and 1 {(cursorY xor oddField) and 1},c1;
dY ← dX + dY {((cursorY xor oddField) and 1)+cursorY}, DCtl ← uNoPic,c2;
uDoCursor ← dY, CALL[Sleep],c3;
{2nd line of "Top Border" (5 clicks): Compute uCurMapAddr, uCursorDiff, init uCurVisAddr, and uCursorStop.}
TopB2:dX ← uInitCurMapAddr or dX, Refresh, L5 ← L5.DCycle6,c1, at[L5.tb2,10,SleepRet];
uCurMapAddr ← dX,c2;
dX ← uInitPicLength,c3;
dX ← dX - dY {uInitPicLength - uDoCursor},c1;
uCursorDiff ← dX,c2;
dX ← dY + 0E {uDoCursor +14’d},c3;
uCursorStop ← dX, CALL[DCycle6],c1;
{1 click of dX←dY LRot1; dX←dX LRot1; dX←dX LRot4}
uCurVisAddr ← dX {uDoCursor,,000000},c2, at[L5.DCycle6,10,DCycleRet];
{Sturgis: install possible fix for cursor at top edge, somewhat crude}
dX ← uDoCursor, NegBr,c3;
dY ← uCursorStop, NegBr, BRANCH[FixA2, $], c1;
dX ← dX and 1, BRANCH[$, FixA3],c2;
uDoCursor ← dX, c3;
dX ← uCurVisAddr,c1;
dX ← dX and ~3F,c2;
uCurVisAddr ← dX, GOTO[FixA1],c3;
FixA3:CANCELBR[$],c3;
FixA1:{no-op}c1;
FixA2:CANCELBR[$],c2;
dY ← uDCBLoc, CALL[Sleep],c3;
{3rd line of "Top Border" (7 clicks): Fetch cursorX, compute uCursorMask & the cursorShift in rhdX. Compute uCurVisAddr, uCurBufAddr, and init uCursorFifo2. If cursorX is off screen or display is off, don’t write into the cursor buffer & go to sleep.}
TopB3:MAR ← [rhdY, dY + cursorXLoc], L5 ← L5.DCycleA,c1, at[L5.DCycle6,10,SleepRet];
dY ← ~0F, CANCELBR[$, 0],c2;
rhdX ← dX ← MD{cursorX} and dY, XDisp,c3;
dY ← dX LRot12 {cursorX RShift4}, DISP4[DMask],c1;
{1 cycle of "dX←mask",c2;}
DMaskRet:Line ← ~3F,c3;
[] ← dY and Line {cursorX and ~3F}, NZeroBr,c1;
{begin modifications to handle cursor just off left edge}
uCursorMask ← dX, BRANCH[$, PossiblyNoCur],c2;
dX ← uCurVisAddr {uDoCursor,,000000} ,GOTO[CurXOn],c3;
PossiblyNoCur:
dX ← dY LRot4,c3;
dX ← dX xor ~0F,c1;
dY ← ~uCursorMask,c2;
uCursorMask ← dY,c3;
[] ← dX, NZeroBr, L5 ← L5.DCycleAx,c1;
dY ← 0, {fake cursorX} BRANCH[$, NoCurBuf],c2;
{end of changes for cursor just off left edge, except for L5.DCycleAx code below}
dX ← uCurVisAddr {uDoCursor,,000000},c3, at[0A,10,DisOn];
CurXOn:Xbus ← uStartPic, XDisp {is display on?},c1;
uCurVisAddr ← dX or dY {uDoCursor,,cursorX}, BRANCH[NoCurBuf, DisOn, 0B],c2;
DisOn:dX ← uInitCurBufAddr,c3, at[0F,10,DisOn];
CurBufAddr:uCurBufAddr ← dX or dY {uInitPicLength,,cursorX}, Refresh, CALL[DCycleA],c1;
{1 click of dX←LRot1 dY; dX←LRot1 dX; dX←dX LRot8}
{dX = cursorX,,0000000000}
dY ← u3FF, GOTO[SetUCursorFifo2], c2, at[L5.DCycleA,10,DCycleRet];
{handle return from DCycle, when L5 = L5.DCycleAx, occurs when cursor just off left edge}
dY ← u3FF,c2, at[L5.DCycleAx,10,DCycleRet];
SetUCursorFifo2:
uCursorFifo2 ← ~dY {111111,,0000000000}, CALL[Sleep],c3;
{special case for 4’th line of "Top Border", occurs when cursor just off of left edge of screen}
L5 ← L5.tb5,c1, at[L5.DCycleAx,10,SleepRet];
dX ← uCursorDiff {[0,PicLength - uDoCursor]},c2;
dY ← LShift1 ~dY {dX=[62,0]}, GOTO[CurEdgeFin],c3;
{normal 4th line of "Top Border" (3 clicks cursor in middle, 4 or 5 clicks cursor on edge): Compute uCursorFifo0, uCursorFifo1, and uCursorFifo2.}
dX ← dX - dY - 1, L5 ← L5.tb5,c1, at[L5.DCycleA,10,SleepRet];
uCursorFifo0 ← dX {dX=cursorX-1,,0000000000},c2;
dX ← dX+dY+1 {dX=cursorX,,0000000000}, ZeroBr,c3;
dX ← dX+dY+1 {dX=cursorX+1,,0000000000}, ZeroBr, Refresh, BRANCH[$, CurAtLeft],c1;
[] ← dX+dY+1 {dY=cursorX+2,,0000000000}, NZeroBr, BRANCH[$, CurAt3F0],c2;
dX ← dX or uCursorDiff {cursorX+1,,PicLength - uDoCursor}, BRANCH[CurAt3E0, Sleep],c3;
{Cursor is on left or right edge.}
CurAtLeft:dX ← dX or uCursorDiff {[1,PicLength - uDoCursor]}, CANCELBR[$],c2;
dY ← LShift1 ~dY {dX=[62,0]}, GOTO[CurEdgeFin],c3;
CurAt3F0:dX ← uCursorDiff {[0,PicLength - uDoCursor]}, CANCELBR[$],c3;
uCursorFifo2 ← ~dY xor dX {[63,PicLength - uDoCursor]}, GOTO[CurAtR],c1;
CurAt3E0:uCursorFifo2 ← dX {[63,PicLength - uDoCursor]},c1;
CurAtR:dX ← dY+1 {dX=[1,0]},c2;
dY ← uCursorFifo0 {cursorX-1,,0000000000},c3;
CurEdgeFin:uCursorFifo0 ← dX,c1;
dX ← dY,c2;
CALL[Sleep],c3;
{4th-12th lines of "Top Border" (2 clicks/line) when the display if off or cursorX is off screen: Sleep for 9 display wakeups. Resume at CopyDone.}
NoCurBuf:rhdX ← dX ← OffTime, CALL[Snore],c3, at[0B,10,DisOn];
{5th-12th lines of "Top Border" (9 clicks/line): Copy 8 lines from the visible region into the cursor buffer while ORing the cursor bit map into the lines.}
CopyInit:uCursorFifo1 ← dX, Refresh,c1, at[L5.tb5,10,SleepRet];
CopyCursor:dY ← uCurMapAddr,c2;
Line ← uCurVisAddr,c3;
MAR ← [rhdY, dY], dY ← dY + 2, L5 ← L5.DCycle,c1;
uCurMapAddr ← dY, [] ← rhdX, XDisp, CANCELBR[$, 2],c2;
dY ← MD{cursor word}, DISP4[DCycle],c3;
{1 click of dX←LRot1 dY; dX←LRot1 dX; dX←dX LRotn}
MAR ← [rhLine, Line+0],c1, at[L5.DCycle,10,DCycleRet];
dY ← dX and uCursorMask,c2;
dY ←MD or dY {visible or Left cursor},c3;
MAR ← [rhLine, Line + 1],c1;
dX ← dX and ~uCursorMask, CANCELBR[$, 2],c2;
dX ←MD or dX {visible or Right cursor},c3;
Line ← Line + 80,c1;
uCurVisAddr ← Line,c2;
Line ← uCurBufAddr,c3;
MAR ← [rhLine, Line+0],c1;
MDR ← dY, dY ← uClockBits,c2;
dY ←dY + 2,c3;
MAR ← [rhLine, Line + 1],c1;
MDR ← dX, WriteOK, CANCELBR[$, 2],c2;
Line ← Line + 80 ,c3;
uClockBits ← dY, Refresh,c1;
dX ← uCopyCount-1, NibCarryBr, LOOPHOLE[niblTiming],c2;
uCurBufAddr ← Line, ClrDPRq, BRANCH[CopyDone, $] ,c3;
uCopyCount ← dX, Refresh, GOTO[CopyCursor],c1;
{13th Line of "Top Border" (3+Field clicks): Update the clock, reset the line number, and preload the CtlFifo (It should be loaded 1 line in advance. Location Field is executed once per frame only.). The clock registers must be updated in the same click.}
CopyDone:dY ← uClockBits {reload dY if we’ve been awoken from Hibernation},c1, at[OffTime,10,HibernateRet];
Line ← RShift1 dY {uClockBits/2},c2;
dY ← dY and 1 {zero line count, preserve oddField},c3;
dX ← uClockLow,c1;
dX ← dX+Line {uClockLow+uClockBits/2}, CarryBr,c2;
Line ← uClockHigh, BRANCH[$, UpClkHigh],c3;
uClockLow ← dX, GOTO[CUC],c1;
UpClkHigh:uClockLow ← dX, Line ← Line + 1,c1;
CUC:uClockHigh ← Line, L5 ← L5.FieldStart,c2;
uClockBits ← dY, CALL[Field],c3;
{——————————————————————————————————————————————————————
Visible Field
——————————————————————————————————————————————————————}
{Line without cursor is 2 clicks, cursor line is 4 clicks, interrupt line is 2 additional clicks.}
FieldStart:DCtl ← uStartPic, L5 ← L5.Field, BRANCH[FieldC, FieldExit],c1;
Field:dX ← ~u3FF{normal fifo entry}, Refresh, BRANCH[FieldC, FieldExit],c1;
FieldC:[] ← dY xor uDoCursor, ZeroBr,c2;
CursorDone:uClockBits ← dY, BRANCH[$, Cursor],c3;
DCtlFifo ← dX + dY, Refresh,c1;
dY ← dY + 2, ClrDPRq, pRet5,c2;
[] ← dY xor uExitLength, ZeroBr, BRANCH[Field, FieldStart],c3;
Cursor:[] ← dY xor uCursorStop, ZeroBr,c1;
dX ← dY + 2, BRANCH[$, CursorLast],c2;
uDoCursor ← dX, GOTO[Curse],c3;
CursorLast:uDoCursor ← ~dY xor dY,c3;
Curse:dX ← uCursorFifo0,c1;
DCtlFifo ← dX + dY,c2;
dX ← uCursorFifo1,c3;
DCtlFifo ← dX + dY,c1;
dX ← uCursorFifo2, GOTO[CursorDone],c2;
FieldExit:dX ← uPicLength, CANCELBR[$],c2;
[] ← dY xor dX, ZeroBr,c3;
uExitLength ← dX, BRANCH[$, FieldDone],c1;
Noop,c2;
Noop,c3;
dX ← uWP,c1;
dX ← dX or uDWakeup, MesaIntRq,c2;
uWP ← dX, GOTO[Field],c3;
FieldDone:dY ← dY + 2, ClrDPRq,c2;
uClockBits ← dY, GOTO[BotBorder],c3;
{——————————————————————————————————————————————————————
Bottom border
——————————————————————————————————————————————————————}
BotBorder:dX ← rhdX ← BotBordTime, Refresh,c1;
dY ← uNoPic, CALL[Hibernate],c2;
{
{——————————————————————————————————————————————————————
Start Vertical Retrace
——————————————————————————————————————————————————————}
StartBlk:dX ← rhdX ← BlankTime, Refresh,c1, at[BotBordTime,10,HibernateRet];
dY ← Blank, CALL[Hibernate],c2;
}
{——————————————————————————————————————————————————————
Vertical Sync
——————————————————————————————————————————————————————}
StartVSync:uClockBits ← Line ← Line xor dY{1}, Refresh,,c1, at[BotBordTime,10,HibernateRet];
Line ← Line and 1,c2;
dX ← Line LRot4,c3;
dY ← dX or StartVSync,c1;
dX ← VSyncTime + Line, rhdX ← VSyncTime, CALL[Hibernate],c2;
{——————————————————————————————————————————————————————
Hibernate, Snore, Sleep
——————————————————————————————————————————————————————}
{Sleep: updates the clock & clears the display wakeup;
Hibernate: Sets DCtl to dY & skips dX display wakeups by calling Sleep.
Snore: Skips dX display wakeups}
Hibernate:DCtl ← dY LRot0,c3;
Snore:dX ← dX - 1, NegBr, Refresh, L5 ← L5.Hibernate,c1, at[L5.Hibernate,10,SleepRet];
Xbus ← rhdX, XDisp, BRANCH[Winter, Spring],c2;
Winter:uDoCursor ← dY xor ~dY {for no cursor}, CANCELBR[Sleep, 0F],c3;
Spring:dY ← 1 {see StartVSync}, RET[HibernateRet],c3;
Sleep:Line ← uClockBits, Refresh,c1;
Line ← Line + 2, pRet5,c2;
uClockBits ← Line, ClrDPRq, RET[SleepRet],c3;
{——————————————————————————————————————————————————————
DCycle
——————————————————————————————————————————————————————}
DCycle:dX ← dY, Xbus ← 0, XDisp, GOTO[NoRot],c*, at[0,10,DCycle];
dX ← LRot1 dY, Xbus ← 0, XDisp, GOTO[NoRot],c*, at[0F,10,DCycle];
dX ← LRot1 dY, Xbus ← 0, XDisp, GOTO[DRot1],c*, at[0E,10,DCycle];
dX ← RRot1 dY, Xbus ← 1, XDisp, GOTO[NoRot],c*, at[0D,10,DCycle];
dX ← dY, Xbus ← 1, XDisp, GOTO[NoRot],c*, at[0C,10,DCycle];
dX ← LRot1 dY, Xbus ← 1, XDisp, GOTO[NoRot],c*, at[0B,10,DCycle];
DCycle6:dX ← LRot1 dY, Xbus ← 1, XDisp, GOTO[DRot1],c*, at[0A,10,DCycle];
dX ← RRot1 dY, Xbus ← 2, XDisp, GOTO[NoRot],c*, at[9,10,DCycle];
dX ← dY, Xbus ← 2, XDisp, GOTO[NoRot],c*, at[8,10,DCycle];
dX ← LRot1 dY, Xbus ← 2, XDisp, GOTO[NoRot],c*, at[7,10,DCycle];
DCycleA:dX ← LRot1 dY, Xbus ← 2, XDisp, GOTO[DRot1],c*, at[6,10,DCycle];
dX ← RRot1 dY, Xbus ← 3, XDisp, GOTO[NoRot],c*, at[5,10,DCycle];
dX ← dY, Xbus ← 3, XDisp, GOTO[NoRot],c*, at[4,10,DCycle];
dX ← LRot1 dY, Xbus ← 3, XDisp, GOTO[NoRot],c*, at[3,10,DCycle];
dX ← LRot1 dY, Xbus ← 3, XDisp, GOTO[DRot1],c*, at[2,10,DCycle];
dX ← RRot1 dY, Xbus ← 0, XDisp, GOTO[NoRot],c*, at[1,10,DCycle];
NoRot:pRet5, DISP2[DLRot],c*;
DRot1:dX ← LRot1 dX, pRet5, DISP2[DLRot],c*;
DLRot:RET[DCycleRet],c*, at[0,4,DLRot];
dX ← dX LRot4, RET[DCycleRet],c*, at[1,4,DLRot];
dX ← dX LRot8, RET[DCycleRet],c*, at[2,4,DLRot];
dX ← dX LRot12, RET[DCycleRet],c*, at[3,4,DLRot];
{——————————————————————————————————————————————————————
DMask
——————————————————————————————————————————————————————}
DMask:dX ← 1, GOTO[DMaskRet],c2, at[0F,10,DMask];
dX ← 3, GOTO[DMaskRet],c2, at[0E,10,DMask];
dX ← 7, GOTO[DMaskRet],c2, at[0D,10,DMask];
dX ← 0F, GOTO[DMaskRet],c2, at[0C,10,DMask];
dX ← 1F, GOTO[DMaskRet],c2, at[0B,10,DMask];
dX ← 3F, GOTO[DMaskRet],c2, at[0A,10,DMask];
dX ← 7F, GOTO[DMaskRet],c2, at[9,10,DMask];
dX ← 0FF, GOTO[DMaskRet],c2, at[8,10,DMask];
dX ← LShift1 0FF, SE←1, GOTO[DMaskRet] {dX ← 1FF},c2, at[7,10,DMask];
dX ← RShift1 u7FF, GOTO[DMaskRet] {dX ← 3FF},c2, at[6,10,DMask];
dX ← u7FF, GOTO[DMaskRet] {dX ← 7FF},c2, at[5,10,DMask];
dX ← RShift1 u1FFF, GOTO[DMaskRet] {dX ← FFF},c2, at[4,10,DMask];
dX ← u1FFF, GOTO[DMaskRet] {dX ← 1FFF},c2, at[3,10,DMask];
dX ← u3FFF, GOTO[DMaskRet] {dX ← 3FFF},c2, at[2,10,DMask];
dX ← RShift1 (~dX xor dX), GOTO[DMaskRet] {dX ← 7FFF},c2, at[1,10,DMask];
dX ← ~dX xor dX, GOTO[DMaskRet] {dX ← FFFF},c2, at[0,10,DMask];