;THE ALTAIR 88-DSK ROM MOVES THIS CODE TO 4C00H THEN
; JUMPS TO IT. POSSIBLE ERRORS ARE:
;C  CRC ON DISK DOESN'T MATCH CALCULATED CRC
;M  MEMORY ERROR READ/BACK FROM MEMORY DOESN'T MATCH
;	WRITE TO MEMORY (NO RAM, BAD RAM, OR WPROT)
;O  OVERFLOW OR OUT OF MEM CAUSED BY TRYING TO LOAD BEYOND
;	FF00 OR BAD "LOAD LIMIT BYTES" ON DISK.


	.ORG $FF00

; RELOCATE $E6 BYTES REMAINING OF LOADER TO 4C00 (19456D)
FF00			LXI	H,$4C00
FF03			LXI	D,$FF18
FF06			MVI	C,$E6
FF08	XFF08:	LDAX	D
FF09			MOV	M,A
FF0A			INX	D
FF0B			INX	H
FF0C			DCR	C
FF0D			JNZ	XFF08
FF10			JMP	$4C00

	.ORG $4C00
4C00			DI				;DISABLE INTERRUPTS
4C01			LXI  SP,4D62	;LOAD STACK POINTER
4C04			XRA  A			;ZERO IN A
4C05			OUT  08			;SELECT DRIVE 0
4C07			MVI  A,04		;HEAD DOWN CMD
4C09			OUT  09			;SEND HEAD DOWN
4C0B			JMP  4C19		;GO TEST FOR TRACK ZERO
4C0E	TMVOK:	IN   08			;GET STATUS
4C10			ANI  02			;TEST FOR MOVE OK
4C12			JNZ  4C0E		;JMP MOVE NOT OK
4C15			MVI  A,02		;STEP OUT CMD
4C17			OUT  09			;SEND STEP OUT
4C19	TTRK0:	IN   08			;GET STATUS
4C1B			ANI  40			;TEST FOR TRACK ZERO
4C1D			JNZ  4C0E		;JMP NOT TRACK ZERO
4C20			LXI  D,0000		;DE->0000H
4C23	NXTTK:	MVI  B,00		;B=0
4C25	THDDN:	IN   08			;GET STATUS
4C27			ANI  04			;TEST FOR HEAD DOWN
4C29			JNZ  4C25		;JMP NOT HEAD DOWN

;SEEK TO SECTOR IN B
4C2C	NXTSEC:	MVI  A,10		;A=10H 16D RETRY COUNT
4C2E	RETRY:	PUSH PSW  		;SAVE RETRY COUNT
4C2F			PUSH D			;NXTMEM
4C30			PUSH B			;B=SECTOR
4C31			PUSH D			;NXTMEM
4C32			LXI  D,8086		;D=80(UNUSED?) E=128=COUNT
4C35			LXI  H,4CD4		;M=POINTER TO INBUFFER
4C38	TSECT:	IN   09			;GET SECTOR# UNDER HEAD AND STATUS
4C3A			RAR  			;TEST SECTOR TRUE
4C3B			JC   4C38		;JMP TSECT IF NOT TRUE
4C3E			ANI  1F			;AND SECTOR MASK 31D
4C40			CMP  B			;DESIRED SECTOR
4C41			JNZ  4C38		;JMP TSECT IF NOT EQUAL

;READ 134 BYTES TWO AT A TIME INTO INBUFFER
4C44	TRDOK:	IN   08			;GET STATUS
4C46			ORA  A			;SET FLAGS TEST FOR READ OK
4C47			JM   4C44		;JMP TRDOK IF NOT READ OK
4C4A			IN   0A			;GET DATA BYTE1
4C4C			MOV  M,A		;MOVE BYTE TO INBUFF
4C4D			INX  H			;BUMP INPOINTER
4C4E			DCR  E			;DECREMENT COUNT
4C4F			JZ   4C5A		;JMP MVBYTS IF DONE
4C52			DCR  E			;DEC COUNT
4C53			IN   0A			;GET DATA BYTE2
4C55			MOV  M,A		;MOVE TO INBUFF
4C56			INX  H			;INCREMENT POINTER
4C57			JNZ  4C44		;JMP TRDOK IF COUNT IN E IS NOT ZERO

;MOVE 128 DATA BYTES FROM BUFF TO MEMORY MAKE A CRC
4C5A	MVBYTS:	POP  H			;HL (M)=0000H FIRST TIME
4C5B			LXI  D,4CD7		;DE POINTS TO BUFFER + 3
4C5E			LXI  B,0080		;B=0=CRC C=128 COUNT
4C61	MVBYT2:	LDAX D			;GET BYTE FROM BUFFER
4C62			MOV  M,A		;MOVE TO DESTINATION 
4C63			CMP  M			;CHECK FOR MEMORY PROBLEM
4C64			JNZ  4CC1		;JMP MERROR IF PROBLEM
4C67			ADD  B			;MAKE A CRC
4C68			MOV  B,A		;SAVE IN B
4C69			INX  D			;INC SRC
4C6A			INX  H			;INC DEST
4C6B			DCR  C			;DEC COUNT
4C6C			JNZ  4C61		;JMP MVBYT2 UNTIL COUNT = 0
;CHECK CRC
4C6F			LDAX D			;DE POINTS TO BUFFER + 131
4C70			CPI  FF			;COMPARE THAT BYTE TO 255
4C72			JNZ  4C78		;JMP FFERR IF NOT EQUAL
4C75			INX  D			;INC DE POINTS TO BUFF+132
4C76			LDAX D			;GET THAT BYTE
4C77			CMP  B			;COMPARE TO CRC
4C78	FFERR:	POP  B			;B=SECTOR
4C79			XCHG 			;DE->NEXT DEST   HL->BUFF+132
4C7A			JNZ  4CB5		;CRC ERROR GO CRCERR

