.title 'Users Table maintenance program'
	.sbttl 'USERS'
version	==	3
revision==	0
	.pabs
	.phex
	.loc	100h
	jmp	TEST
	jmp	START

; 		Program: USERS

; Read in, list, modify, and/or save 
; the Name/Password Table stored on
; track 3, sectors 1-32, and the default
; configuration table stored on all of
; tracks 4 and 5, of the Hard disk.

; Update history

;	Version 1.3 - A (add) command added.
;		      M command changed to NOT allow
;		       mods to unitialized entries. The
;		       'A' command is for that purpose.
;		     ^B option installed.  Entry of 
;		       this produces an automatic jump
;		       to GETCOM (user input point).
;		       See CONIN for the code.
;		      USERS can now be run on the HiNet
;		       master or the direct hard disk.
;		       User can never be used by a
;		       station.
;	Version 1.4 - USERS now handles an optional
;		       type ahead buffer for each
;		       listing.
;	Version 1.5 - The namebuf and cofigbuf tables
;		       are each moved further into
;		       memory so as to accomodate USERS
;		       growing size.	
;	Version 2.0 - The delete command is installed.
;		       Escape now does what ^B used to
;		       do. (Returns user to `Command?`
;		       prompt.)
;	Version 3.0 - Improved I/O messages.   DB  9/1
namebuf=	2000h	; loc for name and pass table
cofigbuf=	6000h	; loc for configuration table
mxdskTRK	=	10h
mxdskSEC	=	80h

; Hard Disk I/O routines are at the end of the program

WBOOT	=	00h
BDOS	=	05h
cr	=	0Dh
lf	=	0Ah
conready=	0Bh	; for CP/M console status
bufread =	0Ah	; for CP/M console buffer reads

;Temporary locations for Name/Password Table entries.
unit:	.byte	00h	; Hex byte (not in table)
TEMPentry:		;Beginning of table line
NAMaddr:.ascii	'        '	; 8 chr ascii string
PASaddr:.ascii	'      '	; 6 chr ascii string
control:.byte	00h		; Hex byte
size:	.byte	00h		; Hex byte

;Temporary locations for Default Table entries.
def1:	.ascii	'        '	; 8 chr ascii string
def2:	.ascii	'        '	; 8 chr ascii string
def3:	.ascii	'        '	; 8 chr ascii string
def4:	.ascii	'        '	; 8 chr ascii string
IObyte:	.byte	00h		; 1 byte CPM I/O map
chrcnt: .byte	00h		; 1 byte count for the
				;the following default
				;type-ahead buffer.
TAbuf:	.ascii	'                                   '
	.ascii	'                                   '
	.ascii	'                                   '
	.ascii	'                                   '


; Step 1 - Check that we are on the Hard disk or HiNet
;	   master.
;
; Step 2 - Read in name and password table, and the
;	   configuration table from the hard disk
;
; Step 3 - Print out current name/pass  map
;          Stop on special 'EOF' (name=0)
;
; Step 4 - Get user commands
;	   A - Add a new entry to the table  	(Acom)
;	   D - Delete an entry from the table   (Dcom)
;	   H - Help				(Hcom)
;	   M - Modify an existing entry		(Mcom)
;	   Q - Quit the program safely		(Qcom)
;	   L - List out 'in mem' map		(Lcom)
;	   S - jump to Step 4			(Scom)
;	   Z - Zero out current table in memory	(Zcom)
;
; Step 4 - Save as current name/pass map on hard disk
;	   if Scom is executed.
;---------
; MAIN BODY
;
TEST:
	;First we test to allow only the Hard disk or
	;HiNet master to use this program.
	lda	47h	  ; A = network user code
	cpi	0FFh	  ; FF= hard disk (no HiNet)
	jrz	START	  ; WE can proceed if Hard disk
	cpi	00h	  ; 00= network master
	jrz	START	  ; We can proceed if Network
	lxi	H,NOGOmsg ; This user is not legitimate
	call	prtmsg	  ; Give him the ax
	jmp	WBOOT	  ; and the boot.

	;User is AOK we can start.  Set the stack and
	;initialize for the Hard disk/Network reads
	;and writes.	
START:	lxi	sp,stack  ; set the stack
	lxi	H,LOGmsg  ; print log-on message
	call	prtmsg
	call	chaMAPbyt ; assign unit 0 to hard disk
			  ;or to network master
	mvi	A,32	  ; A = num of secs to read
	mvi	B,3	  ; B = starting track
	mvi	C,1	  ; C = starting sector
	lxi	H,namebuf ; HL= address of name table
	call	readTABL  ; read in name and pass table
	mvi	A,080h	  ; A = num of secs to read
	mvi	B,4	  ; B = starting track
	mvi	C,1	  ; C = starting sector
	lxi	H,cofigbuf; HL= address of config table
	call	readTABL  ; read in name and pass table
	call	resMAPbyt ; restore users unit 0 assmt
	lxi	H,HELPmsg ; print command summary
	call	prtmsg
;
; GET and interpret user COMmands
;
GETCOM:	
	lxi	H,COMmsg
	call	prtmsg	 ; tell user we are ready
wait:	call	CONSTAT
	jrnc	wait	 ; wait for a user command

	call	CONIN	 ; read in the chr

	cpi	'A'	; Add a new entry to table?
	jz	Acom
	cpi	'D'	; Delete an entry?
	jz	Dcom
	cpi	'H'	; Print a help summary?
	jrz	Hcom	
	cpi	'L'	; List out the table?
	jrz	Lcom
	cpi	'M'	; Modify an entry in the table?
	jz	Mcom
	cpi	'S'	; Save the current table?
	jz	Scom
	cpi	'Q'	; Quit the program?
	jz	Qcom
	cpi	'Z'	; Erase (zero out) the table?
	jz	Zcom
	; The entry was invalid.  Print an error message
	;and get the next command (GETCOM).
	lxi	H,AIDmsg
	call	prtmsg
	jmpr	GETCOM
	
Hcom:	lxi	H,helpmsg
	call	prtmsg
	jmpr	GETCOM

Lcom:
	call	prtTABL	 ; print out name/pass  map?
	jmpr	GETCOM	 ; get next command

Qcom:			 ; Quit the program
	jmp	WBOOT	 ; 

;----------
; Scom  - SAVE THE IN-MEMORY MAPS AS THE PERMANENT
;	  NAME/PASSWORD AND DEFAULT CONFIGURATION
;	  TABLES ON THE HARD DISK (or HINET MASTER).
;

