$MOD186
$PAGELENGTH (45)
$PAGEWIDTH  (136)

;Copyright (C) 1984, 1985 by Xerox Corporation. All rights reserved.

;-- stored as [Eris]<LispCore>Dove>LispBoot.asm
;-- created on  30-Nov-84 13:44:00

;-- last edited by:


;--     Lichtenberg.pa                  31-Jul-85  1:32:36      ;created LispBoot.asm from Ramdskbt.asm

NAME			LispBoot
;--------------------------------------------------------------------------------
;
$NOLIST
$INCLUDE		(HardDefs.asm)		;
$INCLUDE		(IOPDefs.asm)		;
$INCLUDE		(IOPLRam.asm)
$INCLUDE		(RAMBDefs.asm)		;
;INCLUDE		(EEPDefs.asm)		;
$INCLUDE		(DskIOFce.def)		;
$INCLUDE		(DskBDefs.asm)
$INCLUDE		(IOPMacro.asm)
$LIST

;--------------------------------------------------------------------------------

; Local constants:

labelVerifyError	EQU	23h

RootPageRealPage	EQU	0
SysoutVPLo		EQU	0h
SysoutVPHi		EQU	(1h OR (mesaLogicalWordOpieAddress SHL 8)) 

; The equate below, "VMEMTableIORegionOffset" should be set to TWICE the value of the
; constant \Dove.VmemPageRunTableOffset, which is declared in DOVEINPUTOUTPUT.

VMEMTableIORegionOffset	EQU	10804

diskTimeout		EQU	1650


;--------------------------------------------------------------------------------

;********************************************************************************



%*DEFINE		(Zero	(start,end))
			   LOCAL Lbl0
			   (	MOV	SI, OFFSET %start
			%Lbl0:	MOV	BYTE PTR [SI], 0
				INC	SI
				CMP	SI, OFFSET %end
				JL	%Lbl0
				)

;--------------------------------------------------------------------------------

PUBLIC			GermInit

IORegion		SEGMENT	COMMON
			ASSUME	DS:IORegion

dskIOCB			EQU	bootDeviceIORSpace
diskWorkspace		EQU	bootDeviceIORSpace

;from IORDisk.asm:
;------------------

EXTRN			diskFCB: DiskFCBRecord

;from IORDisp.asm:
;------------------

EXTRN			borderLow: BYTE
EXTRN			borderHigh: BYTE
EXTRN			chngdInfo: WORD
borderChanged		EQU	2000H


;from IORRAMBt.asm:
;------------------
EXTRN			bootDeviceIORSpace: DiskBootArea


;from IORMaint.asm:
;------------------

EXTRN			maintPanelCode: WORD
EXTRN			maintPanelChanged: Condition

IORegion		ENDS

IOPEInRam		SEGMENT	PUBLIC
			ASSUME	CS:IOPEInRam
			ASSUME	DS:IORegion
			ASSUME	ES:NOTHING


			ORG	0
GermInit:
; step 1

; set up ClientCondition in disk FCB

			MOV	BX, OFFSET diskFCB.rd0.diskIOPClientCondition
			MOV	[BX].conditionPtr, OFFSET diskWorkspace.diskCondition
			MOV	[BX].clientMaskPtr, 0
; set up disk IOCB (disk characteristics and data address)
			MOV	BX, OFFSET dskIOCB.diskOperationBlock
			MOV	AL, diskFCB.rd0.diskSectorsPerTrack
			MOV	[BX].diskSecPerTrack, AL
			MOV	AL, diskFCB.rd0.diskHeadsPerCylinder
			MOV	[BX].diskHdsPerCyl, AL
			MOV	AX, diskFCB.rd0.diskCylindersPerDrive
			MOV	[BX].cylPerDrive, AX
			MOV	AX, diskFCB.rd0.diskReducedWriteCurrentCylinder
			MOV	[BX].diskReducedWriteCyl, AX
			MOV	AX, diskFCB.rd0.diskPreCompensationCylinder
			MOV	[BX].diskPreCompCyl, AX

			JMP	RamDiskCont

; put DiskRead here, so will be in first sectorSize bytes

; proc to read from disk

DiskRead		PROC	NEAR

