	.title 'Dump a specified CP/M file to a Hard Disk'
	.sbttl 'WRUN0'
version	==	1
revision==	5
	.pabs
	.phex
	.loc	100h
	jmp	START

; 		Program: WRUN0

; This program reads a user specified file into a 
; buffer starting at 1000h. Next, the file data
; is placed on the unit 0 Hard Disk starting at a 
; specified track and sector number.

;     I think this is a very complicated and hard to
; follow program.  Its object is to read in a CP/M file
; (which it does using CP/M file management) and
; store it in a file buffer at 1000h. Then, the user
; is queried for a track and sector number.  The CP/M
; file is then written it to a hard disk starting at
; the specified track and sector (using BIOS calls).
;     A knowledge of both CP/M BDOS functions and
; the Basic I/O System is necessary.

; Update history
;
; 10/21/80 WRUN0 updated to optionally read the command
;          line.  This utilizes CP/M's self constructing
;	   File Control Block at 5Ch.        D.Stein
;
; 10/29/80 WRUN0's File Control Block improved to match
;          CP/M's. Command line is now copied into the
;	   program for safe keeping. ( File I/O des-
;	   troys the CP/M command line. )       D.Stein
;
; i.e.   A>WRUN0 ALLOC.TAB 01 79
;                     ^    ^   ^
; floppy file to read |    |   sector to write 
;    			   track to write on hard disk

; Hard Disk Output routines are at the end of the prog
mxdskSEC    =   80h ; maximum number of sectors on disk
mxdskTRK    =   16  ; maximum number of tracks on disk
DMAaddr: .word	00h ; addr ( in file buffer ) for DMA
FCBaddr:.word	0000h	; address of FCB (here or 5Ch)

; File Control Block. See CP/M users guide for details.
FCB:	.byte	00h
filnam:	.byte	20h,20h,20h,20h,20h,20h
	.byte	20h,20h,20h,20h,20h
	.byte	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
.page
;
; The first 19 bytes of the command line are copied
; into this buffer.  If the command line was used
; instead, CP/M file I/O would wipe it out.
comline: 
	.byte	20h,20h,20h,20h,20h,20h,20h
	.byte	20h,20h,20h,20h,20h,20h,20h
	.byte	20h,20h,20h,20h,20h,20h,20h

DSKname:.byte	00	;Holder for CP/M drive select
FCBcnt:	.byte	00h	;Counter of FCB bytes tranfered
numSEC:	.byte	00h	;Number of sectors read by CP/M
bufaddr:.word	00h	;Address of current FCB location
WBOOT	=	00h	;Warm Boot entry point
BDOS	=	05h	;Common CP/M entry point
incon	=	01h	;CP/M console input function
cstat	=	0Bh	;CP/M console status function
bufread	=	0Ah	;CP/M console buffer function
logdsk	=	0Eh	;CP/M disk select function
open	=	0Fh	;CP/M file open function
close	=	10h	;CP/M file close function
CPMread	=	14h	;CP/M file sector read function
dma	=	1Ah	;CP/M Dir Mem Addr set function
cr	=	0Dh	;carriage return
lf	=	0Ah	;line feed
blank	=	20h	;ascii blank
period	=	2Eh	;ascii period
colon	=	3Ah	;ascii colon
EOF	=	1Ah	;end marker for file & buf I/O

; Space for 12-chr CP/M maintained buffer
conbuf:	.byte	15,0
	.byte	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
clrBYTS:.ascii	'                          '

; Buffer for holding CP/M file
filebuf=1000h	; File Buffer starts here

START:
; Print log-on message
	lxi	H,LOGmsg
	call	prtmsg
; Initialize 
Š	mvi	A,0
	sta	FCBcnt	;zero the counter
;
	lxi	H,filnam;FCB file name location
	shld	bufaddr
;
	lxi	H,FCB
	shld	FCBaddr ;FCB address (if no com line)