Scom:			 ; Save current allocation
			 ; table on hard disk.
	lxi	H,SAVmsg ; Yes. Print 'Saving' message
	call	prtmsg
	call	chaMAPbyt; Assign hard disk to unit 0
	mvi	A,32	 ; A = num of sectors to write
	mvi	B,3	 ; B = starting track
	mvi	C,1	 ; C = starting sector
	lxi	H,namebuf; HL= address of name table
	call	writTABL ; write the D A T to disk
	mvi	A,080h
	mvi	B,4
	mvi	C,1
	lxi	H,cofigbuf
	call	writTABL
	call	resMAPbyt; restore users unit 0 assmt
	lxi	H,COMPmsg
	call	prtmsg	 ; tell user function completed
	jmp	GETCOM	 ; and get next command

;----------
; Zcom - ZERO OUT (ERASE) THE IN-MEMORY TABLES.
;	 NAME/PASSWORD TABLE STARTS AT 2000H.
;	 DEFAULT CONFIGURATION TABLE STARTS AT 6000H.
;

Zcom:	lxi	H,namebuf; HL=addr of table
	lxi	B,16*64  ; BC=length of table
	call	tablclr  ; clear name/pass table
	lxi	H,cofigbuf;HL=addr of table
	lxi	B,128*64 ; BC=length of table
	call	tablclr  ; clear configuration table
	lxi	H,COMPmsg
	call	prtmsg	 ; Tell user function completed
	jmp	GETCOM	 ; and get next command.

tablclr:mvi	M,0	 ; put a 0 into table
	inx	H	 ; next table addr
	dcx	B	 ; decrement the counter
	mov	A,B	 ; test the 2-byte counter
	cpi	0
	jrnz	tablclr
	ora	C
	jrnz	tablclr
	ret		 ; and return when filled.
.page
;----------
; Acom - ADD A NEW ENTRY TO THE TABLES.
;	 INITIALIZE THE NEXT OPEN SPOT IN THE TABLES
;	 AND JUMP INTO THE 'MODIFY' SECTION WHICH
;	 FOLLOWS THIS Acom SECTON.
;

Acom:			 ; Add a new entry into table
;First we find the 1st zero entry in name/pass table
	mvi	A,0	 ; start at 1stline in table

..SRCH:	push	PSW	 ; A=table line number
	mvi	B,16	 ; B=bytes per line in name tbl
	lxi	H,namebuf; HL=addr of start of name tbl
	call	ADDRfind ; sent: A=table line number
			 ; 	 B=bytes per table line
			 ;	HL=start addr of table
			 ; ret:	HL=strt addr of line
	mov	A,M	 ; get 1st byte of that line
	cpi	0	 ; IS IT 0? 0 means its free.
	jrz	..found	 ; YES. Opening in table found.
	pop	PSW	 ; NO. Retreive table line num
	inr	A	 ; and set it to the next line.
	cpi	64	 ; HAVE WE checked all 63 lines
	jrc	..SRCH	 ; NO.  Loop and try next line.

	;Table is filled (63 entries).Tell user no room
	lxi	H,tblfulmsg ;YES. Load `table full` msg
	call	prtmsg	 ; and print it.
	jmp	GETCOM	 ; Get next user command.
	
; Unused line found. Now leave the first character as a
; 0 (that keeps this an unused line for the time being)
; and the next 13 characters (the rest of the name and
; password space) of that entry in name/pass table
; with blanks (ascii 20).  Also, initialize that entry
; (128 chrs) in the default configuration table as 
; blanks except the two bytes (IObyte and chrcnt)
; explained in the code.

..found:;Unused table line number is on TOP of STACK
	;HL=starting address of line of the name table
	inx	H	; Leave the 1st byte a 0
	mov	D,H
	mov	E,L
	inx	D	; DE = HL + 1
	mvi	M,' '	; Put in a blank
	lxi	B,12	; Blank out 14 characters
	LDIR

	;Get the starting addr of unused line in the
	;default configuration table in HL.
	;Get unit number off of the stack.

	pop	PSW	 ; Get unit number off stack
	sta	unit	 ; Meanwhile...Store line num-
 			 ; ber for use in Mcom.
	mvi	B,128	 ; B = bytes per line of table
	lxi	H,cofigbuf ; HL = addr of start of tbl
	call	ADDRfind ; returns addr of that line
			 ;in the table.

	;HL = addr of unused line in the def tbl
	;Now we pad all 128 spaces with blanks then
	;go back and fill in the default IObyte (54h)
	;and the default type-ahead buffer length (0).

	push	H	; save addr of this line
	mov	D,H
	mov	E,L
	inx	D	; DE = HL + 1
	mvi	M,' '	; Put in a blank
	lxi	B,127	; Blank out 128 characters
	LDIR

	pop	H	; restore addr of this line	
	lxi	D,32
	dad	D	; Go 32 bytes in to get to
			; the default IObyte location.
	mvi	M,54h	; Load in the default IObyte.
	inx	H	; Get to the chr-count byte for
			;the default type-ahead buffer.
	mvi	M,0	; Load in the default type-
			;ahead buffer length.

; Tell user what line in table has been selected.
; Jump to getNAM in Mcom (table line modification
; routine) to get the name, password, default con-
; figurations, and preset type-ahead buffer from
; the user.

	lxi	H,addmsg ; `Table line number is` msg
	call	prtmsg	 ; Print msg.
	lda	unit	; Get the table line number
	call	cvtbcd	 ; Make line number decimal
	call	prtbyt	 ; and print it.
	JMP	getNAM	 ; Only operator input is now
			 ; needed.  getNAM is in Mcom
			 ; (modify command) and will
			 ; get all the needed data.
.page
;----------
; Mcom - MODIFY AN EXISTING ENTRY IN THE TABLE.
;	 GET NAME,PASSWORD, DEFAULT ASSIGNMENTS,
;	 IOBYTE VALUE, AND .... FROM THE USER.
;

Mcom:	
; Get the entry number from the user. (0 to 63)
getUNI:	lxi	H,UNImsg ; modify what unit number?
	call	putBUF
	cpi	3	 ; more than two chrs long?
	cp	error
	jp	getUNI
	cpi	1	 ; less than 1 chr long?
	cm	error
	jm	getUNI
	call	makDBYT	 ; make chrs into a byte
	cpi	64	 ; is UNIT more than 63?
	cp	error	 ; YES. print error msg
	jp	getUNI	 ; and ask again.
	sta	unit	 ; NO. Its valid. Save it.

; Check that the entry is in use and can be modified.
; We do this by checking the first byte of that entry.
; If it is 0, then it is not in use and cannot be 
; modified.  An error message is printed telling the
; user to use the 'A' command to make a new entry and
; we jump back to GETCOM to await further instructions.

	; A = a valid entry number (1 to 63)
	mvi	B,16	  ; B =bytes per line of table
	lxi	H,namebuf ; HL=addr of start of table
	call	ADDRfind  ; returned:
			  ; HL=addr of line in table
	mov	A,M	  ; A = 1st byte in the line
	cpi	0	  ; Is entry in use?
	jrnz	..prtline ; Yes. We can proceed.
	lxi	H,badmodmsg
	call	prtmsg	  ; No.  Print `unused` msg
	JMP	GETCOM	  ; and await more commands.

