; DiskBoot.asm -- Alto Type B Disk Boot Loader
; Copyright Xerox Corporation 1979
; Last modified December 21, 1978  2:13 PM by Boggs

; This loader lands in Page 0 and does the following things:
;	Corrects memory parity by BLTing all of core to itself
;	Zeros selected locations in Page 1
;	Copies a loader into Page 1 starting at location X
;	Loads the B-format boot file following the loader page
;	Starts the program by JMP @0
;
; The display shows three lines of debugging information:
;	The Parity error locations, 614-621
;	The first KCB, locations X to X+21
;	The second KCB, locations X+22 to X+43
;
; The format of the lines is:
;	Parity:	DCBR KNMAR DWA CBA PC SAD
;	KCBs:	LINK STATUS CMD HDR LBL DATA BLANK BLANK BLANK
;		 NEXTDA LASTDA BLANK NUMCHARS PN VN SN SN ERRCNT
; The bottom part of each line is made up of tick-marks which should
;  aid in deciphering the bits, should you be so unlucky as to need to.
;
; Boot format file:
;	BootLoader (this thing -- on the first data page of the file)
;	Images of pages 0,2,3,4,5,.....375 (octal)
;	Note that no image of page 1 is restored.
; For more on the format of boot files see the documentation for BuildBoot.
;
; When control enters this loader:
;	The ACs are unmodified from before the boot
;	The PC from before the boot is in location 0
;	The display is off (location 420 contains 0)
;	The interrupt system is disabled
;	This loader is in locations 1-400
;	The label for this page is in locations 402-411
;	The disk status for this page is in location 2
;
; When control leaves this loader:
;	The display is off (420 contains 0, controller may NOT have noticed)
;	The interrupt system is disabled
;	The KCBs are left at location X
;	Memory parity is guaranteed good for BANK 0 ONLY
;
; As of December, 1978 the emulator state from before the boot is no
;  longer saved.  The 2 words starting at location 4 (file byte pos = 6)
;  are reserved for holding the date on which the boot file was made.
;  Boot servers use this information to propagate the most recent
;  versions of boot files
; Older versions of this loader contain 402b in location 1.

	.titl DiskBoot
	.nrel

	0		; The sacrificial word for BLDR to eat

Loc1:	jmp Boot1	; This is location 1 in memory
Loc2:	0		; disk status for this page
Loc3:	0		; spacer to get date in advertised position
Loc4:	.blk 2		; date file was built

; Correct memory parity by BLTing all of memory to itself

Boot1:	mkminusone 0 0
	lda 1 MemEnd
	com 1 3
	blt

; Zero selected parts of Page 1

	mkzero 0 0
	sta 0 @pDIW	; display interrupt bit mask
	sta 0 @pIWW	; interrupts waiting
	sta 0 @pIACTW	; active interrupt channels
	sta 0 @pKBLK0	; disk command chain head
	lda 1 C777
	lda 3 CWCNT
	blks		; 600-777

; Copy the KCBs, DCBs, and loader loop into Page 1.

	jsr .+1
XOff:	lda 0 ImgOff
	add 3 0		; AC0← Image-1
	lda 1 pImgEnd
	lda 3 ImgLen
	neg 3 3
	blt

	lda 0 MarkWrd	; Put display mark words in 530-551
	lda 1 MarkEnd
	lda 3 MarkCnt
	blks

	lda 0 @p0KA
	sta 0 @pKCB0DA	; put DA for 1st page of boot file in KCB0

	lda 0 pDCB0
	sta 0 @pDISP	; Start the display

	lda 2 pKCB0	; Active KCB
	lda 3 pKCB1	; Inactive KCB
	lda 1 C1000	; next data block address - 400
	sta 2 @pKBLK0	; Start the disk
	jmp @pReadIn	; Jump into the loader loop in page 1

C777:	777		; -> last word in page 1 to be cleared
CWCNT:	-177		; # of words to zero in page 1
MemEnd:	176777		; -> last word of real memory
pImgEnd: ImgEnd-D	; -> last word of page 1 image
ImgLen:	ImgEnd-Image+1	; Length of page 1 image
ImgOff:	Image-XOff-1	; Relocation offset
MarkWrd: 111111		; Mark word pattern
MarkEnd: 551		; -> last mark word
MarkCnt: -22		; Number of mark words = length of KCB+Label
p0KA:	402		; -> Label of the boot loader page
pKCB0DA: KCB0DA-D	; -> Disk address in KCB0
pDCB0:	DCB0-D		; -> DCB0
pKCB0:	KCB0-D		; -> KCB0
pKCB1:	KCB1-D		; -> KCB1
C1000:	1000
pDISP:	420		; -> Display control block list head
pDIW:	421		; -> Display vertical interrupt
pIWW:	452		; -> Interrupts waiting
pIACTW:	453		; -> Active interrupt channels
pKBLK0:	521		; -> Disk command block list head - page 0 copy
pReadIn: ReadIn-D	; -> Loader loop in page 1

