;  CP/NET LOADER  FOR CP/NET VER. 1.0
;
;  1982.8.6. BASE
;
TITLE	CP/NET LOADER VER.1.0
;
;  EQUATIONS OF DATA
;
LF	EQU	0AH		;LINE FEED
CR	EQU	0DH		;CARRIAGE RETURN
;
TOP	EQU	0		;MEMORY TOP
BDOS	EQU	5		;BDOS ENTRY
RESFCB	EQU	5CH		;RESIDENT FCB
SCTLNG	EQU	128		;SECTOR LENGTH
;
;  EQUATIONS OF BDOS FUNCTION
;
CRESET	EQU	0		;SYSTEM RESET
CCONOT	EQU	2		;CONSOLE OUT
CBUFPR	EQU	9		;BUFFERED STRING PRINT
CGETVR	EQU	12		;GET VERSION NUMBER
COPEN	EQU	15		;OPEN FILE
CREAD	EQU	20		;READ FILE
CSTDMA	EQU	26		;SET DMA ADDRESS
;
;  START
;
	JMP	START
;
;  BREAK POINT RESTART NUMBER FOR DEBUG
;
BPNUM:	DB	7
;
;  COMMENTS
;
	DB	'COPYRIGHT (C) 1980,'
;
PUSRID:	DB	' DIGITAL RESEARCH '	;USER ID IS SEARCHED BY THIS STRING
;
;  USER ID CODE
;
	DB	0,0,0,0,0,0
;
CDSKER:	DB	'Disk read error$'
;
PDEBBP:	DW	DEBBP		;POINTER OF DEBUGGER BREAK POINT ROUTINE
;
CSYNC:	DB	'Synchronization$'
CARLOD:	DB	CR,LF,'CP/Net is already loaded.$'
CSTUP:	DB	CR,LF,LF,'CP/NET 1.0 Loader'
	DB	CR,LF,'=================',CR,LF,LF,'$'
;
CBIOS:	DB	'BIOS       $'
CBDOS:	DB	'BDOS       $'
CSNIOS:	DB	'SNIOS   SPR$'
CNDOS:	DB	'NDOS    SPR$'
CTPA:	DB	'TPA        $'
;
CLEND:	DB	'CP/NET 1.0 loading complete.$'
CLERR:	DB	CR,LF,'CP/NET Loader error: $'
;
;  START OF MAIN
;
	LXI	SP,PFLNAM
START:
	LXI	H,STACK
	SPHL			;SET STACK POINTER
	LXI	D,0
	MVI	C,CGETVR	;GET VERSION NUMBER
	CALL	BDOS
	LXI	D,200H
	CALL	ANHLDE		;GET CP/NET MODE
	MVI	A,0
	CALL	SUBYHL		;CHECK ZERO
	ORA	L
	JZ	STARTS		;CP/NET IS NOT LOADED OK
	LXI	B,CARLOD	;CP/NET ALREADY LOADED
	CALL	BUFPRN
	LXI	D,0
	MVI	C,CRESET
	CALL	BDOS		;RETURN TO SYSTEM
;
STARTS:
	LHLD	BDOSPT		;GET POINT OF BDOS POINTER
	LXI	D,0FF00H
	CALL	ANHMDE		;OFF LOWER BYTE
	SHLD	FREBOT		;SAVE AVAILABLE AREA TOP
	LDA	RESFCB+1	;GET DEBUG MODE
	STA	FDEBUG
	LXI	B,CSTUP
	CALL	BUFPRN		;START UP COMMENT
;
	LXI	B,CBIOS		;BIOS
	CALL	BUFPRN
	LXI	H,TOP+1
	SHLD	BDOSPT		;SET POINTER OF BIOS ROUTINE POINTER
	LHLD	BDOSPT
	MOV	C,M
	INX	H
	MOV	B,M		;GET BIOS POINT
	DCX	B
	DCX	B
	DCX	B
	CALL	LOCPR		;PRINT BIOS TOP
	LHLD	BDOSPT
	LXI	D,-1
	CALL	SUDEHM		;GET COMPLEMET OF BIOS POINT VALUE
	LXI	D,4		;GET BIAS
	DAD	D
	MOV	B,H
	MOV	C,L
	CALL	LOCPR		;PRINT BIOS LENGTH
	CALL	CRLF