; Print out the line to be modified.

..prtline:
	lxi	H,crlf
	call	prtmsg
	lxi	H,HEADmsg
	call	prtmsg	  ; Space down & print header
	lda	unit	  ; A = unit number
	mvi	B,16	  ; B = bytes per line of tbl
	lxi	H,namebuf ; HL= start of name table
	call	ADDRfind  ; returned:
			  ; HL=addr of line in name tbl
	call	prtname	  ; print that line in name tbl
	lda	unit	  ; A = unit number
	mvi	B,128	  ; B = bytes per line of tbl
	lxi	H,cofigbuf; HL=start of default config-
			  ;uration table.
	call	ADDRfind  ; returned:
			  ; HL=addr in cofig tbl
	call	prtCOF	  ; print line in cofig table
	inx	H	  ; get to next table addr
	call	TAbufprt  ; print type-ahead buffer
	lxi	H,crlf
	call	prtmsg	  ; space down a line

;Ask user if this listing is correct. If YES then we
;proceed.  If NO then we jump back up to get the right
;entry number (getUNI).
..ASKifOK:
	lxi	H,VERIF2msg
	call	prtmsg
	call	CONIN	; get Y or N
	cpi	'N'
	jz	getUNI	; Modify a different entry
	cpi	3	; 3 is Control-C
	jz	WBOOT	; Abort if Control-C
	cpi	'Y'
	cnz	error	; incorrect entry 
	jrnz	..ASKifOK
	lxi	H,crlf
	call	prtmsg	; space down a line
	lxi	H,modinfomsg
	call	prtmsg	  ; print `<CR> for no change`

; Get the name from the user.
; A <CR> entry forces the old entry to be used.
getNAM:	lxi	H,NAMmsg ; what's the name?
	call	putBUF
	cpi	9	 ; more than 8 chrs long?
	cp	error
	jp	getNAM
	cpi	1	 ; less than 1 chr long?
	jrc	..loadN	 ; Yes. Load the old name.
			 ; NO. load the name.
..1:	lxi	B,8	 ; BC = num of byte to transfer
	lxi	H,conbuf+2 ; HL = source address
	lxi	D,NAMaddr  ; DE = destination
	ldir		 ; load Name into temp addr

	lxi	H,NAMaddr
	mvi	B,8	 ; check 8 chrs for upper case
..2:	mov	A,M
	cpi	'a'	 ; is chr lower case?
	jrc	..3	 ; NO. check next letter
	ani	0DFh	 ; make it upper case
	mov	M,A	 ; and put it back
..3:	inx	H	 ; get next chr address
	dcr	B	 ; decrement the counter
	mov	A,B
	cpi	0	 ; all 8 chrs checked?
	jrnz	..2	 ; NO. Loop back 
	jmpr	getPAS	 ; Yes. Continue 
	
..loadN:lda	unit
	mvi	B,16
	lxi	H,namebuf 
	call	ADDRfind
; HL = address of unit in namebuf  table.
	lxi	D,NAMaddr
	lxi	B,8
	ldir		; Copy old entry into Tempentry
; Get the Password from the user
; A <CR> forces the old entry to be used.
getPAS:	lxi	H,PASmsg ; whats the password?
	call	putBUF
	cpi	7	 ; more than 6 chrs long?
	cp	error
	jp	getPAS
	cpi	1	 ; Just a carriage return?
	jrc	..loadP	 ; Yes. Load the old entry
	lxi	B,6	 ; No. Load from console buffer
	lxi	H,conbuf+2
	lxi	D,PASaddr
	ldir		 ; load Password into temp addr
	jmpr	getD1	 ; and get the 1st default

..loadP:lda	unit
	mvi	B,16
	lxi	H,namebuf 
	call	ADDRfind
; HL = addr of unit in namebuf  table.
	lxi	D,8
	dad	D	; HL = addr of passwrd in table
	lxi	D,PASaddr ; DE = destination
	lxi	B,6	  ; BC = num of bytes to copy
	ldir		; Copy from namebuf  to temp


; Get the 1st default assignment from the user
getD1:	lxi	H,DEFmsg  ; Print default header
	call	prtmsg
	lxi	H,DEF1msg ; what's the name?
	call	putBUF
	cpi	9	 ; more than 8 chrs long?
	cp	error
	jp	getD1
	cpi	1	 ; less than 1 chr long?
	jrnc	..load1	 ; No. Its a name.
	lda	unit
	mvi	B,128
	lxi	H,cofigbuf
	call	ADDRfind
; HL = addr of entry in configuration table
	lxi	D,DEF1	 ; DE = destination
	lxi	B,8	 ; BC = num of bytes
	ldir		 ; Copy the bytes
	jmp	getD2	 ; and get the next name

..load1:lxi	H,conbuf+2 ; console buffer address
	lxi	B,8	 ; BC = num of byte to transfer
	lxi	H,conbuf+2 ; HL = source address
	lxi	D,DEF1	 ; DE = destination
	ldir		 ; load Name into temp addr

	lxi	H,DEF1
	mvi	B,8	 ; check 8 chrs for upper case
..2:	mov	A,M
	cpi	'a'	 ; is chr lower case?
	jrc	..3	 ; NO. check next letter
	ani	0DFh	 ; make it upper case
	mov	M,A	 ; and put it back
..3:	inx	H	 ; get next chr address
	dcr	B	 ; decrement the counter
	mov	A,B
	cpi	0	 ; all 8 chrs checked?
	jrnz	..2	 ; NO. Loop back 
			 ; Yes. Continue 

; Get the 2nd default assignment from the user
getD2:	lxi	H,space23
	call	prtmsg
	lxi	H,DEF2msg ; what's the name?
	call	putBUF
	cpi	9	 ; more than 8 chrs long?
	cp	error
	jp	getD2
	cpi	1	 ; less than 1 chr long?
	jrnc	..load2	 ; No. Its a name.
	lda	unit
	mvi	B,128
	lxi	H,cofigbuf
	call	ADDRfind
	lxi	D,8
	dad	D
; HL = addr of entry in configuration table
	lxi	D,DEF2	 ; DE = destination
	lxi	B,8	 ; BC = num of bytes
	ldir		 ; Copy the bytes
	jmp	getD3	 ; and get the next name

..load2:lxi	H,conbuf+2 ; console buffer address
	lxi	B,8	 ; BC = num of byte to transfer
	lxi	H,conbuf+2 ; HL = source address
	lxi	D,DEF2	 ; DE = destination
	ldir		 ; load Name into temp addr

	lxi	H,DEF2
	mvi	B,8	 ; check 8 chrs for upper case
