--last edited December 11, 1981 5:57 PM by GWilliams
--
changed call to LoadRamAndBoot
DIRECTORY
AltoRam USING[LoadRamAndBoot],
IODefs: FROM "iodefs" USING [WriteLine],
MiscDefs: FROM "miscdefs" USING [Zero],
Mopcodes: FROM "mopcodes" USING [zLIW, zJRAM],
SystemDefs: FROM "systemdefs" USING [AllocateHeapNode, FreeHeapNode],
RamDefs: FROM "ramdefs" USING [StartIO],
TridentDefs USING[dcbID, dcReadHLD, dcReadnD, ddMgrPtr, DefaultTfsErrorRtn, diskRestore, drive, dstMinusStatus, FP, KCB, kcbPtr, lCB, lCBZ, lFP, lKCB, lSN, lTfsBT, lTFSDSK, lTFSKDHeader, NoopTfsCleanupRtn, openMode, PAGE, ptr, RTC, Right, statusptr, tfsdskPtr, TfsActOnPages, TfsAssignDiskPage, TfsCantAssignDiskPage, TfsCantCreateDiskFile, TfsCantDeletePages, TfsCantReleasePage, TfsCloseDisk, TfsCreateDDmgr, TfsCreateFile, TfsDeletePages, TfsDoDiskCommand, TfsDoRecovery, TfsGetCb, TfsInitializeCBStorage, TfsOpenFile, TfsRealDA, TfsReleaseDiskPage, TfsVirtualDA, TFSlnWordsPerPage, TfsWritePages, tfsKDversion, TFSmNDisks, TFSmNTracks, TFSmNSectors, TfsWaitQuiet, track, tridentMask, T80mNHeads, T300mNHeads, T300mNVTracks],
InlineDefs: FROM "inlinedefs" USING [BITSHIFT, BITAND, BITOR, COPY];
TfsStart: PROGRAM
IMPORTS AltoRam, TridentDefs, InlineDefs, SystemDefs, MiscDefs, RamDefs,
IODefs
EXPORTS TridentDefs=

BEGIN OPEN TridentDefs, InlineDefs, SystemDefs, RamDefs, IODefs;


-- Ram Stuff, moved from TridentDefs as they are unbound if left there!
locationinRAM: CARDINAL = 500B;-- location of silentbootinram
tfsLock: PUBLIC BOOLEAN;
-- forces (at times) single use of disk
BaduCode: ERROR = CODE;

--this stuff is used by TfsWrite and TfsCreate

oneBitsArray: ARRAY[0..15] OF WORD ← [100000B,40000B,20000B,10000B,4000B,2000B,1000B,400B,200B,100B,40B,20B,10B,4,2,1];
oneBits: PUBLIC DESCRIPTOR FOR ARRAY OF WORD ← DESCRIPTOR[oneBitsArray];

TfsInit: PUBLIC PROCEDURE [initmode: BOOLEAN, driveNumber: CARDINAL ← 0, ddMgr: ddMgrPtr ← NIL, freshDisk: BOOLEAN← FALSE] RETURNS [tfsDsk: tfsdskPtr] =

--
Called by end users of the Tfs Package. The result is a pointer to the disk object. Note: One of the arguments should be the ddMgr

BEGIN

fsNumber: CARDINAL;-- file system number (if a T-300)
lowOnes: WORD = 377B;
p: CARDINAL;-- the result of TfsTryDisk
pages: ARRAY [0..26) OF PAGE;
dAs: DESCRIPTOR FOR ARRAY OF PAGE;
res: INTEGER;
ddLeader, ddFirst: CARDINAL;-- first VDA of disk descriptor
fidTfsSysdir: ARRAY [0..2) OF CARDINAL;
fpTfsSysdir, fpTfsDD: FP;-- file pointers for Sysdir & DD
numChars: INTEGER;
numCharsPtr, fidSysDirPtr: POINTER;
ddBuf: ARRAY [0..1024) OF WORD;
i, j, w, pag, freep: CARDINAL;
bw: CARDINAL;-- word within entire bit map
cAs: DESCRIPTOR FOR ARRAY OF POINTER;

