;----------- Dandelion Processor Program - I/O Processor ----------- ; DESCRIPTION: Boot Program: IOP code. ; Last modification by Roy Ogus: January 28, 1982 4:04 PM ; File: BootMain.asm ; Stored: [Iris]<Workstation>Boot30>BootEPromRAM.dm ; Written by Roy Ogus. ; Modification History: ; Version 1.0 ; - Created (September 8, 1980 2:24 PM) ; - Added hooks for diagnostic booting, AltBoot handling (November 10, 1980 12:32 PM) ; - Data area as definitions (November 10, 1980 12:32 PM) ; Version 1.1 ; - Created (November 11, 1980 2:33 PM) ; - Complemented Control store data in WriteCS (November 11, 1980 2:33 PM) ; Version 2.0 ; - Created (November 12, 1980 12:51 PM) ; - Floppy Streaming (November 12, 1980 12:51 PM) ; - Removal of BootSubs into separate file (November 13, 1980 9:53 AM) ; - Separate Floppy/Rigid soft Go (November 18, 1980 1:08 PM) ; - Link table (November 18, 1980 1:08 PM) ; - Link to PreBoot (December 3, 1980 11:09 AM) ; - CSImageStart, FloppyBuffer variables added (December 3, 1980 11:09 AM) ; - Byte swapping from Floppy (December 4, 1980 11:09 AM) ; Version 2.1 ; - Created (December 8, 1980) ; - Shortened CSImage to 256 locations (December 8, 1980) ; - Floppy buffer is 5 sectors (December 8, 1980) ; Version 2.2 ; - Created (December 22, 1980 4:01 PM) ; - New MP numbers (December 22, 1980 5:13 PM) ; - General CSImage size (December 22, 1980 5:13 PM) ; - Diagnostic Floppy bypasses (January 4, 1981 6:34 PM) ; Version 2.3 (not used) ; Version 2.4 ; - Renamed main program file BootMain.asm (June 17, 1981 1:08 PM) ; - 2D, 2S floppy booting added (June 18, 1981 1:29 PM) ; Version 3.0 ; - Trident0 hook added to FinishPhase0 (November 24, 1981 3:25 PM) ; - FinishPhase0 redone according to new BootType allocation (December 11, 1981 3:10 PM) ; - Set interrupt state moved to BootInit, changed start code (January 13, 1982 4:22 PM) ; - Add links to FloppyInitE and DoSeekCmd, use RestoreCom (January 14, 1982 1:39 PM) ; - Double count check simplification in DoLoadIOP, Do IgnoreBlock (January 28, 1982 3:58 PM) ; DEFNITIONS: get "SysDefs" get "BootDefs" ; EXPORTS: EXP StartNextPhase ; For BootSubs EXP DoBootPhase ; For IOPInitial EXP BootGo,BootGoExt,SetInt ; For Burdock command file and debugging EXP EndPhase0,EndPhase0Floppy,EndPhaseNot0 ; For debugging EXP MoveLinkTableExt ; For debugging ; IMPORTS (from BootSubs): IMP BootInit,CheckAltBootDevice IMP StartNextRead,GetNextWord IMP InitCSTPCImage,TransferCSImage,TransferTPCImage IMP WriteCS IMP SetupUregisters,InformCPBootDevice,ReadMainMem IMP CheckCPStopped,StartCPKernel,StartCP IMP ByteToWord IMP FloppyInit, FloppyInitE,DoSeekCmd IMP PhaseToMP,PutMP,ClearMPanel,IncrMP,DeltaMP,ErrorReport IMP InitCPCmd,WriteCPword,ReadCPWord,Delay IMP StartPreBoot ; From StartIOPBootRAM or StartIOPBootProm ; { This code constitutes the IOP code that will reside in the IOP EProm. This code will be bound with the .bin form of the Phase0 CP microcode that will be loaded by the IOP into Control Store. This microcode will read the Initial microcode from the boot device into main memory, in the case of rigid disk booting. In the case of Floppy booting, the IOP will read the Initial microcode and Initial IOP code from the floppy. The IOP will then interpret the loaded boot file and (conditionally) restart the CP executing Initial. In the next phase, the Pilot microcode, the Germ, and Domino will be read into main memory, and subsequently read and placed by the IOP.} {Notes: Boot file in Main memory should not cross 64K boundary Maximum of 16 loadU blocks in Phase 0 boot file. Allocation in RAM for Testing: Phase0 boot file 2000H (Overlaid by Domino) IOPInitial 3000H (Overlaid by Domino) Boot code start 4000H Floppy Buffer (5 sector) 51D0H CSImage 5BD0H Variables 5ED0H-5F63H Link Table 5F76H-5F9FH User stack 5FA0H - 5FCEH Allocation in Prom: IOP Kernel 0H Boot code start 40H (Boot code+Phase0 boot file) PreBoot code start 1800H Floppy Buffer (5 sectors) 51D0H CSImage 5BD0H Variables 5ED0H-5F63H Link Table 5F76H-5F9FH User stack 5FA0H - 5FCEH } ;------------------------------------------------------ ; RAM storage (definitions in BootDefs definitions file). ; LINK table. ; These are fixed locations for used by external programs. ; This table is copied into RAM at start of boot for use by other programs. ; Location of LinkTable in RAM defined by StartLinkTable in BootDefs.asm. ; Note that the entry for MoveLinkTable is not used in the RAM location, since it will not ; be there before the subroutine is called. This entry is to be called directly in the EProm. TopLinkTable: BootGoExt: jmp BootGo ; 0: Boot entry point DoBootPhaseExt: jmp DoBootPhase ; 1: Start of Boot file interpreter GetNextWordExt: jmp GetNextWord ; 2: Get the next word from the boot file BootInitExt: jmp BootInit ; 3: Boot initialization subroutine ReadMainMemExt: jmp ReadMainMem ; 4: Read a word of main memory InitCPCmdExt: jmp InitCPCmd ; 5: Start a CPport Read or Write WriteCPwordExt: jmp WriteCPword ; 6: Write a CP word ReadCPWordExt: jmp ReadCPWord ; 7: Read a CP word ClearMPanelExt: jmp ClearMPanel ; 8: Clear maintenance panel IncrMPExt: jmp IncrMP ; 9: Increment maintenance panel PutMPExt: jmp PutMP ; 10: Put a number in the Maintenance panel DelayExt: jmp Delay ; 11: Delay subroutine ErrorReportExt: jmp ErrorReport ; 12: Error Report loop MoveLinkTableExt: jmp MoveLinkTable ; 13: Start of MoveLinkTable subroutine FloppyInitExt: jmp FloppyInitE ; 14: External entry point of FloppyInit subroutine DoSeekCmdExt: jmp DoSeekCmd ; 15: External entry point of DoSeekCmd subroutine EndLinkTable: ; ;------------------------------------------------------ ; Boot Start locations: ; EProm entry point (from Kernel, or from RST 0): ; Note: The PreBoot code will first set BootType to DefaultBoot, ; and then check the AltBoot switches to determine for any other value of BootType. ; For soft testing, the initialization in PreBoot is changed in the command file. BootGo: SetInt: di ; Set to "ei" for Mouse Halts in testing ; Initialize the boot stack. lxi sp,BootStackStart ; Initialize stack pointer call BootInit ; Do various system initialization call MoveLinkTable ; Move the link table to RAM (sub. in this module) ; Note: The LinkTable is moved BEFORE the PreBoot diagnostics are run. ; Call the PreBoot diagnostics. call StartPreBoot ; Call the PreBoot Diagnostics, read the AltBoot and set BootType ; Return from the PreBoot diagnostics. ; The PreBoot diagnostics should also call the ReadAltBoot subroutine to read in the BootType. ; The PreBoot code should restore the Link table, and call BootInit if RAM was destroyed. ; Start processing the Phase0 boot file. StartPhase0: lxi h,MPStartPhase0 ; Set MP = 100, MPOffset to 100 shld MPOffset call PutMP ; MP = 100 ; Go to: DoBootPhase ; ; START of the Boot file interpreter. { The boot file interpreter interprets blocks of the Dandelion boot file. The boot file can be in EProm or CP main memory. During Phase 0, the boot file is in EProm, during subsequent phases (currently Phase 1 and phase 2), it is in main memory. The subroutine GetNextWord gets the next 2 bytes from the appropriate place, depending on the Phase. Because CP memory accesses may be involved, the subroutine StartNextRead is needed which starts a CP port access if appropriate. Control store locations less than an address determined by MaxCSImage are written into a control store image area in IOP memory. This image is transferred to control store just before the CP is started executing the next phase. TPC values specified in the boot files are also buffered until the end of the IOP boot phase. U-register handling: U registers can only be written by the IOP when the CP is executing (i.e. not dead or stopped). In addition, if rigid disk booting is required, the IOP can only write the appropriate the U-registers when it is known which rigid disk is on the system.} { Phase 0 starts at 100. End Phase 0 starts at 135. Phase 1 starts at 149. End Phase 1 starts at 190. Phase 2 starts at 199 End Phase 2 starts at 240. } DoBootPhase: call InitCSTPCImage ; Initialize the CS image and the TPC buffer StartBootBlock: lxi h,1 ; Get header word for next block call StartNextRead ; Initiate the read lxi h,Header ; Do the read call GetNextWord lda HeaderHi ; What is it? ani BlockTypeMask jz DoSpecialBlock ; z => a special block type ; Write CONTROL STORE Block. ; It was a control store block. Store count of the number of microinstructions in block. ; A has the number of microinstructions to be read, left justified. DoCSBlock: rlc rlc rlc rlc sta CSInstrCount mov b,a ; Save Count in B rlc ; 2*Count in A add b ; 3*Count = number of words to be read lxi h,0 ; Number to H,L mov l,a call StartNextRead ; Initiate the read of the microinstructions lhld Header mov a,h ; Clear BlockType field ani nBlockTypeMask mov h,a shld CSAddress ; Store CS address (BlockType later masked out) NextCS: mvi c,3 ; Counter for 3 words lxi h,CSBuffer ; Point start of CS buffer GetCSData: call GetNextWord ; Store in CS buffer (H,L is updated) dcr c jnz GetCSData ; nz => still more ; Microinstruction is stored in CSBuffer. call WriteCS ; Write instruction in the control store or the CS image ; Check for end of CS block. lda CSInstrCount dcr a sta CSInstrCount jz BootBlockDone ; z => Block is done ; Do next microinstruction. lhld CSAddress inx h shld CSAddress jmp NextCS ; The current block is completed. BootBlockDone: jmp StartBootBlock ; SPECIAL Blocks. ; It was a special block. Do further decoding to determine which one. ; Low part of header determines further decoding. DoSpecialBlock: lda Header cpi 8 ; Check if a TPC block jc DoTPCBlock ; c => A<8, i.e. TPC cpi 8 ; Check for Last block jz DoLastBlock ; z => A=8 cpi 9 ; Check for load IOP memory jz DoLoadIOP ; z => A=9 cpi 10 ; Check for Load U register jz DoLoadU ; z => A=10 cpi 11 ; Check for load IOP memory jz DoIgnoreBlock ; z => A=11 cpi 12 ; Check for Load U register jz DoSetStartIOP ; z => A=12 UnknownBlock: mvi c,ErrorUnknownBlock ; ERROR: Unknown special Boot file Block jmp ErrorReport ; Report the error ; TPC Block. ; Insert the TPC value in the TPC buffer. Clear the empty flag for the slot. ; Slot address is TPCBuffer + 2*(TPC address) ; The TPC's will later be written into the actual TPC's. ; Header (low) contains the TPC address. DoTPCBlock: lxi h,1 ; Read next word call StartNextRead ; Initiate the read lda Header ; Get the TPC address rlc ; Form 2*(TPC address) lxi b,0 mov c,a ; B,C contains 2*(TPC address) lxi h,TPCBuffer ; Point to the TPC buffer dad b ; H,L ← TPCBuffer + 2*(TPC address) call GetNextWord ; Store the value in TPC buffer (clear Empty flag) jmp BootBlockDone ; IOP memory block. ; The next word contains the IOP starting address, the next the count (in bytes). ; Since there can be an odd number of bytes, maintain 2 counts in the inner loop. ; The wordCount is the (byteCount+1)/2. DoLoadIOP: lxi h,2 ; Read next two words call StartNextRead ; Initiate the read lxi h,IOPAddress call GetNextWord ; Store the address lxi h,IOPCountByte call GetNextWord ; Store the count (in bytes) lhld IOPCountByte ; Convert to words after incrementing to round up inx h call ByteToWord ; Returned in H,L shld IOPCountWord ; Store call StartNextRead ; Initiate the read jmp DecrIOPCount ; Jump to end of the loop to check for 1 word only ; Inner loop. GetIOPData: lhld IOPAddress ; Point to the IOP memory call GetNextWord ; Store in IOP memory (H,L updated to point to next slot) shld IOPAddress ; Save pointer lhld IOPCountByte ; Decrement the byte count by 2 dcx h dcx h shld IOPCountByte ; Store back DecrIOPCount: lhld IOPCountWord ; Decrement the word count by 1 dcx h shld IOPCountWord ; Store back mov a,l ; Check for count = 0 ora h ; Low OR high jnz GetIOPData ; nz => nonzero ; We have one more word to get from the boot file. ; There might be one or two bytes in it. ; The byte count will be 2 for two bytes left, and 1 for one byte left. ; IOPAddress points to the next IOP memory location. LastIOPData: lda IOPCountByte ; Get low part of byte count (assume high part is zero) cpi 1 ; One more byte? jz DoLastIOPByte ; z => 1 byte left cpi 2 ; One more byte? jz DoLastIOPWord ; z => 1 word left BadIOPCount: mvi c,ErrorBadIOPCount ; ERROR: Something wrong with byte count jmp ErrorReport ; One byte left. Have to read the next word into a buffer (use Header). DoLastIOPByte: lxi h,Header ; Point to Header call GetNextWord ; Store in IOP memory (H,L updated) lhld IOPAddress ; Store the byte lda Header ; Get the byte mov m,a ; Store away the byte jmp BootBlockDone ; Done with block ; Two bytes left. Do the normal thing. DoLastIOPWord lhld IOPAddress ; Point to the IOP memory call GetNextWord ; Store in IOP memory (H,L updated) jmp BootBlockDone ; Done with block ; U register block. ; This block specified a load of a U-register block. ; In Phase 0, the pointer to the loadU block is saved for later update of U-registers. ; In Phase not 0, this is ignored (breakpoint). ; Phase 0: ; Save pointer to the LoadU block, increment uBlock counter. ; At end of Phase 0 the blocks are interpreted as follows: ; uBlockType = unconditional => DoWriteUBlock ; uBlockType = BootDevice => DoWriteUBlock ; uBlockType # unconditional => ignore DoLoadU: lda Phase ; Check if Phase 0 ora a ; Set flags jz LoadUPhase0 LoadUNotPhase0: mvi c,ErrorLoadUNotPhase0 ; ERROR: LoadU not in Phase 0 jmp ErrorReport ; Phase 0 load of U register. Save the pointer, and increment the uBlock count. ; Skip over the rest of the u Block. LoadUPhase0: lhld BootAddrIOP ; Get pointer to the rest of the block xchg ; Move to D,E lhld uBlockPtr ; Get pointer to next slot in array mov m,e ; Store low part inx h mov m,d ; Store high part inx h shld uBlockPtr ; Store back pointer lxi h,uBlockCnt ; Increment uBlock Count inr m ; Note: No checking for more than 16 blocks ; Now skip over the rest of the block (17 words). lhld BootAddrIOP ; Get Boot file pointer again mvi d,34 ; Counter for 34 bytes LoadUSkipLoop: inx h ; Increment the pointer dcr d jnz LoadUSkipLoop ; Store back the pointer. shld BootAddrIOP jmp BootBlockDone ; Done with block ; IGNORE Block. ; This block is to be skipped over. ; The next word specifies how manywords to be skipped. DoIgnoreBlock: lxi h,1 ; Read next word call StartNextRead ; Initiate the read lxi h,IgnoreCount ; Read how many words to Skip call GetNextWord ; Store the count lhld IgnoreCount ; Read next words to be skipped call StartNextRead ; Initiate the read IgnoreLoop: lxi h,IgnoreData call GetNextWord ; Throw away the data lhld IgnoreCount ; Decrement the count dcx h shld IgnoreCount mov a,l ; Check for count = 0 ora h ; Low OR high jnz IgnoreLoop ; nz => nonzero ; The block is all done. jmp BootBlockDone ; Done with block ; SET START IOP Block. DoSetStartIOP: lxi h,1 ; Read next word call StartNextRead ; Initiate the read lxi h,StartIOPAddress ; Read next word into Start IOP address slot call GetNextWord jmp BootBlockDone ; Done with block ; LAST BLOCK. This is the end of the boot file. Read the LstBlock Flags and finish the Boot phase. ; Depending on which phase, do the end-of-phase cleanup and start the CP executing if specified. DoLastBlock: lxi h,1 ; Read next word call StartNextRead ; Initiate the read lxi h,LastBlockFlags ; Read next word into LastBlockFlags call GetNextWord lda Phase ; Determine which phase it is ora a jz FinishPhase0 ; z => Finish Phase0. jmp FinishPhaseNot0 ; Finish up a phase other than Phase 0 ; ; PHASE 0 termination. FinishPhase0: lxi h,MPEndPhase0 ; MP = 135 call PutMP ; Check for diagnostic floppy booting. If so, leave the CP alone. call CheckDiagFloppy ora a ; A#0 => Diagnostic floppy booting jnz GoToPhase1DiagFloppy ; nz => Diagnostic floppy booting ; Not diagnostic floppy booting. Transfer CSimage into low control store, load the TPC's call TransferImage ; MP = 136, 137 call StartCPKernel ; Start the CP kernel call IncrMP ; MP = 138 call StartCP ; Issue the ExitKernel command to the CP (unconditional) call IncrMP ; MP = 139 EndPhase0: nop ; BootFlags are now: BootMode=0, CPStopped=0. ; The CP has started execution. ; The microcode will determine which boot devices are present, ie. SA1000 or SA4000, Ethernet. ; This is needed to determine which U-registers to load. ; Memory location 0 will be set to non-zero when this is determined. WaitMem0: lxi h,0 ; H,L ← address 0 call ReadMainMem ; Read main memory 0 ora a jz WaitMem0 ; z => still no valid information sta CPDevices ; Store low byte of Mem 0 call IncrMP ; MP = 140 ; The devices present (including rigid disk type) have been determined by the microcode. ; Check whether the Boot device is the rigid disk or not, from BootType. ; BootType determines what boot device is to be used and is defaulted to 0 (rigid disk booting). Phase0CPStarted: call CheckAltBootDevice ; Check the BootType and set BootDevice ; Setup the U registers (if any), and transmit Host number, DiagBoot and BootDevice. call InformCP ; MP = 141 ; Check which boot device. ; Ethernet booting: same as rigid disk booting, wait for valid boot file in main memory. ; Floppy disk booting: initialize the floppy disk. lda BootDevice cpi BootFloppy ; Is is Floppy booting? jz GoToPhase1Floppy ; z => Floppy booting jmp StartNextPhase ; Rigid, Ethernet booting, wait for valid boot file in main memory ; Floppy disk booting. GoToPhase1DiagFloppy: mvi a,BootFloppy ; Set boot device to Floppy sta BootDevice ; Initialize the floppy disk controller and data structures. GoToPhase1Floppy: call FloppyInit ; Initialize the floppy hardware call IncrMP ; MP = 142 ; Initialize floppy data structures. mvi a,BootSourceFloppy sta BootSource ; BootSource ← Floppy ; Set FloppyBufCnt to zero (empty). This will cause a transfer at the first GetNextWord. lxi h,0 shld FloppyBufCnt ; Set the disk address to start of Initial: SetStartInitial: lxi h,StartInitialCylinder ; Initialize starting cylinder (a word) shld DCylinder mvi a,StartInitialSector ; Initialize starting sector sta Sector mvi a,StartInitialSide ; Initialize starting side sta DSide ; Go to next phase. lxi h,Phase ; Increment phase number inr m call PhaseToMP ; Put Phase*50 + 99 in MP call IncrMP ; Put Phase*50 + 100 in MP EndPhase0Floppy: jmp DoBootPhase ; ; START of new rigid disk Phase. ; This is where all rigid disk booting phases after Phase 0 start executing. StartNextPhase: lxi h,Phase ; Increment phase number inr m call PhaseToMP ; Put Phase*50 + 99 in MP ; MP has Phase*50 + 99 in it. MPOffset is Phase*50 + 100 ; Assumes Rigid disk or Etherbooting here. ; Wait for a valid Boot file in main memory. Memory loc. 1 will be non-zero when this occurs. WaitMem1: lxi h,1 ; Specify memory location 1 call ReadMainMem ; 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 SetNextPhase ; nz => completed ; High byte is zero, check low byte: mov a,c ora a jnz CPError ; nz => Error ; High byte is zero, low byte is zero: jmp WaitMem1 ; A valid boot file is in main memory. Initialize the BootFile Pointer and interpret it. SetNextPhase: mvi a,BootSourceCP ; Set the value of BootSource to CP memory sta BootSource ; Start of BootFile in main memory is at address in B,C: mov l,c ; Start of Boot file in CP memory mov h,b shld BootAddrCP call IncrMP ; MP = Phase*50 + 100 jmp DoBootPhase ; Go and interpret it ; CP has completed in error. C has the error code. CPError: jmp ErrorReport ; ERROR: Error in CP FloppyInitial ; PHASE not zero termination. FinishPhaseNot0: call PhaseToMP ; Put Phase*50 + 99 in MP lxi h,MPEndPhaseNot0+1 ; MP = PhaseNumber*100 + 40 call DeltaMP ; StartPhase+40 ; Check for diagnostic floppy booting. If so, leave the CP alone. call CheckDiagFloppy ora a ; A#0 => Diagnostic floppy booting jnz EndPhaseNot0 ; nz => Diagnostic floppy booting ; Not diagnostic floppy booting. Continue with normal sequence. call CheckCPStopped ; If CP is not stopped, then stop it call IncrMP ; MP = StartPhase+41 ; Transfer CSimage into low control store, load the TPC's call TransferImage ; MP = StartPhase+42, StartPhase+43 ; Now check whether CP is to be started. CheckStartCP: lda LastBlockFlagsHi ; Check InhibitStartCP bit in LastBlockFlags ani InhibitStartCPMask jnz EndPhaseNot0 ; nz => Do not start the CP ; Start the CP. call StartCP ; Issue the ExitKernel command to the CP call IncrMP ; MP = StartPhase+44 EndPhaseNot0: nop GoToNextPhase: ; Wait for CP to disable IOP port, and clear memory location 1. nop ; Go to where specified by StartIOPAddress. This is initialized to StartNextPhase StartIOP: lhld StartIOPAddress pchl ; Go to it ; ; Special SUBROUTINE to move Link table into RAM. ; This subroutine must be in this module. ; Subroutine: MoveLinkTable. ; Copy the Link table from this module to RAM in variable area. ; This is needed since the boot code might be in RAM (soft booting) or Prom. ; The table is copied upwards in memory. ; Copy each item separately. ; Use Header as a counter. SizeLinkTable equ (EndLinkTable-TopLinkTable)/3 ; No of items in Link table MoveLinkTable: lxi h,TopLinkTable ; Source lxi d,StartLinkTable ; Destination in RAM mvi a,SizeLinkTable ; Size of table sta Header MoveLinkLoop: mvi c,SizeLink ; Size of an item MoveItemLoop: mov a,m ; Get source byte stax d ; Store at destination inx h ; Bump pointers inx d dcr c ; Check count jnz MoveItemLoop ; nz => more bytes in link ; The link is moved, do next one. ; Check count. lda Header dcr a sta Header rz ; z => Done ; Decrement destination pointer by 6. xchg ; H,L ← Destination pointer, D,E ← source pointer lxi b,-6 dad b ; H,L ← Destination pointer - 6 xchg ; D,E ← New destination pointer, H,L ← source pointer jmp MoveLinkLoop ; Subroutine: TransferImage. ; Transfer the CS and TPC images. TransferImage: call TransferCSImage ; Transfer image into low control store call IncrMP ; Increment MP call TransferTPCImage ; Load the TPC's jmp IncrMP ; Increment MP ; Jump to IncrMP subroutine and Return. ; Subroutine: InformCP. ; Setup the U registers (if any), and transmit Host number, DiagBoot and BootDevice. InformCP: call SetupUregisters ; Set up the U registers (if any) call InformCPBootDevice ; Tell CP BootDevice, U-registers loaded jmp IncrMP ; Increment MP ; Jump to IncrMP subroutine and Return. ; Subroutine: CheckDiagFloppy. ; Check DiagBoot and BootType to see if diagnostic floppy booting. ; On exit: ; A # 0 if (DiagBoot#0) AND (BootType=AltDiagFloppyBoot) ; A = 0 otherwise. CheckDiagFloppy: 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 NotDiagFloppyBoot ; nz => BootType#AltDiagFloppyBoot ; BootType=AltDiagFloppyBoot (A=0). cma ; Complement sense: A#0 if BootType=AltDiagFloppyBoot ret NotDiagFloppyBoot: xra a ; Return A = 0 ret END BootMain