;CHECK FOR OUT OF MEMORY  CHECK DONE LOADING
4C7D			POP  PSW		;0000H FIRST TIME
4C7E			POP  PSW		;ACC=16
4C7F			LHLD 4CD5		;L=BUFF+1 H=BUFF+2
4C82			PUSH D			;SAVE NEXT DEST  0080 FIRST TIME
4C83			LXI  D,FF00		;DE->BOOTROM(END OF MEMORY)
4C86			CALL 4CCE		;COMPARE1 FF00H,HL OUT OF MEMORY (HL GREATER 
THAN FF00H)  
4C89			POP  D			;  NEXT DEST
4C8A			JC   4CBE		;JMP 'O'UT OF RAM ERROR (HL GREATER THAN FFOOH)
4C8D			CALL 4CCE		;COMPARE2 DE,HL ARE WE DONE LOADING?
4C90			JNC  4CAE		;IF NO CARRY (HL <= NEXT DEST)WE'RE DONE GO 
EXECUTE

;CALCULATE NEXT SECTOR AND TRACK 
4C93			INR  B			;ADD 2 TO SECTOR#
4C94			INR  B			;
4C95			MOV  A,B		;DESIRED NEXT SECTORA
4C96			CPI  20			;TEST IF SECTORA LESS THAN 32
4C98			JC   4C2C		;IF LESS GO GET IT
4C9B			MVI  B,01		;  IF NOT LESS MAKE DESIRED SECTORB=1		
4C9D			JZ   4C2C		;IF SECTORA EQUALED 32 GO GET SECTORB=1 
4CA0 LOOP7:		IN   08			;ELSE GET STATUS
4CA2			ANI  02			;TEST MOVE OK
4CA4			JNZ  4CA0		;UNTIL MOVE IS OK
4CA7			MVI  A,01		;STEP IN CMD
4CA9			OUT  09			;SEND STEP IN CMD
4CAB			JMP  4C23		;START LOADING FROM NEXT TRACK SECTORB=0

;LOAD THE EVEN SECTORS ON A TRACK FIRST
;THEN THE ODD SECTORS

;DONE
4CAE EXIT1:		MVI  A,80		;
4CB0			OUT  08			;CLEAR CONTROLLER
4CB2			JMP  0000		;GO

;CRC ERROR RETRY PSW TIMES
4CB5	CRCERR:	POP  D
4CB6			POP  PSW		;  
4CB7			DCR  A			;DECREMENT RETRY COUNT
4CB8			JNZ  4C2E		;IF NOT 0 GO RETRY

;CLEAR CONTROLLER  SEND TO CONSOLE ERROR MESSAGE 
4CBB			MVI  A,43		;ELSE LOAD A WITH CHAR 'C'RC ERROR
4CBD			.DB  $01
;4CBD  			LXI  B,4F3E		;GARBAGE - SKIP TRICK BD-BF
4CBE OERROR:	MVI  A,4F		;	LOAD A WITH CHAR 'O'VERFLOW
4CC0			.DB  $01
;4CC0			LXI  B,4D3E		;GARBAGE - SKIP TRICK C0-C2
4CC1 MERROR:	MVI  A,4D		;	LOAD A WITH CHAR 'M'EMORY ERROR
4CC3			MOV  B,A		;SAVE CHAR
4CC4			MVI  A,80		;CLEAR CONTROLLER
4CC6			OUT  08			;SEND CLEAR
4CC8			MOV  A,B		;GET CHAR

4CC9 CONOUT:	OUT  01			;SEND ERROR CHAR TO CONSOLE
4CCB			JMP  CONOUT	 	;OVER AND OVER AND OVER...

;TEST FOR OVERFLOW, TEST LOAD LIMIT, COMPARE HL,DE
4CCE SUB1:		MOV  A,D		;		
4CCF			CMP  H			;
4CD0			RNZ				;  
4CD1			MOV  A,E		;
4CD2			CMP  L			;
4CD3			RET

;BEGINNING OF IN BUFFER  
;4CD4
VAR1:	.DB $84				;ADD	H
;4CD5
VAR2:	.DB 0				;NOP
		.DB $4C				;MOV	C,H
;4CD7
VAR3:	.DB $24				;INR	H
		.DB $D6, $56		;SUI	$56
		.DB $16, 0			;MVI	D,0
		NOP					; DATA TRUNCATED