numCharsPtr ← @numChars;
tfsLock ← FALSE;-- allow TfsTryDisk to start
fsNumber ← BITSHIFT[driveNumber, Right*8];-- isolate the file system
driveNumber ← BITAND[driveNumber, lowOnes];-- and the drive number
-- First try to select a disk that does not exist. If the selection succeeds, it is because the controller does not have a multi-drive multiplexor attached. Note that the important bit in the disk number is 10B, because this will cause none of the 8 copies of the selection logic to be enabled. (The drive-select decoder is only 4 bits wide.) 37B is used rather than 17B because 37B is specifically defined as a nonexistent drive on the Dorado.

p ← TfsTryDisk[37B,FALSE];-- see if the controller is connected
IF p = 0 THEN RETURN[NIL];-- No controller
IF p = 1 AND driveNumber # 0 THEN RETURN[NIL];-- Not a multi-drive controller
p ← TfsTryDisk[driveNumber,FALSE];-- Now look for the real drive
IF p # 1 THEN RETURN[NIL];-- Drive not there or not online

-- set up TFSDSK object
tfsDsk ← AllocateHeapNode[lTFSDSK];--get space if user doesn’t supply it.
MiscDefs.Zero[tfsDsk, lTFSDSK];-- clear the area
TfsSetDisk[tfsDsk, initmode, driveNumber];-- store procs, etc.
tfsDsk.tfskd.zone ← tfsDsk;-- ZONE was the area from which
-- storage was allocated. Well, this does not work the same in Mesa as in BCPL. This is only a pointer to a TfsDsk type here, not to a zone.


-- Issue a disk restore if the drive appears to be in trouble

IF statusptr.deviceCk = 1 OR statusptr.seekInc = 1 THEN
TfsDoRecovery[tfsDsk,diskRestore, FALSE];