;
	lxi	H,80h	  ; CP/M Command line address
	lxi	D,comline ; our command line address
	mov	A,M	  ; 80h = length of com line
	inr	A	  ; A = num of bytes to copy
	mov	C,A
	mvi	B,00	  ; BC = num of bytes to copy
	ldir		  ; Copy the CP/M com line 
			  ; into our space for it.

; Get file name from user or at CP/M's FCB at 5Ch.

; Check the command line. Get file name is possible.
	lxi	H,comline ; addr of length of com line
	mov	A,M	; A = length of com line
	cpi	2	; is com line garbage?
	jrc	GETFIL	; Yes. ask user for file name
	lxi	H,5Ch	; No. Load in default FCB addr
	shld	FCBaddr
	jmp	OPENFIL	; Try to open the file.				
; Com line has no useable file name. Get it from user.
GETFIL:
	lxi	H,FCB	; set FCB address to inside
	shld	FCBaddr	; the program.
	lxi	H,entmsg
	call	prtmsg	;ask for file name
	call	putBUF	;read console buffer
; A=length of buffer  /  HL=(addr of 1st buffer chr)-1
	cpi	2	;just car ret?
	jnc	readbuf	;NO. Read file name 
	lxi	H,bfnmsg;Yes.
	call	prtmsg	;print 'bad file name' msg
	jmp	GETFIL	;and ask again.

READBUF:
; First check for a drive select at the start 
; of the file name in the console buffer.
	lxi	H,conbuf+1 ; get console buf address
..1:	inx	H	; get to 1st chr of buffer
	mov	A,M	; get the chr
	cpi	blank	; Is it a blank?
	jrz	..1	; Yes skip it.
	inx	H	; No. Get to 2nd buf chr addr
	mov	A,M	; get 2nd chr
	cpi	colon	; Was 1st chr a drive select?
	dcx	H	; 
	dcx	H	; get back to start of con buf
	jrnz	..2	; No, its only a file name
	inx	H	; Yes. Get to 'drive name' addr
	mov	A,M	; Yes. Get the ascii drive name
	ani	0DFh	; make sure its UPPER CASE
	sui	'A'	; make the ascii chr numeric
	cpi	4	; Is drive select more than 'D'
	push	PSW
	push	H
	lxi	H,bfnmsg
	cnc	prtmsg	; Yes. Print the error message
	pop	H
	pop	PSW
	jnc	GETFIL	; and ask user for the data.
	sta	DSKname	; No. Its valid - we'll save it
	inx	H	; increment to the colon
; Load the file name into the File Control Block
..2:	inx	H	; next buffer chr address
	mov	A,M	; next buffer character
	cpi	blank	; Is chr a blank?
	jrz	..2	; Yes. Skip over it
	cpi	period	; No. Is it a period?
	cz	expand	; Yes. Leave padded blanks
	jrz	..2	; Yes. Now skip to next chr
; Reg A=Valid chr.  Read it into next chr in 'filnam'.
	push	H	;save buf chr addr
	lhld	bufaddr
	cpi	'a'	;Is chr lower case?
	jrc	..3	;NO.
	ani	0DFh	;Yes. Make chr UPPER CASE
..3:	mov	M,A	;store chr at filnam addr
	inx	H	;next filnam addr
	shld	bufaddr
	pop	H	;restore buf chr addr
; increment character counter for FCB
	lda	FCBcnt
	inr	A
	cpi	11	;FCB filled in?
	jz	openfil
	sta	FCBcnt
	jmpr	..2	;get next buf chr
; Try to open the file.
OPENFIL:
	lda	DSKname
	mov	E,A
	mvi	C,logdsk
	call	BDOS	; select the I/O disk
	mvi	C,open
	lded	FCBaddr
	call	BDOS	; open the alleged file
	cpi	0FFh
	jnz	readfil	;AOK open, read into buffer
	lxi	H,fnfmsg
	call	prtmsg	;file not found message
	jmp	WBOOT	;terminal error
