{File name: [Idun]SAx000Initial.mc Description: first microcode read from the disk, gets emulator microcode into CP memory, Author: Jarvis, Created: August 25, 1980, Sturgis: 13-Feb-84 10:59:40: modify germ request to always say "SA4000", rather than distinguishing between SA4000 and SA1000. The new Cedar 5 Nucleus (Or FS or something) seems to only want to deal with SA4000, and no one seems to distinguish between SA1000 and SA4000. The Head does its own test of the hardware bits to decide what the disk is. Sturgis: 22-Jul-83 13:22:26: add quantum test and constant model after [idun]MicrocodePrivate>dlion>sax1000initial.mc Fasnacht June 18, 1981 10:30 AM: delete SetGerm1000 at DDavies February 14, 1981 4:35 PM Jarvis March 24, 1981 11:46 AM bj, 2-Jun-86 11:06:37 } {disk definitions} {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} {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, 3E]; {virtual page number of origin of germ -- 37002B} Set[germPageLow, 2]; Set[germRequest, 0F0]; {offset in first page of germ, POINTER TO Request= LOOPHOLE[1360B]} Set[bootPhysicalVolume, 2]; {first word of request} Set[germDevice, 0F1]; {tells germ the boot device} Set[germSA4000, 3]; Set[germSA1000, 2]; DoneOnceOnlyInit: {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: acRrh _ 0, c3, at[2,4,SetSA1IOCB]; {Point to table of IOCBs} 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 _ rE c3; {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} {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, L0_ 4, c1; acR_ 0FF+1, CALL[BLT3], c2; 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[$, rootPage], c1; MDR_ acR, rB_ rB+1, c2; acR_ acR+rC, CarryBr, GOTO[identityMap], c3; {Start flailing away at the disk. First read the physical volume root page} rootPage: Noop, c2; Noop, c3; 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: []_ 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; {read the emulator boot file or the hard microcode} emuHard: []_ uDiagnostic, ZeroBr, c1, at[0, 10, subrRet]; 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; {hard microcode (quick exit), pick up diagnostic table entry from first page of boot file} 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; {move the germ out of the visible display region} rC_ nextPage, c1, at[1, 10, readBootRet]; rC_ rC+1, c2; {throw in an extra page} rB_ rC LRot8, c3; rB_ rB-1, c1; {last word of germ} acR_ germStart, c2; acR_ rC-acR, c3; transferCount_ acR, ZeroBr, c1; {number pages in germ} rC_ rC xor ~rC, BRANCH[moveGerm1, $], c2; acR_ bootNullGerm, GOTOABS[Maintenance1Loc], c3; moveGerm1: germStart_ rC, c3; acR_ acR LRot8, c1; {number words in germ} Noop, c2; []_ acR, ZeroBr, c3; moveGerm: MAR_ [rBrh, rB+0], BRANCH[$, setGermReq], c1; germStart_ rC, c2; {first word of germ} rE_ MD, c3; MAR_ [rCrh, rC+0], c1; MDR_ rE, c2; rB_ rB-1, c3; rC_ rC-1, c1; Noop, c2; acR_ acR-1, ZeroBr, GOTO[moveGerm], c3; setGermReq: Noop, c2; rC_ germStart, c3; MAR_ [rCrh, germRequest+0], c1; MDR_ bootPhysicalVolume, c2; Xbus_ KStatus, XwdDisp, c3; MAR_ [rCrh, germDevice+0], BRANCH[setGerm1000, $, 2], c1; MDR_ germSA4000, GOTO[setGerm1], c2; setGerm1000: MDR _ germSA4000, c2; {always look like SA1000, for Cedar 5} {setGerm1000: MDR_ germSA1000, c2;} setGerm1: Noop, c3; MAR_ [rCrh, germDevice+1], c1; MDR_ 0, CANCELBR[restoreMap, 0], c2; {start playing with the map, restore the low 256 pages of the map, and unmap the area where their state was saved} restoreMap: rBrh_ 1, c3; rCrh_ 1, c1; rB_ topPage, c2; rC_ 0, L0_ 5, c3; acR_ 0FF+1, CALL[BLT2], c1; {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; {get machine ready for the emulator, first map in the germ} mapGerm: rE_ germPageHigh, c1, at[0B, 10, subrRet]; rE_ rE LRot8, c2; rE_ rE or germPageLow, c3; acR_ transferCount, c1; {number pages in germ} rC_ germStart, L0_ 0, c2; rC_ rC and ~0FF, CALL[mapZap], c3; {This enterprise maps the page before the germ (which just happens to be in the display bank) to virtual page 0FE. The germ uses this page as a disk buffer. In order to avoid losing the page initially mapped to 0FE, we first make page 0FE vacant by swapping it with the first vacant page in the map.} {first swap entries for virtual page 0FE and page just past end (left in rE by mapZap)} rB_ 0FE, c1, at[0, 10, miscRet]; rE_ topPage, L0_ 0E, c2; rBrh_ 1, CALL[memSwap], c3; rE_ rE+1, {now the next available page in the map} c1, at[0E, 10, subrRet]; acR_ germStart, {page 0FE is now unmapped} c2; acR_ acR-0FF-1, c3; MAR_ [rBrh, rB+0], c1; {map in page before germ} MDR_ acR or present, c2; topPage_ rE, 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; Noop, c1, at[1, 10, subrRet]; Noop, 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 7, 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.} MAR_ [rDrh, bootLink+0], c1; Noop, c2; acR_ MD, c3; MAR_ [rDrh, headerAddr+0], c1; MDR_ acR, c2; Noop, c3; MAR_ [rDrh, bootLink+1], c1; CANCELBR[$, 0], c2; rB_ MD, c3; MAR_ [rDrh, headerAddr+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; rC_ rD+labelAddr, BRANCH[rdBurp2, $], c1; GOTO[endRead], c2; {found end of chain, return} rdBurp2: rB_ labelTemplate, L0_ 7, c2; acR_ labelSize, CALL[BLT], c3; MAR_ [rDrh, labelPageLow+0], c1, at[7, 10, subrRet]; MDR_ filePage, c2; GOTO[readLoop], c3; endRead: Noop, c3; Noop, c1; pRet2, c2; RET[readBootRet], c3; {here if boot file pointer was zero} nilBootFile: []_ uDiagnostic, ZeroBr, c3; acR_ 0, BRANCH[noDiagnostics, $], c1; []_ germStart, ZeroBr, c2; BRANCH[noGerm, noEmulator], c3; noEmulator: acR_ bootNoEmulator, GOTOABS[Maintenance2Loc], c1; noGerm: acR_ bootNoGerm, GOTOABS[Maintenance2Loc], c1; {noDiagnostics: acR_ bootNoDiagnostics, GOTOABS[Maintenance3Loc], c2;} {this code tries a disk boot if no hard microcode is installed} noDiagnostics: uDiagnostic_ acR, c2; 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} acR_ 1 RRot1, c3; {increment page bit} MAR_ [rDrh, rE+dataPage], c1; MDR_ rB or acR, 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[diskOp1], 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; MDR_ rE, c2; 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[diskOp1], 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[SA1000OrQ2040Left, $, 2], c3; {SA4008, pages left in cylinder= (28-sector)+(8-head-1)*28} MAR_ [rDrh, headerAddr+1], c1, at[3,4,SA1000OrQ2040Left]; 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} {however, might be a Q2040} SA1000OrQ2040Left: {noop} c1, at[2,4,SA1000OrQ2040Left]; Xbus _ KTest, XwdDisp, c2; DISP2[IsSA1000OrQuantum,1], c3; {SA1004, pages left in cylinder= (16-sector)+(4-head-1)*16} MAR_ [rDrh, headerAddr+1], c1, at[1,4,IsSA1000OrQuantum]; rB _ 3, CANCELBR[SA1000OrQ2040Continue, 0], c2; {q2040, pages left in cylinder = (16-sector)+(8-head-1)*16} MAR_ [rDrh, headerAddr+1], c1, at[3,4,IsSA1000OrQuantum]; rB _ 7, CANCELBR[SA1000OrQ2040Continue, 0], c2; SA1000OrQ2040Continue: 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 total 53 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 total 69 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*;}z20320e12k40(0,4939)\f7 3524t2 1t0 37t2 1t0 18t2 1t0 14t2 1t0 10t2 1t0 23t2 1t0 10t2 1t0 12t2 1t0 15t2 1t0 20t2 1t0 1123t2 1t0 49t2 1t0 6232t2 12t0 46t2 13t0 46t2 6t0 2t2 10t0 7t2 12t0 11t2 8t0 32t2 8t0 11t2 4t0 32t2 15t0 55t2 78t0 41t2 1t0 4177t2 1t0 {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;}z20320k40\f7