	.title	'        Digital Microsystems allocation vector tester  Revision 5.0'
	.setdat	02/29/84		;set the date of publishing on each page
	.settim	11:45:AM		;set the time of publishing on each page
	.setwid	130			;set page width to 130 columns wide
	.setlen	88			;set page length to 90 lines per page
	.xsym				;suppress the symbol table
	.pabs				;set absolute mode
	.phex				;make the output file in hex
	.laddr				;list word address as they actually appear

;		Christopher Brock	January 12, 1984    last revised on leap day (5.0)

BDOS	==	5			;BDOS entry point
CONIN	==	1			;BDOS console status
CONOUT	==	2			;BDOS console output
PSTRING	==	9			;BDOS print string function
RDCONBF	==	10			;BDOS read console buffer function
CONSTAT	==	11			;BDOS console status
SELDSK	==	14			;select disk
CURDSK	==	25			;get current disk
GETALLO	==	27			;get allocation address
GETDPB	==	31			;get disk parameters

DELAY	==	10			;delay inbetween passes
FCB	==	5Ch			;file control block
ENTLENG	==	32			;length of a directory entry
BUFFER	==	0C00h			;base of buffer for the directory
STACK	==	BUFFER

WIDTH	==	64			;bits per line displayed
BELL	==	07h
BS	==	08h			;backspace
TAB	==	09h
LF	==	0Ah			;linefeed
CR	==	0Dh			;carriage return
DEL	==	7Fh			;delete

;		offset equates for the BIOS jump table

BSEL	==	1BH-3
SETTRK	==	1EH-3
SETSEC	==	21H-3
SETDMA	==	24H-3
READ	==	27H-3
SECTRAN	==	30H-3
LOC	==	93			;NET lock BIOS function
UNLOC	==	99			;NET unlock BIOS function


;		offset equates for local variables

DRIVE	==	0			;current drive
ALTDRIVE==	1			;alternate specified drive
BLKSIZE	==	2			;block size code
CLMCNT	==	3			;keeps track of bits per column displayed
BITCNT	==	4			;keeps track of bits per bytes displayed (always 8)
SEGCNT	==	5			;keeps track of bits per eight bit segment displayed
LOGCNT	==	6			;keeps track of the number of logical sectors to read
CURSEC	==	7			;copy of the current sector
ANYERR	==	8			;flag to indicate at least one error occurred
VECSIZE ==	9			;flag to indicate whether block entries are 8 or 16 bits
DERRFLG	==	10			;flag to indicate block allocated in directory, but not in ALV

;		offset equates for indexing into the DPB

CONTROL	==	-16			;byte in extended DPB
NAME	==	-11			;name of partition
MEDIA	==	-2			;media type
SPT	==	0			;Sectors Per Track
BSH	==	2			;block shift factor
BLM	==	3			;size of each block
DSM	==	5			;total number of blocks
DRM	==	7			;total number of directory entries
AL0	==	9			;first eight pre-allocated blocks
AL1	==	10			;next eight pre-allocated blocks
OFF	==	13			;reserved system tracks

;		offset equates for indexing into a directory entry

USERNUM	==	0			;user number
VECT1	==	16			;first allocation vector cell
VECT2	==	18
VECT3	==	20
VECT4	==	22
VECT5	==	24
VECT6	==	26
VECT7	==	28
VECT8	==	30

	.loc	100H			;org at 100h

        SSPD	SPSAVE			;save it for later
        LXI	SP,STACK		;initialize our own SP
	LXI	X,LCLVARS		;set IX to base of the local variables table

START:	LDA	FCB			;get any alternate drive
	MOV	ALTDRIVE(X),A		;save it for later
	LXI	D,MSG1			;print the title
	CALL	PMSG

	MVI	C,CURDSK		;get current disk in use from BDOS
	CALL	BDOS
	MOV	DRIVE(X),A		;save it for later
    	MOV	A,ALTDRIVE(X)		;get any alternate drive
	ORA	A			;any specified?
 	JRZ	DPBLOCK			;if not, skip next
	DCR	A			;less one
	MOV	DRIVE(X),A		;save as drive to use

DPBLOCK:MOV	E,DRIVE(X)		;get drive to bitmap
	MVI	C,SELDSK		;set CALL for disk select
	CALL	BDOS			;let BDOS do it
	MVI	C,GETDPB		;get the address of the disk address block
	CALL	BDOS
	SHLD	DPBASE
	LIYD	DPBASE			;put the the DPB base in IY
	MOV	L,DSM(Y)
	MOV	H,DSM+1(Y)		;read the total number of blocks into HL
	MOV	VECSIZE(X),H		;stash the high byte of DSM and use it as the vector size flag
	SHLD	TOTBITS			;stash it away for later

	MOV	A,BSH(Y)		;read in 
	SUI	2			;it will be 3-7 (make it 1-5)
	MOV	BLKSIZE(X),A		;save it for later
	CPI	5+1			;check for over 5
	JRC	SELD
	CPI	1
	JRNC	SELD

	LXI	D,MSG6			;nonstandard size
	CALL	PMSG			;print the error message
	JMP	EXIT