; File is open.  Load into buffer (until EOF)	
;-----------------------------------
ŠREADFIL:
; Print 'file found' message
	lxi	H,ffmsg
	call	prtmsg
; Initialize the DMA address
	lxi	H,filebuf
	shld	DMAaddr
; Initialize the sector counter
	mvi	A,0
	sta	numSEC	;number of sectors read

readsec:
; Set the dma address
	mvi	C,dma	;dma-set function
	lded	DMAaddr
	call	BDOS	
; Read in a 128-byte sector into the dma address
	mvi	C,CPMread
	lded	FCBaddr
	call	BDOS	;read the sector

; Successful read? If not, EOF assumed.
	cpi	00	;successful read?
	jrz	..1	;yes, continue
	lxi	H,fimmsg;no, print file-in-mem msg
	call	prtmsg
	lda	numSEC	;load number of sectors read
	call	prtbyt	;print the number out
	lxi	H,crlf
	call	prtmsg	;and space down a line
	jmp	PHASE2	;await user command
; Increment the dma address 
..1:	lhld	DMAaddr
	lxi	D,128
	dad	D
	shld	DMAaddr

; Increment the sector counter
	lda	numSEC
	inr	A
	sta	numSEC	; number of sectors read

; Loop back and read another sector
	jmp	readsec
;--------
;Subroutine:	EXPAND
;  Regs  in:
;  Regs out:
; Destroyed:
EXPAND:
; Leave blanks between file name and extension in FCB
	push	PSW	;save condition flags
	lda	FCBcnt	;no. of chrs transfered
	mov	B,A
	mvi	A,8	;eight total spaces
	sta	FCBcnt	;move counter to 8th pos
	sub	B
	cpi	0
	jrz	..2	;no pads nessecary
	jm	prterr	;terminal error
	push	H	;save file name addr
	lhld	bufaddr	;get FCB addr
..3:	dcr	A	;decr counter
	inx	H	;incr buf addr
	cpi	0
	jrnz	..3	;leave more padded blanks
	shld	bufaddr
	pop	H	;restore file name address
..2:	pop	PSW	;restore flags
	ret
.page
;---GET THE STARTING TRACK AND SECTOR, AND GET THE
;   NUMBER OF SECTORS TO READ FROM THE HARD DISK.
PHASE2:


; Check the command line for the track and sector
SCANCOM:
	lxi	H,comline ; command line address
	mov	A,M	; get the length of com line
 	cpi	2	; Is com line just garbage?
	jc	getTRK	; Yes. Get data from user.
; Command line exists.  Pass over the file name
; to the expected track and sector data.
..1:	inx	H	; No. Look for non-blnk
	mov	A,M	; character.
	cpi	blank	; Have we found it?
	jrz	..1	; No. Try next character.
..2:	inx	H	; Yes. Now look for 
	mov	A,M	; next blank character
	cpi	blank	; Have we found it?
	jrnz	..2	; No. Try next character
; Get the starting track number from the command line.
	call	eatblank; Yes. Eat any more blanks.
	call	makHBYT	; And make chr(s) into a byte
	cpi	mxdskTRK; Is it within bounds?
	jrnc	getTRK	; No. Ask user for data.
	sta	curTRK	; Yes. Save as starting track
; Get the starting sector from the commmand line.
	call	eatblank
	call	makHBYT
	cpi	mxdskSEC; Is it within bounds?
	jnc	getTRK	; No. Ask user for data.
	cpi	1	; Is it within bounds?
	jrc	getTRK	; No. sector value is 0
	sta	curSEC	; Yes. save as current sector.
; All hard disk data received from command line.
; Put the data read from the floppy file onto the disk.

	jmp	putDSK	; Write the floppy data to disk

