.title	'Display local hard disk partitions'
	.ident	DIRHRD
version ==	2
revision==	5
patch	==	' '
	.pabs
	.phex
	.loc	100h
;
; Revision	Les Wilson
; 07/15/82	now handles multiple volumes
;
; Revision	Les Wilson
; 08/04/82	expects return from select command
;		to hdc firmware
;
;
; Revision 4:	Clean up code.	Dirhard returns to the
; 12/01/82	user with disk assignments scrambled.
;		Fixed this problem.  DRB
;
; Revision 5:	Clean code more.  Reads now done via	
; 01/05/83	BIOS.  Works for Fox hard disks.
;		Doesn't warmboot after printing one
;		volume as it used to.	       DSB
;
.insert volinfo
;
WBOOT	==	0
WBaddr	==	01h	; Warm boot location
BDOS	==	5
conslout==	2	; CPM 2, Console Output
alloctab==	4000h	; addr of alloc table
usernum ==	47h	; assigned user number loc
cr	==	0Dh	; Ascii carriage return
lf	==	0Ah	; Ascii line feed
true	==	0ffh
false	==	0
HDbyt	==	40h	; device type, regular
FoxHDbyt==	0C0h	; device type, hard Fox

.page
.sbttl	'Read in volume info'
;
	lxi	SP,stack; use our own SP
	lxi	H,LOGmsg ; Print a greeting
	call	prtmsg
	lda	usernum
	ora	A	; don't use if net master
	jrnz	..ok	
	lxi	H,MASTmsg
	call	prtmsg
	jmpr	exit
;
; Read in the hard disk status and print tables
; for each volume which is present
;
..ok:
	lxi	b,statbuf
	call	HDstat
	mvi	a,0
	sta	volnum
volloop:
	call	doVOL
	lda	volnum
	inr	a
	sta	volnum
	cpi	4
	jrnz	volloop ;all 4 volumes done, fall thru
;
exit:	lda	4
	mov	C,A
	call	SELDSK	; restore disk selection
	jmp	WBOOT	 

;--------------------------------
; Do all necessary stuff to get & print one volume's
;  list of partitions.
;
doVOL:
	call	setvolptr
	mov	a,vlipresent(x)
	cpi	true
	rnz		      
	lxi	h,volmsg ;tell them name and # of vol
	call	prtmsg
	lda	volnum
	call	prtbyt
	call	prtvol
	call	gettabl
	call	prttabl
	ret
;--------------------------------
; refuse to continue
;
HDdead: lxi	H,deadMSG
	call	prtmsg
	jmpr	exit
.page
.sbttl	'Read in Alloc table'
gettabl:
	call	chaMAPbyt
	call	readTABL
	call	resMAPbyt
	ret
prtTABL:
	mvi	A,1
	sta	unit	; re-initialize counter
	lxi	H,crlf
	call	prtmsg	; and space down.
..1:	lxi	H,alloctab ; HL = addr of table
	mvi	B,16	; B = bytes per line
	lda	unit	; A = line to find
	call	ADDRfind ; HL returns with addr
	call	prtline ; Print a line in table
	jrc	..ret	; return if carry flag set
	lda	unit	; ELSE, cont with next entry
	adi	3	; increment three lines
	sta	unit
	cpi	63	; 63 partitions checked
	jrc	..1	; No.  Loop back.
..ret:	lxi	H,crlf	; Yes.
	call	prtmsg	
	lxi	H,crlf	;space 2 lines and
	call	prtmsg	;exit
	ret		 
.page
.sbttl	'Subroutines'
;---------------
;Subroutine:	prtline
; Regs	in:	HL=addr in the name/pass  table
; Regs out:	HL=next addr in the name/pass  table
;Destroyed:	A,B,C
;Used by prtTABL to print one line of the alloc table.
;Halt print out if a console chr is found.
;Resume print out when 2nd console chr is found.
prtline:
	push	H	; save name/pass  table address
	call	CONSTAT ; is console chr ready
	jrnc	..4	; NO.
	call	CONIN	; eat the chr
..3:	call	CONSTAT ; is 2nd console chr ready
	jrnc	..3	; wait for it
	call	CONIN	; eat the chr, and proceed