;
	LXI	B,CBDOS		;BDOS
	CALL	BUFPRN
	LHLD	FREBOT		;GET BDOS TOP
	MOV	B,H
	MOV	C,L
	CALL	LOCPR		;PRINT BDOS TOP
	LHLD	BDOSPT
	MOV	C,M
	INX	H
	MOV	B,M
	DCX	B
	DCX	B
	DCX	B		;BIOS TOP
	MOV	D,B
	MOV	E,C
	LHLD	FREBOT
	CALL	SUDEHL		;GET BDOS LENGTH
	MOV	B,H
	MOV	C,L
	CALL	LOCPR		;PRINT BDOS LENGTH
	CALL	CRLF
;
	LXI	H,CSNIOS	;SNIOS.SPR
	SHLD	PFLNAM		;SET FILE NAME POINT FOR ERROR ROUTINE
	MOV	B,H
	MOV	C,L
	CALL	BUFPRN
	LHLD	FREBOT		;GET LOADING POINT
	MOV	B,H
	MOV	C,L
	LXI	D,FSNIOS	;FCB POINT OF SNIOS.SPR
	CALL	LOAD		;LOAD SNIOS.SPR
	SHLD	TOPPNT		;SAVE SNIOS TOP
	LXI	D,-1
	CALL	SUDEHL		;CHECK ERROR
	ORA	L
	JNZ	$+6		;NOT ERROR
	JMP	ERROR		;SNIOS.SPR LOAD ERROR
;
	LHLD	TOPPNT
	MOV	B,H
	MOV	C,L
	CALL	LOCPR		;PRINT SNIOS TOP
	LXI	B,TOPPNT
	LXI	D,FREBOT
	CALL	SUDMBM		;GET SNIOS LENGTH
	MOV	B,H
	MOV	C,L
	CALL	LOCPR		;PRINT SNIOS LENGTH
	CALL	CRLF
	LHLD	TOPPNT		;SET SNIOS TOP AS THE BOTTOM OF NDOS
	SHLD	FREBOT
;
	LXI	H,CNDOS		;NDOS.SPR
	SHLD	PFLNAM
	MOV	B,H
	MOV	C,L
	CALL	BUFPRN
	LHLD	FREBOT		;GET LOADING POINT
	MOV	B,H
	MOV	C,L
	LXI	D,FNDOS		;GET FCB POINT
	CALL	LOAD		;LOAD NDOS.SPR
	SHLD	TOPPNT
	LXI	D,-1
	CALL	SUDEHL		;CHECK LOAD ERROR
	ORA	L
	JNZ	$+6		;NOT ERROR
	JMP	ERROR		;NDOS.SPR LOADING ERROR
;
	LHLD	TOPPNT
	MOV	B,H
	MOV	C,L
	CALL	LOCPR		;PRINT NDOS TOP
	LXI	B,TOPPNT
	LXI	D,FREBOT
	CALL	SUDMBM		;GET LENGTH
	MOV	B,H
	MOV	C,L
	CALL	LOCPR		;PRINT LENGTH
	CALL	CRLF
	LHLD	TOPPNT
	INX	H
	INX	H
	INX	H
	SHLD	PNDOSC		;SAVE NDOS COLD START ROUTINE POINTER
;
	LXI	B,CTPA		;TPA
	CALL	BUFPRN
	LXI	B,TOP
	CALL	LOCPR		;TOP OF TPA
	LHLD	TOPPNT
	MOV	B,H
	MOV	C,L
	CALL	LOCPR		;LENGTH IS NDOS TOP
	CALL	CRLF
	LHLD	PNDOSC
	INX	H
	INX	H
	INX	H
	XCHG
	LXI	B,PUSRID
	CALL	CHKUSC		;CHECK USER ID CODE
	CALL	CRLF
	LXI	B,CLEND
	CALL	BUFPRN		;PRINT LOADING END COMMENT
	CALL	CRLF
	CALL	GOTDOS		;TO NDOS OR BREAK
;
;  ERROR ROUTINE
;
ERROR:
	LXI	SP,PFLNAM
	LXI	B,CLERR
	CALL	BUFPRN		;LOADER ERROR
	LHLD	PFLNAM		;GET ERROR DATA COMMENT POINT
	MOV	B,H
	MOV	C,L
	CALL	BUFPRN		;PRINT ERROR DATA