;		select the drive through BDOS and BIOS

SELD:	MOV	E,DRIVE(X)
	MVI	C,SELDSK
	CALL	BDOS

	MOV	C,DRIVE(X)		;and now through the BIOS
	MVI	E,BSEL
	CALL	BIOS
	MOV	E,M
	INX	H
	MOV	D,M
	SDED	XLTADR			;save the XLT address for later

;		indicate to the console which drive we're working on

	LXI	D,MSG1A
	CALL	PMSG			;print "Drive"
	MVI	A,'A'
	ADD	DRIVE(X)		;get drive used and add an ascii A to it
	CALL	CHAROUT
	CALL	CRLF

;		print the partition name

	BIT	6,MEDIA(Y)
	JRZ	SHAR			;skip if the drive is a floppy
	LXI	D,MSG19
	CALL	PMSG			;print "Partition name:"
	PUSH	Y			;save IY for a moment
	LXI	B,8 < 8+4		;set up the count for eight characters
	LXI	H,LOCSTG+1		;load HL with the address of our lockstring buffer

..LOOP:	MOV	A,NAME(Y)
	MOV	M,A			;stash the name of the partition in case it is needed for later
	CALL	CHAROUT
	INX	Y			;increment the DPB pointer
	INX	H			;bump our local pointer to the lockstring
	DCR	C
	CZ	ADJUST
	DJNZ	..LOOP
	JR	CONT


ADJUST:	LXI	D,5
	DAD	D			;bump HL past the 5 +'s in the lock string
	MVI	C,5			;make sure C won't hit 0
	RET

CONT:	POP	Y			;return IY just as it was found
	CALL	CRLF

;		print the shared status on the console

SHAR:	LXI	D,MSG8A
	CALL	PMSG			;print "Partition Status:"

	BIT	6,CONTROL(Y)
	JRNZ	SHARED
	LXI	D,MSG8			;print "Not Shared"
	JMPR	AROUND

;		at this point the partition is shared, so let's lock it...

SHARED:	LXI	H,LOCSTG
	SHLD	4Ah			;store the address of our lockstring
LOCLP:	MVI	E,LOC
	CALL	BIOS
	LDA	49h
	ANA	A
	JRNZ	LOCLP			;wait until it is accepted


	LXI	D,MSG9			;print "Shared"
AROUND:	CALL	PMSG

;		print the size of the disk

	LXI	D,MSG2A
	CALL	PMSG			;print "drive capacity is..."
	LHLD	TOTBITS
	INX	H			;convert from 0-X to 1-X
	MOV	B,BLKSIZE(X)
	DCR	B			;adjust
..LOOP:	DAD	H			;multiply the blocks by the block size
	DJNZ	..LOOP		

	CALL	PDECML
	MVI	A,'k'
	CALL	CHAROUT			;print "k"

;		print the block size

	LXI	D,MSG2			;print "block size is..."
	CALL	PMSG
	MOV	B,BLKSIZE(X)
	LXI	H,512			;set 1/2k counter
..LUPE:	DAD	H			;multiply * 2=1024
	DJNZ	..LUPE			;loop until <A>= 0
	CALL	PDECML			;print size in K

	LXI	D,MSG3			;print "bytes per block"
	CALL	PMSG

	MVI	ANYERR(X),0		;reset the ANYERR flag
	MOV	L,DRM(Y)
	MOV	H,DRM+1(Y)		;put the total number of directory entries in HL
	SRLR	H			;shift register H right 0 -> B7 , B0 -> Carry
	RARR	L			;shift register L right Carry -> B7
	SRLR	H
	RARR	L			;HL has now been divided by 4

	INR	L			;increment once because DRM is one less
	MOV	LOGCNT(X),L		;HL now has the number of 128 byte records to read from BIOS

	MOV	L,OFF(Y)
	MOV	H,OFF+1(Y)		;read in the track offset into HL
	DCX	H			;less one for the precount bias
	SHLD	TRACK			;the offset is the first track to be read

	LXI	B,BUFFER
	SBCD	DMAADR			;set DMAADR to the base of the buffer
	MVI	E,SETDMA
	CALL	BIOS			;set the DMA address for the first time

;		get the base of the allocation vector table from BDOS and store it away
;		if partition is shared, the allocation vector is read from the disk at this point
;		also do the physical reading of the directory

	CALL	READIR			;go read in the directory dynamically

	MVI	C,GETALLO		;get the allocation address
	CALL	BDOS
	SHLD	ALLOADR			;save it for later

	BIT	6,CONTROL(Y)		;check to see if the partition was shared
	JRZ	AFTER			;skip if not

..ULKLP:MVI	E,UNLOC			;try to unlock the partition and loop until sucessfull
	CALL	BIOS
	LDA	49h
	ANA	A
	JRNZ	..ULKLP