; No useable data on the command line.
; Get track and sector number from the user.
getTRK:	lxi	H,crlf	 ; space down a line
	call	prtmsg
	lxi	H,TRKmsg ; ask which track
	call	putBUF	 ; read console buffer
; A=length of buffer \ HL=(addr of 1st buf chr)-1
	cpi	0	 ; just a car ret?
	push	PSW
	lxi	H,errmsg
	cz	prtmsg
	pop	PSW
	jz	getTRK	    ; ask again
	lxi	H,conbuf+2  ; get console buffer addr
	call	makHBYT	    ; make chrs into a hex byte
	cpi	mxdskTRK    ; is it with in bounds?
	jz	savTRK	    ; Yes.
	jc	savTRK	    ; Yes.
	lxi	H,errmsg    ; No. Print error message
	call	prtmsg
	jmp	getTRK	    ; and try again.
savTRK:	sta	curTRK	    ; Yes. Store entry

getSEC:	lxi	H,SECmsg ; ask which sector
	call	putBUF	 ; read console buffer
; A=length of buffer \ HL=(addr of 1st buf chr)-1
	cpi	0	 ; just a car ret?
	push	PSW
	lxi	H,errmsg
	cz	prtmsg
	pop	PSW
	jz	getSEC	; ask again
	lxi	H,conbuf+2 ; get console buffer addr
	call	makHBYT	; make chrs into a hex byte
	cpi	1	; is it within bounds?
	jrc	..2	; too low?	
	cpi	mxdskSEC; too high?
	jz	savSEC	; No. save the byte
	jc	savSEC	; No. save the byte
..2:	lxi	H,errmsg; Yes. Print the error message
	call	prtmsg
	jmp	getSEC	; and ask again.
savSEC:	sta	curSEC	; Yes.  Store entry

; Valid track and sector number received. 
; Display starting track and sector to the user.
; Also, display number of sectors to write.

	lxi	H,crlf	; space down a line
	call	prtmsg	
	lxi	H,HEADmsg ; print the header
	call	prtmsg
	lxi	H,space4  ; space over 4 spaces
	call	prtmsg
	lda	curTRK
	call	prtbyt	  ; print current track
	lxi	H,space4  ; space over 4 spaces
	call	prtmsg
	lda	curSEC	   
	call	prtbyt	  ; print current sector
	lxi	H,space4  
	call	prtmsg
	lxi	H,space4
	call	prtmsg	  ; space over 8 spaces
	lda	numSEC
	call	prtbyt	  ; print no. of secs to write

; Verify data accuracy. Jump back to getTRK if bad data
	
ASKifOK:lxi	H,crlf	 ; space down a line
	call	prtmsg
	lxi	H,VERmsg
	call	prtmsg	 ; print 'data correct?' msg
	mvi	C,incon
	call	BDOS	 ; get console chr
	ani	0DFh	 ; make it upper case
	cpi	'N'
	jz	getTRK	 ; Data is incorrect
	cpi	'Y'
	jz	putDSK	 ; User says data is AOK
	cpi	3	 ; 3 is a Control-C
	jz	WBOOT	 ; User wants to abort
	lxi	H,errmsg
	call	prtmsg	 ; print error message
	jmpr	ASKifOK	 ; bad entry. Ask again

; Write data to specified track and sectors
; on the hard disk.

putDSK:	lxi	H,crlf
	call	prtmsg	  ; space down a line
	call	chaMAPbyt ; assign unit 0 to hard disk
	call	writFILE  ; write the file to disk
	call	resMAPbyt ; restore users unit 0 assmt

	lxi	H,finmsg  ; tell user were done
	call	prtmsg
	jmp	WBOOT	  ; and WBOOT

;----END OF MAIN BODY
;
; UTILITY SUBROUTINES
;
;----------
; Subroutine: 	eatblank
; Regs  in:	HL= Present buffer address
; Regs out:	HL= Addr of 1st non-blank buffer addr
;		A = num of chrs before next blank
; Destroyed	A,B
eatblank:
	mvi	B,0	; B is the chr counter