ERSTOP:
	MVI	A,-1
	RAR
	JNC	ERSTOS
	LXI	H,TOP
	SPHL
	DI
	EI
	HLT
	JMP	ERSTOP
;
ERSTOS:
	EI
	HLT
;
;  CONSOLE OUT
;  INPUT
;   C:DATA
;
CONOT:
	LXI	H,WCONOT
	MOV	M,C
	LHLD	WCONOT
	MVI	H,0
	XCHG
	MVI	C,002H
	CALL	BDOS
	RET
;
;  BUFFER PRINT
;  INPUT
;  BC:STRING POINT
;
BUFPRN:
	LXI	H,WBUFPR+1
	MOV	M,B
	DCX	H
	MOV	M,C		;SAVE PARAMETER
	LHLD	WBUFPR
	XCHG
	MVI	C,CBUFPR
	CALL	BDOS
	RET
;
;  OPEN FILE			NOT USED
;  INPUT
;  BC:FCB POINT
;
	LXI	H,WOPEN+1
	MOV	M,B
	DCX	H
	MOV	M,C
	LHLD	WOPEN
	XCHG
	MVI	C,COPEN
	CALL	BDOS
	RET
;
;  READ SEQUENTIAL		NOT USED
;  INPUT
;  BC:FCB POINT
;
	LXI	H,WREAD+1
	MOV	M,B
	DCX	H
	MOV	M,C
	LHLD	WREAD
	XCHG
	MVI	C,CREAD
	CALL	BDOS
	RET
;
;  SET DMA ADDRESS		NOT USED
;  INPUT
;  BC:DMA ADDRESS
;
	LXI	H,WSRDMA+1
	MOV	M,B
	DCX	H
	MOV	M,C
	LHLD	WSRDMA
	XCHG
	MVI	C,CSTDMA
	CALL	BDOS
	RET
;
;  CARRIAGE RETURN & LINE FEED
;
CRLF:
	MVI	C,CR
	CALL	CONOT
	MVI	C,LF
	CALL	CONOT
	RET
;
;  PRINT NIBBLE BY HEXADECIMAL
;  INPUT
;   C:DATA
;
NIBBLE:
	LXI	H,WNIBLE
	MOV	M,C
	MVI	A,9
	LXI	H,WNIBLE
	CMP	M
	JNC	NIBBLS		;0 TO 9
	LDA	WNIBLE		;A TO F
	ADI	'A'
	SUI	10
	MOV	C,A
	CALL	CONOT
	JMP	NIBBEN
;
NIBBLS:				;0 TO 9
	LDA	WNIBLE
	ADI	'0'
	MOV	C,A
	CALL	CONOT
NIBBEN:
	RET
;
;  PRINT BYTE DATA BY HEXADECIMAL
;  INPUT
;   C:DATA
;
HXPRN:
	LXI	H,WHXPRN
	MOV	M,C
	LDA	WHXPRN
	ANI	0F8H
	RAR
	RAR
	RAR
	RAR
	MOV	C,A
	CALL	NIBBLE		;PRINT HIGHER NIBBLE
	LDA	WHXPRN
	ANI	00FH
	MOV	C,A
	CALL	NIBBLE		;PRINT LOWER NIBBLE
	RET
;
;  PRINT WORD DATA
;  INPUT
;  BC:DATA
;
LOCPR:
	LXI	H,WLOCPR+1
	MOV	M,B
	DCX	H
	MOV	M,C		;SAVE DATA
	MVI	C,' '
	CALL	CONOT
	MVI	C,' '
	CALL	CONOT		;PRINT SPACE
	LHLD	WLOCPR
	MOV	A,H
	MOV	C,A
	CALL	HXPRN		;HIGHER BYTE
	LHLD	WLOCPR
	MOV	A,L
	MOV	C,A
	CALL	HXPRN		;LOWER BYTE
	MVI	C,'H'
	CALL	CONOT
	RET
;
;  CHECK USER ID CODE
;  INPUT
;  DE:NDOS ENTRY
;  BC:ID CODE AREA
;
CHKUSC:
	LXI	H,PNDOS+1
	MOV	M,D
	DCX	H
	MOV	M,E		;SAVE NDOS ENTRY POINT
	DCX	H
	MOV	M,B
	DCX	H
	MOV	M,C		;SAVE ID CODE AREA