AFTER:	CALL	BLDMAP			;go build a byte map based on the directory image

	CALL	CKMULT			;check to see if there is any multiple allocations

	CALL	CRLF

	CALL	CMPMAP			;go compare the bit and byte maps
	CALL	DISPLAY
	SHLD	FREECNT			;save the freecount for later

	CALL	CRLF
	CALL	CRLF
	LXI	D,MSG4			;print "Space remaining ..."
	CALL	PMSG
	MOV	B,BLKSIZE(X)		;get block size code
	LHLD	FREECNT			;get the free count tabulated by DISPLAY
	DCR	B			;bump the count one
	JRZ	PRNFREE			;skip any multiplying if 0
..LOOP:	DAD	H			;multiply by size of block
	DJNZ	..LOOP

PRNFREE:CALL	PDECML			;print size of free space
	MVI	A,'k'
	CALL	CHAROUT			;print a "k"

	CALL	CRLF
	BIT	0,ANYERR(X)		;check to see if any errors occurred
	LXI	D,MSG18
	CZ	PMSG

;		see if there were any fatal errors

	BIT	0,ANYERR(X)
	JRZ	REPEAT			;skip it all if no errors occurred

	LXI	D,MSG23
	CALL	PMSG			;print "Fatal error(s) occurred:

..POLL:	MVI	C,RDCONBF
	LXI	D,KEYBUFF		;load up DE with the base of the keyboard buffer
	CALL	BDOS

	LDA	KEYBUFF+1		;retreive the number of keys entered
	CPI	1
	JRNZ	..RETRY			;try again if anything other than one key was pressed

	LDA	KEYBUFF+2		;get the first character
	ANI	5Fh			;make it a capital letter
	CPI	"P"
	JZ	AFTER
	CPI	"C"
	JRZ	REPEAT
	CPI	"E"	
	JRZ	EXIT

;		response not acceptable, so try again...

..RETRY:LXI	D,MSG24			;reprint the prompt
	CALL	PMSG

	JR	..POLL

;		see if time to repeat

REPEAT:	MVI	C,CONSTAT
	CALL	BDOS
	ANA	A
	JRZ	CKRPT			;continue checking if no key has been pressed

	MVI	C,CONIN
	CALL	BDOS			;dispose of the character
	JMPR	EXIT


CKRPT:	LDA	80h
	ANA	A
	JRZ	EXIT			;check the character count and exit if 0

	LDA	83h
	CPI	':'			;see if the command line specified an alternate drive
	JRZ	CK85

	LDA	82h			;no alternate drive specified so take the second character
	JMPR	RDBYTE

CK85:	LDA	80h			;make sure that the command buffer extends past 83h
	CPI	4
	JRC	EXIT
	LDA	85h			;take the fifth character in the command buffer

RDBYTE:	CPI	'R'
	JRNZ	EXIT

	MVI	B,DELAY			;delay a bit before doing another round
..LP:	LXI	H,-1

..LOOP:	DCX	H			;HL delays about a second and B multiplies that
	MOV	A,H
	ORA	L
	JRNZ	..LOOP
	DJNZ	..LP
	JMP	START

EXIT:	LSPD	SPSAVE			;get CCP SP
	RET				;direct return to CCP

;		This subroutine module compares the bit and byte maps.
;		Assumes that READIR, BLDMAP and CKMULT have been preiously run.

CMPMAP:	LHLD	DMAADR			;set HL to the base of the byte map built by BLDMAP
	LIYD	ALLOADR			;set IY to the base of BDOS's allocation vector table

..1CPLP:MOV	C,0(Y)			;put the first eight blocks into C
	MVI	B,8

..2CPLP:XCHG				;DE= byte map pointer
	LHLD	MAXMADR			;use the maximum memory address as the table limiter
	ANA	A			;make sure that the carry flag is clear
	DSBC	D
	RC				;the carry flag will be set if we are one past the byte map
	XCHG				;HL = byte map pointer

	MVI	D,0
	MOV	A,M
	ANA	A			;read in the byte map entry and set the flags
	CNZ	SETDNZ			;adjust D if necessary
	XRA	A			;clear A
	RLCR	C			;rotate register C, with carry flag set according to bit 7
	CC	SETANZ			;adjust A if necessary
	CMP	D			;compare D to A
	CNZ	ALLOERR			;report the error to the console if nomatch
	INX	H			;bump the byte map pointer
	DJNZ	..2CPLP			;go back and do another bit
	INX	Y			;bump the ALV pointer
	JMPR	..1CPLP

SETDNZ:	INR	D			;change D from 0 to 1
	RET

SETANZ:	INR	A			;change A from 0 to 1
	RET