..4:	mov	A,M
	cpi	'a'	 ; is chr lower case?
	jrc	..5	 ; NO. check next letter
	ani	0DFh	 ; make it upper case
	mov	M,A	 ; and put it back
..5:	inx	H	 ; get next chr address
	dcr	B	 ; decrement the counter
	mov	A,B
	cpi	0	 ; all 8 chrs checked?
	jrnz	..4	 ; NO. Loop back 
			 ; Yes. Continue 

; Get the 3rd default assignment from the user
getD3:	lxi	H,space23
	call	prtmsg
	lxi	H,DEF3msg ; what's the name?
	call	putBUF
	cpi	9	 ; more than 8 chrs long?
	cp	error
	jp	getD3
	cpi	1	 ; less than 1 chr long?
	jrnc	..load3	 ; No. Its a name.
	lda	unit
	mvi	B,128
	lxi	H,cofigbuf
	call	ADDRfind
	lxi	D,16
	dad	D
; HL = addr of entry in configuration table
	lxi	D,DEF3	 ; DE = destination
	lxi	B,8	 ; BC = num of bytes
	ldir		 ; Copy the bytes
	jmp	getD4	 ; and get the next name

..load3:lxi	H,conbuf+2 ; console buffer address
	lxi	B,8	 ; BC = num of byte to transfer
	lxi	H,conbuf+2 ; HL = source address
	lxi	D,DEF3	 ; DE = destination
	ldir		 ; load Name into temp addr

	lxi	H,DEF3
	mvi	B,8	 ; check 8 chrs for upper case
..6:	mov	A,M
	cpi	'a'	 ; is chr lower case?
	jrc	..7	 ; NO. check next letter
	ani	0DFh	 ; make it upper case
	mov	M,A	 ; and put it back
..7:	inx	H	 ; get next chr address
	dcr	B	 ; decrement the counter
	mov	A,B
	cpi	0	 ; all 8 chrs checked?
	jrnz	..6	 ; NO. Loop back 
			 ; Yes. Continue 

; Get the 4th default assignment from the user
getD4:	lxi	H,space23
	call	prtmsg
	lxi	H,DEF4msg ; what's the name?
	call	putBUF
	cpi	9	 ; more than 8 chrs long?
	cp	error
	jp	getD4
	cpi	1	 ; less than 1 chr long?
	jrnc	..load4	 ; No. Its a name.
	lda	unit
	mvi	B,128
	lxi	H,cofigbuf
	call	ADDRfind
	lxi	D,24
	dad	D
; HL = addr of entry in configuration table
	lxi	D,DEF4	 ; DE = destination
	lxi	B,8	 ; BC = num of bytes
	ldir		 ; Copy the bytes
	jmp	getIOB	 ; and get the IOBYTE

..load4:lxi	H,conbuf+2 ; console buffer address
	lxi	B,8	 ; BC = num of byte to transfer
	lxi	H,conbuf+2 ; HL = source address
	lxi	D,DEF4	 ; DE = destination
	ldir		 ; load Name into temp addr

	lxi	H,DEF4
	mvi	B,8	 ; check 8 chrs for upper case
..8:	mov	A,M
	cpi	'a'	 ; is chr lower case?
	jrc	..9	 ; NO. check next letter
	ani	0DFh	 ; make it upper case
	mov	M,A	 ; and put it back
..9:	inx	H	 ; get next chr address
	dcr	B	 ; decrement the counter
	mov	A,B
	cpi	0	 ; all 8 chrs checked?
	jrnz	..8	 ; NO. Loop back 
			 ; Yes. Continue 

; Get the IObyte from the user.
getIOB:
	lxi	H,crlf
	call	prtmsg
	lxi	H,IOBmsg
	call	putBUF
	cpi	3	; longer than 3 characters?
	cp	error
	cp	getIOB
	cpi	0	; is buffer length 0
	jrnz	..10	; No. Make it a hex byte
	lda	unit	; Yes. Load the old IOBYTE
	mvi	B,128
	lxi	H,cofigbuf
	call	ADDRfind
	lxi	D,32
	dad	D
	mov	A,M
	jmpr	..11	
..10:	call	makHBYT
..11:	sta	IOBYTE

getTAbuf:
	lxi	H,TABmsg
	call	prtmsg		; print type-ahead info
	lxi	H,TAbufmsg	; request input 
	call	putBUF		; and get it. A=length
	cpi	32		; more than 31 chrs?
	cp	ERROR		; Yes. Point out error
	cp	getTAbuf	; and ask again.
	cpi	1		; Less than 1 chr long?
	jrc	..LDold		; Yes. Load old TA buf
	jrnz	..LDnew		; No.  Load new TA buf
	lxi	H,conbuf+2	; Entry was 1 chr long
	mov	A,M		; Is it a `0`?
	cpi	'0'		; (0 means kill entry)
	jrnz	..LDnew		; No.
	mvi	A,0		; Yes. Make A=0
	lxi	H,conbuf+1	; Load a 0 into
	mov	M,A		; the buffer length
	lxi	H,chrcnt	; and into the temp
	mov	M,A		; holder.
	jmp	prnt		; Print the entry

..LDnew:lxé	H,conbuf+±	» HÌ =CP/Í buffer
	lxi	D,chrcnt	; DE =loc in temp entry
	mvi	B,00
	mov	C,A		
	inx	B		; BC =lenth of TA buf
	LDIR			; Copy TA buf into temp
	jmpr	UPRcase		; make TA buf upr case

..LDold:lda	unit
	mvi	B,128
	lxi	H,cofigbuf 
	call	ADDRfind
; HL = addr of present unit in cofig table.
	lxi	D,33	 ; go in 33 bytes to TA buf adr
	dad	D	 ; HL = addr of TA buf in table
	lxi	D,chrcnt ; DE = destinatn in temp hldr
	lxi	B,32	 ; BC = num of bytes to copy
	LDIR		 ; Copy from namebuf to temp

UPRcase:; Make type-ahead buffer upper case.
	; Make all @'s into <CR>'s.
	lxi	H,TAbuf
	mvi	B,31	 ; check 31 TA chrs 
..chk:	mov	A,M
	cpi	'@'	 ; is this our special chr?
	jrnz	..UPRchk ; NO. check for up/low case
	mvi	M,0Dh	 ; Yes. Put in a car ret
	jmpr	..getnxt ; and check the next chr.
..UPRchk:
	cpi	'a'	 ; Is chr lower case?
	jrc	..getnxt ; NO. check next letter
	ani	0DFh	 ; Yes. make it upper case
	mov	M,A	 ; and put it back.
..getnxt:
	inx	H	 ; Get next chr address
	dcr	B	 ; decrement the counter
	mov	A,B
	cpi	0	 ; all 31 chrs checked?
	jrnz	..chk	 ; NO. Loop back 