CHKUSN:				;ONE DATA POINT LOOP
	MVI	A,-1
	RAR
	JNC	CHKUSE		;END (NOT USED)
	LXI	H,CNTLDR
	MVI	M,-1
	INX	H
	MVI	M,-1		;INITIALIZE SEARCH COUNT
CHKUSL:				;CHARACTER CHECK LOOP
	LDA	CNTLDR
	INR	A
	STA	CNTLDR		;LOADER POINTER COUNT UP
	MOV	C,A
	MVI	B,0
	LHLD	PIDCOD		;GET ID CODE AREA
	DAD	B		;GET DATA POINT
	LDA	CNTNDS
	INR	A
	STA	CNTNDS		;NDOS POINTER COUNT UP
	MOV	C,A
	MVI	B,0
	PUSH	H
	LHLD	PNDOS
	DAD	B		;GET NDOS DATA POINT
	POP	B
	LDAX	B
	CMP	M		;COMPARE CODE
	JNZ	$+6		;NOT MATCH
	JMP	CHKUSL		;TO NEXT CHARACTER
;
	MVI	A,23		;CHECK LENGTH  NAME & USER ID TOTAL LENGTH
	LXI	H,CNTLDR
	CMP	M
	JNC	$+4		;NOT OK
	RET			;OK MATCH CODE
;
	MVI	A,0		;CHECK END OF COMPARE
	LXI	D,PNDOS
	CALL	SUDMBY
	ORA	L
	SUI	001H
	SBB	A		;CHECK END OF MEMORY
	XCHG
	PUSH	PSW
	MVI	A,17		;NAME LENGTH -1
	INX	H
	SUB	M
	SBB	A		;CHECK NAME MATCH
	POP	B
	MOV	C,B
	ORA	C
	RAR
	JNC	CHKNXT		;NOT END TO NEXT
	LXI	H,CSYNC		;COMPARE FAIL
	SHLD	PFLNAM		;SYNCHRONIZATION ERROR
	JMP	ERROR
;
CHKNXT:				;CHECK NEXT ADDRESS
	LHLD	PNDOS
	INX	H		;UP START ADDRESS
	SHLD	PNDOS
	JMP	CHKUSN		;CHECK AGAIN
;
CHKUSE:				;END DUMMY
	RET
;
;  BREAK POINT FOR DEBUGGER
;
DEBBP:
	DI			;RESTART INSTRUCTION IS SET HERE
	RET
;
;  GOTO COLD BOOT OF NDOS
;
GOTDOS:
	LXI	H,PNDOSC
	SPHL			;SET STACK TO ENTRY POINT SAVE AREA
	DCX	H
	MOV	A,M
	CPI	'B'
	JNZ	GOTDOE		;NOT BREAK
	LDA	BPNUM		;BREAK, SO GET RESTART NUMBER
	ADD	A
	ADD	A
	ADD	A
	ORI	0C7H		;MAKE RESTART CODE
	LHLD	PDEBBP
	MOV	M,A		;SAVE RESTART CODE
	CALL	DEBBP		;TO BREAK ROUTINE
GOTDOE:				;TO NDOS COLD START ROUTINE
	RET