..4:	inx	H	; get to next buffer address
	mov	A,M
	cpi	blank	; Is chr a blank?
	jrz	..4	; Yes. keep scanning.
	inr	B	; No. Increment chr counter
	push	H	; and save non-blnk chr addr
..5:	inx	H	; get to next chr address
	inr	B	; increment chr counter
	mov	A,M	; get the chr
	cpi	blank	; Is chr a blank?
	jrnz	..5	; No. Keep scanning for one.
	dcr	B	; Yes. Adjust the chr counter
	mov	A,B	; and put it in A.
	pop	H	; restore non-blnk chr addr
	ret		; and return.

;----------
; Subroutine:	prtmsg
; Regs  in:	HL=addr of string to be printed
; Regs out:	none
; Destroyed:	A,HL,C
prtmsg:	mov	A,M
	ora	A
	rz		; finished if a null
	push	H
	mov	C,A
	call	CONOUT
	pop	H
	inx	H
	jmpr	prtmsg

;----------
; Subroutine:	prtbyt
; Regs  in:	A=byte to be printed
; Regs out:	none
;Destroyed:	A,any and/or all others
; Print a byte to 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
	mov	C,A
	jc	CONOUT
	adi	'A'-'9'-1
	mov	C,A
	jmp	CONOUT
;----------
; Subroutine:	prterr
; Regs  in:	none
; Regs out:	none
; Destroyed:
;Terminate the program with a message and warm boot.
PRTERR:	lxi	H,TERMmsg
Š	call	prtmsg	;print 'TERMINAL ERROR' msg
	jmp	WBOOT

;----------
; Subroutine: 	makHBYT
; Regs  in:	A = length of buffer
;		HL= addr of 1st buffer chr
; Regs out:	A=hex byte made from console buffer
;		HL= addr of last chr used
;Destroyed:	B,C
;Make a hex byte from one or two buffer chrs
makHBYT:
	cpi	1	   ; just one chr?
	mvi	B,0
	jrz	..2	   ; process 1st chr only
;multiply first chr by 16 and save in B
	mov	A,M	; get 1st chr
	inx	H	; get 2nd chr address
	cpi	'A'
	jrc	..1
	ani	0DFh	; make all letters upper case
	sui	'A'-'9'-1
..1:	sui	'0'
	cpi	0
	jrz	..2	; skip mult if nibble is 0
	ora	A	; reset carry flag
	rlc
	rlc
	rlc
	rlc
	mov	B,A	;save 16*firstnumber in B
..2:	mov	A,M	; get 2nd chr
	cpi	'A'
	jrc  	..3
	ani	0DFh	; make all letters upper case
	sui	'A'-'9'-1
..3:	sui	'0'
	ora	A	; reset the flags
	add	B	; add the two chrs
	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
..4:	inr	A
	daa
	djnz	..4


;----------
;		Subroutine: putBUF
; Regs  in:	HL=address of message to print
; Regs out:	A =number of chrs put in buffer
; 		HL=(addr of 1st buf chr)-1
;Destroyed:
;Put console input in a buffer
putBUF:
	call	prtmsg
	call	clrBUF	 ; clear the console buffer	
	mvi	C,bufread ; CP/M console buffer read
	lxi	D,conbuf ; address of console buffer
	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:
;Clear the console buffer at address 'conbuf'
clrBUF:
	lxi	B,12
	lxi	H,clrBYTS
	lxi	D,conbuf+2
	ldir
	ret

;----------
; Output Messages
;
LOGmsg:	.ascii	[cr][lf]'WRUN0 VER. '
	.byte	version+'0','.'
	.byte 	revision/10+'0',revision@10+'0'
	.ascii	[cr][lf]
	.ascii	'CP/M Floppy disk file to hard disk '
	.asciz	'write utility program.'[cr][lf][lf]