ALLOERR:PUSH	H			;save the byte map pointer
	PUSH	B			;save the rotate counter and ALV byte
	MOV	E,A
	PUSH	D			;move the byte map flag and push it on the stack
	PUSH	H			;save another copy of the byte map pointer for use locally
	LXI	D,MSG20
	CALL	PMSG			;print "Error ! Directory and Allocation Table do not match"

	POP	H			;recall the extra copy of the byte map pointer
	LDED	DMAADR

	ANA	A			;clear the carry
	DSBC	D			;make HL = the absolute allocation vector
	SHLD	ABSVECT			;store it in case DIRERR needs it

	MOV	A,VECSIZE(X)
	ANA	A			;test VECSIZE to see if we are dealing with 8 or 16 bit vectors
	MOV	A,L			;put a copy in A in case PBYTE is called
	JRNZ	..BSKIP			;jump if it is a 16 bit vector
	CALL	PBYTE			;print its value
	JMPR	..CSKIP

..BSKIP:CALL	PWORD			;print its value
	
..CSKIP:LXI	D,MSG21
	CALL	PMSG			;print "In Directory:  "

	POP	B
	PUSH	B			;put a copy of the map status word in BC
	BIT	0,B
	LXI	D,MSGNO
	CNZ	DIRERR			;change the message address to "Yes" if non zero
	CALL	PMSG

	LXI	D,MSG22
	CALL	PMSG			;print "In ALV:  "

	POP	B			;recall local copy of BC for the last time
	BIT	0,C			;test the bit that caused this error condition
	LXI	D,MSGNO
	CNZ	CHGMSG			;change the message address to "Yes" if non zero
	CALL	PMSG
	CALL	CRLF
	BIT	0,DERRFLG(X)		;see if the dirctory error flag was set
	CNZ	PRNENT			;go find and print the associated directory entry
	POP	B
	POP	H			;return the registers as we found them
	RET

DIRERR:	MVI	ANYERR(X),1		;set the any error flag
	MVI	DERRFLG(X),1		;set the directory error flag
CHGMSG:	LXI	D,MSGYES		;change the message address to "Yes"
	RET

PRNENT:	PUSH	Y
	CALL	LSTENTS			;call the routine that finds a block number
	CALL	CRLF
	RES	0,DERRFLG(X)		;reset the error condition
	POP	Y
	RET

;		this module checks to see if any block has been allocated more than once
;		before entering:
;			The subrutine modules READIR and BLDMAP must be called before entering.
;			DMAADR must be set to the base of the directory image in memory.
;			TOTBITS must be set to total number of bits in the allocation table.

CKMULT:	LHLD	DMAADR			;set HL to base of the byte map that has been built
	LBCD	TOTBITS			;set HL with the size of the byte map
	MVI	A,01			;compare it against a 01H

CKLOOP:	CCI
	RPO				;if BC=0, then return to caller
	CMP	M			;CCI will not set the carry bit
	CC	BLKERR			;if greater than one, block has been allocated more than once
	JMPR	CKLOOP

BLKERR:	MVI	ANYERR(X),1		;set the ANYERR flag
	PUSH	PSW			;save the compare byte
	PUSH	B			;save the byte map counter
	SHLD	BMAPADR			;save the byte map address
	LXI	D,MSG15
	CALL	PMSG			;print multiple allocation warning
	LHLD	BMAPADR
	LDED	DMAADR
	ANA	A
	DSBC	D			;subract the byte map offset
	SHLD	ABSVECT			;save the absolute allocation vector
	MOV	A,VECSIZE(X)
	ANA	A			;test the vector size flag
	MOV	A,L			;put a copy in A in case PBYTE is called
	JRNZ	..BSKIP			;jump if it is a 16 bit vector
	CALL	PBYTE			;print its value
	JMPR	..CSKIP
..BSKIP:CALL	PWORD			;print its value

..CSKIP:LXI	D,MSG16
	CALL	PMSG			;print "number of times allocated:"
	LHLD	BMAPADR
	MOV	L,M
	MVI	H,0			;read in the count from the byte map.
	CALL	PDECML			;print its value to tell how many times
	CALL	LSTENTS			;go print all associated entries
	LHLD	BMAPADR			;return HL as we found it
	POP	B			;recall the byte map seaarch count
	POP	PSW			;recall the comparison byte
	RET

;		list all directory entries associated with the vector supplied in ABSVECT

LSTENTS:LXI	H,-1
	SHLD	ENTNUM			;reset the directory entry number indicator

	LXI	Y,BUFFER-ENTLENG	;load IY with the base of the directory image -1FCB

..NXENTR:LXI	D,ENTLENG
	DADY	D			;add one entry length to IY

	LHLD	ENTNUM			;bump the entry count by one
	INX	H
	SHLD	ENTNUM

	LDED	ENTRIES			;load DE with the total number of entries in the directory

	ANA	A			;clear the carry flag first
	DSBC	D			;HL-DE ENTNUM-ENTRIES
	RZ				;quit now because we have gone one too far

	MVI	A,31
	CMP	USERNUM(Y)
	JRC	..NXENTR		;go to the next entry if user number is not within 0-31