;----------
;Print out the header for the line, and print it.
prnt:	lxi	H,HEADmsg
	call	prtmsg
	lxi	H,TEMPentry	; addr of Temp line
	call	prtname		; print the Temp line
	lxi	H,def1
	call	prtCOF	 	; print default configs
	inx	H		; get to next tbl addr
	call	TAbufprt	; print type-ahead buf
	lxi	H,crlf
	call	prtmsg		; and space down a line
;Ask user if this listing is correct
..ASKifOK:
	lxi	H,VERIFYmsg
	call	prtmsg
	call	CONIN	; get Y or N
	cpi	'N'
	jz	GETCOM	; User wants re-enter data
	cpi	3	; 3 is Control-C
	jz	WBOOT	; Abort if Control-C
	cpi	'Y'
	cnz	error	; incorrect entry 
	jrnz	..ASKifOK
;now we figure out addr of line in table
putTABL:lda	unit	 ; A = unit num of addr needed
	mvi	B,16	 ; B = bytes per line of table
	lxi	H,namebuf; HL= addr of start of table
	call	ADDRfind ; get table addr of this unit
; HL = addr of this unit in name/password table
;now we copy the 16 temp bytes into the table
	lxi	B,16	 ; bytes per line of table
	xchg		 ; get table destination in DE
	lxi	H,TEMPentry
	LDIR		 ; put Temp name/pass into tbl

	lda	unit
	lxi	H,cofigbuf
	mvi	B,128
	call	ADDRfind
; HL = addr of this unit in configuration table.
;now we copy 128 temp bytes into the table.
	lxi	B,128
	xchg
	lxi	H,def1	; put configs and type-ahead
	LDIR		; buffer into config table.

;Notify user that function completed. Get next command.
	lxi	H,COMPmsg
	call	prtmsg	 ; tell user function completed
	jmp	getCOM	 ; get next user command
.page
;------------
;  Dcom  -   DELETE AN ENTRY IN THE TABLE. FIRST WE 
;            VERIFY THE ENTRY WITH THE USER, THEN
;	     DELETE THE ENTRY BY BUMPING DOWN ALL
;	     THE PROCEEDING TABLE ENTRIES.
; Get the entry number from the user. (0 to 63)
Dcom:	lxi	H,UNImsg ; modify what unit number?
	call	putBUF
	cpi	3	 ; more than two chrs long?
	cp	error
	jp	Dcom
	cpi	1	 ; less than 1 chr long?
	cm	error
	jm	Dcom
	call	makDBYT	 ; make chrs into a byte
	cpi	64	 ; is UNIT more than 63?
	cp	error	 ; YES. print error msg
	jp	Dcom	 ; and ask again.
	sta	unit	 ; NO. Its valid. Save it.
; Print out the line to be deleted.
..prtline:
	lxi	H,crlf
	call	prtmsg
	lxi	H,HEADmsg
	call	prtmsg	  ; Space down & print header
	lda	unit	  ; A = unit number
	mvi	B,16	  ; B = bytes per line of tbl
	lxi	H,namebuf ; HL= start of name table
	call	ADDRfind  ; returned:
			  ; HL=addr of line in name tbl
	call	prtname	  ; print that line in name tbl
	lda	unit	  ; A = unit number
	mvi	B,128	  ; B = bytes per line of tbl
	lxi	H,cofigbuf; HL=start of default config-
			  ;uration table.
	call	ADDRfind  ; returned:
			  ; HL=addr in cofig tbl
	call	prtCOF	  ; print line in cofig table
	inx	H	  ; get to next table addr
	call	TAbufprt  ; print type-ahead buffer
	lxi	H,crlf
	call	prtmsg	  ; space down a line
;Ask user if this listing is correct. If YES then we
;proceed.  If NO then we jump back up to get the right
;entry number (Dcom).
..ASKifOK:
	lxi	H,VERIF3msg
	call	prtmsg
	call	CONIN	; get Y or N
	cpi	'N'
	jz	Dcom	; Delete a different entry
	cpi	3	; 3 is Control-C
	jz	WBOOT	; Abort if Control-C
	cpi	'Y'
	cnz	error	; incorrect entry 
	jrnz	..ASKifOK; ask again

	lda	unit	; User wants to delete line
..kill:	push	PSW
	call	movLINE	; bump down higher table line
	jrc	..done	; cry bit is set if were done
	pop	PSW
	inr	A	; increment unit number
	cpi	64
	jrnz	..kill	; done if all 64 entries bumped
	push	PSW
..done:	pop	PSW	; just for stack balance
	lxi	H,COMPmsg
	call	prtmsg	; tell user function completed
	jmp	GETCOM	; and get the next command.

;---------
; Subroutine: movLINE
; Regs  in: 	A = line number in table
; Regs out:	none
; Destroyed:	any/all
;
; Bump down the next table entry into the given
;table entry line number.  We do this first for
;the name/password table and then the configuration
;table. We first test for the last entry number (64)
;and then we test for zeroed name entries. We 
;return with the carry bit set in either case.

movLINE:cpi	64
	stc		; set carry just in case
	rz		; were at the top of the table

	push	PSW	; save our line num
	mvi	B,16
	lxi	H,namebuf
	call	ADDRfind ; HL will be addr of line
	lxi	D,16
	xchg
	dad	D	 ; HL = addr of NEXT line num
			 ; DE = addr of given line num
;---Check for a zeroed proceeding entry.
;   Zero out the given line if thats the case.	
	mov	A,M	 ; Check first byte for 0
	cpi	0	 ; Is this a deleted entry?
	jrnz	..cont	 ; NO. Continue with set up.
	mov	H,D
	mov	L,E	 ; HL = addr of given line num
	inx	D	 ; DE = HL + 1
	mvi	M,0
	lxi	B,15
	LDIR		 ; Zero out the given line.
	pop	PSW	 ; Cancel our previous push.
	stc		 ; Set carry bit as flag.
	ret		 ; Rest of tbl is blank.
;---A 0 in the table would have meant no more entries.
..cont:	lxi	B,16	 ; 16 bytes per table line
	LDIR		 ; Bump down the next line into	
			 ; the given line number.

	pop	PSW	 ; restore line num
	mvi	B,128
	lxi	H,cofigbuf
	call	ADDRfind ; HL will be addr of line
	lxi	D,128
	xchg
	dad	D	 ; HL = addr of NEXT line num
			 ; DE = addr of given line num
	lxi	B,128	 ; 128 bytes per table line
	LDIR		 ; Bump down the next line into	
			 ; the given line number.
	ora	A	 ; Make sure cry bit is reset.
	ret		 ; One line has been bumped

;---------
;		Subroutine: prtTABL
; Regs  in:	none
; Regs out:	none
; Destroyed	A,H,L
;Print the disk name/pass and default configuration
;table halting if a name value of 0 is found. 