;
; Test the first byte in each line of the table.
; Halt print and return immediately if the size is 0.
; Check the first of three entries.
;
..4:	pop	H	; restore name/pass  tabl addr
	mov	A,M	; get the size
	sta	size	; store the size
	cpi	0	; Entry on this line
	stc		; Set carry in case
	rz		; No. Return
	push	H	;Table line is ok.  Print it
	lxi	H,crlf	; space down a line
	call	prtmsg
	lxi	H,space3
	call	prtmsg	; and space over 3.
	pop	H	; HL = size byte addr
	inx	H	; HL = 8 chr name addr
	mvi	B,8
	call	prtchr	; print 8 chr name
	call	prtSIZ	; print the size
	lxi	D,8	; move to next line
	dad	D
	mov	A,M	; get size
	cpi	0	; Is it 0
	stc		; Set carry in case
	rz		; Yes. Return
	inx	H	; No. Get to name addr
	sta	size	; and store the size
	push	H	;Table line is ok.  Print it
	lxi	H,space6 ; space over 4 spaces
	call	prtmsg
	pop	H
	mvi	B,8
	call	prtchr	; print 8 chr name
	call	prtSIZ
.page
	lxi	D,8
	dad	D
	mov	A,M	; get size
	cpi	0	; Is it 0
	stc		; Set carry in case
	rz		; Yes. Return
	inx	H	; No. Get to name addr
	sta	size	; and store the size
	push	H	;Table line is ok.  Print it
	lxi	H,space6 ; space over 4 spaces
	call	prtmsg
	pop	H
	mvi	B,8
	call	prtchr	; print 8 chr name
	call	prtSIZ	; print the size
	inx	H	; No. Get to name addr
	ora	A	; No. Reset carry flag
	ret		; and return.
.page
;--------------
; Subroutine prtSIZ:  Print size of current entry 
;
; Regs in:	none
; Regs out:	none
; Destroyed	A
;
prtSIZ:
	push	H	; save currnt tabl addr
	lda	size	; get the entry size
	lxi	H,msg256K
	cpi	1	; is size 1
	cz	prtmsg	; Yes. Print 256K msg
	jrz	..return ; and return.
	lxi	H,msg512K
	cpi	2	; is size 2
	cz	prtmsg	; Yes. Print 512K msg
	jrz	..return ; and return.
	lxi	H,msg1M
	cpi	3	; is size 3
	cz	prtmsg	; Yes. Print 1 Meg msg
	jrz	..return ; and return.
	lxi	H,msg2M
	cpi	4	; is size 4
	cz	prtmsg	; Yes. Print 2 Meg msg
	jrz	..return ; and return.
	lxi	H,msg4M
	cpi	5		; is size 5
	cz	prtmsg	; Yes. Print 256K msg
	jrz	..return ; and return.
	lxi	H,msg8M
	cpi	6	; is size 6
	cz	prtmsg	; Yes. Print 8 Meg msg
	jrz	..return ; and return.
	lxi	H,Qmsg	; No valid size found.
	call	prtmsg	; Print  msg,
..return:
	pop	H	; restore table address
	ret		; and return.
.page
;--------------
; Subroutine ADDRfind:	Find an addr of line in table
; Regs	in:    A  = addr of line in table needed
;	       B  = Bytes per line of the table
;	       HL = addr of the start of the table
; Regs out:    HL = Addr of that line in the table 
; Destroyed:   A,B
;
ADDRfind:
	cpi	0	  ; first line of table
	rz		  ; then were done
..1:	push	PSW	  ; save table line number
	mov	A,B	  ; incr table <Reg B> times 
..2:	inx	H
	dcr	A
	cpi	0	  ; Are we through this line
	jrnz	..2	  ; No. continue incrementing
	pop	PSW	  ; Yes. Restore line counter
	dcr	A	  ; decr table line number
	cpi	0	  ; Are we all done
	jrnz	..1	  ; No.incr to next line
	ret		  ; Yes. Return.
.page
.sbttl	'CRT IO subroutines'
;---------------
; Subroutine Prtmsg:  Print a message on the console
;  Regs in:   HL = address of string (ended by null)
;  Regs out:  none
;  Destroyed: A, HL
;
prtmsg:
	mov	A,M
	ora	A
	rz
	call	CONOUT
	inx	H
	jmpr	prtmsg
;---------------
; Subroutine prtchr:  Print # of chars to console
; Regs	in:	B  = length of string
;		HL = addr of string
; Regs out:	HL = addr of last chr printed
; Destroyed:	B,A
;
prtchr:
	mov	A,M
	push	B
	push	H
	call	CONOUT
	pop	H
	pop	B
	dcr	B
	mov	A,B
	cpi	0	; all B chrs printed
	rz
	inx	H	; next chr addr
	jmpr	prtchr	
;---------------
; Print a character on the console
;  Regs in:   A = character to be printed
;  Regs out:  none
;  Destroyed: none
;
CONOUT:
	push	B
	push	D
	push	H
	mov	E,A
	mvi	C,Conslout ;CPM 2, Console Output
	call	BDOS
	pop	H
	pop	D
	pop	B
	ret