;		at this point, IY is pointing to a valid directory entry

	MOV	E,VECT1(Y)
	MOV	D,VECT1+1(Y)		;take the first vector and index into the byte map
	CALL	..CMPVCTR

	MOV	E,VECT2(Y)
	MOV	D,VECT2+1(Y)
	CALL	..CMPVCTR		;compare the second  vector

	MOV	E,VECT3(Y)
	MOV	D,VECT3+1(Y)
	CALL	..CMPVCTR		;compare the third vector

	MOV	E,VECT4(Y)
	MOV	D,VECT4+1(Y)
	CALL	..CMPVCTR		;compare the fourth vector

	MOV	E,VECT5(Y)
	MOV	D,VECT5+1(Y)
	CALL	..CMPVCTR		;compare the fifth vector

	MOV	E,VECT6(Y)
	MOV	D,VECT6+1(Y)
	CALL	..CMPVCTR		;compare the sixth vector

	MOV	E,VECT7(Y)
	MOV	D,VECT7+1(Y)
	CALL	..CMPVCTR		;compare the seventh vector

	MOV	E,VECT8(Y)
	MOV	D,VECT8+1(Y)
	CALL	..CMPVCTR		;compare the eighth vector

	JMPR	..NXENTR


..CMPVCTR:LHLD	ABSVECT			;put the offending vector in HL
	MOV	A,VECSIZE(X)
	ANA	A			;set the flags
	JRNZ	CMP16			;jump if the vectors are 16 bit

;		8 bit allocation vector compare routine. H will always be 0

	MOV	A,L
	CMP	D			;compare the first vector to L
	PUSH	D
	PUSH	PSW
	CZ	OUTCUR
	POP	PSW			;recall the known bad vector
	POP	D			;recall the two vectors for test

	CMP	E
	RNZ				;quit now if no match
	JMP	OUTCUR			;go display the info if a match and return to caller

CMP16:	ANA	A			;clear the carry flag first
	DSBC	D			;HL-DE , if HL = DE, then Z flag = 0
	RNZ				;quit now if no match
	JMP	OUTCUR			;output all pertinent info to the console & return to caller



;		at this point, an entire directory image exists starting at BUFFER

BLDMAP:	LIYD	DPBASE			;make sure IY has the pointer to the DPB
	LHLD	DMAADR			;the byte map starts at the end of the directory image
	MOV	E,L
	MOV	D,H
	INX	D			;make DE point one past HL
 	LBCD	TOTBITS			;maximum buffer size
	MVI	M,0
	LDIR				;fill the entire buffer with zeros

	LHLD	TOTBITS			;load HL with the total number of bits in the directory
	LDED	DMAADR
	DAD	D			;add it to the base of the byte map
	SHLD	MAXMADR			;store it away for later

	LXI	H,-1
	SHLD	ENTNUM			;reset the directory entry count to -1

	MOV	L,DRM(Y)
	MOV	H,DRM+1(Y)		;read in the total number of directory entries into HL
	INX	H			;adjust it
	SHLD	ENTRIES			;save it in the permanent location in case LSTENTS needs it

	LXI	D,MSG11
	CALL	PMSG			;print "Number of directory entries"
	LHLD	ENTRIES
	CALL	PDECML			;print the amount
	CALL	MLOOP			;go build a byte map from the dierctory image

;		set the the pre allocated blocks for the directory

	LIYD	DPBASE			;set IY pointing to the base of the DPB
	LHLD	DMAADR			;set HL pointing to the base of the byte map
	MVI	A,01			;byte map entry -indicates that block has been allocated
	MVI	B,8			;set the rotate counter for eight rotates

..LP1:	RLCR	AL0(Y)
	CC	SETBYTE			;if carry set, mark the block in the byte map
	INX	H			;move HL to the next entry in the byte map
	DJNZ	..LP1

	MVI	B,8			;set the rotate counter for another eight rotates
..LP2:	RLCR	AL1(Y)
	CC	SETBYTE			;if carry set, mark the byte in the byte map
	INX	H
	DJNZ	..LP2
	RET

SETBYTE:MOV	M,A
	RET


MLOOP:	LXI	Y,BUFFER-ENTLENG	;load IY with the base of the directory image -1FCB

..NXENTR:LXI	D,ENTLENG
	DADY	D			;add one entry length to IY

	LHLD	ENTNUM			;bump the entry count by one
	INX	H
	SHLD	ENTNUM			;ENTNUM starts counting from zero

	LDED	ENTRIES			;load DE with the total number of entries in the directory

	ANA	A			;clear the carry flag first
	DSBC	D			;HL-DE ENTNUM-ENTRIES
	RZ				;quit now because we have gone one too far

	MVI	A,31
	CMP	USERNUM(Y)
	JRNC	..STEPB			;continue test if user number is within 0-31

	MVI	A,0E5H
	CMP	USERNUM(Y)
	JRZ	..NXENTR		;if true, then this is an erased entry

	MVI	A,0E8H
	CMP	USERNUM(Y)
	JRZ	..NXENTR		;if zero, then this is an erased entry