; The following code is copied into Page 1 starting a location X.

X = 626

; disk control blocks

Image:
KCB0:	KCB1+X-Image	; Link to the other KCB
D = Image-X
	0		; status
	44000		; command: Read Header, Label, Data
	KCB1DA-D	; Header address -> Disk address word in KCB1
	KCB1DA-D	; Label address.  Read in on top of Header
	0		; Data address.  This moves through memory
	0		; OK interrupt bit mask. not used
	0		; Error interrupt bit mask. not used
	0		; blank
KCB0DA:	0		; Disk address for this KCB, label area for KCB1
	0		; previous disk address
	0		; blank
	0		; numChars
	0		; page number
	0		; version
	0		; serial number high
	0		; serial number low
ErrCnt:	0		; incremented for each disk error

KCB1:	KCB0-D		; Link to the other KCB
	0		; status
	44000		; command: Read Header, Label, Data
	KCB0DA-D	; Header address -> Disk address word in KCB0
	KCB0DA-D	; Label address.  Read in on top of Header
	0		; Data address.  This moves through memory
	0		; OK interrupt bit mask. not used
	0		; Error interrupt bit mask. not used
	0		; blank
KCB1DA:	0		; Disk address for this KCB, label area for KCB0
	0		; previous disk address
	0		; blank
	0		; numChars
	0		; page number
	0		; version
	0		; serial number high
	0		; serial number low
	0		; Pad to an even number of words

; Display control blocks

DCB0:	DCB1-D		; Head of a chain of 9 DCBs
	0
	0
	200		; 200 blank lines to space to center of screen

DCB1:	DCB2-D
	100006		; low resolution, 6 words/scan line
	614		; Parity error locations
	1

DCB2:	DCB3-D
	100006		; low resolution, 6 words/scan line
	530		; mark words for parity error locations
	1

DCB3:	DCB4-D
	0
	0
	10		; skip 20 scan lines

DCB4:	DCB5-D
	100022		; low resolution, 22 words/scan line
	KCB0-D		; KCB0
	1

DCB5:	DCB6-D
	100022		; low resolution, 22 words/scan line
	530		; mark words for KCB1
	1

DCB6:	DCB7-D
	0
	0
	10		; skip 20 scan lines

DCB7:	DCB8-D
	100022		; low resolution, 22 words/scan line
	KCB1-D		; KCB1
	1

DCB8:	0
	100022		; low resolution, 22 words/scan line
	530		; mark words for KCB2
	1

; Main loop of the loader.  This code runs in Page 1.
; Enter with a transfer started to read in page 0.
; Note that the next page read will go into page 2.
; On entry the ACs contain:
;	AC1/ 1000B
;	AC2/ Pointer to KCB0 (active)
;	AC3/ Pointer to KCB1 (inactive)

ReadIn:	mkzero 0 0
	sta 0 1 3	; clear the status in the inactive KCB
	lda 0 5 2	; data block address of active KCB
	add 1 0		; plus 400B  (1000B initially)
	sta 0 5 3	; yields data block address for inactive KCB

KWait:	lda 0 1 2
	snz 0 0		; wait for the command to complete
	 jmp KWait

	lda 1 ErrorMask
	and 0 1 szr	; Error?
	 jmp ReRead	; Yes. Retry the read
	lda 0 14 3	; numChars
	lda 1 FullPage
	se 0 1		; Is the page full?
	 jmp Start	; No. That was the last one.
	mov 2 0		; Exchange exchange current and inactive KCBs
	mov 3 2
	mov 0 3
	movzr 1 1	; AC1← 400B
	jmp ReadIn	; Read next page

pKBLK1:		521	; disk command block list head -- page 1 copy
pDISP1:		420	; display command block list head -- page 1 copy
ErrorMask:	367
FullPage:	1000	; bytes

; Come here to start the program.

Start:	mkzero 0 0
	sta 0 @pKBLK1	; stop the disk
	sta 0 @pDISP1
	jmp @0		; the program begins in location 0

; Come here on disk error.

ReRead:	mkzero 0 0	; Clear the status
	sta 0 1 2
	sta 2 @pKBLK1	; Restart the disk
	isz ErrCnt
	 nop
	jmp KWait	; Last word of boot loader image

ImgEnd = .-1

	.end