.page
;---------------
; Subroutine Prtbyt:  Print a byte on the console
;  Regs in:   A = byte to be printed
;  Regs out:  none
;  Destroyed: A
;
prtbyt:
	push	PSW
	rrc
	rrc
	rrc
	rrc
	ani	0Fh	; don't print leading zeros
	jrz	..1
	call	prtnbl
..1:	pop	PSW
prtnbl: ani	0Fh
	adi	'0'
	cpi	'9'+1
	jrc	CONOUT
	adi	'A'-('9'+1)
	jmpr	CONOUT
;---------------
; Convert binary to BCD
;  Regs in:   A = byte to be converted
;  Regs out:  A = byte, in BCD format
;  Destroyed: B
cvtbcd:
	ora	A
	rz
	mov	B,A
	xra	A
..1:	inr	A
	daa
	djnz	..1
	ret
;---------------
; Subroutine CONSTAT:  Does console have a character
; Regs	in:	none
; Regs out:	carry bit set if chr ready
; Destroyed:	
CONSTAT:
	lxi	H,..1
	push	H	; return to ..1
	lded	1
	lxi	H,03h
	dad	D
	pchl
..1:	rrc		; set parity bit if
	ret		;chr is ready.
.page
.sbttl	'Hard disk read write subroutines'
;---------------
;Subroutine:	chaMAPbyt
; Regs	in:	none
; Regs out:	none
;Destroyed:	all
; Save the previous assignment for restoration.
; Current unit 0 assignment (network,etc) returns in A
; BIOS address of the byte returns in HL
;
chaMAPbyt:
	mvi	C,0
	call	SELDSK	; select unit 0 f
	call	CPMmap	; get current unit 0 assignment
	sta	UNITno	; save it for later restoration
	sub	A
	mov	M,A	; Make it unit number 0
	dcx	H	; point at the media type
	mov	A,M	; get the media type
	sta	DEVtype ; store for later
	dcx	H	; point to volume number
	mov	A,m
	sta	savevol ; save it
	inx	H	; back to where we were
	lda	STATbuf+5; DMS or Xebec controller*
	cpi	'X'	; X if Xebec (fox)
	jrnz	..dms
	mvi	M,FoxHDbyt
	ret
..dms:	mvi	M,HDbyt ; assign unit 0 to a hard disk
	ret
;--------------
; Subroutine  resMAPbyt: restore previous unit assign
; Regs	in:	none
; Regs out:	none
; Destroyed:	any and/or all registers
; Current unit 0 assignment (hard disk) returns in A
; BIOS address of the byte returns in HL
;
resMAPbyt:
	lxi	B,0
	call	seldsk	; Select drive A
	call	cpmMAP	; Get addr of unitno
	lda	UNITno
	mov	M,A	; Restore unit number
	dcx	H	; Point at media type
	lda	DEVtype
	mov	M,A	; Restore media type
	dcx	H
	lda	savevol
	mov	m,A	; restore volume number
	ret
.page
;--------------
; Subroutine readTABL:	Read DAT from HD into buffer
; Regs	in:	none
; Regs out:	none
; Destroyed:	All
; Network Hard Disk Track 0, sectors 121-128
;
readTABL:
	mov	A,vlipresent(x)
	cpi	true
	rnz		;stat buff has a 0 if no drive
	mvi	A,121	;else, read the table
	sta	cursec	;set value for first sector
	lxi	H,alloctab
	shld	curDMA	;set value for first DMA addr
;;;;;	call	HOME
	ora	A	; reset the carry flag
..1:	rc		; return if carry bit set
	mvi	C,0	; read unit 0
	call	SELDSK	; select hard disk
	call	CPMmap
	dcx	H
	dcx	H	; point to volume # in BIOS
	lda	volnum	
	mov	m,A	; Stuff volume number there
	lxi	B,0
	call	SETTRK	; select track 0
	lda	cursec	; load current sector
	mov	C,A
	call	SETSEC	; select current sector
	lbcd	curDMA
	call	SETDMA	; select proper buffer location
	call	READ	; and read from the disk
	call	INRdata ; increment DMA addr and sector
	jmpr	..1	; read until INRaddr sets carry
;---------------
;Subroutine INRdata: increment DMA address and sect #
; Regs	in:	none
; Regs out:	carry bit* (used as a flag)
;Destroyed:
;
; *Set the carry bit if last sector (128) has been read
;
INRdata:
	lhld	curDMA	; get current DMA address
	lxi	D,128
	dad	D	; increment by 128 bytes
	shld	curDMA	; and save it

	lda	cursec	; get the current sector
	inr	A
	sta	cursec
	cpi	129	; past 128th sector*
	jrnc	..1
	ora	A	; no. Resume reading or writing
	ret