;		if we arrived here then we have a trashed entry

	MVI	ANYERR(X),1		;set the ANYERR flag
	LXI	D,MSG14
	CALL	PMSG			;print "invalid directory entry"
	CALL	OUTCUR			;print the pertinent data
	JMPR	..NXENTR


..STEPB:MOV	E,VECT1(Y)
	MOV	D,VECT1+1(Y)		;take the first vector and index into the byte map
	CALL	..CHKVCTR

	MOV	E,VECT2(Y)
	MOV	D,VECT2+1(Y)
	CALL	..CHKVCTR		;check the second  vector

	MOV	E,VECT3(Y)
	MOV	D,VECT3+1(Y)
	CALL	..CHKVCTR		;check the third vector

	MOV	E,VECT4(Y)
	MOV	D,VECT4+1(Y)
	CALL	..CHKVCTR		;check the fourth vector

	MOV	E,VECT5(Y)
	MOV	D,VECT5+1(Y)
	CALL	..CHKVCTR		;check the fifth vector

	MOV	E,VECT6(Y)
	MOV	D,VECT6+1(Y)
	CALL	..CHKVCTR		;check the sixth vector

	MOV	E,VECT7(Y)
	MOV	D,VECT7+1(Y)
	CALL	..CHKVCTR		;check the seventh vector

	MOV	E,VECT8(Y)
	MOV	D,VECT8+1(Y)
	CALL	..CHKVCTR		;check the eighth vector

	JMP	..NXENTR


;		this routine checks an allocation vector and if good, plots it in the byte map

..CHKVCTR:MOV	A,VECSIZE(X)
	ANA	A			;check VECSIZE to see if this disk uses 8 or 16 bit vectors
	JRNZ	INDEX			;it uses 16, so everything is all set
	PUSH	D
	MOV	E,D
	MVI	D,0			;move D to E and set D to 0
	CALL	INDEX
	POP	D
	MVI	D,0			;now use the vector that came in E and fall into INDEX

INDEX:	LHLD	DMAADR			;HL = DMAADR
	DAD	D			;add the vector to Byte Map base address
	XCHG				;put it in DE    DE = DMAADR + vector

	LHLD	MAXMADR			;load the highest possible vector address into HL
	ANA	A			;clear the carry
	DSBC	D
	XCHG				;HL = DMAADR + vector
	JRC	ILVEC			;branch if vector is out of range
	INR	M			;increment that location
	RET

ILVEC:	MVI	ANYERR(X),1		;set the any error flag
	PUSH	H
	LXI	D,MSG10			;print "Error-   Invalid block"
	CALL	PMSG
	POP	H			;HL= vector + DMAADR
	LDED	DMAADR
	ANA	A			;clear the carry flag first
	DSBC	D			;strip off DMAADR   HL = vector
	CALL	PWORD			;fall into OUTCUR

;		this routine outputs information about the current FCB

OUTCUR:	LXI	D,MSG12			;print "at FCB number"
	CALL	PMSG

	LHLD	ENTNUM			;get the current FCB number
	CALL	PWORD			;print it
	MVI	A,TAB
	CALL	CHAROUT

	LHLD	ENTNUM
	CALL	PDECML			;now print it in decimal

	LXI	D,MSG13			;print "at Record number"
	CALL	PMSG

	LHLD	ENTNUM			;get the current FCB number
	SRLR	H
	RARR	L
	SRLR	H
	RARR	L			;FCB number has been divided by 4

	PUSH	H
	CALL	PWORD
	MVI	A,TAB
	CALL	CHAROUT
	POP	H
	CALL	PDECML			;print the decimal number and return to caller

;		now print a DDT style screen dump

	CALL	CRLF
	CALL	CRLF
	PUSH	Y
	POP	H			;get the base of the directory entry in HL
	PUSH	H			;save it on the stack
	CALL	DUMPHEX
	CALL	PSPACE
	POP	H			;get another copy of directory entry address
	PUSH	H
	CALL	PSPACE
	CALL	DUMPASC

	CALL	CRLF

	POP	H
	LXI	D,16
	DAD	D			;make HL point to second half of the directory entry
	PUSH	H
	CALL	DUMPHEX
	CALL	PSPACE
	CALL	PSPACE			;print a space one more time and fall into DUMPASC
	POP	H

DUMPASC:MVI	B,16			;print 16 bytes at a time
PLOP2:	MOV	A,M
	CALL	PASCII			;show it in ascii this time
	INX	H
	DJNZ	PLOP2
	RET

DUMPHEX:MVI	B,16			;print 16 bytes at a time
PLOP1:	MOV	A,M
	CALL	PBYTE
	CALL	PSPACE
	INX	H			;point HL to the next character to be printed
	DJNZ	PLOP1
	RET



;		This subroutine will read the entire directory in from the BIOS
;		Enter with the following variables set:

;		DMAADR		with the start of the buffer
;		TRACK		set to first track less 1
;		LOGCNT		total 128 byte logical sectors in the entire directory

