mirror of
https://github.com/livingcomputermuseum/Darkstar.git
synced 2026-03-02 10:06:45 +00:00
39 lines
27 KiB
Plaintext
39 lines
27 KiB
Plaintext
head 1.1;
|
||
branch 1.1.1;
|
||
access ;
|
||
symbols start:1.1.1.1 Xerox:1.1.1;
|
||
locks ; strict;
|
||
comment @# @;
|
||
|
||
|
||
1.1
|
||
date 2001.08.12.22.22.28; author freier; state Exp;
|
||
branches 1.1.1.1;
|
||
next ;
|
||
|
||
1.1.1.1
|
||
date 2001.08.12.22.22.28; author freier; state Exp;
|
||
branches ;
|
||
next ;
|
||
|
||
|
||
desc
|
||
@@
|
||
|
||
|
||
|
||
1.1
|
||
log
|
||
@Initial revision
|
||
@
|
||
text
|
||
@{File name: [Iris]<WMicro>DLion>SAx000Initial.mc
|
||
Copyright (C) 1981, 1982, 1983, 1984, 1986, 1987 by Xerox Corporation. All rights reserved.
|
||
Description: first microcode read from the disk, gets emulator microcode into CP memory,
|
||
|
||
Last Edited by:
|
||
RDH 22-Apr-87 10:21:35 Add last edit line to reflect MDS relief.
|
||
AHL 9-Aug-86 18:09:14 MDS relieve. See comment at label GFT. (This line added by RDH to satisfy my need for order.)
|
||
Dennis DEG 1-Sep-84 22:20:25 Add copyright notice.
|
||
JMM 1-Nov-83 12:57:00 Added support for Quantum Q2080.
|
||
AeF AEF 7-Oct-83 11:24:58 Use IOPage offsets from Dandelion.df!
|
||
JMM 19-Sep-83 18:49:21 - fixed Germ request initialization to get correct location.
|
||
JMM 28-Jul-83 13:57:57 - remove addressing bug caused by growth of germ request-data address offset beyond byte size.
|
||
JMM 22-Jul-83 11:07:00 - Accomodate changes for Germ as a result of going over to 32-bit procedure descriptors.
|
||
Last Edited by JXF August 14, 1982 11:18 AM New test for quantum drive.
|
||
Last Edited by FXH 18-May-82 14:27:42 add sa1000/quantum determination.
|
||
Last Edited by ETN Jan 14, 1982 14:40 change cons. for extracting filePageHi from BootId from 7 to 7F.
|
||
Last Edited by JGS Nov 18, 1981 8:58 move germ to mds 0.
|
||
Last Edited by JXF Oct 22, 1981 13:12 If diagnostics are not installed, boot Emulator instead of crashing.
|
||
Last Edited by AEF Jun 18, 1981 10:30 delete SetGerm1000 at
|
||
Last Edited by DD Feb 14, 1981 16:35
|
||
Last Edited by PXJ Mar 24, 1981 11:46
|
||
Last Edited by PXJ August 25, 1980}
|
||
|
||
|
||
{disk definitions}
|
||
{null findSectorCmd for SA1000}
|
||
Set[SA1000FindSectCmd, 20];
|
||
{have SA1000 reject Label and Data fields when looking for Headers}
|
||
Set[SA1000HeaderLoopMsk, 43];
|
||
{KControl bits, low byte}
|
||
Set[stepBit, 80],
|
||
Set[inBit, 40],
|
||
Set[firmwareEnable, 20];
|
||
Set[SA4FindSect, 6],
|
||
Set[SA1FindSect, 0];
|
||
{KControl bits, high byte}
|
||
Set[driveSelectBit, 4],
|
||
Set[faultClearBit, 2];
|
||
{KStatus bits, high byte}
|
||
Set[track00Bit, 2],
|
||
Set[seekCompleteBit, 4];
|
||
{IOCB status error indicators}
|
||
Set[badBits, 3F];
|
||
Set[verifyBit, 1];
|
||
|
||
{IOCB page offsets}
|
||
Set[statusAddr, 3]; {status word}
|
||
{ 4 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}
|
||
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]];
|
||
|
||
|
||
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]}
|
||
|
||
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;
|
||
|
||
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];
|
||
|
||
FinishIsSA1000orQuantum:
|
||
uQuantumSA1000MaxHeadNum ¬ rB, c2;
|
||
acRrh ¬ 0 {Point to table of IOCBs}, c3;
|
||
|
||
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;
|
||
|
||
Noop, c1;
|
||
currentCylinder ¬ rE, c2;
|
||
acR ¬ badBits, c3;
|
||
|
||
uBadBits ¬ acR, c1;
|
||
acR ¬ driveSelectBit, c2;
|
||
acR ¬ acR LRot8, c3;
|
||
|
||
acR ¬ acR or firmwareEnable, c1;
|
||
seekMask ¬ acR, c2; {seek Mask ¬ drive select or firmwareEnable}
|
||
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;
|
||
|
||
{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, GFT { InitRequest }], c3;
|
||
|
||
{ The germ is in memory, but the map is wrong. The first page of the germ is its GFT. We move it from virtual page 1 to virtual page 200. Then shift virtual pages down by 1. The Remap loop stops at page FE, but I dont think the germ will ever get bigger. AHL }
|
||
|
||
GFT: rBrh ¬ 1, rB ¬ 1, c1;
|
||
Noop, c2;
|
||
rCrh ¬ 2, rC ¬ 0, c3;
|
||
|
||
MAR ¬ [rBrh, rB], { read page 1 map } c1;
|
||
rB ¬ 0FE, CANCELBR[$,2], c2;
|
||
rS ¬ MD, c3;
|
||
|
||
Map ¬ [rCrh, rC], { page 200 ¬ old page 1 } c1;
|
||
MDR ¬ rS, c2;
|
||
rS ¬ MD, c3;
|
||
|
||
|
||
Remap: MAR ¬ [rBrh, rB], { FE ¬ 200, FD ¬ FE, 1 ¬ 2 } c1;
|
||
MDR ¬ rS, rB ¬ rB - 1, CANCELBR[$,2], ZeroBr, WriteOK, c2;
|
||
rS ¬ MD, BRANCH[Remap, DoneRemap], c3;
|
||
|
||
DoneRemap:
|
||
{ end AHL }
|
||
|
||
|
||
{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;
|
||
|
||
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:
|
||
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 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, c1; {reading first page is a special case}
|
||
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, c3; {zero is okay}
|
||
|
||
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¬ 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}
|
||
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;
|
||
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, c3; {enable firmware, drive select}
|
||
|
||
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)+(uQuantumSA1000MaxHeadNum-head)*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
|
||
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*;}
|
||
|
||
{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;}
|
||
|
||
|
||
{am I a sa1000 or quantum???
|
||
assume on cyl 0, disk ready;
|
||
send 257 step pulses, one back; if on cyl 0 => sa1000}
|
||
|
||
@
|
||
|
||
|
||
1.1.1.1
|
||
log
|
||
@first add
|
||
@
|
||
text
|
||
@@
|