; calculate next disk address from DOB (prev. address and label)
CalcNextAddr:		MOV	BX, OFFSET dskIOCB.diskOperationBlock
			MOV	AX, WORD PTR [BX].diskLabel.diskDontCare
			MOV	CX, WORD PTR [BX].diskLabel.diskDontCare+2
			TEST	AX, CX
			JZ	IncrPrevAddress
			CMP	AX, 0FFFFH
			JNE	UseAddressInAXCX
; end-of-file: set carry and return
			XOR	AX,AX
			STC
			RET

; secondary entry point for new file -- disk address in AX:CX
DiskReadNewFile:	MOV	BX, OFFSET dskIOCB.diskOperationBlock
; AX:CX contains next sector address: store into DOB
UseAddressInAXCX:	MOV	WORD PTR [BX].diskHeader, AX
			MOV	WORD PTR [BX].diskHeader+2, CX
			JMP	SHORT InitIOCB
; label contains nil: increment previous address
IncrPrevAddress:	JMP	SHORT InitIOCB
			MOV	CX, WORD PTR [BX].diskHeader+2
			INC	CL
			CMP	CL, [BX].diskSecPerTrack
			JL	StoreNewAddress
			XOR	CL, CL
			INC	CH
			CMP	CH, [BX].diskHdsPerCyl
			JL	StoreNewAddress
			XOR	CH, CH
			INC	[BX].diskHeader.diskCylinder
StoreNewAddress:	MOV	WORD PTR [BX].diskHeader+2, CX
; initialize other IOCB fields
InitIOCB:		MOV	AL, read
InitIOCBCont:		%Zero	(dskIOCB.diskDataInfoRec+2, dskIOCB.diskOperationBlock)
			MOV	dskIOCB.diskDataXferDirection, AL
			MOV	AX,CS:RunLength
			MOV	dskIOCB.diskPageCount, AX
			NOT	AX
			INC	AX
			MOV	[BX].diskMinusSectorCount, AX
			MOV	[BX].diskHeaderError, 0
			MOV	[BX].diskLabelError, 0
			MOV	[BX].diskDataError, 0
			MOV	[BX].diskLastError, 0
; put IOCB onto disk queue
EnqueueIOCB:		MOV	diskFCB.rd0.diskIOPNextLow, OFFSET dskIOCB
			MOV	diskFCB.rd0.diskIOPNextHigh, (IOPIORegionOpieAddress SHL 8)
; wake up handler and wait for return notify
			%NotifyCondition	(OFFSET diskFCB.diskConditionWork)
			%WaitForCondition	(OFFSET diskWorkspace.diskCondition,noTimeout)
;			CMP	AL,conditionTimeout		; must be an error...
;			JZ	DiskReadError
; check for good completion
			TEST	dskIOCB.diskError, 0FFH
			JNZ	DiskReadError
			CMP	diskFCB.diskHandlerState, normalDiskHandlerState
			JE	DiskReadDone
			MOV	diskFCB.diskHandlerState, normalDiskHandlerState
; determine error type (eventually -- just retry for now):
;  (a) CRC error -- retry
;  (b) wrong cylinder error -- recalibrate, retry
;  (c) other errors -- ?

; Check for label verify  error... it's special.
DiskReadError:		MOV	diskFCB.diskStartHandlerForIOP, 0FFFFH
			MOV	BX,OFFSET dskIOCB.diskOperationBlock
			CMP	WORD PTR [BX].diskLastError, labelVerifyError
			JZ	SHORT labelError

			DEC	cs:LispBootRetryCount
			JZ	SHORT TooManyRetries
			JMP	InitIOCB
DiskReadDone:		XOR	AX,AX
			CLC
			RET
labelError:		MOV	diskFCB.rd0.diskIOPNextLow, 0
			MOV	diskFCB.rd0.diskIOPNextHigh, 0
			MOV	diskFCB.diskHandlerState, normalDiskHandlerState
			MOV	AX,labelVerifyError
			STC
			RET

;if too many retries, start over from the beginning (at OpieReentry)
TooManyRetries:		mov	maintPanelCode,2217
			%NotifyCondition       (OFFSET maintPanelChanged)
			%WaitForSystem	; gives opie a chance to run the mp handler