READIR:
NEXTRK:	LBCD	TRACK			;begin by bumping the track by one

	INX	B
	SBCD	TRACK

	MVI	E,SETTRK
	CALL	BIOS

	MVI	CURSEC(X),0FFH		;reset the current track and sector

;		bump the sector by one

NEXSEC:	LDED	XLTADR			;move the XLT table address into DE
	LHLD	1
	LXI	B,SECTRAN
	DAD	B			;compute the SECTRAN address for HL

;		check if we have reached the last sector on this track

	INR	CURSEC(X)
	MOV	C,CURSEC(X)
	MOV	A,SPT(Y)
	CMP	C			;check if we are past the sectors per track
	JRZ	NEXTRK

	MVI	B,0			;call SECTRAN
	CALL	BIOS2

	MOV	C,L
	MOV	B,H
	MVI	E,SETSEC
	CALL	BIOS

	MVI	E,READ
	CALL	BIOS			;now do the physical read
	ANA	A			;check to see if any errors occurred
	JRZ	DMA
	LXI	D,MSG17			;indicate that a BIOS error occurred and abort
	CALL	PMSG
	JMP	EXIT

;		bump the DMA address by 128 for next time

DMA:	LHLD	DMAADR
	LXI	D,128
	DAD	D
	SHLD	DMAADR			;save it
	MOV	C,L
	MOV	B,H			;BC now has the DMA address
	MVI	E,SETDMA
	CALL	BIOS

	DCR	LOGCNT(X)
	RZ				;return if done with all of the directory

	JMPR	NEXSEC


;		This large subroutine module will make a visual bitmap on the console screen.
;		It will also tabulate the free space count, return its value in HL.
;		Before entering:
;			1. Set ALLOADR with the base of the allocation vector table.
;			2. Set TOTBITS with the total number of bits in the allocation vector table.
 
DISPLAY:LXI	D,MARGIN
	CALL	PMSG			;print the margin

	LXI	H,0			;use HL as the free bytes counter
	SHLD	LINEADR			;clear the dispalyed line address
	LDED	ALLOADR			;get the table base address
	LBCD	TOTBITS			;get the total number of bits
	INX	B			;add one because the counter will exit when 0, without printing

DOLINE:	CALL	CRLF			;followed by a CR, LF
	PUSH	H			;save the free space count
	LHLD	LINEADR
	CALL	PWORD
	PUSH	B
	LXI	B,WIDTH
	DAD	B			;add 64 to the diplayed line address
	SHLD	LINEADR
	POP	B
	POP	H
	CALL	PSPACE
	CALL	PSPACE

	MVI	CLMCNT(X),WIDTH		;set the column counter
	MVI	SEGCNT(X),8		;set the eight bit segment count

DOBYTE:	LDAX	D			;get the byte
	INX	D			;kick the pointer for next time
	MVI	BITCNT(X),8		;set the bits per byte counter

DOBIT:	RLC				;runn'em through carry
	PUSH	PSW
	MVI	A,'1'
	CNC	ZERO			;carry not set ; make it a '0'
	CALL	CHAROUT
	POP	PSW			;restore the state of the flags
	EXAF				;save AF stackless style

;		check to see if finished with all bits

	DCX	B			;decrement total bit count
	MOV	A,B			;check to see if BC = 0
	ORA	C
	RZ				;if so, we're finished (exit point of this module)
	EXAF				;restore bit pattern

;		check to see if finished with the current line

	DCR	CLMCNT(X)		;decrement the column count	
	JRZ	DOLINE			;new line if zero
  
;		check to see if finished with a four byte segment

	DCR	SEGCNT(X)		;decrement the eight bit displayed segment count
	JRNZ	SKIPSPC

	EXAF
	CALL	PSPACE
	EXAF				;restore the bit pattern
	MVI	SEGCNT(X),8		;set the sequence for another four bytes

;		check to see if finished with all bits in the byte

SKIPSPC:DCR	BITCNT(X)
	JRNZ	DOBIT			;not finished yet
	JMPR	DOBYTE			;new byte if zero
;	-	end of console bit map display loop	-


;	**	from here on is the low level support routines	**

BIOS:	MVI	D,0
	LHLD	1			;pick up the warm boot vector
	DAD	D			;add the offset provided in DE
BIOS2:	PCHL				;JP (HL)

PMSG:	MVI	C,PSTRING		;uses all registers
	JMP	BDOS

CRLF:	MVI	A,CR			;saves all registers
	CALL	CHAROUT
	MVI	A,LF
	JR	CHAROUT

PSPACE:	MVI	A,' '			;all registers returned unaffected
	JMPR	CHAROUT

ZERO:	INX	H			;increment the free blocks count
	DCR	A			;make the ascii 1 into 0
	RET

;		Binary to decimal output routine. Assumes 16 bit number in <HL>
;		Returns unaffected:	NONE (all registers are used)

PDECML:	LXI	B,-10
	LXI	D,-1