-- set up disk parameters
tfsDsk.tfskd.model ← DetermineDiskModel[tfsDsk];-- 80 or 300
IF (tfsDsk.tfskd.model # 300 AND fsNumber # 0) OR fsNumber > 2
THEN BEGIN
FreeHeapNode[tfsDsk];-- no such file system
RETURN[NIL];
END;

tfsDsk.tfskd.kdh.nDisks ← TFSmNDisks;
tfsDsk.tfskd.kdh.nTracks ← TFSmNTracks;
IF tfsDsk.tfskd.model = 80 THEN tfsDsk.tfskd.kdh.nHeads ← T80mNHeads
ELSE tfsDsk.tfskd.kdh.nHeads ← T300mNHeads;
tfsDsk.tfskd.kdh.nSectors ← TFSmNSectors;
tfsDsk.tfskd.firstVTrack ← fsNumber*T300mNVTracks;
tfsDsk.tfskd.nVtracks ← TFSmNTracks - tfsDsk.tfskd.firstVTrack;
IF tfsDsk.tfskd.model = 300 AND tfsDsk.tfskd.nVtracks > T300mNVTracks
THEN tfsDsk.tfskd.nVtracks ← T300mNVTracks;

-- Set up Sysdir’s file pointer for this disk

fidTfsSysdir[0] ← 100000B;-- directory bit is on
fidTfsSysdir[1] ← 100;-- serial number
fidSysDirPtr ← @fidTfsSysdir;
InlineDefs.COPY[fidSysDirPtr,lSN,@fpTfsSysdir.serialNumber];

-- just moved serial number into Sysdir’s FP, now finish up
-- Also put FP in the disk object
fpTfsSysdir.version ← 1;
fpTfsSysdir.leaderVirtualDA ← 1;
InlineDefs.COPY[@fpTfsSysdir,lFP,@tfsDsk.tfskd.fpTFSSysDir];

IF ~freshDisk THEN--do not try to read descriptor if this is a fresh disk.
{-- Skip all code down to ddMgr initialization if freshDisk=TRUE
--
Read SysDir’s label to see if it exists(why not use TfsOpenFile?)
-- vda of SysDir
FOR i IN [0..26) DO pages[i] ← i + 1;ENDLOOP;
dAs ← DESCRIPTOR[@pages,26];-- build descriptor of same
-- check header and label of sysdir
res←TfsActOnPages[tfsDsk,cAs,dAs,fpTfsSysdir,0,0,dcReadnD,NIL,dcReadnD,NIL, NoopTfsCleanupRtn, DefaultTfsErrorRtn,TRUE, 1];

IF res < 0 THEN-- Had a check error
BEGIN
FreeHeapNode[tfsDsk];-- free the object
RETURN[NIL];
END;

-- Get the virtual disk address of the first page of the disk descriptor

[leaderPage: ddLeader, firstPage: ddFirst]←TfsOpenFile[tfsDsk,
"DiskDescriptor.", read,
tfsDsk.dsk.fpDiskDescriptor];
IF ddFirst = 0 THEN
BEGIN WriteLine["Can’t open Disk Descriptor "]; RETURN[NIL]; END;
pages[0] ← ddLeader;
pages[1] ← ddFirst;
dAs ← DESCRIPTOR[@pages, 2];

-- Build the Disk Descriptor’s FP and store it in the disk object

--
tfsDsk.tfskd.fpTFSDD.serialNumber.word1 ← 0;
--
tfsDsk.tfskd.fpTFSDD.serialNumber.word2 ← 101;
--
tfsDsk.tfskd.fpTFSDD.version ← 1;
--
tfsDsk.tfskd.fpTFSDD.leaderVirtualDA ← ddLeader;
tfsDsk.tfskd.fpTFSDD ← tfsDsk.dsk.fpDiskDescriptor↑;
--move the whole rec at once, and use the right #’s

-- Read page 1 of the disk descriptor (tfskd)

--res←TfsActOnPages[tfsDsk,cAs,dAs,fpTfsDD,0,0,dcReadHLD,numCharsPtr,dcReadHLD, @ddBuf,NoopTfsCleanupRtn, DefaultTfsErrorRtn, FALSE, 0];
res←TfsActOnPages[tfsDsk,cAs,dAs,fpTfsDD,1,1,dcReadHLD,numCharsPtr,dcReadHLD, @ddBuf,NoopTfsCleanupRtn, DefaultTfsErrorRtn, FALSE, 0];

-- Simulate ReadBlock, then check version

numChars ← lTFSKDHeader;
InlineDefs.COPY[@ddBuf,lTFSKDHeader,@tfsDsk.tfskd];

IF tfsDsk.tfskd.version # tfsKDversion THEN
BEGIN
FreeHeapNode[tfsDsk];
RETURN[NIL];
END;

-- Set up disk address array for disk descriptor

FOR i IN [1..lTfsBT+1] DO
pages[i] ← tfsDsk.tfskd.vdadiskDD[i];-- put in the addresses
ENDLOOP;
--dAs ← DESCRIPTOR[@tfsDsk.tfskd.vdadiskDD,lTfsBT+1];
dAs ← DESCRIPTOR[@pages[0], lTfsBT+1];
-- Count free pages
freep ← 0;
i ← 0;
pag ← 1;
-- bitmap starts on 2nd page of file.
bw ← 0;
-- word number in the bitmap (up to 2293)

UNTIL bw >= tfsDsk.tfskd.kdh.diskBTsize DO
IF 0 = bw MOD 1024 THEN-- test to read next page
BEGIN
pag ← pag + 1;
i ← 0;
res←TfsActOnPages[tfsDsk,cAs,dAs,fpTfsDD,pag,pag,dcReadHLD,numCharsPtr,
dcReadHLD,@ddBuf,NoopTfsCleanupRtn, DefaultTfsErrorRtn, FALSE,0];
END;
w ← ddBuf[i];-- get a word out of the bitmap
SELECT w FROM

0 => freep ← freep + 16;-- every page free

-1 => NULL;-- none free

ENDCASE =>BEGIN-- some yes, some no
FOR j IN [0..16) DO
IF 0 = BITAND[1,BITSHIFT[w,Right*j]]
THEN freep ← freep + 1;
ENDLOOP;-- j IN [0..16)
END;-- ENDCASE

bw ← bw + 1;-- count bit map pages
i ← i + 1;-- index within a bitmap page
ENDLOOP;
-- UNTIL bw > ...

-- Note free pages

tfsDsk.tfskd.kdh.freePages ← freep;
};--
this is the enclosing END of "IF ~freshDisk THEN"


-- start DD manager

IF initmode THEN
BEGIN -- (ddMgr is an argument to TfsInit)
IF ddMgr = NIL THEN ddMgr ← TfsCreateDDmgr[];
tfsDsk.tfskd.ddMgr ← ddMgr;
END;

RETURN[tfsDsk];

END;
-- of TfsInit

TfsTryDisk: PROCEDURE [driv: INTEGER, dontReSelect: BOOLEAN] RETURNS [state: CARDINAL] =

-- Try to access the disk and return one of the following values:
--
--
0 if controller appears not to work
--
1 if disk appears to be present
--
2 if disk appears to be absent

BEGIN

oldDrive: INTEGER;
result: CARDINAL;

WHILE tfsLock DO NULL ENDLOOP;-- This is a global writeable variable
tfsLock ← TRUE;-- Allow no other activity
TfsWaitQuiet[FALSE];-- Quiet the disk
--
--
This is the coding for USC(oldDrive, 17B) >0
--
oldDrive ← drive↑;-- get the drive number from Alto
oldDrive ← ABS[oldDrive];
IF oldDrive > 17B THEN oldDrive ← 0;

result ← TryDisk[driv];

-- If selected a nonexistent drive, must leave controller pointing at the
-- previously-selected drive, which is assumed to exist. (Note that drive 0
-- must exist or the controller won’t work - this is a hardware restriction).

IF result = 2 THEN [] ← TryDisk[oldDrive];
tfsLock ← FALSE;
RETURN[result];
END;
-- of TfsTryDisk


TryDisk: PROCEDURE [driv: INTEGER] RETURNS [result: CARDINAL] =

BEGIN
timedOut: BOOLEAN;-- TRUE if sector pulses absent
retry: CARDINAL;
inTime: INTEGER;-- program’s clock


[] ← StartIO[20B];-- turn off and reset controller
DO-- UNTIL wrLate = 0
ptr↑ ← NIL;-- zero the KCB chain pointer
drive↑ ← BITOR[driv,100000B];-- force a drive select
statusptr↑ ← dstMinusStatus;-- merely initialization
track↑ ← -1;-- force a seek

-- Now see if the unit responds. Let each StartIO work for 1/20th of a second. If status has not been set after the last StartIO, timedOut will be true. The reason for several StartIO’s is that we may be trying to select a non-existent disk, which will not provide sector pulses and corresponding wakeups.

FOR retry IN [1..4] DO
[] ← StartIO[40B];-- causes microcode to start
timedOut ← FALSE;-- reset switch
inTime ← RTC↑;-- start the clock

DO
IF statusptr↑ # dstMinusStatus THEN EXIT;-- did status change?
IF RTC↑ - inTime >1 THEN timedOut ← TRUE;
NULL;
IF timedOut THEN EXIT;
ENDLOOP;

IF NOT timedOut THEN EXIT;
ENDLOOP;
--
IF timedOut THENRETURN[0];
IF statusptr↑.wrLate = 0 THEN EXIT;
ENDLOOP;

-- Which status bit to test? A drive will select if power is on (even if the
-- disk is not spinning): NotSelected is therefore only an indication of a
-- non-ex or fully powered down drive. The OnLine indication is best, although
-- if the drive is in the middle of a restore, it is conceivable that OnLine
-- goes away.

IF statusptr.notOnline =0 THEN result ← 1
ELSE result ← 2;

RETURN[result];
END;
-- of TryDisk


DetermineDiskModel: PROCEDURE [tfsDsk: tfsdskPtr] RETURNS [model: CARDINAL] =

-- returns 80 if the disk drive is a T-80, 300 if it’s a T-300

BEGIN

kcbArea: KCB;-- instance of a KCB
kcb: kcbPtr;-- pointer to KCB

kcb ← @kcbArea;
WHILE tfsLock DO NULL ENDLOOP;-- allow no disk activity
tfsLock ← TRUE;
TfsWaitQuiet[FALSE];-- Quiet the disk

DO
MiscDefs.Zero[kcb, lKCB];
kcb.drive ← tfsDsk.dsk.driveNumber;-- store drive number
--
--
Don’t do any I/O; just select an illegal head for a T-80
--
kcb.diskAddress.head ← T80mNHeads;-- illegal because of zero-origin
kcb.id ← dcbID;-- store the seal
ptr↑ ← kcb;-- wake up the microcode
WHILE ptr↑ # NIL DO NULL ENDLOOP;-- wait for pointer to zero
IF statusptr.headError = 1 THEN model ← 80
ELSE model ← 300;
IF statusptr.wrLate = 0 THEN EXIT;
ENDLOOP;

tfsLock ← FALSE;
-- TfsDoRecovery[tfsDsk,diskReset,FALSE];kill red light on T-80
RETURN[model];

END;
-- of DetermineDiskModel

TfsSetDisk: PROCEDURE [disk: tfsdskPtr, initMode: BOOLEAN, driveNumber: CARDINAL] =

--
Sets up constant part of disk structure (procedures, etc.)

BEGIN

disk.dsk.ActOnDiskPages ← TfsActOnPages;
disk.dsk.WriteDiskPages ← TfsWritePages;
disk.dsk.CreateDiskFile ← TfsCreateFile;
disk.dsk.DeleteDiskPages ← TfsDeletePages;
disk.dsk.AssignDiskPage ← TfsAssignDiskPage;
disk.dsk.ReleaseDiskPage ← TfsReleaseDiskPage;
disk.dsk.CloseDisk ← TfsCloseDisk;
disk.dsk.VirtualDiskDA ← TfsVirtualDA;
disk.dsk.RealDiskDA ← TfsRealDA;
disk.dsk.InitializeDiskCBZ ← TfsInitializeCBStorage;
disk.dsk.DoDiskCommand ← TfsDoDiskCommand;
disk.dsk.GetDiskCb ← TfsGetCb;

-- Deny access in certain cases. WriteDiskPages is not in this list because it has several uses that do not modify the bit table.

IF NOT initMode THEN
BEGIN
disk.dsk.CreateDiskFile ← TfsCantCreateDiskFile;
disk.dsk.DeleteDiskPages ← TfsCantDeletePages;
disk.dsk.AssignDiskPage ← TfsCantAssignDiskPage;
disk.dsk.ReleaseDiskPage ← TfsCantReleasePage;
END;

-- file pointers

disk.dsk.fpSysDir ← @disk.tfskd.fpTFSSysDir;-- fp for SYSDIR
disk.dsk.fpDiskDescriptor ← @disk.tfskd.fpTFSDD;-- Disk Descriptor
disk.dsk.fpWorkingDir ← @disk.tfskd.fpTFSWD;-- Working Directory

-- working directory name

disk.dsk.nameWorkingDir ← @disk.tfskd.wdNameBlk;

-- Other parameters

disk.dsk.lnPageSize ← TFSlnWordsPerPage;
disk.dsk.driveNumber ← driveNumber;
disk.dsk.retryCount ← 16;
disk.dsk.totalErrors ← 0;
disk.dsk.diskKd ← @disk.tfskd.kdh.nDisks;-- ptr to KDH
disk.dsk.lengthCBZ ← lCBZ;
disk.dsk.lengthCB ← lCB;
IF initMode THEN
disk.tfskd.initmode ← 1 ELSE disk.tfskd.initmode ← 0;

END;
-- of TfsSetDisk

RamBoot
: PUBLIC PROCEDURE [bootVector: CARDINAL] =
--see changed as "Global" level of this file - GW

BEGIN

IF bootVector = tridentMask THEN
BEGIN
AltoRam.LoadRamAndBoot["TriconDriver.br", ];--lock in core and boot! Also add Cleanup Proc.
END;

END;
-- of RamBoot

SilentBootInRam: PROCEDURE [arg: CARDINAL] =

-- Argument is used by microcode. We are going to jump to a routine written in microcode with this procedure.

MACHINE CODE BEGIN

Mopcodes.zLIW, locationinRAM/256, locationinRAM MOD 256;
Mopcodes.zJRAM;

END;
-- of SilentBootInRam

END.
-- of TfsStart