;
;  LOAD ONE FILE
;  INPUT
;  BC:BOTTOM OF FREE AREA
;  DE:FCB
;  OUTPUT
;  HL:TOP OF PROGRAM  -1 ERROR
;
LOAD:
	MOV	H,B
	MOV	L,C
	SHLD	LDBOTM		;SAVE BOTTOM
	XCHG
	SHLD	LDFCB		;SAVE FCB POINT
	MVI	C,CSTDMA
	LXI	H,-SCTLNG	;SUBTRUCT ONE SECTOR LENGTH
	DAD	D
	SHLD	LDDMA		;SAVE DMA POINT FOR PARAMETER READ
	XCHG
	CALL	BDOS		;SET DMA ADDRESS TO SCRATCH AREA
	LHLD	LDFCB
	XCHG
	MVI	C,COPEN
	CALL	BDOS		;OPEN FILE
	CPI	-1
	MOV	H,A
	MOV	L,A
	RZ			;OPEN ERROR (NOT FOUND)
	CALL	OSREAD		;GET PARAMETER SECTOR
	LHLD	LDDMA
	INX	H
	MOV	E,M
	INX	H
	MOV	D,M		;GET CODE AREA LENGTH
	INX	H
	INX	H
	MOV	C,M
	INX	H
	MOV	B,M		;GET DATA AREA LENGTH
	XCHG
	SHLD	LDLNGT		;SAVE CODE AREA LENGTH
	DAD	B		;GET TOTAL LENGTH
	XCHG
	LHLD	LDBOTM		;GET BOTTOM
	XCHG
	XRA	A
	SUB	L
	MOV	L,A
	MVI	A,0
	SBB	H
	MOV	H,A
	DAD	D		;SUBTRUCT LENGTH FROM BOTTOM POINT
	MVI	L,0		;GET LOADING TOP
	SHLD	LDTOP		;SAVE LOADING TOP (PROGRAM TOP)
	XCHG
	LXI	H,-SCTLNG
	DAD	D		;SUBTRUCT ONE SECTOR LENGTH
	SHLD	LDDMA		;SET RELOCATION DATA BUFFER TOP
	CALL	OSREAD		;GET DATA & IGNORE
	LHLD	LDLNGT
	LXI	D,SCTLNG-1
	DAD	D		;ADJUST BOUNDARY
	MOV	A,L
	RAL
	MOV	A,H
	RAL			;GET SECTOR COUNT OF CODE AREA
	LHLD	LDTOP		;GET LOADING TOP
LOADLP:				;ONE SECTOR LOADING LOOP
	STA	LDCNT		;SAVE COUNT
	SHLD	LDPNT		;SAVE LOADING POINT
	XCHG
	MVI	C,CSTDMA
	CALL	BDOS		;SET DMA ADDRESS
	CALL	OSREAD		;READ ONE SECTOR DATA
	LHLD	LDPNT
	LXI	D,SCTLNG	;ONE SECTOR LENGTH
	DAD	D		;GET NEXT DMA ADDRESS
	LDA	LDCNT
	DCR	A		;SECTOR COUNT DOWN
	JNZ	LOADLP		;TO NEXT SECTOR
	LHLD	LDDMA		;GET BUFFER POINT FOR RELOCATION DATA
	XCHG
	MVI	C,CSTDMA
	CALL	BDOS		;SET TO RELOCATION BUFFER POINT
	LHLD	LDLNGT		;GET LENGTH TO GET RELOCATION DATA TOP
	MOV	B,H
	MOV	C,L
	XCHG
	LHLD	LDTOP		;CODE TOP
	XCHG
	DAD	D		;GET TOP OF RELOCATION DATA
	PUSH	H		;SAVE RELOCATION DATA POINT
	MOV	H,D		;SET RELOCATION BIAS
LOADRL:				;RELOCATION LOOP
	MOV	A,B
	ORA	C
	JNZ	$+8		;NOT TO END
	POP	H		;END OF RELOCATION
	LHLD	LDTOP		;TOP OF PROGRAM
	RET			;END OF LOADING
;
	DCX	B
	MOV	A,E
	ANI	07H
	JNZ	LOADRB		;NOT BYTE BOUNDARY
	XTHL			;BYTE BOUNDARY,  GET DATA POINT
	MOV	A,L
	ANI	07FH
	JNZ	LOADRS		;NOT SECTOR BOUNDARY
	PUSH	B
	PUSH	D
	PUSH	H
	LHLD	LDFCB		;GET FCB POINT
	XCHG
	MVI	C,CREAD
	CALL	BDOS		;GET ONE SECTOR DATA
	POP	H
	POP	D
	POP	B
	LHLD	LDDMA		;GET DATA TOP POINT
	ORA	A
	JNZ	OSRDER		;NO DATA, SO ERROR
LOADRS:
	MOV	A,M		;GET NEXT RELOCATION DATA
	INX	H
	XTHL
	MOV	L,A
LOADRB:
	MOV	A,L
	RAL			;GET ONE BIT DATA
	MOV	L,A
	JNC	$+6		;NOT RELOCATE
	LDAX	D		;RELOCATE
	ADD	H
	STAX	D
	INX	D
	JMP	LOADRL		;TO NEXT DATA