..1:	stc		; set the carry flag
	ret		; and return
.page
.sbttl	'volume info tables and routines'
;---------------
; Subroutine setvolptr:  set the x register to point
;		to volume info for volume in volnum
; Regs in:  none
; Regs out: x points to volume info
; Destroyed: A,DE,HL
;
setvolptr:
	lda	volnum
	slar	a	;*2
	mov	e,a
	mvi	d,0
	lxi	h,vliindex
	dad	d
	mov	e,m
	inx	h
	mov	d,m
	push	d
	pop	x
	ret
;
;	routine to print volume label
prtvol:
	mvi	a,' '
	call	conout
	mov	a,vlivollabel(x)
	call	conout
	mov	a,vlivollabel+1(x)
	call	conout
	mov	a,vlivollabel+2(x)
	call	conout
	mov	a,vlivollabel+3(x)
	call	conout
	mov	a,vlivollabel+4(x)
	call	conout
	mov	a,vlivollabel+5(x)
	call	conout
	mov	a,vlivollabel+6(x)
	call	conout
	mov	a,vlivollabel+7(x)
	call	conout
	mov	a,vlivollabel+8(x)
	call	conout
	mov	a,vlivollabel+9(x)
	call	conout
	mvi	a,' '
	call	conout
	ret
.page
.sbttl	'BIOS call routines'
;
CONIN:	
	lded	1
	lxi	H,06h
	dad	D
	pchl
SELDSK:
	lhld	1
	lxi	D,18h
	dad	D
	pchl
SETTRK:
	lhld	1
	lxi	D,1Bh
	dad	D
	pchl
SETSEC:
	lhld	1
	lxi	D,1Eh
	dad	D
	pchl
SETDMA:
	lhld	1
	lxi	D,21h
	dad	D
	pchl
READ:  
	lhld	1
	lxi	D,24h
	dad	D
	pchl

cpmMAP:
	lhld	1
	lxi	D,60h
	dad	D
	pchl

HDstat:
	lhld	1
	lxi	d,81h
	dad	d
	pchl

.page
.sbttl	'Define storage'
;
volnum: .blkb	1	;current volume
vliindex:
	.word	vli0
	.word	vli1
	.word	vli2
	.word	vli3
statbuf:
	.blkb	8	;command status
vli0:	.blkb	vlibufsiz
vli1:	.blkb	vlibufsiz
vli2:	.blkb	vlibufsiz
vli3:	.blkb	vlibufsiz
HARDcom:.byte	0	; command byte
HARDdsk:
HARDsec:.byte	0	; sector or partition number
HARDtrk:.word	0
	.byte	0,0,0Ah,0 ; -not used-
HARDstat:.blkb	8	; result status
saveSP: .word	0

UNITno: .byte	0	; storage for drive A unit
DEVtype:.byte	0	; storage for drive A type
saveVOL:.byte	0	; may as well save volume too

curdma: .word	0	; current DMAaddr for disk I/O
curSEC: .byte	00h	; current sector for disk I/O
cpmtrk: .word	0
cpmsec: .byte	0
unit:	.byte	00h	; unit number of entry in table
size:	.byte	00h	; size of entry in stable
.page
.sbttl	'CRT Messages'
;
LOGmsg: .ascii	[cr][lf]' DIRHARD version '
	.byte	version+'0','.'
	.byte	revision/10+'0',revision@10+'0'
	.byte	patch
	.asciz	' for multi volume hard disks.'[cr][lf]
HEADmsg:.ascii	'                       '
	.ascii	' Current Hard Disk Partitions'
	.ascii	[cr][lf]'                       '
	.ascii	' ----------------------------'
crlf:	.asciz	[cr][lf]
space3: .asciz	'   '
space6: .asciz	'      '
msg256K:.asciz	'  256K bytes'
msg512K:.asciz	'  512K bytes'
msg1M:	.asciz	'    1M bytes'
msg2M:	.asciz	'    2M bytes'
msg4M:	.asciz	'    4M bytes'
msg8M:	.asciz	'    8M bytes'
Qmsg:	.asciz	'    ???     '
volmsg: .asciz	[cr][lf]'Partitions on Volume '
deadMSG:.asciz	[cr][lf]'Hard disk not operational.'
MASTmsg:.ascii	[cr][lf]'Use DIRNET instead of DIRHARD.'
;
	.blkw	16
stack:
;
.end

cr][lf]'Hard disk not operational.'
MASTmsg:.ascii	[cr][lf]'Use DIRNET instead of DIRHARD.'
;
	.blkw	1