;-----------  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