;
;  READ ONE SECTOR DATA
;
OSREAD:
	LHLD	LDFCB		;GET FCB
	XCHG
	MVI	C,CREAD
	CALL	BDOS		;READ ONE SECTOR
	ORA	A
	RZ			;NOT ERROR
OSRDER:				;NO DATA, SO ERROR
	POP	H		;OVERRIDING RETURN
	LXI	H,-1
	RET
;
;  LOADING ROUTINE WORKING
;
LDDMA:	DS	2		;DMA ADDRESS
LDLNGT:	DS	2		;CODE AREA LENGTH
LDFCB:	DS	2		;FCB POINTER
LDBOTM:	DS	2		;BOTTOM POINT OF FREE AREA
LDTOP:	DS	2		;TOP POINT OF PROGRAM
LDCNT:	DS	1		;LOAD SECTOR COUNT
LDPNT:	DS	2		;LOADING POINTER
;
;  AND ROUTINES
;  HL=HL AND A
;  HL=HL AND DE
;
	MOV	E,A
	MVI	D,0
ANHLDE:
	MOV	A,E
	ANA	L
	MOV	L,A
	MOV	A,D
	ANA	H
	MOV	H,A
	RET
;
;  HL=(DE) AND A
;  HL=(HL) AND DE
;
	XCHG
	MOV	E,A
	MVI	D,0
ANHMDE:
	XCHG
	LDAX	D
	ANA	L
	MOV	L,A
	INX	D
	LDAX	D
	ANA	H
	MOV	H,A
	RET
;
;  SUBTRUCT ROUTINES
;  HL=A - HL
;  HL=DE - HL
;
SUBYHL:
	MOV	E,A
	MVI	D,0
SUDEHL:
	MOV	A,E
	SUB	L
	MOV	L,A
	MOV	A,D
	SBB	H
	MOV	H,A
	RET
;
;  HL=(DE) - (BC)
;
SUDMBM:
	MOV	L,C
	MOV	H,B
	MOV	C,M
	INX	H
	MOV	B,M
	LDAX	D
	SUB	C
	MOV	L,A
	INX	D
	LDAX	D
	SBB	B
	MOV	H,A
	RET
;
;  HL=(DE) - A
;
SUDMBY:
	MOV	L,A
	MVI	H,000H
	LDAX	D
	SUB	L
	MOV	L,A
	INX	D
	LDAX	D
	SBB	H
	MOV	H,A
	RET
;
;  HL=A - (HL)
;  HL=DE - (HL)
;
	MOV	E,A
	MVI	D,000H
SUDEHM:
	MOV	A,E
	SUB	M
	MOV	E,A
	MOV	A,D
	INX	H
	SBB	M
	MOV	D,A
	XCHG
	RET
;
;  WORKING
;
PFLNAM:	DW	CDSKER		;LOAD ERROR COMMENT POINTER
WCONOT:	DB	0		;WORK FOR CONSOLE OUT
WBUFPR:	DW	0		;WORK FOR BUFFER PRINT
WOPEN:	DW	0		;WORK FOR OPEN FILE
WREAD:	DW	0		;WORK FOR READ SEQUENTIAL
WSRDMA:	DW	0		;WORK FOR SET DMA
WNIBLE:	DB	0		;NIBBLE OUT WORKING
WHXPRN:	DB	0		;HEXA PRINT WORKING
WLOCPR:	DW	0		;WORK FOR WORD PRINT
;
;  FOR ID CODE CHECK
;
PIDCOD:	DW	0
PNDOS:	DW	0
CNTLDR:	DB	0
CNTNDS:	DB	0
;
;
	DS	60		;STACK AREA
STACK:
;
BDOSPT:	DW	BDOS+1		;POINTER DATA FOR DOS
	DW	0
FREBOT:	DW	0
TOPPNT:	DW	0
;
	DS	9
;
;  LOADING FILE FCB
;
FNDOS:				;FOR NDOS.SPR
	DB	0,'NDOS    SPR'
	DB	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
FSNIOS:				;FOR SNIOS.SPR
	DB	0,'SNIOS   SPR'
	DB	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;
FDEBUG:	DS	1
PNDOSC:	DS	2
;
;
	END