prtTABL:
	mvi	A,0
	sta	unit		; re-initialize 
	lxi	H,crlf
	call	prtmsg
	lxi	H,HEADmsg
	call	prtmsg		; print table header

..1:	lxi	H,namebuf
	mvi	B,16
	lda	unit
	call	ADDRfind
	call	prtname		; Print a line in name
	rc			; table. Return if crry
	lxi	H,cofigbuf
	mvi	B,128
	lda	unit
	call	ADDRfind
	call	prtCOF		; Print default configs
	inx	H		; get to next table addr
	call	TAbufprt	; Print type-ahead buf
	lda	unit
	inr	A		; increment line number
	sta	unit
	cpi	0FFh		; 255 entries maximum
	jrnz	..1
	ret

;----------
;		Subroutine:	prtname
; Regs  in:	HL=addr in the name/pass  table
; Regs out:	HL=next addr in the name/pass  table
;Destroyed:	A,B,C
;Print one line in the table.
;Halt print out if a console chr is found.
;Resume print out when 2nd console chr is found.
prtname:
	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 size (first entry in each line of the table)
;Halt print and return immediately if the size is 0.

..4:	pop	H	; restore name/pass  tabl addr
	mov	A,M		; get the size
	cpi	0		; End of Table?
	jz	STOPprt		; Yes. Gracefully Return
;Table line is assumed ok.  Print it
	push	H
	lxi	H,crlf		; space down a line
	call	prtmsg
	lda	unit		; unit number in A
prtUNI:	call	cvtbcd
	call	prtbyt		; print the unit number
	lxi	H,space4	; space over 4 spaces
	call	prtmsg
	pop	H
prtN:	mvi	B,8
	call	prtchr		; print 8 chr name
	push	H
	lxi	H,space4	; space over 4 spaces
	call	prtmsg
	pop	H
	inx	H		; get to password addr
prtPAS:	mvi	B,6
	call	prtchr		; print 6 chr password
	push	H
	lxi	H,space4
	call	prtmsg
	pop	H
	inx	H		; next addr in table
	inx	H		; next addr in table
	inx	H		; next addr in table
	ora	A		; clear A
	ret
;---------
; Subroutine: prtCOF
; Regs  in:
; Regs out:
; Destroyed:
; Print a line in the default configuration table
prtCOF:
	push	H
	lxi	H,def1msg
	call	prtmsg
	pop	H
	mvi	B,8
	call	prtchr
	push	H
	lxi	H,def2msg
	call	prtmsg
	pop	H
	inx	H
	mvi	B,8
	call	prtchr
	push	H
	lxi	H,def3msg
	call	prtmsg
	pop	H
	inx	H
	mvi	B,8
	call	prtchr
	push	H
	lxi	H,def4msg
	call	prtmsg
	pop	H
	inx	H
	mvi	B,8
	call	prtchr
	inx	H
	push	H
	mov	A,M
	push	PSW
	lxi	H,space4
	call	prtmsg
	pop	PSW
	call	prtbyt
	pop	H
	ret

;----------
;		Subroutine: TAbufprt
; Regs  in:	HL = addr of 0th type-ahead buffer chr
;		     (which is the length of the TA buf)
; Regs out:	none
; Destroyed:	any/all
; Print the Default type-ahead buffer. Return
; immediately if the length ( [HL] ) is 0.
TAbufprt:
	mov	A,M
	ani	00011111b; length must be less than 32
	cpi	0	 ; Is length 0?
	rz		 ; return if nothing to print.
	push	H
	lxi	H,TAbufmsg
	call	prtmsg
	pop	H
	mov	B,M	; B = length of TA buffer
	inx	H	; HL= addr of 1st TA buf chr
	call	prtchr	; Print that many (reg B)
	ret		; characters and were done.

;----------
;		Subroutine: CONSTAT
; Regs  in:	none
; Regs out:	carry bit set if chr ready
; Destroyed:	
CONSTAT:
	mvi	C,conready
	call	BDOS
	rrc		; set parity bit if
	ret		;chr is ready.
;----------
;		Subroutine: putBUF
; Regs  in:	HL=address of message to print
; Regs out:	A =number of chrs put in buffer
;Destroyed:
;Put console input in a buffer
putBUF:
	call	prtmsg
	call	clrBUF	 ; clear the console buffer	
	mvi	C,bufread
	lxi	D,conbuf
	call	BDOS	 ; put console input in buffer
	lxi	H,conbuf+1
	mov	A,M	 ; put num of buffer chrs in A
	ret