LOOP:	DAD	B
	INX	D
	JRC	LOOP
	LXI	B,10
	DAD	B
	XCHG
	MOV	A,H
	ORA	L
	PUSH	D
	CNZ	PDECML
	POP	D
	MOV	A,E
	ADI	'0'
	JMPR	CHAROUT

;		print a word in in hex format -enter in HL
;		Returns unaffected:	HL, DE, BC

PWORD:	MOV	A,H
	CALL	PBYTE
	MOV	A,L			;fall into PBYTE
	CALL	PBYTE
	MVI	A,'H'
	JMPR	CHAROUT			;print the last character and return to caller

;		print a byte in hex format -enter in A
;		Returns unaffected:	HL, DE, BC

PBYTE:	PUSH	PSW
	RRC
	RRC
	RRC
	RRC
	CALL	NIB			;print upper nibble
	POP	PSW

NIB:	ANI	0FH			;mask off the high nibble
	ADI	'0'			;add the ascii offset
	CPI	'9'+1
	JRC	CHAROUT			;finish up at CHAROUT
	ADI	'A'-('9'+1)		;convert to 10-15 hex (A-F) and fall through

;		enter with a character to be output in A, saves all registers
;		Returns unaffected:	HL, BC, DE

CHAROUT:EXX
	MOV	E,A
	MVI	C,CONOUT
	CALL	BDOS
	EXX				;return all registers
	RET

;		enter with a character to be output in A, saves all registers

PASCII:	CPI	' '
	JRC	PDOT

	CPI	DEL
	JRNC	PDOT
	JMPR	CHAROUT

PDOT:	MVI	A,'.'
	JMPR	CHAROUT
 
MSG1:	.ascii	'
DMS disk allocation vector diagnostic    Rev 5.0
$'

MSG1A:	.ascii	'
Drive:                                $'

MSG2A:	.ascii	'
Disk capacity:                        $'

MSG2:	.ascii	'
Allocated disk block size:            $'

MSG3:	.ascii	'  bytes per block$'

MSG4:	.ascii	'Space remaining:  $'

MSG6:	.ascii	'
Nonstandard disk  -parameter block error,  aborting...'

MSG7:	.ascii	'
$'

MSG8A:	.ascii	'Partition status:                     $'
MSG8:	.ascii	'Not '
MSG9:	.ascii	'Shared$'

MSG10:	.ascii	'

Error !  Invalid block:  $'

MSG11:	.ascii	'
Number of directory entries:          $'

MSG12:	.ascii	'

    DCB number:  $'

MSG13:	.ascii	'     Record number:  $'

MSG14:	.ascii	'

Error !  Invalid directory entry$'

MSG15:	.ascii	'

Error ! This block allocated more than once:  $'

MSG16:	.ascii	'  # of times allocated:  $'

MSG17:	.ascii	'
BIOS read error occurred, aborting...$'

MSG18:	.ascii	'
No fatal errors encountered.
$'

MSG19:	.ascii	'Partition name:                       $'

MSG20:	.ascii	'
Error !               Directory / Allocation Vector mismatch
Block number:   $'

MSG21:	.ascii	'      In directory:  $'

MSG22:	.ascii	'      In ALV:  $'

MSG23:	.ascii	[BELL],'Fatal error(s) occurred. Choose one of the following options:

  P   re- Print all errors.
  C   Continue testing (if in repeat mode).
  E   Exit.

'

MSG24:	.byte	CR				;start here if reprinting the prompt
	.ascii	'  -->   ',[BS],[BS]'$'

MSGYES:	.ascii	'Yes$'

MSGNO:	.ascii	'No $'

MARGIN:	.ascii	'
       01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF
$'
LOCSTG:	.byte	13			;the partition name in the DPB is always 8+5 characters long
	.blkb	4
	.ascii	'+++++'
	.blkb	4
  
KEYBUFF:.byte	2			;tells BDOS that the buffer will hold two characters
	.blkb	3			;make room for fill byte and the buffer itself

LCLVARS:.blkb	11			;must equal the number of local variable equates

XLTADR:	.blkw	1			;storage for sector translation address
TOTBITS:.blkw	1			;total bits to read (0-X)
LINEADR:.blkw	1			;storage for the displayed line address
FREECNT:.blkw	1			;storage for free space count
ALLOADR:.blkw	1			;allocation table vector address
DMAADR:	.blkw	1			;storage for the current DMA address
TRACK:	.blkw	1			;storage for the current track
MAXMADR:.blkw	1			;MAXimum Map ADdRess
ENTNUM:	.blkw	1			;counts the number of entries searched 
ENTRIES:.blkw	1			;permanent storage for the number of entries
BMAPADR:.blkw	1			;temporary storage for the current ailing byte map address
ABSVECT:.blkw	1			;temporary storage for the current ailing allocation vector
DPBASE:	.blkw	1			;storage for FCB base
SPSAVE:	.blkw	1			;storage for CCP's stack
	.end