Forever:		JMP	Forever

DiskRead		ENDP


; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

RamDiskCont:		MOV	borderHigh, 0
			MOV	borderLow, 0
			OR	chngdInfo, borderChanged
			MOV	maintPanelCode, 1000
			%NotifyCondition	(OFFSET maintPanelChanged)


; This step initializes the VtblCurrentOffset variable, which is used by the
; MakeEntryInVmemTable routine for collecting the runs of pages in the sysout.

			MOV	AX,VMEMTableIORegionOffset
			MOV	CS:VtblCurrentOffset,AX

			MOV	CS:RunLength, 1
			MOV	BX,OFFSET dskIOCB.diskOperationBlock
			MOV	[BX].diskOperation,ReadDiskLabelAndData

; The next major step is to load in the root page, which is at a known physical disk
; address.  This sector is going to be loaded into real page zero.

			MOV	BX, OFFSET dskIOCB.diskOperationBlock
			MOV	AX, rootPageCylinder
			MOV	CX, rootPageHeadAndSector
			MOV	dskIOCB.diskDataPtrLow, RootPageRealPage
			MOV	dskIOCB.diskDataPtrHigh, (extendedBusOpieAddress SHL 8)
			MOV	dskIOCB.diskDataInfoRec,0	; clear out flags
			OR	dskIOCB.diskDataInfoRec, MASK diskUseLEDs  ; pretty lights.

			MOV	cs:LispBootRetryCount, 10
			
ReadRootPage:		CALL	DiskReadNewFile

; We've read in the root page.  Time to look up the pilot boot file on the page.

			MOV	CX,(extendedBusOpieAddress SHL 8)
			MOV	DX,RootPageRealPage
			%EstablishIOPAccess(generalMapRegister,CX-DX)
			ADD	DI, rootPageHeaderSize	; set up for 1st file ID (diagnostics)
			MOV	CH, ES:[DI].DFIDcylinderHigh
			MOV	CL, ES:[DI].DFIDcylinderLow
			MOV	DH, ES:[DI].DFIDhead
			MOV	DL, ES:[DI].DFIDsector

; CX-DX contains the sysout DA.
			MOV	cs:sysoutDACyl,CX
			MOV	cs:sysoutDAHdSect,DX

			inc	maintPanelCode
			%NotifyCondition	(OFFSET maintPanelChanged)
; load one complete file

			MOV	cs:LispBootRetryCount, 10

; Read first sector of file into starting address of Vmem



; Make the first entry in the table.
			MOV     AX,0			; file page zero
			MOV	CX,cs:sysoutDACyl
			MOV	DX,cs:sysoutDAHdSect
			CALL	MakeEntryInVmemTable


; Load file.

			MOV	BX, OFFSET dskIOCB.diskOperationBlock
			MOV	AX,cs:sysoutDACyl
			MOV	CX,cs:sysoutDAHdSect
			MOV	dskIOCB.diskDataPtrLow, SysoutVPLo
			MOV	dskIOCB.diskDataPtrHigh,SysoutVPHi
			OR	dskIOCB.diskDataInfoRec, MASK incrementDataPtr

			CALL	DiskReadNewFile
			JNC	DiskGotFirstPage

DiskErrorFirstPage:	JMP	TooManyRetries
			
DiskGotFirstPage:

; The first page of the file is a waste (it's a leader page)
; Back up the data ptr to the beginning

			call	BackUpDataPtr

			mov	maintPanelCode,1000
			
; We've read the first sector of the file into memory.   If we get here, the data 
; ptr should be pointing at page 100h,
; Now, loop and read in the rest of it.


; To speed reading the sysout in, we're going to transfer 100 pages at a shot.



LoadSectorLoop:	

			MOV	BX, OFFSET dskIOCB.diskOperationBlock
			MOV	cs:RunLength, 100
			MOV	[BX].diskOperation, ReadDiskData    ; That's a VVR for real people.
	
			inc	maintPanelCode
			%NotifyCondition	(OFFSET maintPanelChanged)
			

			CALL	DiskRead
			JC	LoadSectorLoopExit

; For some reason it looks like the disk controller code is either reading
; one page too little or advancing too much.  Backing up the data ptr
; will keep it on track.

			PUSH	AX
			CALL	BackUpDataPtr
			POP	AX

			JMP	LoadSectorLoop

LoadSectorLoopExit:
			
; Some kind of error has happened.  If a label verify, check for end else end.
			CMP	AX,labelVerifyError	; label error?
			JNZ	SHORT AllDone		; must be at end of file


; Temporary - first label verify means all done
			JMP	SHORT AllDone

; Check for end of file.
			MOV	BX, OFFSET dskIOCB.diskOperationBlock
			MOV	AX, WORD PTR [BX].diskLabel.diskFilePageLow
			MOV	CX, WORD PTR [BX].diskLabel.diskDontCare
			MOV	DX, WORD PTR [BX].diskLabel.diskDontCare+2
			CMP	CX, 0FFFFH
			JZ	SHORT AllDone		; really got an EOF.

			CALL	MakeEntryInVmemTable
			MOV	WORD PTR [BX].diskHeader, CX
			MOV	WORD PTR [BX].diskHeader+2, DX
			MOV	WORD PTR [BX].diskLabel.diskDontCare, 0
			MOV	WORD PTR [BX].diskLabel.diskDontCare+2, 0
			JMP	LoadSectorLoop
			

			
; All done.
AllDone:
			mov	maintPanelCode,1111
			%NotifyCondition	(OFFSET maintPanelChanged)

			MOV	diskFCB.rd0.diskIOPNextLow, 0
			MOV	diskFCB.rd0.diskIOPNextHigh, 0

			MOV	diskFCB.diskStartHandlerForIOP,0
			MOV	diskFCB.diskStartHandlerForMesa,0FFFFH
			
			RET

;--------------------------------------------------------------------------------

; Subroutine BackUpDataPtr - backs up the data ptr in the IOCB by one page

BackUpDataPtr:		MOV	AX,dskIOCB.diskDataPtrLow
			MOV	CX,dskIOCB.diskDataPtrHigh
			DEC	AH
			CMP	AX,0FFh		; did we underflow?
			JNZ	SHORT BackupXit
			MOV	AH,0
			DEC	CL
BackupXit:		MOV	dskIOCB.diskDataPtrLow, AX
			MOV	dskIOCB.diskDataPtrHigh, CX
			RET

;--------------------------------------------------------------------------------

; The following local subroutine makes entries in the VMEM table in the IORegion

; Calling parameters:
;		AX = file page number
;		CX = Cylinder of disk address
;		DX = Head/Sector of disk address

; The format of an entry in the table is:
;
;		---> [fphi,fplo]	file page hi,lo (one word)
;		     [cylhi,cyllo]	cylinder number (one word)
;		     [hd,sec]		head and sector (one byte each)
;		     [fphi,fplo]	next entry's fphi and fplo or 0 for end of table


MakeEntryInVmemTable:
		PUSH	DI		; save old DI
		MOV	DI,cs:VtblCurrentOffset	; get current loc in tbl
		
		MOV	BYTE PTR DS:[DI]+0,AH	; file page
		MOV	BYTE PTR DS:[DI]+1,AL
		MOV	BYTE PTR DS:[DI]+2,CH   ; cylinder
		MOV	BYTE PTR DS:[DI]+3,CL
		MOV	BYTE PTR DS:[DI]+4,DH   ; hd/sec
		MOV	BYTE PTR DS:[DI]+5,DL
		MOV	BYTE PTR DS:[DI]+6,0    ; in case it's the last one
		MOV	BYTE PTR DS:[DI]+7,0
		
		ADD	cs:VtblCurrentOffset,6	; point VtblCurrentOffset at next one
		POP	DI
		RET




;--------------------------------------------------------------------------------

; LOCAL STORAGE:

			EVEN			; 80186 likes this.
sysoutDACyl		DW	?		; DA of first page of sysout
sysoutDAHdSect		DW	?
LispBootRetryCount	DB	?
			DB	?
VtblCurrentOffset	DW	?
hundredsCounter		DW	?
RunLength		DW	?




IOPEInRam		ENDS


			END