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.22; author freier; state Exp; branches 1.1.1.1; next ; 1.1.1.1 date 2001.08.12.22.22.22; author freier; state Exp; branches ; next ; desc @@ 1.1 log @Initial revision @ text @{ ----------- Dandelion Processor Program - I/O Processor ----------- DESCRIPTION: Boot Program: IOP Initial code for Floppy Booting. Last modification by Roy RXO : June 30, 1981 5:17 PM File: IOPInit.asm Stored: [Iris]DLion>IOPInit.asm Written by Roy RXO . Edited: Dennis DEG , 1-Sep-84 22:11:53 add copyright notice. } { Copyright (C) 1981 by Xerox Corporation. All rights reserved. } ; Modification History: ; Version 1.0 ; - Created (November 16, 1980 5:02 PM) ; Version 2.2 ; - Created (December 23, 1980 12:18 PM) ; - Check for Mem 1 as pointer (December 23, 1980 12:18 PM) ; - Diagnostic Floppy bypasses (January 4, 1981 6:34 PM) ; - Indexed DiagBoot for Diagnostic Floppy (January 5, 1981 4:45 PM) ; Version 2.4 ; - Added 2D,2S floppy booting (June 18, 1981 7:08 PM) ; - Fixed Floppy Phase 2 offset (June 18, 1981 7:40 PM) ; - Check for zero PVRP slots (June 18, 1981 7:40 PM) ; DEFNITIONS: get "SysDefs" get "BootDefs" get "BootLinkDefs" ; Link information { This code constitutes the IOP code runs during Phase 2 of floppy booting. It gets control after FloppyInitial.mc has been started in the CP. To make the FloppyInitial.db boot file for the Floppy disk do the following Assemble IOPInit: i8085a IOPInit Bind IOPInitial: i8085b IOPInitial Make .db file: MakeBoot FloppyInitial.db FloppyInitial.fb IOPInitial.bin/3000 (Use command file: MakeFloppyInitial.cm) IOPInitial fetches the Physical Volume Root Page (PVRP), computes the floppy disk addresses of the Germ (and Othello), the soft microcode, and the hard microcode. IOPInitial leaves them in IOP RAM. IOPInitial then interprets the "Germ" (and Othello) CPR file and stores it into CP main memory. It then sets up the disk address of the soft microcode (if DiagBoot is zero), and transfers control to the EProm code at DoBootPhase. If DiagBoot is non-zero, then the hard microcode boot file is set up, using DiagBoot as an index. } {Notes: CPR block in Main memory should not cross 64K boundary } ; ;------------------------------------------------------ ; Start location: IOPInitialGo: jmp IOPInitialStart ;------------------------------------------------------ ; RAM variables: ; Starting disk addresses: ; Germ (really Othello) GermCylinder: ds 2 GermSector: ds 1 GermSide: ds 1 ; Soft microcode. SoftMCCylinder: ds 2 SoftMCSector: ds 1 SoftMCSide: ds 1 ; Hard microcode. HardMCCylinder: ds 2 HardMCSector: ds 1 HardMCSide: ds 1 ; CPR block variables. ; Write main memory CPport control block (PCB). WritePCB: ds 2 ; Word 0: CP buffer pointer (low): ds 2 ; Word 1: CP buffer pointer (high) ds 2 ; Word 2: CP buffer count (words) ds 2 ; Word 3: Pointer to IOP buffer (unused) CPRBlockCnt: ds 2 ; Count of words used during block processing CPRBlockData: ds 2 ; Data during block processing CPRBlockDataHi equ CPRBlockData+1 InitMaxSector: dw MaxSectorNo+1 ; Maximum sector number+1 ; ; Start of Initial execution. ; The CP is executing FloppyInitial. ; Wait until it completes execution and sets Main memory 1 to nonzero. IOPInitialStart: lxi h,Phase ; Increment phase number inr m lxi h,MPStartPhase2Floppy+1 ; Put 250 in MPOffset shld MPOffset dcx h ; Put 249 in MPanel call PutMPExt ; Check for diagnostic floppy booting. If so, leave the CP alone. call CheckInitDiagFloppy ora a ; A#0 => Diagnostic floppy booting jnz FinishDiagInitial ; nz => Diagnostic floppy booting ; Not diagnostic floppy booting. Check Main memory. InitialWaitMem1: lxi h,1 ; Specify memory location 1 call ReadMainMemExt ; Read main memory 1 ; Check for completion (low byte in A, high byte in B): ; high byte # 0 => Valid completion, ; high byte = 0, low byte # 0 => Error, error code in low byte, ; high byte = 0, low byte = 0 => not completed. mov c,a ; Save low byte mov a,b ; Get high byte ora a jnz FloppyInitialDone ; nz => completed ; High byte is zero, check low byte: mov a,c ora a jnz FloppyInitialError ; nz => Error ; High byte is zero, low byte is zero: jmp InitialWaitMem1 ; CP has completed. Get the addresses in the Physical Volume root page. FloppyInitialDone: call IncrMPExt ; Put 250 in MPanel call GetPVRP ; Read the PVRP from the floppy, compute disk addresses lxi h,MPStartInterpretGerm ; Put 260 in MPanel call PutMPExt jmp DoInterpretCPR ; CP has completed in error. C has the error code. FloppyInitialError: jmp ErrorReportExt ; ERROR: Error in CP FloppyInitial ; START of the CPR file interpreter. { The CPR contains blocks af data destined for CP main memory. The interpreter reads a block and stores it in main memory. The format of a CPR block is as follows where each item is a word: Block count (in words) - Zero means last block CP real address high - High 16 bits of long real address CP real address low - Low 16 bits of long real address "count" words At this point we know that the floppy disk is enabled, and the current state is correct. Also the "Germ" disk address has been computed and stored. BootSource specifies the Floppy. } DoInterpretCPR: lxi h,GermCylinder ; Point to the Germ disk address call SetDiskAddr ; Initialize the disk address ora a ; Check for invalid address jnz StartCPRBlock ; nz => valid address ; Error: mvi c,ErrorZeroGermAddress ; ERROR: Zero Germ Address jmp ErrorReportExt ; Report the error ; Since we know that the BootSource is the Floppy we don't have to do any StartNextRead's. StartCPRBlock: lxi h,CPRBlockCnt ; Read the block count call GetNextWordExt xra a ; Check if it is zero lhld CPRBlockCnt cmp l ; Check low part jnz DoCPRBlock ; nz => valid CPR block ; Low part was zero, check the high part. cmp h ; Check high part jnz DoCPRBlock ; nz => valid CPR block ; Count was zero, thus end of CPR file. EndCPRFile: jmp FinishIOPInitial ; Finsih up the Initial execution ; Interpret a CPR Block. ; The block is of nonzero length. DoCPRBlock: lhld CPRBlockCnt ; Store block count in PCB shld WritePCB+CPCnt ; Get the memory address. GetCPRAddr: lxi h,WritePCB+CPAddr1 ; Point to the high address in PCB call GetNextWordExt lxi h,WritePCB+CPAddr3 ; Point to the low address in PCB call GetNextWordExt ; Start the CP write through the port. StartCPRWrite: mvi a,CPWriteCmd ; Write command lxi h,WritePCB ; Point to the WritePCB call InitCPCmdExt ; Initialize the transfer CPRBlockLoop: lxi h,CPRBlockData ; Point to data slot call GetNextWordExt ; Get the word lhld CPRBlockData ; H,L _ Data word xchg ; D,E _ Data word call WriteCPwordExt ; Write word into port ; Decrement the count and check for zero. lhld CPRBlockCnt ; Decrement the word count by 1 dcx h shld CPRBlockCnt ; Store back xra a cmp l ; Check low part for zero jnz CPRBlockLoop ; nz => nonzero cmp h ; Check high part for zero jnz CPRBlockLoop ; nz => nonzero ; The current block is completed (count is zero). Go and do the next block. jmp StartCPRBlock ; Diagnostic floppy booting. ; Read the PVRP and complete the Initial phase. FinishDiagInitial: call IncrMPExt ; MP = 250 call GetPVRP ; Read the PVRP from the floppy, compute disk addresses ; Go to FinishIOPInitial. ; The CPR file has been interpretted. Finish off Initial's execution and transfer control back to the ; EProm code at DoBootPhase. Set up the disk address to the soft microcode, ; unless DiagBoot is true, then set up the disk address to the hard microcode. FinishIOPInitial: lxi h,MPEndPhase2Floppy ; MP = 285 call PutMPExt lda DiagBoot ; Check DiagBoot ora a jnz SetHardMCDiskAddr ; nz => set the hard microcode disk address ; Boot file is the soft microcode. SetSoftMCDiskAddr: call IncrMPExt ; MP = 286 lxi h,SoftMCCylinder ; Point to the soft mc disk address DoSetDiskAddr: call SetDiskAddr ; Initialize the disk address ora a ; Check for invalid address jnz ExitIOPInitial ; nz => valid address ; Error: mvi c,ErrorZeroSoftMCAddress ; ERROR: Zero Soft MC Address jmp ErrorReportExt ; Report the error ; Indicate stage in MP. ExitIOPInitial: lxi h,MPStartPhase2Rigid ; MP = 200 shld MPOffset call PutMPExt jmp DoBootPhaseExt ; Interpret the boot file. { DiagBoot was indicated. This indicates that the hard microcode boot file should be interpretted. The hard microcode file is actually a concatenation of boot files, indexed by the value of DiagBoot. The first page of the hard microcode boot file is an array of pointers which is indexed by DiagBoot to determine the word address of the start of the actual boot file. The code here uses DiagBoot to index into the table and then fix the disk address so that the next call to GetNextWord will start accessing the first word of the file. } ; Clear the flag in DiagBoot. SetHardMCDiskAddr: call IncrMPExt ; MP = 286 call IncrMPExt ; MP = 287 lxi h,HardMCCylinder ; Point to the hard mc disk address call SetDiskAddr ; Initialize the disk address ora a ; Check for invalid address jnz GetDiagBoot ; nz => valid address ; Error: mvi c,ErrorZeroHardMCAddress ; ERROR: Zero Hard MC Address jmp ErrorReportExt ; Report the error ; The table at the start of the boot file has the first two words reserved. ; DiagBoot = 1 is mapped to Entry 2, etc. GetDiagBoot: lda DiagBoot ; Increment DiagBoot inr a call DiscardFloppyWords ; Discard the first entries in the table ; The next word will contain the word pointer to the start of the boot file. lxi h,CPRBlockData ; Put the pointer into CPRBlockData call GetNextWordExt ; Compute the disk address of the page containing the start of the boot file. lda CPRBlockDataHi ; Get high part of word index mov c,a ; Use as counter in C lxi h,HardMCSector ; Point to sector number ; Loop, updating the hard disk address. HardMCAddrLoop: inr m ; Increment sector number lda InitMaxSector ; Compare to max sector+1 cmp m jz InitTrackCross ; z => Sector number = MaxSector+1, i.e crossed track boundary ; Didn't cross the track boundary, see if we're done. HardMCAddrCheck: dcr c jnz HardMCAddrLoop ; nz => Disk address not yet correct ; Disk address now is for the first page of the file. Set the address and check offset in the page. lxi h,HardMCCylinder ; Point to the hard mc disk address call SetDiskAddr ; Initialize the disk address (know that address is nonzero) lda CPRBlockData ; Look at low part ora a jz ExitIOPInitial ; z => First word is at start of page, no more to do ; The first word is within the page. Discard the words before. A has number of words to discard. call DiscardFloppyWords ; The next word accessed by GetNextWord will be the first word of the file. jmp ExitIOPInitial ; Crossed Track boundary. Fix up the disk address. ; Single-sided disk: ; HardMCSector _ 1; ; HardMCCylinder _ HardMCCylinder + 1; ; Double-sided disk: ; HardMCSector _ 1; ; IF HardMCSide = 0 THEN HardMCSide _ 1 ; ELSE {i.e. HardMCSide = 1} BEGIN DSide _ 0; ; HardMCCylinder _ HardMCCylinder + 1; ; END; InitTrackCross: mvi a,1 ; HardMCSector _ 1; sta HardMCSector in FDCStatusReg ; Check in external status reg. whether single or double-sided ani FDCTwoSidedMask jz DoSingleSide ; z => single sided ; Double sided disk. lda HardMCSide xri Side1Mask sta HardMCSide ; HardMCSide _ HardMCSide xor Side1Mask jnz HardMCAddrCheck ; nz => HardMCSide =1, i.e. was 0 ; HardMCSide = 0, i.e. was 1. Increment the cylinder number. DoSingleSide: lda HardMCCylinder inr a sta HardMCCylinder jmp HardMCAddrCheck ; ; IOPInitial SUBROUTINES. ; Subroutine: GetPVRP. ; Read the physical volume root page from the disk. Compute the HardMC, SoftMC, and Germ ; disk addresses and store in IOP RAM. GetPVRP: ; Set starting disk address to PVRP. lxi h,StartPVRPCylinder ; Initialize starting cylinder (a word) shld DCylinder mvi a,StartPVRPSector ; Initialize starting sector sta Sector mvi a,StartPVRPSide ; Initialize starting side sta DSide ; Set the floppy buffer to empty. This will trigger a disk access when GetNextWord is called. lxi h,0 ; FloppyBufCnt _ 0 shld FloppyBufCnt ; Read and discard the first uninteresting words (StartHardMCIndex words) in the I/O page. ; Use the low part of CPRBlockCnt as a counter. DiscardFirstPVRP: mvi a,StartHardMCIndex call DiscardFloppyWords ; The next word will be the start of the HardMC disk address GetHardMCPVRP: lxi h,HardMCCylinder ; Point to the Cylinder location call GetNextWordExt lxi h,HardMCSector ; Point to the Sector/Side location call GetNextWordExt ; Discard the next DiskFileID header. mvi a,SizeDiskFileID-SizeDiskAddr call DiscardFloppyWords ; The next word will be the start of the SoftMC disk address GetSoftMCPVRP: lxi h,SoftMCCylinder ; Point to the Cylinder location call GetNextWordExt lxi h,SoftMCSector ; Point to the Sector/Side location call GetNextWordExt ; Discard the next DiskFileID header. mvi a,SizeDiskFileID-SizeDiskAddr call DiscardFloppyWords ; The next word will be the start of the Germ disk address GetGermPVRP: lxi h,GermCylinder ; Point to the Cylinder location call GetNextWordExt lxi h,GermSector ; Point to the Sector/Side location call GetNextWordExt ret ; Subroutine: DiscardFloppyWords. ; Read and discard a nember of words from the disk. ; On entry: A = Number of words (<256) to be discarded ; CPBlockCnt and CPRBlockData are used. DiscardFloppyWords: sta CPRBlockCnt DiscardLoop: lxi h,CPRBlockData ; Point to the data word call GetNextWordExt lxi h,CPRBlockCnt ; Check for last junk word dcr m jnz DiscardLoop ; nz => still more ret ; Subroutine: SetDiskAddr ; Set up the desired disk address for the boot file, and set the floppy buffer to empty. ; On entry: H,L has pointer to a disk address. ; On exit: A=0 => Disk address was zero (i.e. Side = Cylinder = Sector = 0) ; A#0 => Disk address was nonzero SetDiskAddr: mov e,m ; Get low part of Cylinder inx h mov d,m ; D,E _ Cylinder inx h xchg ; H,L = desired cylinder, D,E has disk address pointer shld DCylinder ; Store in desired cylinder xchg ; D,E _ cylinder, H,L _ disk address pointer mov a,m ; A _ Sector sta Sector ora d ; A _ Sector OR CylinderHi ora e ; A _ Sector OR CylinderHi OR CylinderLo mov b,a ; Save Sector OR CylinderHi OR CylinderLo inx h ; Point to side mov a,m ; A _ Side sta DSide ora b ; A # 0 for valid address, = 0 for zero address ; Set the floppy buffer to empty. This will trigger a disk access when GetNextWord is called. lxi h,0 ; FloppyBufCnt _ 0 shld FloppyBufCnt ret ; Subroutine: CheckInitDiagFloppy. ; Check DiagBoot and BootType to see if diagnostic floppy booting. ; On exit: ; A # 0 if (DiagBoot#0) AND (BootType=AltDiagFloppyBoot) ; A = 0 otherwise. CheckInitDiagFloppy: lda DiagBoot ; Check DiagBoot first ora a rz ; z => DiagBoot = 0, not diag floppy booting ; DiagBoot was not zero. Check if diagnostic floppy booting. lda BootType ; Check the BootType xri AltDiagFloppyBoot ; A _ 0 if BootType=AltDiagFloppyBoot jnz NotInitDiagFloppyBoot ; nz => BootType#AltDiagFloppyBoot ; BootType=AltDiagFloppyBoot (A=0). cma ; Complement sense: A#0 if BootType=AltDiagFloppyBoot ret NotInitDiagFloppyBoot: xra a ; Return A = 0 ret END IOPInit @ 1.1.1.1 log @first add @ text @@