;----------
;		Subroutine: clrBUF
; Regs  in:	none
; Regs out:
; Destroyed:
;Pad the console buffer with ascii 20`s
clrBUF:
	lxi	B,36	    ; Clear 36 bytes
	lxi	H,conbuf+2
	mvi	M,' '		; [HL] = blank
	mov	D,H
	mov	E,L
	inx	D		; DE=HL+1
	LDIR			; Bump over 36 blanks
	ret
;----------
;		Subroutine: makDBYT
; Regs  in:	A=length of console buffer
; Regs out:	A=decimal byte made from console buffer
;Destroyed:	HL,A,B,C
;Make a decimal byte from one or two buffer chrs
makDBYT:
	cpi	1	   ; just one chr
	mvi	B,0
	lxi	H,conbuf+2 ; load 1st chr addr
	jrz	..1
;multiply first chr by 10 and save
	mov	A,M
	sui	'0'	; make ascii chr numeric
	mov	B,A	; save original number
	rlc
	rlc
	rlc
	mov	C,A
	mov	A,B
	rlc
	add	C
	mov	B,A	;save 10*number in B
	inx	H	; get 2nd chr addr
..1:	mov	A,M
	sui	'0'	; make ascii chr numeric
	add	B	; add the two chrs
	ret
;----------

;----------
;		Subroutine: makHBYT
; Regs  in:	A=length of console buffer
; Regs out:	A=hex byte made from console buffer
;Destroyed:	HL,A,B,C
;Make a hex byte from one or two buffer chrs
makHBYT:
	cpi	1	   ; just one chr?
	mvi	B,0
	lxi	H,conbuf+2 ; load 1st chr addr
	jz	aa1	   ; process 1st chr only
;multiply first chr by 16 and save in B
	mov	A,M	; get 1st chr
	inx	H	; get to next chr
	cpi	'A'
	jm	aa2
	ani	0DFh	; make all letters upper case
	sui	'A'-'9'-1
aa2:	sui	'0'
	cpi	0
	jz	aa1	; skip mult if nibble is 0
	ora	A	; reset carry flag
	rlc
	rlc
	rlc
	rlc
	mov	B,A	;save 16*firstnumber in B
aa1:	mov	A,M	; get 2nd chr
	cpi	'A'
	jm	aa3
	ani	0DFh	; make all letters upper case
	sui	'A'-'9'-1
aa3:	sui	'0'
	ora	A	; reset the flags
	add	B	; add the two chrs
	ret

;---------
;		Subroutine: ADDRfind
; Regs  in:    A = A line in table whose addr is 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
;Find an addr of a line in a table
ADDRfind:
; A = line in table to find \  HL= start addr of table
	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.
;---------
;		Subroutine: STOPprt
; Regs  in:	none
; Regs out:	none
;Destroyed:	HL,A
;Gracefully abort from a subroutine and set carry bit
STOPprt:
	lxi	H,crlf	; space down a line
	call	prtmsg
	stc		; set the carry bit
	ret

;----------
;		Subroutine: cvtbcd
; Regs  in:	A=byte to be converted
; Regs out:	A=byte, in BCD format
; Destroyed:	B
;Convert binary to BCD
cvtbcd:
	ora	A
	rz
	mov	B,A
	xra	A
..1:	inr	A
	daa
	djnz	..1
	ret
;----------
;		Subroutine: CONIN
;Fetch a character from the console.
;Make all input letters UPPER CASE,
; and abort if chr is a ^C.
CONIN:	mvi	C,1
	call	BDOS
	cpi	3	;3 is ^C
	jz	WBOOT	;boot if ^C
	cpi	1Bh	;1B is ESCAPE
	jz	GETCOM	;Auto jump to
			;get a new command
	cpi	'a'
	rm
	cpi	'z'+1
	rp
	sui	'a'-'A'
	ret
;----------
;		Subroutine: prtbyt
; Regs  in:	A=byte to be printed
; Regs out:	none
; Destroyed:	A,B,C
;Print a byte on the console
prtbyt:
	push	PSW	; save the chr
	rlc
	rlc
	rlc
	rlc
	call	prtnbl
	pop	PSW
	call	prtnbl
	ret
prtnbl:	ani	0Fh
	adi	'0'
	cpi	'9'+1
	jc	CONOUT
	adi	'A'-('9'+1)
	jmp	CONOUT
;----------
;		Subroutine: prtchr
; Regs  in:	B =length of string
;		HL=addr of string
; Regs out:	none
;Destroyed:	B,A
;Print a specified number of chrs to the console
;Print any <CR>s (0Dh) found as an atsign (@).
prtchr: mov	A,B
	cpi	0
	rz		; return if no chrs to print
	mov	A,M
	cpi	0Dh	; Is chr a carriage return?
	jrnz	..prt	; No. Print the character.
	mvi	A,'@'	; Yes. Make the CR into an @
..prt:	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	
;----------
;		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: Error
; Regs  in:	none
; Regs out:	none
;Destroyed:	HL
;Notifly operator that an incorrect entry has been made
ERROR:	
	push	PSW	; save status flag
	lxi	H,errmsg
	call	prtmsg
	pop	PSW
	ret
;----------
;		Subroutine: CONOUT
; Print a character on the console
;  Regs in:	A = character to be printed
;  Regs out:	none
;  Destroyed:	C
CONOUT:
	mov	C,A
	lxi	D,09h
	lixd	WBOOT+1
	dadx	D
	pcix
;----------
; Messages
LOGmsg:	.ascii	'USERS version '
	.byte	version+'0','.'
	.byte	revision/10 + '0',revision@10+'0'
	.ascii	[cr][lf]'Name/Password/Configuration'
	.asciz	' Table Program'[cr][lf][lf]
COMmsg:	.asciz	[cr][lf][lf]' Command ?'
UNImsg:	.asciz	[cr][lf]'    Entry    (0,1,..63)?'
ADDmsg:	.asciz	[cr][lf]'First available line is '
NAMmsg:	.asciz	[cr][lf]'    Name (up to 8 chrs)?'
PASmsg:	.asciz	[cr][lf]'Password (up to 6 chrs)?'
Defmsg:	.asciz	[cr][lf]'Defaults (up to 8 chrs)'
def1msg:.asciz	' A:'
def2msg:.asciz	' B:'
def3msg:.asciz	' C:'
def4msg:.asciz	' D:'
IOBmsg:	.asciz	' IObyte:'
TABmsg:	.ascii	[cr][lf]' Enter the desired "initial '
	.ascii	'type-ahead buffer" for use right'
	.ascii	' after log in.'[cr][lf]
	.ascii	'Use a 0<CR> for erasing the present '
	.ascii	'one, or just a <CR> for no change.'
	.ascii	[cr][lf]'Use the atsign (@) to imply a'
	.ascii	' <CR> inside the buffer.  i.e. STAT@'
	.ascii	'B:@PAYROLL@'[cr][lf]'The maximum '
	.asciz	'buffer length is 31 characters.'
TAbufmsg:
	.ascii	[cr][lf]
	.asciz	'          Type-ahead buffer: '
AIDmsg:	.asciz	' Please type H for a command summary.'
Helpmsg:.ascii	[cr][lf]'  USERS Command Summary '
	.ascii	[cr][lf]'-------------------------'
	.ascii	[cr][lf]
	.ascii	[cr][lf]'A - Add a new entry to'
	.ascii	' the table'[cr][lf]
	.ascii	'D - Delete an entry in the table'
	.ascii	[cr][lf]'H - Print this Help summary'
	.ascii	[cr][lf]'L - List out current table'
	.ascii	[cr][lf]'M - Modify an '
	.ascii	'entry in the table'
	.ascii	[cr][lf]'Q - Quit the '
	.ascii	'program without change'
	.ascii	[cr][lf]'S - Save as '
	.ascii	'the permanent table'
	.ascii	[cr][lf]'Z - Zero out the entire table'
	.ascii	[cr][lf]
	.ascii	[cr][lf]'Use Control-C to abort '
	.ascii	'the program at any time.'[cr][lf]
	.ascii	'NOTE: No permanent changes are saved '
	.ascii	'unless the Save (S) command is used.'
crlf:	.asciz	[cr][lf]
HEADmsg:.ascii	[cr][lf]'Entry   Name  '
	.ascii	'   Password                   '
	.ascii	' Defaults                    IObyte'
	.ascii	[cr][lf]'----  --------'
	.ascii	'    ------     ---------------'
	.asciz	'---------------------------- ------'
VERIFYmsg:
	.asciz [cr][lf]'Is this listing correct? '
VERIF2msg:
	.asciz [cr][lf]'Is this the entry to modify? '
VERIF3msg:
	.asciz	[cr][lf]'Is this the entry to delete? '
SAVmsg:	.ascii	[cr][lf]'WAIT - Saving Name/'
	.asciz	'Password/Configuration Table '
COMPmsg:.asciz	[cr][lf]'Function Completed'
space4:	.asciz	'    '
space23:.asciz	[cr][lf]'                       '
tblfulmsg:
	.ascii	[cr][lf]'Table is full (63 entries use'
	.asciz	'd).  Use the Modify (M) command.'
badmodmsg:
	.ascii	[cr][lf]'That line does not have an'
	.asciZ	' entry.  Use the Add (A) command.'
modinfomsg:
	.ascii	[cr][lf]'Use the carriage return <CR>'
	.asciz	' to leave an entry unchanged.'
NOGOmsg:.ascii	[cr][lf]'USERS cannot be used on '
	.asciz	'this station.'[cr][lf][lf][lf]
errmsg:	.ascii	[cr][lf]' Incorrect entry. '
	.ascii  'Use ESC to escape, CTRL-C to abort. '
	.asciz	'Please try again.'

conbuf:	.byte	36,0
	.byte	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	.byte	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
clrBYTS:.ascii	'                          '



;*******************************************
;*                                         *
;* HARD DISK I/O DATA, DEFS, & SUBROUTINES *
;*                                         *
;*******************************************

WBOOT	=	0
HDbyt	=	10000000b ; byte assigns hard disk to 0
NETbyt	=	11000000b ; byte assign network to 0
MAPbyt:	.byte	00h	; users unit 0 assignment
DMAaddr:.word	00h	; current DMAaddr for disk I/O
curTRK:	.WORD	00h	; current Track for disk I/O
curSEC:	.byte	00h	; current sector for disk I/O
numSEC:	.byte	00h	; num of sectors for disk I/O
;
;----------
;Subroutine:	chaMAPbyt
; Regs  in:	none
; Regs out:	none
;Destroyed:	any and/or all registers

; Change the unit 0 assignment to that of a hard disk
; or the network IF we are the network master.
; Save the previous assignment for restoration.
chaMAPbyt:
	mvi	C,0
	call	SELDSK	; select unit 0 f
	call	CPMmap	; get current unit 0 assignment
; Current unit 0 assignment (network,etc) returns in A
; BIOS address of the byte returns in HL
	sta	MAPbyt	; save it for later restoration
	lda	47h	; Check if we are on the netwrk
			;master.
	cpi	0FFh	; Are we on the hard disk?
	jrz	..hddsk ;
	mvi	M,NETbyt;  No. Make the network asst.
	ret	
..hddsk:mvi	M,HDbyt	; YES. Assign unit 0 to HD disk
	ret
;----------
;Subroutine:  resMAPbyt
; Regs  in:	none
; Regs out:	none
;Destroyed:	any and/or all registers

; Restore the previous unit 0 assignment
resMAPbyt:
	call	CPMmap	; get current unit 0 assignment
;Current unit 0 assignment (hard disk) returns in A
;BIOS address of the byte returns in HL
	lda	MAPbyt	; original unit 0 assignment
	mov	M,A	; restore previous assignment
	ret
;----------
;Subroutine:	readTABL
; Regs  in:	 A= number of sectors to read
;	        HL= starting DMA address (table in mem)
;		 B= starting track
;		 C= starting sector
; Regs out:	none
;Destroyed:
readTABL:
	sta	numSEC	; save num of secs to read
	mov	A,B
	sta	curTRK	;set value for first track
	mov	A,C
	sta	curSEC	;set value for first sector
	shld	DMAaddr	;set value for first DMA addr
	ora	A	; reset the carry flag
..1:	rc		; return if carry bit set
	mvi	C,0
	call	SELDSK	; select hard disk
	lda	curTRK
	mov	C,A
	mvi	B,0
	call	SETTRK	; select track 0
	lda	curSEC	; load current sector
	mov	C,A
	call	SETSEC	; select current sector
	lbcd	DMAaddr
	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:	writTABL
; Regs  in:	 A= number of sectors to write
;	        HL= starting DMA address (table in mem)
;		 B= starting track
;		 C= starting sector
; Regs out:	none
;Destroyed:
writTABL:
	sta	numSEC	; save num of secs to read
	mov	A,B
	sta	curTRK	;set value for first track
	mov	A,C
	sta	curSEC	;set value for first sector
	shld	DMAaddr	;set value for first DMA addr
	ora	A	; reset the carry flag
..2:	rc
	
	mvi	C,0
	call	SELDSK	; select hard disk
	lda	curTRK
	mvi	B,0
	mov	C,A
	call	SETTRK	; select track 0
	lda	cursec	; load current sector
	mov	C,A
	call	SETSEC	; select current sector
	lbcd	DMAaddr
	call	SETDMA	; select proper buffer location
	call	WRITE	; and write to the disk
	call	INRdata	; increment DMA addr and sector
	jmpr	..2	; read until INRaddr sets carry
;----------
;Subroutine:	INRdata
; Regs  in:	none
; Regs out:	carry bit is set/reset (used as a flag)
;Destroyed:
; Decrement the sector counter. Set carry flag if done
; Increment the DMA address and sector number
INRdata:

dcrSEC:	lda	numSEC	; number of SECs left to write
	dcr	A	; decrement,
	sta	numSEC	; and save.
	cpi	0	; Are we done writing sectors?
	jrnz	..3	; NO. Increment the data
	stc		; YES. Set the carry bit
	ret		; and return.

..3:	lhld	DMAaddr	; get current DMA address
	lxi	D,128
	dad	D	; increment by 128 bytes
	shld	DMAaddr	; and save as new DMA address

	lda	curSEC	; get the current sector
	inr	A	; increment,
	sta	curSEC	; and save as current sector
	cpi	mxdskSEC   ; past last sector?
	jrz	..4	   ; no, return
	jrc	..4	   ; no, return

	lda	curTRK	; get next track number
	cpi	mxdskTRK+1  ; past last track?
	jnc	error	; Yes. Terminal error. Abort.
	inr	A
	sta	curTRK
	mvi	A,1	; No. Reset sector number to 1
	sta	curSEC	; and save
..4:	ora	A	; reset carry flag
	ret		; and return.

;----------
; Call bios directly using WBaddr in low memory
WBaddr	=	WBOOT + 1

HOME:
	lhld	WBaddr
	lxi	D,15h
	dad	D
	pchl
	
SELDSK:
	lhld	WBaddr
	lxi	D,18h
	dad	D
	pchl

SETTRK:
	lhld	WBaddr
	lxi	D,1Bh
	dad	D
	pchl

SETSEC:
	lhld	WBaddr
	lxi	D,1Eh
	dad	D
	pchl

SETDMA:
	lhld	WBaddr
	lxi	D,21h
	dad	D
	pchl

READ:
	lhld	WBaddr
	lxi	D,24h
	dad	D
	pchl

WRITE:
	lhld	WBaddr
	lxi	D,27h
	dad	D
	pchl

CPMMAP:
	lhld	WBaddr
	lxi	D,60h
	dad	D
	pchl

SETBYT:
	lhld	WBaddr
	lxi	D,66h
	dad	D
	pchl

	.blkb	100h
stack:

.end