entmsg:	.asciz	[cr]'Enter file name  - '
commsg:	.asciz	[cr][lf]'No file name found'
bfnmsg:	.asciz	[cr][lf]'Invalid file name found'
fnfmsg:	.asciz	[cr][lf]'File not found'
ffmsg:	.asciz	[cr][lf]'File found'
fimmsg:	.asciz	[cr][lf]'File in memory.  Sectors read: '
RDYmsg:	.asciz	[cr][lf]'Ready. '
VERmsg:	.ascii	[cr][lf]' Is data correct and ready to '
	.asciz	'be written to the hard disk ?'
HEADmsg:.ascii	[cr][lf]'  TRACK  SECT  TOTAL SECTORS'
	.asciz	[cr][lf]'  -----  ----      -----'[cr][lf]
INRmsg:	.asciz	[cr][lf]' Incrementing to track '
errmsg:	.ascii	[cr][lf]'Incorrect entry.  Control-C '
	.asciz	'aborts program.  Please try again.'
TERMmsg:.asciz	[cr][lf]'***  TERMINAL ERROR  ***'
endmsg:	.asciz	[cr][lf]'Exiting from WRUN0'
finmsg: .ascii	[cr][lf]
	.asciz	[cr][lf]' Data written to Hard Disk'
space4:	.asciz	'    '
crlf:	.asciz	[cr][lf]
TRKmsg:	.asciz	[cr][lf]'Starting track  number (in hex)? '
SECmsg:	.asciz	[cr][lf]'Starting sector number (in hex)? '
.page
;*******************************************
;*                                         *
;* HARD DISK OUT DATA, DEFS, & SUBROUTINES *
;*                                         *
;*******************************************

HDbyt	=	10000000b ; byte assigns hard disk to 0
MAPbyt:	.byte	00h	; users unit 0 assignment
curSEC:	.byte	00h	; current sector for disk I/O
curTRK:	.byte	00h	; current track 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.
; Save the previous assignment for restoration.
chaMAPbyt:
	mvi	C,0
	call	SELDSK	; select unit 0 
	call	CPMmap	; get current unit 0 assignment
; Current unit 0 assignment (network,etc) returns in A
; BIOS address of the CP/M MAP byte returns in HL
	sta	MAPbyt	; save it for later restoration
	mvi	M,HDbyt	; assign unit 0 to a hard 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 CP/M MAP byte returns in HL
	lda	MAPbyt	; original unit 0 assignment
	mov	M,A	; restore previous assignment
	ret

;----------
;Subroutine:	writFILE
; Regs  in:	none
; Regs out:	none
;Destroyed:

; Write from the buffer to the hard disk
; File contents start at 1000h. (filebuf)
writFILE:
	lxi	H,filebuf
	shld	DMAaddr	;set value for first DMA addr
	ora	A	; reset the carry flag
..1:	rc
	mov	C,0
	call	SELDSK	; select hard disk
	lda	curTRK	; load current track
	mov	C,A
	call	SETTRK	; select requested track 
	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, sector--
			; decrement sector counter.
	jmpr	..1	; 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	..2	; NO. Increment the data
	stc		; YES. Set the carry bit
	ret		; and return.

..2:	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	..3	   ; no, return
	jrc	..3	   ; no, return

	lxi	H,INRmsg; 'moving to next track' msg
	call	prtmsg
	lda	curTRK	; get next track number
	cpi	mxdskTRK+1  ; past last track?
	jnc	prterr	; Yes. Terminal error. Abort.
	inr	A
	sta	curTRK
	call	prtbyt	; print the track number
	mvi	A,1	; No. Reset sector number to 1
	sta	curSEC	; and save
..3:	ora	A	; reset carry flag
	ret		; and return.

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

CONOUT:
	lhld	WBaddr
	lxi	D,09h
	dad	D
	pchl

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

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	60
stack:

.end

