{File name: [Idun]<WDLion>LispTridentInitial.mc
Lichtenberg 2-Aug-84 1:28:03 fixed obscure leader pages bug.
Lichtenberg 20-Jul-84 14:42:48 -- Mesa 11.0 upgrades installed.
Lichtenberg 27-Jun-84 21:22:36 -- a stab at Lisp Initial
Lichtenberg 28-Jun-84 21:16:17 -- Lisp lives on Trident!!!!!!!
Lichtenberg 8-Jul-84 12:23:51 -- Put in code to build burp table on IOCB page
Lichtenberg 8-Jul-84 16:14:23 -- Trident boot now automatic for 16k ctl store
Description: first microcode read from the Trident disk, gets emulator microcode into CP memory,
Author: Neely,
Created: Neely ,December 11, 1981 12:38 PM
Last Edited by Neely February 17, 1982 10:16 AM: - fix to boot link in ucode file & cyl cross.
Last Edited by Neely February 17, 1982 7:02 AM: - fix to handle first page with boot link.
Last Edited by Neely February 3, 1982 9:44 AM: - Moved RegDef of uDevOrd to dandelion.df.
Last Edited by Neely February 2, 1982 4:16 PM: - Retries during Initial.
Last Edited by Neely January 15, 1982 9:27 PM: - Fixed SD.Request.location.deviceOrdinal bug.
Last Edited by Neely January 15, 1982 2:13 PM: - Fixed rCrhm = 1 bug.
Last Edited by Neely January 14, 1982 2:37 PM: - Restored extract of filePageHi from BootID.
Last Edited by Neely January 13, 1982 7:49 PM: - 30 secs., fixed multiDrive bug, filePageHi bug.
Last Edited by Neely January 12, 1982 6:31 PM: - Fixed IOCB update and filePageHi bugs.
Last Edited by Neely January 4, 1982 1:30 PM: - Fixed IOCBdiskLabel bug.
Last Edited by Neely December 31, 1981 5:03 PM: - Fixed register bug @ xTest+1.
Last Edited by Neely December 18, 1981 2:09 PM: - Fix NegBr probs and clientHeader probs.
Last Edited by Neely December 17, 1981 5:46 PM: - IOCB.clientHeader←0/0/0
Last Edited by Neely December 17, 1981 10:09 AM: - Recal as well as Reset
Last Edited by Neely December 15, 1981 5:14 PM: - Make all Rets [x, 10, z]
Last Edited by Neely December 11, 1981 12:38 PM:}
RegDef[uLinkPtr, U, 27{uTT}];{uLinkPtr}
RegDef[uFirstPage,U,49];
Set[hardMicrocodeFirstPage,13’d];
{word offsets}
{into Working Page}
Set[WPinitCSB, 48];
Set[WPrdLblCtl, 42];
Set[WPverLblCtl, 46];
Set[WPvrrLabelParam, 40];
Set[WPvvrLabelParam, 44];
{into IOCBs}
Set[IOCBcHeader, 0];{clientHeader}
Set[IOCBcHeaderCyl, 0];{clientHeader.cylinder}
Set[IOCBcHeaderHS, 1];{clientHeader.head§or}
Set[IOCBdataPtrLo, 4];
Set[IOCBdataPtrHi, 5];
Set[IOCBtries, 6];
Set[IOCBpageCount, 7];
Set[IOCBcStatus, 8];{Controller Status}
Set[IOCBdStatus, 9];{Disk Status}
Set[IOCBdHeader, 0A];
Set[IOCBdiskAdr, 0E];
Set[IOCBfilePageLo, 0F];
Set[IOCBseekDrive, 11];
Set[IOCBseekCyl, 12];
Set[IOCBseekHead, 13];
Set[IOCBhdrCtl, 16];
Set[IOCBlabelParam, 18];
Set[IOCBdataCtl, 1E];
Set[IOCBlabelParam, 18];
Set[IOCBlabelErrMask, 1B];
Set[IOCBclientLabel, 20];
Set[IOCBcLblFilePageLo, 25];
Set[IOCBcLblFilePageHi, 26];
Set[IOCBcLblBootLink, 28];
Set[IOCBcLblBootLink1, 29];
Set[IOCBdiskLabel, 30];
Set[IOCBdLblBootLink, 38];
{values }
Set[vDStatusEndCyl, 40];
Set[vDStatusAnyAtten, 80];
Set[vCStatusLastField, 6]; {Last Field Mask}
Set[vCStatusDataField, 6];
Set[vCStatusLblField, 4];
Set[vCStatusVerErrLRot8, 8];
Set[vCmdTagHd, 40];
Set[vCmdHd5, 5];
Set[vCmdTagCtl, 20];
Set[vCmdResetRecal, 0A];
Set[vLabelSize, 0A];
Set[vT300Heads, 19’d];
Set[vT80Heads, 5];
Set[vSecsPerTrack, 30’d];
Set[vNumHeadsBox, 2F];
{physical volume boot files}
{useful data formats extracted from Boot.mesa
BootFileType: TYPE= {hardMicrocode, softMicrocode, germ, pilot, debugger, debugee};
DiskFileID: TYPE= RECORD[fID: File.ID, firstPage: File.PageNumber, da: DiskAddress];
PVBootFiles: POINTER TO ARRAY BootFileType[hardMicrocode..pilot] OF DiskFileID= 2;
After reading from the disk, PVBootFiles moved to memory location 2}
Set[bootingInfo, 8];{origin of PVBootFiles in physical volume root page}
Set[DiskFileIDSize, 9];{number of words in DiskFileID}
Set[bootingInfoSize, Mul[DiskFileIDSize, 4]];{size of PVBootFiles}
{things salted away in page 0}
Set[availableDevices, 0];{devices available for booting, set up by Phase 0}
Set[bootReadyFlag, 1];{non-zero indicates boot file is ready}
Set[hardFileID, 2];{hard microcode DiskFileID, copied from physical volume root page}
Set[emulatorFileID, 0B];{emulator microcode DiskFileID, copied from physical volume root page}
Set[germFileID, 14];{germ DiskFileID, copied from physical volume root page}
Set[bootFileID, 1D];{working DiskFileID, copied from one of the above fileID’s}
Set[bootPage, 22];
Set[bootDiskAddr, 24];
Set[labelTemplate, 26];{template label used by boot loading routines}
{ *****{germ definitions}
Set[germPageHigh, 0];{virtual page number of origin of germ -- 1B}
Set[germPageLow, 1];
Set[sFirstGermRequest, 320’b];{start of germ request in SD}
Set[sLastGermRequest, 377’b];{end of germ request in SD}
Set[RequestSize, 60’b];{size of germ request in SD}
Set[SD.Request.version, 320’b];
Set[RequestVersionHigh, 7];
Set[RequestVersionLow, 56’b];
Set[SD.Request.action, 321’b];
Set[bootPhysicalVolume, 2];
Set[SD.Request.location, 322’b];
Set[SD.Request.location.deviceType, 322’b];
Set[germPilotDisk, 64’d];
Set[SD.Request.location.devOrd, 323’b];
*****}
Set[sLastGermRequest, Add[sFirstGermRequestLow, 57’b]];{end of germ request in SD}
Set[RequestSize, 60’b];{size of germ request in SD}
Set[SD.Request.version, Add[sFirstGermRequestLow, 00’b]];
Set[RequestVersionHigh, 7];
Set[RequestVersionLow, 56’b];
Set[SD.Request.action, Add[sFirstGermRequestLow, 01’b]];
Set[bootPhysicalVolume, 2];
Set[SD.Request.location, Add[sFirstGermRequestLow, 02’b]];
Set[SD.Request.location.deviceType, Add[sFirstGermRequestLow, 02’b]];
Set[germPilotDisk, 64’d];
Set[SD.Request.location.deviceOrdinal, Add[sFirstGermRequestLow, 03’b]];
Set[bootNotEnoughBanks, 57’d]; {makes 257 error code if trident boots with 4k storage}
Set[MicroDBNumber,3]; {second DB is microcode}
DoneOnceOnlyInit:
{Initialization}
rE← 0,c1;
germStart← rE,c2;
Noop,c3;
acR← 2,c1;
acR← acR LRot8,c2;
uBootStart← acR,c3; {boot file starts at 200}
{===========================================================================}
{**** START of NEW CODE for LISP *****}
{*}acR← uDiagnostic, ZeroBr,c1;
{*}[]← acR{uDiagnostic} - 1, NZeroBr, BRANCH[pLispBoot, pMesaBoot],c2;
pLispBoot:BRANCH[LispBoot, MesaBoot],c3;
pMesaBoot: CANCELBR[MesaBoot, 1],c3;
{map virtual pages 0-255 to real pages 0-255, first we must save the current mapping of the lowest virtual pages}
MesaBoot2: uDiagnostic← 0,c2;
Noop,c3;
MesaBoot:
rB ← 0AA{Lisp},c1;
uLispBootMsg ← rB,c2;
{MCtl ← 0} Noop,c3;
{**** END of NEW CODE for LISP *****}
{===========================================================================}
{map virtual pages 0-255 to real pages 0-255, first we must save the current mapping of the lowest virtual pages}
rBrh← 1,c1;
rCrh← 1,c2;
rB← 0,c3;
rC← topPage, L3← 0,c1;
acR← 0FF+1, CALL[L3BLT3],c2;
acR← present,c1, at[0, 10, L3BLTRet];
rC← 0FF+1,c2;
rB← 0,c3;
{set up identity map for benefit of the disk microcode}
identityMap:
MAR← [rBrh, rB+0], BRANCH[$, InitIOCB],c1;
MDR← acR, rB← rB+1,c2;
acR← acR+rC, CarryBr, GOTO[identityMap],c3;
InitIOCB:rBrh ← 0,c2;
rB ← 0FF+1,c3; {addr of IOCB}
rD ← bUBitSignAdr,c1;
KCtl ← rD LRot0,c2; {Select boot drive}
Noop,c3;
{Initialize IOCB.clientHeader=0/0/0}
MAR ← [rBrh, IOCBcHeaderCyl+0],c1;
MDR ← 0,c2;
rCrh← 0,c3;
MAR ← [rBrh, IOCBcHeaderHS+0],c1;
MDR ← 0,c2;
rDrh← 0,c3;
{Merge drive info into IOCB. Uses rB=100=IOCBaddr & rD=bUBitSignAdr}
rC ← rB+IOCBseekDrive, L0← 0,c1;
CALL[merge3],c2;
rC ← rB+IOCBhdrCtl, L0← 1,c1, at[0, 10, mergeRet];
CALL[merge3],c2;
rC ← rB+IOCBdataCtl, L0← 2,c1, at[1, 10, mergeRet];
CALL[merge3],c2;
rC ← rB+WPrdLblCtl, L0← 3,c1, at[2, 10, mergeRet];
CALL[merge3],c2;
rC ← rB+WPverLblCtl, L0← 4,c1, at[3, 10, mergeRet];
CALL[merge3],c2;
[] ← rD LRot8,XDisp, c1, at[4, 10, mergeRet];
DISP4[CSBIndex],c2;
rC ← 0, {drive 0} GOTO[IOCBDA],c3, at[8, 10, CSBIndex];
rC ← 4, {drive 1} GOTO[IOCBDA],c3, at[4, 10, CSBIndex];
rC ← 8, {drive 2} GOTO[IOCBDA],c3, at[2, 10, CSBIndex];
rC ← 0C, {drive 3}c3, at[1, 10, CSBIndex];
IOCBDA:MAR ← [rBrh, IOCBdiskAdr+0],c1;
MDR ← rC,c2;
acR ← rC,c3;
acR ← RShift1 acR,c1;
acR ← RShift1 acR,c2;
uDevOrd ← acR,c3;
InitCSB:rB ← rB+WPinitCSB, {adr Init vals for CSB}c1;
rC ← rC+rB+1,c2;
acR ← 0FF+1,c3;
MAR ← [rCrh, rC+0],c1;
MDR ← acR,c2;
rCrh ← 2,c3;
rC ← 0{*** IOPageLow ***}, L3← 1,c1; {CSB at 14000}
acR ← 10, CALL[L3BLT3],c2;
{Set tiUnumHeads based on boot drive type(i.e. T80/T300)}
{select head 5}
rB ← U0400,c1, at[1, 10, L3BLTRet];
rB ← rB or vCmdHd5, L0 ← 0,c2; {Select Head 5}
rC ← vCmdTagHd, CALL[SetRst1],c3;{delays after tagReset}
Xbus ← KStatus, XwdDisp, {test bit 9&10}c3, at[0, 10, SetRst3Ret];
DISP2[DiskType, 1],c1;
typeT300:acR ← vT300Heads, GOTO[setHeads], c2, at[3, 10, DiskType];
typeT80: acR ← vT80Heads, c2, at[1, 10, DiskType];
setHeads: tiUnumHeads ← acR,c3;
{ write the number of heads onto the IOCB page}
rB ← 0FF + 1 {addr of IOCB}, c1;
, c2;
, c3;
MAR ← [rBrh, vNumHeadsBox + 0], c1;
MDR ← acR, c2;
, c3;
rB ← U0400,c1;
rB ← rB or vCmdResetRecal, L0 ← 1,c2;
rC ← vCmdTagCtl, CALL[SetRst1],c3; {Reset Disk Check}
rCrh ← 0, GOTO[rootPage],c3, at[1, 10, SetRst3Ret];
{===========================================================================}
{**** START of NEW CODE for LISP *****}
{** Lisp uses identity map for all of real memory for benefit of the disk microcode}
LispBoot:
rB← 0,c1;
Q ← 55{Mesa},c2;
[]← Q xor uLispBootMsg, ZeroBr,c3;
acR← 03{B}0{dirtyRef}, BRANCH[$, MesaBoot2],c1;
Q{100}← 0FF+1,c2;
nextId3:rBrh← 1,c3;
{acR{dirtyRef}, rB{10000}, Q{100}, map 2↑12 pages as identity}
nextId:MAR← [rBrh, rB+0],c1;
MDR← acR, acR ← acR + Q{100}, CarryBr,c2;
rB← rB+1, BRANCH[nextId, $],c3;
incSeg:acR ← acR + 1, NibCarryBr{2↑12 pages},c1;
rC ← topPage{virtual}, BRANCH[nextId3, Zdone],c2;
Zdone:rC ← rC LRot8,c3;
Ybus ← 0E - rC, PgCarryBr{if rC is low or eq},c1;
acR ← 0B0{2mb+dirty}, BRANCH[ZnextId3, doneId],c2;{%%}
{acR{2mb+dirty}, rB{10000}, Q{100}, map next 2↑11 pages as identity}
ZnextId:MAR← [rBrh, rB+0],c1;
MDR← acR, acR ← acR + Q{100}, CarryBr,c2;
rB← rB+1, BRANCH[ZnextId, $],c3;
ZincSeg:Ybus ← acR + 1{9}, NibCarryBr{2↑12{11} more pages},c1;
acR ← acR + 1, BRANCH[ZnextId3, doneId],c2;
ZnextId3:Noop, GOTO[ZnextId],c3;
doneId:acR{dirty;page FF}← ~0DF,c3;
rCrh←1,c1;
rC← 040,c2;
rC{14000} ← rC LRot8,c3;
{acR{FF20}, rB{12000{11800}}, rCrh,rC{14000}, remaining vp’s mapped to FF}
Scrap:MAR← [rBrh, rB+0], BRANCH[$, doneScrp],c1;
Scrap2:MDR← acR{-1}, rB← rB+1,c2;
Ybus ← rB - rC{4000}, ZeroBr, GOTO[Scrap],c3;
doneScrp:Noop,c2;
Noop,c3;
{acR{-1}, rCrh,rC{14000}, change 65 map entries to protect the map and iopage to point to FF{-1}}
Protect65:Map{14000}← [rCrh, rC+0],c1;
MDR← acR{-1}, rC← rC, ZeroBr,c2;
rC← rC - 0FF - 1, BRANCH[Protect65, $],c3;
{Mesa11: Real Page 20000 is IOPage for Mesa11 but stack for Lisp}
{Divert the reading of page 20000 from newIOPage to oldIOPage}
rCrh ← 2{IOPageHigh},c1;
acR ← 40,c2;
acR ← acR LRot8,c3;
Map{20000} ← [rCrh{2}, 0],c1;
MDR{4031} ← acR or 31,c2;
Noop,c3;
GOTO[InitIOCB],c1;
{**** END of NEW CODE for LISP *****}
{===========================================================================}
{Now we’re ready to read the root page.}
{There is only one IOCB. DCB[0] points to it. DCB[0] can be used for any drive.
The IOCB is initialized with a da=0/0/0 .}
rootPage:rD← 0FF+1,c1; {rD(rh)= addr of IOCB}
rF ← 2, L3 ← 0,c2; {read data into pg. 2}
acR ← 1, CALL[doVrr1],c3;
{save the useful stuff from the physical volume root page}
rC← 2,c1, at[0, 10, xferGoodRet];
rB← rC LRot8,c2;
rB← rB+bootingInfo, L3← 2,c3;
acR← bootingInfoSize, CALL[L3BLT2],c1;
{** lisp **}
rC ← 2, c1, at[2, 10, L3BLTRet];
rC ← rC LRot8, c2;
rCrh ← 0, c3;
MAR ← [rCrh, hardMicrocodeFirstPage + 0], c1;
, c2;
rC ← MD, c3;
uFirstPage ← rC, c1;
, c2;
, c3;
{read the emulator boot file or the hard microcode}
emuHard:[]← uDiagnostic, ZeroBr,c1;
rC← bootFileID, BRANCH[$, emuHard0],c2;
rB← hardFileID, L0← 8, GOTO[emuHard1],c3;
emuHard0: rB← emulatorFileID, L0← 8,c3;
emuHard1:acR← DiskFileIDSize, CALL[BLT2],c1;
acR← 2, L2← 0,c1, at[8, 10, subrRet];
nextPage← acR, CALL[readBoot3],c2;
rC← uDiagnostic, ZeroBr,c1, at[0, 10,readBootRet];
acR← nextPage, BRANCH[$, readGerm],c2;
{===========================================================================}
{**** START of NEW CODE for LISP *****}
Noop,c3;
Noop,c1;
Ybus← rC{uDiagnostic}-1, NZeroBr,c2;
Noop, BRANCH[$, doDiag],c3;
{test if we have lisp or diagnostics in real memory}
rC ← 15{passH},c1;
rB ← 3,c2;
rBrh{0} ← rB{300} ← rB LRot8,c3;
MAR← [rBrh, rB+0F{passA}],c1;
rC{passH} ← rC LRot8, CANCELBR[$, 2],c2;
rC ← MD xor rC,c3;
rC ← rC xor 0E3{passL},c1;
Ybus ← rC, NZeroBr,c2;
Noop, BRANCH[$, notLisp],c3;
{ We have Lisp; Restore the map.}
{set map[0..3FFFF] to vacant and interpret FPTOVP}
LispInit:rB{7FFF}← ~1 RRot1, rBrh← 1,c1;
rB{3FFF}← rB RShift1,c2;
rC ← 60{vacant},c3;
vacLp:MAR← [rBrh{0C1}, rB+0], ZeroBr,c1;
MDR← rC{vacant}, rB← rB-1, NibCarryBr, BRANCH[$, vDone],c2;
vac3:Noop, BRANCH[$, vacLp]{match to vacRef+1},c3;
vacRef:{Refresh,}c1;
Xbus ← 1, XDisp, GOTO[vac3],c2;
vDone: Noop, CANCELBR[$, 1],c3;
{update Interface page and interpret FPTOVP}
{Map[InterfacePageVp] ← 3}
acRrh ← 26’b{INTERFACEspace}, CANCELBR[$, 1],c1;
acR ← 20’b{INTERFACEbase=10000’b},c2;
acR ← acR LRot8,c3;
rB ← 3{real interface page},c1;
rB{300} ← rB LRot8,c2;
rBrh ← rB ← rB + 03{B}0{dirty},c3;
Map{161000} ← [acRrh,acR],c1;
MDR ← rB{3B0},c2;
rC ← 0C{(NRealPages{3072})/256},c3;
MAR← [rBrh, 15’b{MachineType} + 0],c1;
MDR ← 6{\DANDELION},c2;
rC{C00} ← rC LRot8,c3;
Q ← topPage{virtual},c1;
Q ← Q + 40,{ map not included}c2;
Q{NRealPages} ← Q + {02}{0A8}{-56 mp301}0FF{+1}{bank 0 was not incl but},c3;
MAR← [rBrh, 70’b{NRealPages} + 0],c1;
MDR ← Q{NRealPages} {← topPage}{rC{C00}},c2;
Noop,c3;
{%% no segment crossing of FPTOVP[i-1] ptr ??? }
{interpret FPTOVP setup}
{for i{acR} ← 501’b to MaxRealPage{rC}}
{unless FPTOVP[i-1]=none{-1}}
{do MAP[FPTOVP[i-1]]:vp ← i}
MAR← [rBrh, 73’b{FPTOVPStart} + 0],c1;
rBrh ← 1,c2;
acR{F2Vpage} ← MD,c3;
acR{F2VrealPage+1} ← acR + 2{file1=real2}{+1},c1;
acRrh ← acR ← acR LRot8,c2;
acR ← acR and ~0FF,c3;
acR{F2V+500b} ← acR + 40,c1;
rC ← 0FF + 1,c2;
rC{501b} ← rC + 41,c3;
{interpret FPTOVP Loop }
{acR:FPTOVP[i-1] ptr }
{rB:FPTOVP[i-1]:vp}
{rC:i ← 501b}
{Q:NRealPages= C00}
{rBrh:10000{Map}}
{spin2:GOTO[spin2],c*;}{%%%}
f2vLp:MAR← acR ← [acRrh, acR + 0],c1;
rB{7FFF} ← (rB xor ~rB) RShift1,c2;
rB{vp} ← MD and rB{7FFF},c3;
Ybus ← rB + rB, NegBr,c1;
rC ← rC LRot8, XRefBr, BRANCH[$, none],c2;
Ybus ← rC + 0F, NibCarryBr{nondisplay bank?}, BRANCH[$, fvMod],c3;
MAR← [rBrh{1}, rB + 0], BRANCH[fvNo, $],c1;
MDR ← rC{i}, GOTO[none],c2;
fvNo:Noop, GOTO[none],c2;
fvMod:MAR← [rBrh{1}, rB + 0], BRANCH[fvMNo, $],c1;
MDR ← rC{i} + 70{move over flags to "dp" bit}, GOTO[none],c2;
fvMNo:Noop, GOTO[none],c2;
none:rC ← rC LRot8, CANCELBR[$, 1],c3;
rC ← rC + 1,c1;
Ybus ← rC xor Q{NRealPages}, ZeroBr,c2;
acR ← acR + 1, BRANCH[f2vLp, $],c3;
{spin3:GOTO[spin3],c*;}{%%%}
{done with interpret FPTOVP}
Noop,c1;
rBrh ← 1,c2;
Noop,c3;
rB ← 0FF,c1;
rC ← 40,c2;
rC{4000} ← rC LRot8,c3;
{Map[IOPageVp=0FF] ← 500}
MAR{100FF}← [rBrh{1}, rB + 0],c1;
MDR{4001} ← rC{4000} + 1,c2;
rC{100} ← 0FF + 1,c3;
rC{200} ← rC + rC,c1;
rC{400} ← rC + rC,c2;
uBootStart← rC{400}, {GOTO[StartNewInit],}c3;
bankTest: Q ← 0,c1;
Bank ← rB ← 0,c2;
btLoop: rC ← ~ PPort, BRANCH[$, {GOTO[}MultiBank],c3;
btLL: rC ← (rC LRot8) xor Q,c1;
Ybus ← rC and 3, NZeroBr,c2;
Q ← Q + {0FF +} 1, BRANCH[$, NotEnoughBanks],c3;
Bank ← rB +4,c1;
rB ← rB +4, NibCarryBr,{}{%}GOTO[btLoop],c2;
MultiBank: rB← 4,c1;
rBrh{0} ← rB{400h}← rB LRot8, c2; {boot file starts at 200}
rC← MicroDBNumber{3rd DB for Trident},c3; {*** Changed for auto Lisp boot ***}
MAR← [rBrh, rC+0],c1;
rC{400q}{100} ← 0FF + 1,c2;
rC← MD,c3;
rC← rC+rB,c1;
uBootStart← rC{400},c2;
{===========================================================================}
{**** START of NEW CODE for LISP *****}
Noop,GOTO[GoNewInit],c3;
GoNewInit:{copy data diverted from newIOPage to oldIOPage back to newIOPage}
rBrh ← 1,c1;
rB ← 40,c2;
rB ← rB LRot8,c3;
acR ← 0FF + 1, L0← 0D,c1;
rCrh ← 2,c2;
rC ← 0,GOTO[BLT],c3;
{BLT cnt/acR:100 from/rB:14000 to/rC:20000}
{clear oldIOPage to zeros}
rBrh ← 1,c1, at[0D{free?}, 10, subrRet];
rB ← 40,c2;
rB ← rB LRot8,c3;
{Initialize uIOPage register}
rC ← rB or 1, c1;
Noop, c2;
uIOPage ← rC{4001}, c3;
ioclp:MAR ← [rBrh{14000}, rB+0], BRANCH[$, ioclrDone],c1;
MDR ← acR and ~acR,c2;
rB ← rB +1, PgCarryBr, GOTO[ioclp],c3;
ioclrDone:
Noop,c2;
GOTO[StartNewInit],c3;
{**** END of NEW CODE for LISP *****}
{===========================================================================}
{Tridents without 16k control store are not allowed yet}
NotEnoughBanks: acR ← bootNotEnoughBanks, GOTOABS[Maintenance2Loc], c1;
BackFromNewInit:
c1;
TOS{8002h} ← RRot1 5,c2;
MCtl ← TOS{8002h}, GOTO[exitToEmulator],c3;
{**** END of NEW CODE for LISP *****}
{===========================================================================}
{hard microcode (quick exit), pick up diagnostic table entry from first page of boot file}
{===========================================================================}
{**** START of NEW CODE for LISP *****}
doDiag:rB ← 055{Mesa}, GOTO[doDiag2],c1;
notLisp:rB ← 055{Mesa}, GOTO[doDiag2],c1;
doDiag2:uLispBootMsg ← rB,c2;
{**** END of NEW CODE for LISP *****}
{===========================================================================}
rB← 2,c3; {boot file starts at 200}
rB← rB LRot8,c1;
rC← rC+1,c2;
Noop,c3;
MAR← [rBrh, rC+0],c1;
Noop,c2;
rC← MD,c3;
rC← rC+rB,c1;
uBootStart← rC,c2;
GOTO[exitToEmulator],c3;
{read the germ}
readGerm:germStart← acR,c3;
rB← germFileID,c1;
rC← bootFileID, L0← 9,c2;
acR← DiskFileIDSize, CALL[BLT],c3;
L2← 1,c1, at[9, 10, subrRet];
CALL[readBoot3],c2;
{
We now have the germ in real memory. Restore the map for pages 0-255. Then move the germ to MDS 0, starting at page 1. Initialize the Request in the germ’s SD.
}
RestoreMap:
rBrh← 1,c1, at[1,10,readBootRet];
rCrh← 1,c2;
rB← topPage,c3;
rC← 0, L0← 5,c1;
acR← 0FF+1, CALL[BLT3],c2;
{vacate the pages just used to restore the low ones}
rB← topPage,c1, at[5, 10, subrRet];
rC← rB+1,c2;
acR← 0FF+1,c3;
MAR← [rBrh, rB+0],c1;
MDR← vacant, L0← 0B,c2;
acR← acR-1, CALL[BLT],c3;
{Move germ to MDS 0, page 1}
rC ← germStart,c1, at[0B, 10, subrRet];
rB ← rC LRot8,c2;
rBrh ← 0,c3;
rD ← nextPage,c1;
rD ← rD - rC, ZeroBr,c2;
transferCount ← rD, BRANCH[moveGerm1, $],c3; {number pages in germ}
acR← bootNullGerm, GOTOABS[Maintenance2Loc],c1;
moveGerm1:germStart← acR xor ~acR,c1;
rFrh ← germPageHigh, rF ← 0 + germPageLow,c2;
rF ← rF LRot8,c3;
mg2:Map ← [rFrh, rF],c1;
Noop,c2;
rCrh ← rC ← MD,c3;
acR ← 0FF + 1,c1;
rC ← rC and ~0FF, L0 ← 0C,c2;
CALL[BLT],c3;
rF ← rF + 0FF + 1,c1, at[0C, 10, subrRet];
rD ← rD - 1, ZeroBr,c2;
rE ← LShift1 0FF, SE ← 1, BRANCH[mg2, InitRequest],c3;
{Initialize Request in germ’s SD}
InitRequest: {rE has 1FF = start of SD -1}
rC ← sFirstGermRequestHigh,c1;
rC ← rC LRot8,c2; {Constants use an 8-bit data path.}
rE ← rE + rC + 1, {correct page}c3;
Map ← rF ← [rFrh, rE + 0],c1;
rC ← sFirstGermRequestLow,c2;
rBrh ← rB ← MD,c3;
{InitRequest:
Map ← rF ← [rFrh, rE + 1],c1;
rC ← sFirstGermRequest,c2;
rBrh ← rB ← MD,c3;
}
ZeroReq:MAR ← [rBrh, rC+0],c1;
MDR ← rD, rC ← rC + 1, PgCarryBr,c2; {rD zero from above}
BRANCH[ZeroReq, $],c3;
rD ← RequestVersionHigh,c1;
rD ← rD LRot8,c2;
rD ← rD or RequestVersionLow,c3;
MAR ← [rBrh, SD.Request.version+0],c1;
MDR ← rD,c2;
Noop,c3;
MAR ← [rBrh, SD.Request.action+0],c1;
MDR ← bootPhysicalVolume,c2;
Noop,c3;
MAR ← [rBrh, SD.Request.location.deviceType+0],c1;
MDR ← germPilotDisk,c2;
doneReq:MCtl ← 0, GOTO[exitToEmulator],c3;
{Read the first page of the bootFile. Calculate the proper label by reading the label from the disk and filing in the correct fileID and page number}
readBoot3:Noop,c3;
readBoot:rB← bootDiskAddr,c1;
rC← rD+IOCBcHeader, L3← 3,c2; {disk address of boot}
acR← 2, CALL[L3BLT],c3;
{** New for Lisp: Copy addr of first page of boot file to IOCB page}
rB← bootDiskAddr,c1, at[3, 10, L3BLTRet]; {nil disk address?}
rC← rD or 80{uLinkPtr}{+{1}headerAddr}, L0← 0E{*free?},c2; {save for lisp}
acR← 2, CALL[BLT],c3;
rB ← 82, {** New for Lisp - sets up loc of burp table}c1, at[0E, 10, subrRet];
uLinkPtr ← rB {** New for Lisp **},c2;
rB← bootDiskAddr,c3; {nil disk address?}
{ ** End of new stuff for Lisp **}
MAR← [rBrh, rB+0],c1;
rB← rB+1,c2;
acR← MD,c3;
MAR← [rBrh, rB+0],c1;
Noop,c2;
acR← acR or MD,c3;
[]← acR, ZeroBr,c1;
BRANCH[$, nilBootFile],c2;
rF← nextPage, L3← 1,c3;
acR← 1, CALL[doVrr2],c1; {read 1 starting at page 2}
rC← rD+IOCBclientLabel,c1, at[1, 10, xferGoodRet];
rB← bootFileID, L3← 4,c2;
acR← 6, CALL[L3BLT],c3;
rE← rE and 7F,c1, at[4, 10, L3BLTRet];
rE← rE LRot8,c2; {rE← high bits of page#}
rE← LShift1 rE,c3;
MAR← [rCrh, rC+0],c1;
acR← 7,c2;
acR← MD and acR,c3;
MAR← [rCrh, rC+0],c1;
MDR← acR or rE,c2;
Noop,c3;
MAR← [rDrh, IOCBcLblFilePageLo+0],c1,;
rB← bootDiskAddr,c2;
rC← MD,c3; {read low 16 bits of page #}
rC← rC+1, {reading first page is a special case}c1;
filePage← rC,c2; {restore disk address}
rC← rD+IOCBcHeader, L0← 3,c3;
acR← 2, CALL[BLT2],c1;
rF← nextPage, L3← 2,c1, at[3, 10, subrRet];
acR← 1, CALL[doVvr3],c2; {read 1 starting at page 2}
acR← 0A, GOTOABS[Maintenance2Loc],c1, at[2, 10, xferLblVerRet]; {was bootDeviceError}
acR← nextPage,c1, at[2, 10, xferGoodRet];
acR← acR+1,c2;
nextPage← acR,c3;
MAR← [rDrh, IOCBcLblFilePageHi+0],c1;
acR← ~7,c2;
acR← MD and acR, {Mask out 3bit Label flags}c3;
MAR← [rDrh, IOCBcLblFilePageHi+0],c1;
MDR← acR,c2;
Noop,c3;
{check for VERY special case of a boot link in the first page}
MAR← [rDrh, IOCBcLblBootLink+0],c1;
Noop,c2;
acR← MD,c3;
MAR← [rDrh, IOCBcLblBootLink1+0],c1;
Noop,c2;
rB← MD,c3;
[]← acR or rB, ZeroBr,c1;
BRANCH[rbLink, rbNotLink],c2;
rbLink:Noop, {boot link in the first page}c3;
MAR← [rDrh, IOCBcHeader+0],c1;
MDR← acR,c2;
Noop,c3;
MAR← [rDrh, IOCBcHeader+1],c1;
MDR← rB, CANCELBR[$, 0],c2;
acR ← 0, {to zero out boot link}c3;
MAR← [rDrh, IOCBcLblBootLink+0],c1;
MDR← acR,c2;
Noop,c3;
MAR← [rDrh, IOCBcLblBootLink1+0],c1;
MDR← acR,c2;
rbNotLink:rC← labelTemplate,c3;
rB← rD+IOCBclientLabel, L0← 6,c1;
acR← vLabelSize, CALL[BLT3],c2;
{read the rest of the file from the Pilot Volume}
readLoop:L1← 1,c1, at[6, 10, subrRet];
CALL[pagesLeftInCylinder],c2;
transferCount← acR, NZeroBr,c1, at[1, 10, PLCRet];
BRANCH[$, readRun],c2;
Noop,c3;
{no pages left in cylinder, advance to next cylinder}
MAR← [rDrh, IOCBcHeaderHS+0],c1;
MDR← 0,c2; {start at head 0, sector 0}
Noop,c3;
MAR← [rDrh, IOCBcHeaderCyl+0],c1;
Noop,c2;
acR← MD,c3;
MAR← [rDrh, IOCBcHeaderCyl+0], L1← 2,c1;
MDR← acR+1, CALL[pagesLeftInCylinder],c2; {step in one cylinder}
Noop,c1, at[2, 10, PLCRet];
transferCount← acR,c2;
readRun:rF← ~0FF, L3← 3,c3;{** Was: rF ← nextPage}
{*** New stuff for Lisp ***}
{Transfer count reduced to 0FF}
Ybus ← acR and rF, NZeroBr, c1;
rF ← nextPage, BRANCH[oldTCnt,newTCnt],c2;
oldTCnt: GOTO[readRun1],c3;
newTCnt: acR ← 0FF, GOTO[readRun1], c3;
readRun1:
Ybus ← rF + acR, PgCarryBr{new transferCount},c1;
Noop, BRANCH[oldTC, newTC],c2;
oldTC:Noop, GOTO[readRun2],c3;
newTC:acR ← 0-rF, GOTO[readRun2],c3;
readRun2:
Noop,c1;
Noop,c2;
acR← acR and 0FF,c3;
{*** End New Stuff for Lisp ***}
transferCount ← acR, CALL[doVvr2],c1; {TransferCount ← ACR for Lisp}
rB← transferCount,c1, at[3, 10, xferGoodRet];
acR← filePage,c2;
acR← acR+rB,c3; {next page in file}
filePage← acR,c1;
acR← nextPage,c2;
acR← acR+rB,c3; {next page in memory}
nextPage← acR,c1;
Noop,c2;
GOTO[readLoop],c3;
{burped while reading run of pages, controllerStatus in rF.}
readBurp:MAR← [rDrh, IOCBpageCount+0], {get # of sectors remaining}c1, at[3, 10, xferLblVerRet];
rB← transferCount,c2;
acR← MD, {number sectors remaining}c3;
acR← rB - acR, {number sectors transferred}c1;
transferCount← acR, {zero is okay}c2;
rE← filePage,c3;
rE← rE+acR+1 {+1 because one sec read via Vrr},c1; {file page for next label}
filePage← rE,c2;
rB← nextPage,c3;
rB← rB+acR+1 {+1 because one sec read via Vrr},c1; {next available page for vvr}
nextPage← rB,c2;
rF← rB-1, L3← 4,c3; {page used by vrr}
acR← 1, CALL[doVrr2],c1; {transfer 1 page}
{Copy boot link to header, and check for end of file, FFFF in both words of boot link.}
MAR← [rDrh, IOCBdLblBootLink+0] ,c1,at[4, 10, xferGoodRet];
Noop,c2;
acR← MD,c3;
MAR← [rDrh, IOCBcHeader+0],c1;
MDR← acR, c2;
Noop,c3;
MAR← [rDrh, IOCBdLblBootLink+1], c1;
CANCELBR[$, 0],c2;
rB← MD,c3;
MAR← [rDrh, IOCBcHeader+1],c1;
MDR← rB, CANCELBR[$, 0],c2;
[]← acR or rB, ZeroBr,c3;
acR← acR+1, BRANCH[rdBurp1, $],c1;
acR← bootBrokenChain, GOTOABS[Maintenance3Loc],c2; {boot chain link is zero}
rdBurp1:rB← rB+1,c2;
[]← acR or rB, ZeroBr,c3;{FFFF+1 or FFFF+1 = 0 => end}
rC← rD+IOCBclientLabel, BRANCH[rdBurp2, endRead],c1;
rdBurp2:
{*** New stuff for Lisp ***}
Noop,c2;
Noop,c3;
{*1}MAR← [rDrh, IOCBcHeader{headerAddr}+0],c1;
MDR← acR-1,c2;
Noop,c3;
{*2}MAR← [rDrh, IOCBcHeader{headerAddr}+1],c1;
MDR← rB-1, CANCELBR[$, 0],c2;
{*2}Q← uLinkPtr,c3;
Temp ← filePage, c1;
rK ← uFirstPage, c2;
, c3;
{*5}MAR← [rDrh, Q{uLinkPtr}+0],c1;
MDR← Temp - rK,c2;
Noop,c3;
{*5}MAR← [rDrh, Q{uLinkPtr}+1],c1;
MDR← acR-1, CANCELBR[$, 0],c2;
Noop,c3;
{*5}MAR← [rDrh, Q{uLinkPtr}+2],c1;
MDR← rB-1, CANCELBR[$, 0],c2;
Q{uLinkPtr} ← Q +3, PgCarryBr,c3;
acR← vLabelSize{labelSize}, BRANCH[there1, $],c1;
{Noop,} L0← 7, GOTO[there2],c2;
there1:uLinkPtr ← Q{uLinkPtr+3}, L0← 7,c2;
there2:rB← labelTemplate, CALL[BLT],c3;
{*** End new stuff for Lisp ***}
{rB← labelTemplate, L0← 7,c2;
acR← vLabelSize, CALL[BLT],c3;}
MAR← [rDrh, IOCBcLblFilePageLo+0],c1, at[7, 10, subrRet];
MDR← filePage,c2;
GOTO[readLoop],c3;
endRead:pRet2,c2;
RET[readBootRet],c3;
{here if boot file pointer was zero}
nilBootFile:[]← uDiagnostic, ZeroBr,c3;
acR← 1 {disk Boot}, BRANCH[noDiagnostics, $],c1;
[]← germStart, ZeroBr,c2;
BRANCH[noGerm, noEmulator],c3;
noEmulator:acR← bootNoEmulator, GOTOABS[Maintenance2Loc],c1;
noGerm:acR← bootNoGerm, GOTOABS[Maintenance2Loc],c1;
{this code tries a disk boot if no hard microcode is installed}
noDiagnostics:uDiagnostic← 0,c2;
bootDevice ← acR {disk Boot}, GOTO[emuHard],c3;
{subroutines}
{doVvr and doVrr do either a vvr or vrr operation to the boot drive.
TridentBootIOCB.bravo set up an IOCB that has.
.microNext=0
.dcbOffset=0 (DCB[0] can be and is used for any drive)
.headerParam=verify, IncrDataPtr=TRUE, firstIOCB=TRUE
.dataParam=read
Early parts of TridentInitial do the following.
Set up DCB[0].microNext=ptr-to-the-only-IOCB, (never changed).
Particularize IOCB based on boot drive.
Additionally both vrr and vvr REQUIRE:
acR=pageCount,
rD(rh)=IOCB addr.,
rF=MemoryPageNumber,
IOCB.clientHeader=Header,
vvr also REQUIRES:
IOCB.clientLabel=Label
Both vrr and vvr RETURN:
rD(rh) unchanged,
rF=ControllerStatus,
IOCB.clientHeader=last in run.
IOCB.pageCount=upDated (0 If good completion)
IOCB.dataPtr=last in run.
vvr also RETURNS:
IOCB.clientLabel=updated
vrr also RETURNS:
IOCB.clientLabel = IOCB.diskLabel as read}
doVrr2:Noop,c2;
doVrr3:Noop,c3;
doVrr1:L1 ← 0,c1;
rB ← rD+WPvrrLabelParam, CALL[doXfer],c2;
rB ← rD+IOCBdiskLabel,c1, at[0, 10, doXferGoodRet];
rC ← rD+IOCBclientLabel, L0← 1,c2;
acR ← 0A, CALL[BLT],c3;
xUpdateHS:MAR← [rDrh, IOCBcHeaderHS+0],c1, at[1, 10, subrRet];
acR ← vSecsPerTrack, c2;
rB← MD,c3; {rB ← head sector}
rC ← rB+1,c1;
rC ← rC and 0FF,c2;
[]← rC xor acR, ZeroBr,c3;
BRANCH[$, xLastSec],c1;
Noop, GOTO[xIncrHS]c2;
xLastSec:rB ← rB or 0FF,c2;{so +1 yields sec=0 head+1}
xIncrHS:rB ← rB+1,c3;
MAR← [rDrh, IOCBcHeaderHS+0],c1;
MDR← rB, pRet3, c2; {update head sector}
RET[xferGoodRet],c3;
doVvr2:Noop,c2;
doVvr3:Noop,c3;
doVvr1:L1 ← 1,c1;
rB ← rD+WPvvrLabelParam, CALL[doXfer], c2;
MAR← [rDrh, IOCBcLblFilePageLo+0],c1, at[1, 10, doXferGoodRet];
Noop, c2;
rB← MD,c3;
MAR← [rDrh, IOCBcLblFilePageLo+0],c1;
MDR← rB+1, c2; {update client label}
GOTO[xUpdateHS],c3;
{doXfer completes the set-up of the IOCB and starts the microcode. It then waits for the inProgress bit to go off. If there were no errors, then it returns via pRet1/doXferGoodRet. If there is a PURE label verify error, then it returns via pRet3/xferLblVerRet. In either case rF has the status. For other error conditions doXfer retries the operation and if IOCB.tries goes to zero it goes to Maintenance2Loc with a bootDeviceError code.}
doXfer:rF ← rF LRot8,c3;
MAR← [rDrh, IOCBpageCount+0],c1;
MDR← acR, c2; {set IOCB.pageCount}
rC ← rD+IOCBlabelParam,c3;
{** generalize TridentInitial to read past 0th segment}
MAR← [rDrh, IOCBdataPtrHi+0],c1;
MDR← rF and 0FF,c2; {IOCB.dataPtrLo}
Noop,c3;
MAR← [rDrh, IOCBdataPtrLo+0],c1;
MDR← rF and ~0FF, L0← 2,c2; {set IOCB.dataPtrLo}
acR← 4, CALL[BLT],c3; {vvr/vrr to labelParam}
rB ← rD+IOCBcHeader, GOTO[Xzzy],c1, at[2, 10, subrRet];
XRetry:rB ← rD+IOCBcHeader,c1;
Xzzy:rC ← rD+IOCBdHeader, L0← 4,c2;
acR ← 2, CALL[BLT],c3;
MAR← [rDrh, IOCBcLblFilePageLo+0],c1, at[4, 10, subrRet];
acR ← 0C0, c2;
rB← MD,c3;
MAR← [rDrh, IOCBfilePageLo+0],c1;
MDR← rB, c2; {set IOCB.filePageLo}
acR ← acR LRot8,c3;
MAR← [rDrh, IOCBcStatus+0],c1;
MDR← acR, c2; {C000=InPrg&GoodComp}
acR ← acR LRot12, {acR = 0C00}c3;
MAR ← [rDrh, IOCBcHeader+1],c1; {get head, sector}
CANCELBR[$, 2], LOOPHOLE[wok], c2;
rB← MD,c3;
rB ← rB LRot8,c1; {sector, head}
rB ← rB and 0FF, c2;
rB← rB or acR,c3;
MAR← [rDrh, IOCBseekHead+0],c1;
MDR← rB, c2; {set IOCB.seekHead}
rC ← vCStatusVerErrLRot8, {used in err recovery}c3;
MAR ← [rDrh, IOCBcHeader+0],c1; {get cylinder}
rC ← rC LRot8, {used in err recovery} c2;
rB← MD,c3;
MAR← [rDrh, IOCBseekCyl+0],c1;
MDR← rB or acR, c2; {set IOCB.seekCyl}
KCmd ← acR LRot0,c3; {0C00=ctlTest&firmEnab}
MAR← [rDrh, IOCBlabelErrMask+0],c1;
rB← vCStatusLastField, {used in err recovery} c2;
rB← MD or rB, {used in err recovery}c3;
XWait:MAR ← [rDrh, IOCBcStatus+0], CANCELBR[$]c1;
rC ← rC or vCStatusLblField, {used in err recovery} c2;
rF← MD,c3;
acR ← U4000,c1;
[] ← rF, NegBr, {Neg => still in Progress}c2;
[] ← acR and rF, ZeroBr, BRANCH[$, XWait],c3;
XDone:rB ← rB and rF, BRANCH[XOK, XErr], c1;
XOK:pRet1,c2;
RET[doXferGoodRet],c3;
XErr:[] ← rB xor rC, ZeroBr, { 0 => label verify err }c2;
BRANCH[XNotLblVer,XLblVer],c3;
XLblVer:Noop, c1;
pRet3, c2;
RET[xferLblVerRet],c3;
XNotLblVer:rB ← rB and vCStatusLastField,c1;
rB ← rB xor vCStatusDataField, ZeroBr, {0=> data fld err}c2;
BRANCH[XChkRetry,XAdjIOCB],c3;
XAdjIOCB:MAR← [rDrh, IOCBpageCount+0],c1;
Noop, c2;
rB← MD,c3;
MAR← [rDrh, IOCBpageCount+0],c1;
MDR← rB+1, c2;
Noop,c3;
MAR← [rDrh, IOCBdataPtrLo+0],c1;
Noop, c2;
rB← MD,c3;
MAR← [rDrh, IOCBdataPtrLo+0],c1;
MDR← rB-1, c2;
Noop,c3;
XChkRetry:MAR← [rDrh, IOCBtries+0],c1;
Noop, c2;
rB← MD,c3;
MAR← [rDrh, IOCBtries+0],c1;
MDR← rB-1, ZeroBr, c2;
BRANCH[XRetry, XHardErr],c3;
XHardErr:acR← 0B, GOTOABS[Maintenance2Loc],c1; {was bootDeviceError}
{Uses data left in last header to compute pages left in cylinder, returns result in acR.}
pagesLeftInCylinder: Noop,c3;
MAR← [rDrh, IOCBcHeader+1],c1;
rB← tiUnumHeads, CANCELBR[$, 0],c2;
rE← MD,c3;
acR← rE LRot8,c1;
acR← acR and 0FF,c2; {head}
rE← rE and 0FF,c3; {sector}
acR← rB-acR-1, NegBr,c1;
rB← vSecsPerTrack, BRANCH[multiply, OffEnd],c2;
OffEnd:acR← 0,c3; {off the end of the cylinder}
rE← 0,c1;
pRet1, GOTO[pgLft1],c2;
{multiply, multiplier in rB, multiplicand in acR, uses rC, result left in Q
timing:45 cycles main loop is 3 cycles times 15 iterations
4 cycles last iteration
3 cycles preamble
1 cycles postamble
total53 cycles (2 MOD 3}
multiply:Noop,c3;
Q← acR,c1;
acR← 0’x,c2;
rC← 10’x,c3;
mult0:[]← Q and 1, ZeroBr,c1;
rC← rC-1, ZeroBr, BRANCH[mult1, mult2],c2;
mult1:acR← DARShift1 (acR+rB), BRANCH[mult0, mult3],c3;
mult2:acR← acR DARShift1, BRANCH[mult0, mult3],c3;
mult3:Q← ~Q, c1;
acR← Q+vSecsPerTrack, pRet1, GOTO[pgLft1],c2;
pgLft1:acR← acR-rE, RET[PLCRet],c3;
{This subroutine is used to transfer commands to the selected disk. Upon entry rB has the Bus value and rC has the Tag constant shifted right by 8. Subroutine must set the Bus in c1 and the Tag in c3 of click1. Then it must wait at least two clicks to reset the tag.}
SetRst3:Noop,c3;
SetRst1:KCmd ← rB LRot0,c1;
rC ← rC LRot8,c2;
KCmd ← (rB or rC) LRot0,c3;
rC ← 10, {used in wait following tag reset}c1;
Noop,c2;
Noop,c3;
{In c3 of click3 the tag is reset.}
Noop,c1;
Noop,c2;
KCmd ← rB LRot0,c3;
SRWait:CANCELBR[$],c1;
rC ← rC - 1, ZeroBr,c2;
BRANCH[$, SRWait],c3;
pRet0,c1;
RET[SetRst3Ret],c2;
{L3BLT exists because there are too many calls on BLT}
L3BLT2:Noop,c2;
L3BLT3:Noop,c3;
L3BLT:L0 ← 0,c1;
CALL[BLT3],c2;
Noop,c1, at[0, 10, subrRet];
pRet3,c2;
RET[L3BLTRet],c3;
{This subroutine performs: (rC↑) ← (rC↑) or (rD). Destroys acR}
merge3:Noop,c3;
merge1:MAR ← [rCrh, rC+0],c1;
Noop,c2;
acR ← MD,c3;
MAR ← [rCrh, rC+0],c1;
MDR ← acR or rD, pRet0,c2;
RET[mergeRet],c3;