{File name: Lisp11SAx000Initial.mc
Lichtenberg 2-Aug-84 1:28:03 fixed obscure leader pages bug.
Lichtenberg 13-Jul-84 18:15:31 uIOPage finally right this time.
Purcell 13-Jul-84 18:02:02 uIOPage was incorrectly set for lisp
Purcell 2-Jul-84 14:15:55 zero oldIOPage
Purcell 2-Jul-84 4:44:35 set uIOPage like mesa 10 before lisp {??}
Purcell 1-Jul-84 23:37:15 use newIOPage and buffer it in oldIOPage
Purcell 1-Jul-84 22:25:58 Added support for Quantum Q2080
Purcell 1-Jul-84 22:25:58 Accomodate changes for Germ as a result of going over to 32-bit procedure descriptors
Purcell 1-Jul-84 22:25:58 Use IOPage offsets from Dandelion.df!
Purcell 14-May-84 22:03:08 Mesa 11.0 Upgrade 2080 & germ
Purcell 23-Feb-84 23:23:07 detect multibanks
Purcell 15-Feb-84 2:29:05 load 4mb; scrap to page 0FF
Purcell February 14, 1984 8:03 PM skip "zero banks" in FPTOVP
Purcell February 6, 1984 12:40 PM Lisp MCtl ← 8002h
Purcell January 19, 1984 7:53 PM; MIN[topPage, AC0] removed
Purcell January 18, 1984 4:14 PM; mesa: MCtl 0, MIN[topPage, AC0]
Purcell January 17, 1984 11:21 AM; added NewInit section
Purcell January 17, 1984; renamed from nLispSAx000Initial.mc
Purcell January 16, 1984 6:34 PM; correct test of vp>2↑14
Purcell December 30, 1983 3:53 PM; max real mem 3-8MB
Purcell December 27, 1983 3:06 PM; max real mem 2.0MB
Purcell November 26, 1983 2:25 PM; {*0} max real mem 1.5MB
Purcell April 16, 1983 5:32 PM; uses password 15e3 at 17
Purcell April 16, 1983 4:22 PM; try 800h pages $$
Purcell April 16, 1983 1:16 PM; don’t bother refresh
Purcell April 13, 1983 10:47 AM; uLispBootMsg{0DE}=55 to boot mesa
Purcell April 6, 1983 8:44 AM; skip over interface page
Purcell April 1, 1983 4:53 PM; new sysout booting
Purcell March 21, 1983 10:27 PM; Quantum support
Purcell March 6, 1983 2:56 PM; define uLinkPtr
Purcell March 6, 1983 9:45 AM; store boot disk address in IOCBs.cpr
Purcell December 6, 1982 6:39 PM: map for 4MB boot file
Purcell November 28, 1982 1:18 PM: LispSAx000Initial: save boot link for Lisp
Purcell November 22, 1982 9:03 AM: link ← 0D for BLT
Purcell November 19, 1982 4:54 PM: boot Lisp instead of diagnostics
File name: [Idun]<WDLion>SAx000Initial.mc
Description: first microcode read from the disk, gets emulator microcode into CP memory,
Author: Jarvis,
Created: August 25, 1980,
JGS November 18, 1981 8:58 AM: move germ to mds 0.
Last Edited by Neely January 14, 1982 2:40 PM - change cons. for extracting filePageHi from BootId from 7 to 7F.
Last Edited by Jim Frandeen October 22, 1981 1:12 PM: If diagnostics are not installed, boot Emulator instead of crashing.
Last Edited by Fasnacht June 18, 1981 10:30 AM: delete SetGerm1000 at
Last Edited by DDavies February 14, 1981 4:35 PM
Last Edited by Jarvis March 24, 1981 11:46 AM}
{disk definitions}
{RegDef[uLispBootMsg, U, 0DE];} {also in Dandelisp.df}
RegDef[uLinkPtr, U, 27{uTT}];{uLinkPtr}
RegDef[uFirstPage,U,49];
Set[hardMicrocodeFirstPage,13’d];
{null findSectorCmd for SA1000} Set[SA1000FindSectCmd, 20];
{have SA1000 reject Label and Data fields when looking for Headers}
Set[SA1000HeaderLoopMsk, 43];
{control bits, low byte}{Set[stepBit, 80], Set[inBit, 40], Set[firmwareEnable, 20];}
Set[SA4FindSect, 6], Set[SA1FindSect, 0];
{control bits, high byte}{Set[driveSelectBit, 4], Set[faultClearBit, 2];}
{IOCB status error indicators}Set[badBits, 3F]; Set[verifyBit, 1];
{IO page offsets}{Set[diskCSB, 1];}{%}
{IOCB page offsets}
Set[statusAddr, 3];{status word}
{not used, used to be pointer to next IOCB, always 0}
Set[seekAddr, 5];{pointer to seek IOCB}
Set[transferAddr, 6];{pointer to transfer IOCB}
Set[vrrAddr, 7];{pointer to vrr parameter area}
Set[vvrAddr, 8];{pointer to vrr parameter area}
Set[headerAddr, 9];{header -- 2 words}
Set[labelAddr, 0B];{label -- 0A words}
Set[labelPageLow, 10];{low 16 bits of file page number}
Set[miscBitsAddr, 11];{filePageHi[0..6], unused[0..5], immutable[0], temporary[0], zeroSize[0]}
Set[bootLink, 13];{disk address of next run of pages in boot file}
Set[labelSize, 0A];
{parameter area offsets}
Set[sectors, 0];{number of sectors to transfer}
Set[headerLoopMsk, 6];{specifies non-fatal errors when looking for a header}
Set[dataPage, 0D];{page number of data area in main storage}
Set[haltWord, 0F];{requires head in high 5 bits}
Set[findWord, 10];{requires head in high 5 bits}
{transfer IOCB offsets}
Set[parameters, 1];{pointer to parameter area}
{seek IOCB offsets}
Set[cylinders, 0];{-(number of cylinders to move heads)}
Set[stepHigh, 6];{set step level high}
Set[stepLow, 8];{set step level low}
{Miscellaneous disk constants}
Set[SA1000HeadCount,Sub[4,1]];
Set[SA4000HeadCount,Sub[4,1]];
Set[Q2040HeadCount,Sub[8,1]];
Set[Q2080HeadCount,Sub[7,1]];
{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 Mesa 11}
{
Set[germMapOffset, 2];
Set[germPageHigh, 0];{virtual page number of origin of germ -- 1B}
Set[germPageLow, 1];
Set[sFirstGermRequestHigh, 001’b];{start of germ request in SD - high byte}
Set[sFirstGermRequestLow, 240’b];{start of germ request in SD - low byte}
}
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]];
{germ definitions mesa10}
{
{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.deviceOrdinal, 323’b];
}
DoneOnceOnlyInit:
{For the four disk drives, the following applies:
Q2040 - ~HeadSlelect16 = ~Sector. The two pins are connected physically.
Q2040 - ~Sector = TRUE. Using positive logic.
SA4000- ~SA1000/SA4000 = TRUE. Positive logic.
SA1000- ~SA1000/SA4000 = FALSE & ~Sector = FALSE. Also positive logic.}
{First modify the IOCB for an SA1000 if necessary}
Xbus ← KStatus, XwdDisp,c1; {what type of disk is this?}
acR ← 0FF+1, DISP2[SetSA1IOCB, 2],c2; {Point to table of IOCBs}
{there is an SA1000 drive connected. Set the LabelDataTag bit in the HeaderLoopMsk and turn off the "Wait for Sector mark" command in the FindWord}
SetSA1IOCB:
{Test for SA1000 or Quantum depending on bit 9 of KTest after writing to
bit H16 of KCtl:
KTest[9]=0 => SA1000
KTest[9]=1 => Quantum Q2040. For the Quantum Q2080 KCtl[0]=~KTest[9]}
{MESA 10:
Xbus ← KTest, XwdDisp, c3, at[2,4,SetSA1IOCB];
DISP2[IsSA1000orQuantum,1],c1;
IsSA1000orQuantum:
rB ← 7 {sa1000}, GOTO[FinishIsSA1000orQuantum], c2, at[3,4,IsSA1000orQuantum];
rB ← 3 {quantum}, GOTO[FinishIsSA1000orQuantum], c2, at[1,4,IsSA1000orQuantum];
FinishIsSA1000orQuantum:
uQuantumSA1000MaxHeadNum ← rB,c3;
Noop,c1;
Noop,c2;
acRrh ← 0,c3;
}{MESA 11:
}
rB ← 80,c3, at[2,4,SetSA1IOCB];
KCtl ← rB LRot8,c1;
{Test for an SA1000 or Quantum}
Xbus ← KTest, XwdDisp, c2;
DISP2[IsSA1000orQuantum,1],c3;
{ Xbus ← KTest, XwdDisp, c3, at[2,4,SetSA1IOCB];
DISP2[IsSA1000orQuantum,1],c1;
}
IsSA1000orQuantum:
rB ← SA1000HeadCount {sa1000}, GOTO[FinishIsSA1000orQuantum], c1, at[1,4,IsSA1000orQuantum];
KCtl ← 0,c1, at[3,4,IsSA1000orQuantum]; {Test for a Quantum Q2040 or Q2080}
Xbus ← KTest, XwdDisp, c2;
DISP2[IsQ2040orQ2080,1],c3;
IsQ2040orQ2080:
rB ← Q2080HeadCount {Q2080}, GOTO[FinishIsSA1000orQuantum], c1, at[1,4,IsQ2040orQ2080];
rB ← Q2040HeadCount {Q2040}, GOTO[FinishIsSA1000orQuantum], c1, at[3,4,IsQ2040orQ2080];
{IsSA1000orQuantum:
rB ← 7 {sa1000}, GOTO[FinishIsSA1000orQuantum], c2, at[3,4,IsSA1000orQuantum];
rB ← 3 {quantum}, GOTO[FinishIsSA1000orQuantum], c2, at[1,4,IsSA1000orQuantum];}
FinishIsSA1000orQuantum:
uQuantumSA1000MaxHeadNum ← rB,c2;
acRrh ← 0 {Point to table of IOCBs},c3;
{JOIN}
MAR ← [acRrh, vrrAddr+0],c1; {get addr of vrr parameters}
rE ← SA1FindSect,c2; {prepare to set FindSectCmd}
acR ← MD,c3;
MAR ← [acRrh, acR+headerLoopMsk],c1; {set up new HeaderLoopMsk}
MDR ← SA1000HeaderLoopMsk, LOOPHOLE[wok], CANCELBR[$,2],c2;
UFindSect ← rEc3; {set FindSect mark cmd for
SA1000.}
MAR ← [acRrh, vvrAddr+0],c1; {get addr of vvr parameters}
rE← 0,c2; {set up source of 0 for
below}
acR ← MD,c3;
MAR ← [acRrh, acR+headerLoopMsk],c1; {set up new HeaderLoopMsk}
MDR ← SA1000HeaderLoopMsk, LOOPHOLE[wok], CANCELBR[DiskInitDone,2],c2;
{Connected to an SA4000 so set the Find Sector Mark command properly}
SetSA4IOCB: acR ← SA4FindSect,c3, at[3,4,SetSA1IOCB];
UFindSect ← acR,c1;
rE← 0,c2; {source of 0}
DiskInitDone:germStart← rE,c3;
acRrh← 1,c1; {set up stuff for IO page}
currentCylinder← rE,c2;
acR← badBits,c3;
uBadBits← acR,c1;
acR← driveSelectBit,c2;
acR← acR LRot8,c3;
acR← acR or firmwareEnable,c1;
seekMask← acR, {seek Mask← drive select or firmwareEnable}c2;
acR← 4,c3;
acR← acR LRot8,c1;
acR← acR or 20,c2;
haltBits← acR,c3; {halt bits← 420}
acR← 0F8,c1;
acR← acR LRot8,c2;
headMask← acR,c3; {headMask← F800}
acR← 2,c1;
acR← acR LRot8,c2;
uBootStart← acR,c3; {boot file starts at 200}
{*}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;
{{topPage ← MIN[topPage, AC0]}
rB← topPage,c1;
rC ← 0AC,c2;
rC ← rC LRot4,c3;
Ybus ← rB{topPage} - rC{AC0}, CarryBr,c1;
{MCtl ← 0, }BRANCH[$, trim],c2;
rC ← topPage, GOTO[mbjoin],c3;
trim:topPage ← rC, GOTO[mbjoin],c3;
}
mbjoin:rBrh← 1,c1;
rCrh← 1,c2;
rB← 0,c3;
rC← topPage, L0← 4,c1;
acR← 0FF+1, CALL[BLT3],c2;
{BLT3[from: 10000, to: 1topPage, cnt: 100h]}
{block transfer, takes count in acR, from in rB, and to in rC, returns first word past from block in rE}
acR← present,c1, at[4, 10, subrRet];
rC← 0FF+1,c2;
rB← 0,c3;
{set up identity map for benefit of the disk microcode}
identityMap:MAR← [rBrh, rB+0], BRANCH[$, idDone],c1;
MDR← acR, rB← rB+1,c2;
acR← acR+rC, CarryBr, GOTO[identityMap],c3;
idDone:Noop,c2;
Noop, GOTO[rootPage],c3;
{** 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{11000}, Q{100}, map next 2↑12 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{FirstRealPageToMapHigh},c1;
rC← 040{FirstRealPageToMap},c2;
rC{14000} ← rC LRot8,c3;
{acR{FF20}, rB{12000}, 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 old iopage (as known to sysout) 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;
{Start flailing away at the disk. First read the physical volume root page}
rootPage:rBrh← 0,c1;
rCrh← 0,c2;
rDrh← 0,c3;
rErh← 1,c1;
rD← 0FF+1,c2; {base address of IOCB page}
rE← headerAddr,c3;
MAR← [rDrh, rE+0],c1; {cylinder 0}
MDR← 0,c2;
rB← 2,c3; {read starting at page 2}
MAR← [rDrh, rE+1],c1; {head 0, sector 0}
MDR← 0, CANCELBR[$, 0], L1← 0,c2;
acR← 1, CALL[doVrr],c3; {read 1 sector}
transferRet: Ybus← acR and uBadBits, ZeroBr,c1, at[0, 10, transferRet];
transferIOCB← rE, BRANCH[$, here1],c2;
acR← bootDeviceError, GOTOABS[Maintenance1Loc],c3;
{save the useful stuff from the physical volume root page}
here1:rC← 2,c3; {copy PVBootFiles}
rB← rC LRot8,c1;
rB← rB+bootingInfo, L0← 0,c2;
acR← bootingInfoSize, CALL[BLT],c3;
rC ← 2, c1, at[0, 10, subrRet];
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;
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] ← {140}500’b}
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[$, GoNewInit{UniBank}],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← 3{2nd .db},c3;
MAR← [rBrh, rC+0],c1;
rC{400q}{100} ← 0FF + 1,c2;
rC← MD,c3;
rC← rC+rB,c1;
uBootStart← rC{400},c2;
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;
BackFromNewInit:
Noop, c1;
TOS{8002h} ← RRot1 5,c2;
MCtl ← TOS{8002h}, GOTO[exitToEmulator],c3;
{hard microcode (quick exit), get diagnostic table entry from first page of boot file}
doDiag:rB ← 055{Mesa}, GOTO[doDiag2],c1;
notLisp:rB ← 055{Mesa}, GOTO[doDiag2],c1;
doDiag2:uLispBootMsg ← rB,c2;
rB← 2,c3; {boot file starts at 200}
{{topPage ← MIN[topPage, AC0]}
rB← topPage,c1;
rC ← 0AC,c2;
rC ← rC LRot4,c3;
Ybus ← rB{topPage} - rC{AC0}, CarryBr,c1;
rB← 2, BRANCH[$, trim1],c2; {boot file starts at 200}
rC ← topPage, GOTO[mbjoin1],c3;
trim1:topPage ← rC, GOTO[mbjoin1],c3;
}
mbjoin1:
rB← rB LRot8,c1;
rC← uDiagnostic,c2;
rC← rC{uDiagnostic=1}+1,c3;
MAR← [rBrh, rC+0],c1;
rC{400q}{100} ← 0FF + 1,c2;
{**}{rC{1000q}{200} ← rC+rC{rC← MD},c3;}
rC← MD,c3;
rC← rC+rB,c1;
uBootStart← rC{400},c2;
MCtl← 0, GOTO[exitToEmulator],c3;{%mesa small mem}
{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← 20{0FF+1},c3;
MAR← [rBrh, rB+0],c1;
MDR← vacant, L0← 0B,c2;
acR← acR LRot8{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+headerAddr, L0← 1,c2; {disk address of boot}
acR← 2, CALL[BLT],c3;
{block transfer, takes count in acR, from in rB, and to in rC, returns first word past from block in rE}
{*4}rB← bootDiskAddr,c1, at[1, 10, subrRet];
rC← rD or 80{uLinkPtr}{+{1}headerAddr}, L0← 0E{*free?},c2; {save for lisp}
acR← 2, CALL[BLT],c3;
rB ← 82,c1, at[0E{*free?}, 10, subrRet];
uLinkPtr ← rB,c2;
rB← bootDiskAddr,c3; {nil disk address?}
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;
rB← nextPage, L1← 1,c3;
acR← 1, CALL[doVrr2],c1; {read 1 starting at page 2}
[]← acR and uBadBits, ZeroBr,c1, at[1, 10, transferRet];
rC← rD+labelAddr, BRANCH[$, here2],c2; {write fileID into label}
acR← bootDeviceError, GOTOABS[Maintenance1Loc],c3;
here2:rB← bootFileID, L0← 2,c3;
acR← 6, CALL[BLT2],c1; {+low 16 bits of page #}
rE← rE and 7F,c1, at[2, 10, subrRet];
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;
rC← rC-1,c3;
MAR← [rCrh, rC+0],c1; {read low 16 bits of page #}
rB← bootDiskAddr,c2;
rC← MD,c3;
rC← rC+1, {reading first page is a special case}c1;
filePage← rC,c2; {restore disk address}
rC← rD+headerAddr, L0← 3,c3;
acR← 2, CALL[BLT2],c1;
rB← nextPage, L1← 5,c1, at[3, 10, subrRet];
acR← 1, CALL[doVvr3],c2; {read 1 starting at page 2}
[]← acR and uBadBits, ZeroBr,c1, at[5, 10, transferRet];
acR← nextPage, BRANCH[$, here3],c2;
acR← bootDeviceError, GOTOABS[Maintenance1Loc],c3;
here3:acR← acR+1,c3;
nextPage← acR,c1; {label template}
acR← labelSize,c2;
rB← rD+labelAddr, L0← 6,c3;
rC← labelTemplate, CALL[BLT2],c1;
{read the rest of the file from the Pilot Volume}
readLoop:L1← 1,c1, at[6, 10, subrRet];
CALL[pagesLeftInCylinder3],c2;
transferCount← acR, ZeroBr,c1, at[1, 10, miscRet];
L1← 4, BRANCH[readRun, $],c2;
{no pages left in cylinder, advance to next cylinder}
Noop,c3; {step in one cylinder}
MAR← [rDrh, headerAddr+1],c1;
MDR← 0, CANCELBR[$, 0],c2; {start at head 0, sector 0}
Noop,c3;
MAR← [rDrh, headerAddr+0],c1;
Noop,c2;
acR← MD,c3;
MAR← [rDrh, headerAddr+0], L1← 2,c1;
MDR← acR+1, CALL[pagesLeftInCylinder3],c2;
Noop,c1, at[2, 10, miscRet];
transferCount← acR, L1← 4,c2;
readRun:rB← nextPage, CALL[doVvr],c3;
rE← acR and uBadBits, ZeroBr,c1, at[4, 10, transferRet];
rB← transferCount, BRANCH[readBurp, $],c2;
acR← filePage,c3;
acR← acR+rB,c1; {next page in file}
filePage← acR,c2;
acR← nextPage,c3;
acR← acR+rB,c1; {next page in memory}
nextPage← acR,c2;
GOTO[readLoop],c3;
{burped while reading run of pages, status in acR. rB has number of sectors requested}
readBurp:[]← rE and ~verifyBit, ZeroBr,c3;
MAR← [rDrh, vvrAddr+0], BRANCH[$, verifyError],c1; {get # of sectors remaining}
acR← bootDeviceError, GOTOABS[Maintenance3Loc],c2; {not a verify error}
verifyError:rC← acR LRot4,c2; {shift field bits}
rE← MD,c3; {parameter area}
MAR← [rDrh, rE+sectors],c1;
rC← rC and 0C,c2;
acR← MD,c3; {number sectors remaining}
[]← rC xor 8, ZeroBr,c1; {label verify error?}
acR← rB-acR, BRANCH[$, verErr1],c2; {number sectors transferred}
acR← bootDeviceError, GOTOABS[Maintenance1Loc],c3; {not in label}
verErr1:transferCount← acR, {zero is okay}c3;
rE← filePage,c1;
rE← rE+acR+1,c2; {file page for next label}
filePage← rE,c3;
rB← nextPage,c1;
rB← rB+acR+1,c2; {next available page for vvr}
nextPage← rB,c3;
rB← rB-1, L1← 6,c1; {page used by vrr}
acR← 1, CALL[doVrr3],c2; {transfer 1 page}
[]← acR and uBadBits, ZeroBr,c1, at[6, 10, transferRet];
BRANCH[$, verErr3],c2;
acR← bootDeviceError, GOTOABS[Maintenance1Loc],c3;
verErr3:Noop,c3;
{Copy boot link to header, and check for end of file, FFFF in both words of boot link.}
{*1,2 Check for end of file before copying boot link to header}
{*0 stop reading after 768Kw max real memory}
{*0}MAR← [rDrh, labelPageLow+0],c1;
Noop,c2;
acR← MD,c3;
{*0}acR← acR LRot8,c1;
Ybus ← acR - 0C, {NibCarryBr{vPage> 768*4},}c2;
Noop, BRANCH[$, endRead1],c3;
MAR← [rDrh, bootLink+0],c1;
Noop,c2;
acR← MD,c3;
{*1MAR← [rDrh, headerAddr+0],c1;
MDR← acR,c2;
Noop,c3;
*}MAR← [rDrh, bootLink+1],c1;
CANCELBR[$, 0],c2;
rB← MD,c3;
{*2MAR← [rDrh, headerAddr+1],c1;
MDR← rB, CANCELBR[$, 0],c2;
Noop,c3;
*}Noop,c1;
Noop,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;
rC← rD+labelAddr, BRANCH[rdBurp2, $],c1;
GOTO[endRead],c2; {found end of chain, return}
rdBurp2:Noop,c2;
Noop,c3;
{*1}MAR← [rDrh, headerAddr+0],c1;
MDR← acR-1,c2;
,c3;
MAR← [rDrh, 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← labelSize, BRANCH[there1, $],c1;
{Noop,} L0← 7, GOTO[there2],c2;
there1:uLinkPtr ← Q{uLinkPtr+3}, L0← 7,c2;
there2:rB← labelTemplate, CALL[BLT],c3;
MAR← [rDrh, labelPageLow+0],c1, at[7, 10, subrRet];
MDR← filePage,c2;
GOTO[readLoop],c3;
endRead:Noop,c3;
endRead1:Noop,c1;
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}
doVvr3:Noop,c3;
doVvr:MAR← [rDrh, vvrAddr+0],c1;
GOTO[doTransfer],c2;
{does verify, read, read operation to the disk
Takes number of sectors in acR, page number in rB, and disk address in header area.
Returns status in acR
Clobbers rE}
doVrr2:Noop,c2;
doVrr3:Noop,c3;
doVrr:MAR← [rDrh, vrrAddr+0],c1; {base of vrr parameters}
CANCELBR[$, 0],c2;
doTransfer:rE← MD,c3;
MAR← [rDrh, rE+sectors],c1; {set up paramter area}
MDR← acR,c2; {sector count}
Noop,c3;
MAR← [rDrh, rE+dataPage],c1;
MDR← rB - 1, CANCELBR[$, 0],c2; {first page in main storage}
Noop,c3;
MAR← [rDrh, rD+ transferAddr],c1; {base of transferIOCB}
acR← rE, CANCELBR[$, 0],c2; {base of vrr parameter area}
rE← MD,c3;
MAR← [rDrh, rE+parameters],c1;
MDR← acR, CANCELBR[$, 0],c2;
rC← acR,c3;
MAR← [rDrh, headerAddr+1],c1; {read head}
CANCELBR[$, 0],c2;
acR← MD,c3;
acR← acR LRot4,c1;
acR← acR RRot1,c2;
acR← acR and headMask,c3;
acR← acR or haltBits,c1;
Noop,c2;
Noop,c3;
MAR← [rDrh, rC+haltWord],c1; {write halt word}
MDR← acR, CANCELBR[$, 0],c2;
acR← acR or UFindSect,c3;
MAR← [rDrh, rC+findWord],c1; {write find word}
MDR← acR, CANCELBR[$, 0], L0← 2,c2;
rC← rE, CALL[seek],c3;
[]← acR and uBadBits, ZeroBr, L0← 3,c1, at[2, 10, transferRet];
BRANCH[transferError, $],c2;
rE← rC, CALL[diskOp],c3;
transferRet1:Noop,c1, at[3, 10, transferRet];
pRet1,c2;
transferRet2:RET[transferRet],c3;
transferError:GOTO[transferRet1],c3;
{call with IOCB in rE, returns when disk operation complete with status in acR}
{diskOp1:Noop,c1;
diskOp2:Noop,c2;
diskOp:acR← IOPageLow,c3, at[2, 4];
MAR← [acRrh, diskCSB+0],c1;}diskOp:
Noop,c1;
acRrh ← IOPageHigh,c2;
{AEF 9/14/83 - why is this instruction at[2, 4]?}
acR ← uIOPage,c3, at[2, 4];
MAR← [acRrh, DiskCSBOffsetIOCB+0],c1;
MDR← rE,c2;
{***
{*}acR← firmwareEnable,c3;
{*}
{* observe segment crossings}
{*}
{*}MAR← [rDrh, statusAddr+0],c1; {set invalid status}
{*}MDR← badBits,c2;
{*}KCtl← acR LRot0,c3; {start the transfer}
{*}
{*}transferWait:
{*}acR← ~KStatus, BRANCH[$, trRef], c1;
{*}trWa2:[]← acR LRot8, XDisp,c2; {busy?}
{*}Q ← Q + 1, NibCarryBr, BRANCH[trDone, transferWait, 0E],c3;
{*}
{*}trRef:Noop, c2;
{*}Noop,c3;
{*}{Refresh,} GOTO[trWa2],c1;
{*}
{*}trDone:MAR← [rDrh, statusAddr+0], CANCELBR[$, 1],c1;
{*}pRet0, LOOPHOLE[natc],c2;
{*}acR← MD, RET[transferRet],c3; {return status in acR}
***}
Noop,c3;
MAR← [rDrh, statusAddr+0],c1; {set invalid status}
MDR← badBits,c2;
acR← firmwareEnable,c3; {start the transfer}
KCtl← acR LRot0,c1;
transferWait:acR← ~KStatus, CANCELBR[$, 0],c2, at[0F, 10, transferWait];
[]← acR LRot8, XDisp,c3; {test firmware busy}
MAR← [rDrh, statusAddr+0], BRANCH[$, transferWait],c1;
pRet0, LOOPHOLE[natc],c2, at[0E, 10, transferWait];
acR← MD, RET[transferRet],c3; {return status in acR}
{call with current cylinder in currentCylinder, and desired cylinder in cylinder field of header}
seek:MAR← [rDrh, headerAddr+0],c1;
rB← currentCylinder, CANCELBR[$, 0],c2;
acR← MD,c3; {target}
rB← rB-acR, ZeroBr,c1; {delta number of cylinders}
currentCylinder← acR, BRANCH[$, noSeek],c2;
[]← rB, NegBr,c3;
acR← 0, BRANCH[seekOut, $],c1;
acR← inBit, GOTO[seek1],c2;
seekOut: rB← -rB,c2;
seek1:acR← acR or seekMask, {enable firmware, drive select}c3;
MAR← [rDrh, seekAddr+0],c1; {address of seek IOCB}
CANCELBR[$, 0],c2;
rE← MD,c3;
MAR← [rDrh, rE+cylinders],c1;
MDR← rB,c2;
Noop,c3;
MAR← [rDrh, rE+stepHigh],c1;
MDR← acR or stepBit, CANCELBR[$, 0],c2;
Noop,c3;
MAR← [rDrh, rE+stepLow],c1;
MDR← acR, CANCELBR[$, 0],c2;
rE← rE+1, GOTO[diskOp],c3;
noSeek:acR← 0,c3;
Noop,c1;
pRet0, GOTO[transferRet2],c2;
{Be careful, these routines are device dependent! Only routines for SA1004 and SA4008 are supplied}
{Uses data left in last header to compute pages left in cylinder, returns result in acR.}
pagesLeftInCylinder3: Noop,c3;
pagesLeftInCylinder: Noop,c1; {SA4000 or SA1000?}
Xbus← KStatus, XwdDisp,c2;
BRANCH[SA1000Left, $, 2],c3;
{SA4008, pages left in cylinder= (28-sector)+(8-head-1)*28}
MAR← [rDrh, headerAddr+1],c1, at[3,4,SA1000Left];
rB← 7, 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, NegBr, L0← 0,c1;
rB← 28’d, BRANCH[multiply, $],c2;
acR← 0,c3; {off the end of the cylinder}
OffEnd:rE← 0,c1;
pRet1, GOTO[pgLft1],c2;
{return from multiply}
divMultRet:acR← Q+28’d, pRet1, GOTO[pgLft1],c2, at[0, 10, divMultRet];
{SA1004, pages left in cylinder= (16-sector)+(4-head-1)*16}
SA1000Left:MAR← [rDrh, headerAddr+1],c1, at[2,4,SA1000Left];
rB← uQuantumSA1000MaxHeadNum, 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, NegBr,c1;
rB← acR LRot4, BRANCH[SA1000More, $],c2; {(4-head-1)*16}
acR← 0, GOTO[OffEnd],c3; {off the end of the cylinder}
SA1000More:Noop,c3;
Noop,c1;
acR← rB+16’d, pRet1,c2;
pgLft1:acR← acR-rE, RET[miscRet],c3;
{multiply, call with 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:Q← acR,c*;
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, pRet0,c1;
RET[divMultRet],c*;
{divide, call with dividend in acR, divisor in rB, uses rC, result left in Q remainder in acR
timing:64 cycles main loop is 4 cycles times 16 iterations
3 cycles preamble
2 cycles postamble
total69 cycles (0 MOD 3)}
{divide:Q← acR,c*;
acR← 0,c2;
rC← 10’x,c3;
div0:acR← acR DALShift1, Cin← 1,c*;{shifts in a zero!!!!!}
acR← acR-rB, NegBr,c2;
rC← rC-1, ZeroBr, BRANCH[div1, div2],c3;
div1:Q← Q or 1, BRANCH[div0, div3],c1;
div2:acR← acR+rB, BRANCH[div0, div3],c1;
div3:pRet0,c2;
RET[divMultRet],c*;}
{compare two blocks of memory, takes count in acR, and addresses in rB, and rC, clobbers rE,
returns count in acR where compare first lost, (acR=0)=> compare succeeded}
{compare3:Noop,c3;
compare:MAR← [rBrh, rB+0],c1;
[]← acR, ZeroBr,c2;
rE← MD, BRANCH[comp1, $],c3;
GOTO[endBLT1],c1;
comp1:MAR← [rCrh, rC+0],c1;
Noop,c2;
rE← rE xor MD,c3;
Noop,c1;
Noop,c2;
[]← rE, ZeroBr,c3;
acR← acR-1, BRANCH[$, comp2],c1;
acR← acR+1, pRet0, GOTO[endBLT2],c2;
comp2:rB← rB+1,c2;
rC← rC+1, GOTO[compare],c3;}
{increments header}
{incrHdr:MAR← [rDrh, headerAddr+1],c1;
CANCELBR[$, 0],c2;
rE← MD,c3;
acR← rE and 0FF,c1; {sector}
acR← acR+1,c2;
[]← acR-27’d, NegBr,c3;
rE← rE and ~0FF, BRANCH[incHd, $],c1; {head}
rE← rE or acR,c2;
incHdr0:Noop,c3;
incHdr1:MAR← [rDrh, headerAddr+1],c1;
MDR← rE, pRet0, CANCELBR[$, 0],c2;
RET[subrRet],c3;
incHd:rE← rE LRot8,c2;
rE← rE+1,c3;
[]← rE-7, NegBr,c1;
rE← rE LRot8, BRANCH[$, incHdr0],c2;
incCyl:rE← 0,c3;
MAR← [rDrh, headerAddr+0],c1;
Noop,c2;
acR← MD,c3;
MAR← [rDrh, headerAddr+0],c1;
MDR← acR+1, GOTO[incHdr0],c2;}