DataMuseum.dk

Presents historical artifacts from the history of:

CP/M

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about CP/M

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦4219dd1aa⟧ TextFile

    Length: 70016 (0x11180)
    Types: TextFile
    Names: »SPZ.MAC«

Derivation

└─⟦692ac107c⟧ Bits:30005923 PolyPascal-80 V3.10 arbejdsdiskette 1
    └─ ⟦this⟧ »SPZ.MAC« 

TextFile

	.Z80
	TITLE	SPZ - CP/M DISK UTILITY

$VER	DEFL	'2'			;VERSION NUMBER
$MOD	DEFL	'5'			;MODIFICATION LEVEL

	DB	'             '
	DB	'   SUPERZAP 2   '
	DB	' FOR SUPERBRAIN '
	DB	'                '
	DB	'    W.M.DAVIDSON'
	DB	'  H.J.SHELDRAKE '
	DB      '                '
	DB	'                '

;
;	CURSOR CHARACTER EQUATES (MUST BE 01H TO 01FH)
;

$LEFT	EQU	008H		;CURSOR LEFT  IS ^H
$RIGHT	EQU	00CH		;CURSOR RIGHT IS ^L
$UP	EQU	00BH		;CURSOR UP    IS ^K
$DOWN	EQU	00AH		;CURSOR DOWN  IS ^J
$TAB	EQU	009H		;CURSOR TAB   IS ^I
$ESC	EQU	01BH		;ESCAPE       IS ESC
$INSRT	EQU	'V'-040H	;INSERT       IS ^V
$DELETE	EQU	'G'-040H	;DELETE       IS ^G
$QUIT	EQU	'Q'-040H	;QUIT EDIT    IS ^Q
$END	EQU	'Z'-040H	;END EDIT     IS ^Z
;
; SCREEN CONTROL FOR SUPERBRAIN
;
CLSSTR:	DB	0CH,00H,00H,00H	;CLEAR SCREEN
CLLSTR:	DB	1BH,7EH,'K',00H	;CLEAR LINE
CRPSTR:	DB	1BH,'Y',00H,00H	;CURSOR POSITION PREFIX
FLAGCH:	DB	7FH		;FLAG CHARACTER IN LIST MODE

	.XLIST
;
;---------------- MACRO DEFINITIONS
;
;
; $RTN - STANDARD ROUTINE ENTRY
;
$RTN	MACRO	$RTNN
	ENTRY	$RTNN
$RTNN:	DS	0
	ENDM
;
; $PANEL - LOAD HL AND DISPLAY PANEL
;
$PANEL	MACRO	$PNLNM
	LD	HL,$PNLNM	;POINT TO PANEL
	CALL	DPNL		;DISPLAY IT
	ENDM
;
; $FLD - LOAD HL AND DISPLAY FIELD
;
$FLD	MACRO	$FLDNM
	LD	HL,$FLDNM
	CALL	DFLD
	ENDM
;
; $NPANEL - CLEAR SCREEN AND DISPLAY PANEL
;
$NPANEL	MACRO	$PNLNM
	CALL	DHDR
	$PANEL	$PNLNM
	ENDM
;
; $STRO - PRINT STRING AT (HL)
;
$STRO	MACRO	$STRNM
	LD	HL,$STRNM
	CALL	STRO
	ENDM
;
; $IFLD - LOAD HL, DISPLAY FIELD, GET AND FOLD INPUT
;
$IFLD	MACRO	$FLDNM
	LD	HL,$FLDNM		;POINT TO FIELD
	CALL	DFLD			;DISPLAY IT
	CALL	CHRF			;GET INPUT
	ENDM
;
; $MTCH - CALL BYTE MATCHER
;
$MTCH	MACRO	$LST
	LD	HL,$LST
	CALL	MTCH
	ENDM
;
; $EXVA - EXECUT VECTORED ACTION
;
$EXVA	MACRO	$LST
	LD	DE,$LST
	CALL	DOIT
	ENDM
;
; $HEXW - DISPLAY HEX WORD
;
$HEXW	MACRO	$WORD
	LD	HL,($WORD)
	CALL	HEXW
	ENDM

	.LIST
;
;---------------- GLOBAL EQUATES ----------------
;
CR	EQU	0DH
LF	EQU	0AH
FALSE	EQU	000H
TRUE	EQU	0FFH
CMD	EQU	80H
FBUFF	EQU	80H
;
;---------------- CPM SYSTEM CALL CODES
;
CPM	EQU	05H		;CPM CALL ADDRESS
CONIO	EQU	06H		;DIRECT CONSOLE I/O
RESET	EQU	0DH		;RESET DISK SYSTEM
SETDEF	EQU	0EH		;SET DEFAULT DRIVE
OPEN	EQU	0FH		;OPEN FILE
CLOSE	EQU	10H		;CLOSE FILE
FNDFST	EQU	11H		;FIND FIRST DIRECTORY MATCH
FNDNXT	EQU	12H		;FIND NEXT DIRECTORY MATCH
GETDEF	EQU	19H		;GET CURRENT DRIVE ID
READRN	EQU	21H		;READ RANDOM RECORD
WRITRN	EQU	22H		;WRITE RANDOM RECORD
FILESZ	EQU	23H		;COMPUTE FILE SIZE
SETRN	EQU	24H		;SET RANDOM RECORD

;
;---------------- DEFAULT FCB IMAGE
;
WRKFCB	EQU	5CH		;DEFAULT FCB ADDRESS
WRKDR	EQU	WRKFCB+0	;DRIVE
WRKFN	EQU	WRKDR+1		;FILE NAME BODY
WRKFT	EQU	WRKFN+8		;FILE NAME EXTENSION
WRKEX	EQU	WRKFT+3		;EXTENT NUMBER
WRKS1	EQU	WRKEX+1		;CPM RESERVED
WRKS2	EQU	WRKS1+1		;CPM RESERVED
WRKRC	EQU	WRKS2+1		;RECORD COUNT THIS EXTENT
WRKMP	EQU	WRKRC+1		;ALLOCATION MAP FOR EXTENT
WRKNR	EQU	WRKMP+16	;NEXT SEQUENTIAL RECORD
WRKRR	EQU	WRKNR+1		;2 BYTE RANDOM RECORD NUMBER
WRKOV	EQU	WRKRR+2		;RANDOM OVERFLOW FLAG

FREESP:	DW	ENDCDE		;ALLOW USER CODE INSERTION

;
;---------------- MESSAGES
;
HLAREA	EQU	0109H		;HELP   IN LINES 01-10 (01 FOR 09)
DRAREA	EQU	0E08H		;DIRECTORY LINES 14-21 (14 FOR 08)

HDRMSG:	DB	0,29,'SUPERZAP VERSION ',$VER,'.',$MOD,0

;
;---------------- GLOBAL WORK AREAS
;
MEMRY:	DS	2		;FREE MEMORY SPACE
READST:	DB	0FFH		;RETURN CODE FROM READ OPERATIONS
INCH:	DB	0		;INPUT CHARACTER
TYCURC:	DB	0		;CURRENT CHARACTER FOR TYPE
RELREC:	DW	0		;CURRENT RECORD NUMBER
BUFPOS:	DS	1
BASEAD:	DS	3
SAVREC:	DW	0		;SAVE RECORD DURING SET
SAVFSC:	DW	0		;RECORD TO BE READ
RO:	DB	0		;READ ONLY FILE FILE
NEWDE@:	DS	2		;ADDRESS OF ENTRY JUST FOUND
NXTDE@:	DS	2		;NEXT POSITION IN TABLE
TOPDE@:	DW	0		;TOP OF DIRECTORY TABLE
FSTDE@:	DW	0		;BOTTOM OF DIRECTORY TABLE
DECNT:	DB	0		;NUMBER OF ENTRIES READ
PRTCNT:	DB	0		;NUMBER OF ENTRIES DISPLAYED
PRTENT:	DB	0		;ENTRY NUMBER TO BE PRINTED
SELDE:	DS	1		;SELECTED DIRECTORY ENTRY
DIROFF:	DB	0		;DIRECTORY DISPLAY OFFSET
DEFDRV:	DS	1		;CURRENT DRIVE ID
REQDRV:	DS	1		;REQUIRED DRIVE ID
CURAN:	DS	1		;CURRENT ABSOLUTE DRIVE NUMBER
ERRFLD:	DW	0		;ERROR FIELD ON SCREEN
	DB	0		;END OF FIELD MARK
ERRTXT:	DW	0		;ADDRESS EOF ERROR TEXT
PRVERR:	DW	0		;ADDRESS OF PREVIOUS TEXT
WTG:	DB	0		;NEXT PROCESS MODE
AFNSTR:	DB	'???????????'
DSKCMD:	DB	'DSK:'
PGEPTR:	DS	2		;ADDRESS OF PAGE POINTER LIST
CURPG@:	DS	2		;ADDRESS OF CURRENT PAGE ENTRY
MAXPG@:	DS	2		;ADDRESS OF LAST PAGE ENTRY
RPANEL:	DS	1		;DISPLAY PANEL REQUEST
;
; SCRATCHPAD DATA
;
SPADDR:	DS	2		;SCRATCHPAD BUFFER ADDRESS
SPTYPE:	DS	1		;NONE/PHYSICAL/RELATIVE
SPSECT:	DS	2		;SECTOR NUMBER
SPDRIV:	DS	1		;ABSOLUTE DRIVE NUMBER
SPNAME:	DS	12		;UFN OR TRACK NUMBER
	DB	0		;END OF FIELD MARK
SPDMSG:	DB	'Drive ',0
SPTMSG: DB	' Track ',0
SPSMSG:	DB	' Sector ',0
SPEMTY:	DB	'Empty',0
;
;---------------- LIST MODE FCB
;
LMDFCB	EQU	$

LMDDR:	DB	0		;DRIVE
LMDFN:	DS	8		;FILE NAME
LMDFT:	DS	3		;FILE TYPE
LMDEX:	DB	0		;EXTENT NUMBER
LMDS1:	DB	0
LMDS2:	DB	0
LMDRC:	DB	0		;RECORD COUNT
LMDD0:	DS	16		;CLUSTER ALLOC MAP
LMDCR:	DB	0		;CURRENT RECORD

;
; LOCAL BIOS COPY - USED TO SIMPLIFY DIRECT BIOS CALLS
;
LBIOS 	EQU	$		;START OF LOCAL BIOS

WBOOT:	DS	3
CONST:	DS	3
CONIN:	DS	3
CONOUT:	DS	3
LIST:	DS	3
PUNCH:	DS	3
READER:	DS	3
HOME:	DS	3
SELDSK:	DS	3
SETTRK:	DS	3
SETSEC:	DS	3
SETDMA:	DS	3
READ:	DS	3
WRITE:	DS	3
LISTST:	DS	3
SECTRN:	DS	3

ELBIOS	EQU	$		;END OF LOCAL BIOS

;
; INIT - SPZ INITIALISATION
;
	$RTN	INIT
	LD	HL,(06H)
	LD	SP,HL		;SET STACK TO BASE OF BDOS
	LD	HL,(1)		;LOAD BIOS VECTOR ADDRESS
	LD	DE,LBIOS
	LD	BC,ELBIOS-LBIOS
	LDIR			;SET UP LOCAL BIOS VECTOR
	LD	HL,AFNSTR
	CALL	LSEL		;SET LIST SELECTION TO ALL
	LD	HL,(FREESP)	;FIND TOP OF PROG
	LD	(SPADDR),HL	;SET SCRATCHPAD ADDRESS
	LD	DE,080H
	ADD	HL,DE		
	LD	(MEMRY),HL	;PUT WORK AREA ABOVE SCRATCHPAD
	XOR	A
	LD	(SPTYPE),A	;SET SCRATCHPAD EMPTY
	LD	HL,0
	LD	(ERRTXT),HL	;CLEAR ERROR MESSAGE FIELD
	LD	(PRVERR),HL	;AND PREVIOUS ERROR
	LD	C,GETDEF
	CALL	CPM		;GET DEFAULT DRIVE NUMBER
	LD	(DEFDRV),A	;SAVE IT
	LD	(CURAN),A	;SET CURRENT ABSOLUTE DISK NUMBER
	LD	A,(WRKDR)
	OR	A
	JR	Z,INIT01	;IF DRIVE ID IN COMMAND
	DEC	A
	LD	(CURAN),A	;USE THAT AS CURRENT
INIT01	EQU	$		;ENDIF
	LD	HL,CMD		;POINT TO COMMAND AREA
INIT02	EQU	$		;LOOP
	INC	HL
	LD	A,(HL)
	OR	A
	JR	Z,INIT05	;QUIT IF END OF COMMAND
	CP	' '
	JR	Z,INIT02	;IGNORE SPACES
	INC	HL
	LD	A,(HL)
	CP	':'		
	JR	NZ,INIT03	;IF CMD IS DRIVE ID
	INC	HL		;SKIP PAST IT
	JR	INIT04
INIT03	EQU	$		;ELSE
	DEC	HL		;POINT TO FIRST CHARACTER
INIT04	EQU	$		;ENDIF
	LD	DE,DSKCMD
	LD	BC,4
	CALL	CPST
	JR	NZ,INIT05	;IF DISK OPTION
	CALL	SETP		;SET DISK MODE
	JR	INIT06
INIT05	EQU	$		;ELSE
	CALL	SETD		;ASSUME DIRECTORY MODE
	LD	HL,WRKFN
	LD	A,(HL)
	CP	' '
	JR	Z,INIT08	;IF NOT NULL OPTION
	LD	B,11
INIT09	EQU	$		;LOOP
	LD	A,(HL)
	CP	'?'
	JR	Z,INIT10	;EXIT IF AFN INDICATED
	INC	HL
	DJNZ	INIT09		;TILL FN AND FT SCANNED
	CALL	SETF		;MUST BE UFN
	JR	INIT12
INIT10	EQU	$		;ON '?' FOUND
	LD	HL,WRKFN
	CALL	LSEL		;SET LIST SELECTION TO AFN GIVEN
INIT12	EQU	$		;ENDIF
INIT08	EQU	$		;ENDIF
INIT06	EQU	$		;ENDIF
	LD	A,(CURAN)	
	CALL	CHDR		;INITIALISE DISK CONTROL BLOCKS
	JR	NZ,INIT13	;IF ILLEGAL DISK
	LD	A,(DEFDRV)
	CALL	CHDR		;USE DEFAULT DISK
	LD	HL,ILDMSG
	LD	(ERRTXT),HL	;SET ERROR MESSAGE
INIT13	EQU	$
;
; MAIN - SPZ MAINLINE
;
	$RTN	MAIN
MAIN01	EQU	$		;LOOP
	LD	A,(WTG)
	$MTCH	MAINLS		;TEST CODE
	JR	NZ,MAIN02	;IF INVALID ACTION EXIT
	$EXVA	MAINVC		;EXEC ACTION
	JR	MAIN01
MAIN02	EQU	$		;ENDLOOP
	CALL	CLRS
	LD	A,(DEFDRV)
	LD	E,A
	LD	C,SETDEF
	CALL	CPM		;RESTORE ORIGINAL DEFAULT
	JP	0		;EXIT TO SYSTEM

ILDMSG:	DB	'** Invalid Disk Specified',0
;
; MAINLINE ACTION VECTOR
;
MAINLS:	DB	4,'XFDP'
MAINVC	EQU	$
	DW	ENDR		;END RUN
	DW	FDMD		;FILE DISPLAY MODE
	DW	DRMD		;DIRECTORY MODE
	DW	PSMD		;PHYSICAL SECTOR MODE

;
; ENDR - END SPZ RUN
;
	$RTN	ENDR
	XOR	A
	LD	(WTG),A
	RET

;
; FDMD - FILE DISPLAY MODE
;
	$RTN	FDMD
	LD	HL,(FDMDER)
	LD	(ERRFLD),HL	;SET ERROR FIELD POINTER
	LD	A,0FFH
	LD	(FDMDSI),A	;REQUEST SI DISPLAY
	LD	(RPANEL),A	;REQUEST PANEL DISPLAY
	CALL	TFLE
	LD	A,(FLERR)
	OR	A
	JR	Z,FDMD03	;IF FILE ERROR
	CALL	SETD		;SET DIRECTORY MODE
	JP	FDMD04
FDMD03	EQU	$		;ELSE
FDMD05	EQU	$		;LOOP
	LD	A,(RPANEL)
	OR	A
	JR	Z,FDMD11	;IF PANEL REQUIRED
	XOR	A
	LD	(RPANEL),A	;RESET REQUEST
	$NPANEL	FDMDPN		;DISPLAY FILE MODE PANEL
	LD	HL,FILEMS	;POINT TO FILE MESSAGE
	LD	A,(COMFLG)
	OR	A
	JR	Z,FDMD09	;IF .COM FILE
	LD	HL,LOADMS	;POINT TO LOAD MESSAGE
FDMD09	EQU	$		;ENDIF
	CALL	DFLD
	$FLD	FSPMSG
	CALL	DSPI		;DISPLAY SCRATCHPAD INFO
FDMD11	EQU	$		;ENDIF
	CALL	ERRP		;PROCESS ERRORS
	LD	A,(FDMDSI)
	OR	A
	JR	Z,FDMD10	;IF SI DISPLAY REQUIRED
	CALL	DFSI		;DISPLAY FILE SECTOR INFO
	LD	HL,FBUFF
	CALL	WRBF		;DISPLAY BUFFER CONTENTS
	XOR	A
	LD	(FDMDSI),A	;RESET REQUEST
FDMD10	EQU	$		;ENDIF
FDMD07	EQU	$		;LOOP
	$IFLD	SELMSG		;PROMPT SELMSG AND GET COMMAND
	$MTCH	FDMDLS
	JR	Z,FDMD06	;EXITIF VALID
	CALL	ALRM		;SOUND THE ALARM
	JR	FDMD07
FDMD06	EQU	$		;ENDLOOP
	$EXVA	FDMDVC
	LD	A,(WTG)
	CP	'F'
	JR	NZ,FDMD08	;EXIT IF MODE NO LONGER F
	JP	FDMD05
FDMD08	EQU	$		;ENDLOOP
	LD	C,CLOSE
	LD	DE,WRKFCB
	CALL	CPM
FDMD04	EQU	$		;ENDIF
	RET

COMSTR:	DB	'COM'		;.COM FILE TYPE

;
; FILE DISPLAY MODE MESSAGES, PANEL AND ACTION VECTOR
;
SELMSG:	DB	9,10,'Select Function ===> ',00
SETMSG:	DB	11,36,'Enter Hex Sector',0	;OVERLAID BY CURMSG
FDMDER:	DB	7,0				;ERROR POSITION
FILEMS:	DB	11,53,'File Offset ',0
LOADMS:	DB	11,53,'Load Address',0

FDMDPN:	DB	14				;FIELD COUNT
	DB	02,00,'N  Next sector',0
	DB	03,00,'P  Previous sector',0
	DB	02,22,'T  Top of file',0
	DB	03,22,'E  Last sector of file',0
	DB	02,54,'Z  Exit from Superzap',0
	DB	03,54,'L  Exit to file list',0
	DB	04,00,'C  Change Sector',0
	DB	04,22,'S  Select Sector',0
	DB	04,54,'X  Scratchpad operations',0
	DB	11,04,'File-Name',0
	DB	11,16,'Access',0
CURMSG:	DB	11,36,'Current-Sector  ',0	;OVERLAID BY SETMSG
FILE:	DB	12,00
DRIVNM:	DB	'd:'
FILENM:	DB	'filename.typ',0
	DB	12,17,'R/'
FDMDRS:	DB	's ',0				;ACCESS INDICATOR
FSPMSG:	DB	06,00,'Scratchpad :- ',0
;
; FILE STATISTICS FIELDS
;
WRSNFL:	DB	12,41,0
WRFOFL:	DB	12,55,0
SFSNIP:	DB	12,45,0

FDMDLS:	DB	9,'NCPLTESZX'
FDMDVC	EQU	$
	DW	NXFS		;NEXT FILE SECTOR
	DW	FSCH		;FILE SECTOR CHANGE
	DW	PRFS		;PREVIOUS FILE SECTOR
	DW	SETD		;SELECT DIRECTORY MODE
	DW	FRFS		;POSITION TO FIRST FILE SECTOR
	DW	LSFS		;POSITION TO LAST FILE SECTOR
	DW	SFSN		;SET FILE SECTOR NUMBER
	DW	SETX		;SET EXIT MODE
	DW	FSPM		;SCRATCHPAD MANAGER

FDMDSI:	DS	1		;SI REQUEST FLAG

;
; NXFS - READ NEXT FILE SECTOR
;
	$RTN	NXFS
	LD	HL,(RELREC)
	INC	HL
	LD	(RELREC),HL	;INCREMENT RECORD NUMBER
	CALL	RDFS		;ATTEMPT TO READ RECORD
	JR	NZ,NXFS02	;IF GOOD READ
	LD	A,TRUE
	LD	(FDMDSI),A	;REQUEST SI DISPLAY
	JR	NXFS01
NXFS02	EQU	$		;ELSE
	CALL	ALRM		;SOUND ALARM
NXFS01	EQU	$		;ENDIF
	RET

;
; PRFS - READ PREVIOUS FILE SECTOR
;
	$RTN	PRFS
	LD	HL,(RELREC)
	LD	A,H
	OR	L
	JR	NZ,PRFS01	;IF RECORD ZERO
	CALL	ALRM		;SOUND ALARM
	JR	PRFS02
PRFS01	EQU	$
	DEC	HL
	LD	(RELREC),HL	;DECREMENT RECORD POINTER
	CALL	RDFS		;ATTEMPT TO READ IT
	JR	NZ,PRFS03	;IF GOOD READ
	LD	A,TRUE
	LD	(FDMDSI),A	;REQUEST SI DISPLAY
	JP	PRFS04
PRFS03	EQU	$		;ELSE
	CALL	ALRM		;SOUND ALARM
PRFS04	EQU	$		;ENDIF
PRFS02	EQU	$		;ENDIF
	RET

;
; FSCH - FILE SECTOR CHANGE
;
	$RTN	FSCH
	LD	A,(RO)
	OR	A
	JR	Z,FSCH01	;IF READ ONLY FILE
	CALL	ALRM		;SOUND THE ALARM
	JR	FSCH02
FSCH01	EQU	$		;ELSE
	CALL	SCCH		;GO INTO SECTOR CHANGE MODE
	LD	A,(SCCHWR)
	OR	A
	JR	Z,FSCH03	;IF WRITE REQUIRED
	CALL	WRFS		;WRITE OUT SECTOR
	JR	FSCH04
FSCH03	EQU	$		;ELSE
	CALL	RDFS		;READ SECTOR
FSCH04	EQU	$		;ENDIF
	LD	A,TRUE
	LD	(RPANEL),A	;REDISPLAY FILE MODE PANEL
	LD	(FDMDSI),A	;REQUEST SI DISPLAY
FSCH02	EQU	$		;ENDIF
	RET			

;
; FRFS - POSITION TO FIRST FILE SECTOR
;
	$RTN	FRFS
	LD	HL,0
	LD	(RELREC),HL
	CALL	RDFS		;READ THE SECTOR
	LD	A,TRUE
	LD	(FDMDSI),A	;REQUEST SI DISPLAY
	RET

;
; LSFS - POSITION TO LAST FILE SECTOR
;
	$RTN	LSFS
	LD	DE,WRKFCB
	LD	C,FILESZ	;COMPUTE FILE SIZE
	CALL	CPM
	LD	HL,(WRKRR)
	DEC	HL
	LD	(RELREC),HL	;SET UP RECORD TO READ
	CALL	RDFS		;READ THE RECORD
	LD	A,TRUE
	LD	(FDMDSI),A	;REQUEST SI DISPLAY
	RET

;
; SFSN - SET FILE SECTOR NUMBER
;
	$RTN	SFSN
	LD	HL,SELMSG
	CALL	CFLD		;CLEAR FUNCTION PROMPT
	LD	HL,(RELREC)
	LD	(SAVREC),HL	;SAVE RECORD NUMBER
	$FLD	SETMSG		;DISPLAY SET MESSAGE
	LD	HL,0
	LD	(RELREC),HL	;ZERO RECORD NUMBER
SFSN01	EQU	$
	CALL	DFSI		;DISPLAY FILE SECTOR INFO
	$IFLD	SFSNIP		;POSITION AND GET INPUT
	$MTCH	HEXCHR
	JR	NZ,SFSN02	;IF VALID
	EX	DE,HL		;DIGIT TO DE
	LD	HL,(RELREC)
	CALL	H16D		;HL=HL*16+DIGIT
	LD	(RELREC),HL	;SAVE NEW RECORD NUMBER
	JR	SFSN03
SFSN02	EQU	$
	CP	$ESC
	JR	NZ,SFSN04	;ELSE IF ESC
	LD	HL,(SAVREC)
	LD	(RELREC),HL	;RESTORE SECTOR NUMBER
	JR	SFSN03
SFSN04	EQU	$
	CP	$LEFT
	JR	NZ,SFSN06	;ELSE IF BACKSPACE
	LD	HL,RELREC+1
	XOR	A
	RRD
	DEC	HL
	RRD			;RELREC=RELREC/16
	JR	SFSN03
SFSN06	EQU	$
	CP	CR
	JR	NZ,SFSN07	;ELSE IF C/R
	CALL	RDFS		;READ SECTOR
	JR	Z,SFSN08	;IF BAD READ
	CALL	ALRM		;SOUND THE ALARM
	XOR	A
	LD	(INCH),A	;DONT EXIT
SFSN08	EQU	$		;ENDIF
	JR	SFSN03
SFSN07	EQU	$		;ELSE 
	CALL	ALRM		;ERROR
SFSN03	EQU	$
	LD	A,(INCH)
	CP	CR
	JR	Z,SFSN99	;EXITIF C/R
	CP	$ESC
	JR	Z,SFSN99	;OR ESC
	JP	SFSN01
SFSN99	EQU	$		;ENDLOOP
	$FLD	CURMSG		;REDISPLAY CURRENT SECTOR MESSAGE
	LD	A,TRUE
	LD	(FDMDSI),A	;REQUEST DISPLAY
	RET
;
; FSPM - FILE SCRATCHPAD MODE
;
	$RTN	FSPM
	$NPANEL	PSPMPN		;DISPLAY PANEL
	$FLD	PSPCUR		;POSITION FOR CURRENT INFO
	LD	A,(CURAN)
	ADD	A,41H
	CALL	CHRO		;DISPLAY DRIVE
	LD	A,':'
	CALL	CHRO
	$STRO	FILENM
	$STRO	SPSMSG
	$HEXW	RELREC		;SECTOR
	$FLD	PSPSPD		;POSITION FOR S/P DATA
	CALL	DSPD		;DISPLAY SCRATCHPAD DATA
	CALL	SPCI		;GET COMMAND
	$EXVA	FSPMV		;PROCESS COMMAND
	LD	A,0FFH
	LD	(RPANEL),A	;REQUEST PANEL
	LD	(FDMDSI),A	;REQUEST SECTOR INFO
	RET

FSPMV:	DW	FSPX
	DW	FLSP
	DW	FXSP

	$RTN	FSPX
	RET
;
; SPCI - GET SCRATCHPAD COMMAND
;
	$RTN	SPCI
SPCI01	EQU	$		;LOOP
	$IFLD	SELMSG		;GET COMMAND
	$MTCH	PSPML
	JR	Z,SPCI02	;EXIT IF VALID
	CALL	ALRM		;SOUND ALARM
	JR	SPCI01
SPCI02	EQU	$		;ENDLOOP
	RET
;
; DSPI - DISPLAY S/P INFO
;
	$RTN	DSPI
	LD	A,(SPTYPE)
	OR	A
	JR	NZ,DSPI01	;IF EMPTY
	$STRO	SPEMTY
	JR	DSPI02
DSPI01	EQU	$
	DEC	A
	JR	NZ,DSPI03	;ELSE IF PHYSICAL
	$STRO	SPDMSG
	LD	A,(SPDRIV)
	ADD	A,41H
	CALL	CHRO		;DISPLAY DRIVE
	$STRO	SPTMSG
	$HEXW	SPNAME		;TRACK
	$STRO	SPSMSG
	$HEXW	SPSECT		;SECTOR
	JR	DSPI02
DSPI03	EQU	$		;ELSE FILE RELATIVE
	LD	A,(SPDRIV)
	ADD	A,041H
	CALL	CHRO
	LD	A,':'
	CALL	CHRO
	$STRO	SPNAME		;DISPLAY FILE NAME
	$STRO	SPSMSG
	$HEXW	SPSECT		;AND SECTOR
DSPI02	EQU	$		;ENDIF
	RET

;
; FXSP - EXCHANGE WITH SCRATCHPAD
;
	$RTN	FXSP
	LD	A,(SPTYPE)
	OR	A
	JR	NZ,FXSP01	;IF PAD EMPTY
	CALL	ALRM		;RING BELL
	JR	FXSP02
FXSP01	EQU	$		;ELSE
	LD	A,(RO)
	OR	A
	JR	Z,FXSP03	;IF READ ONLY
	CALL	ALRM		;ERROR
	JR	FXSP04		;ELSE
FXSP03	EQU	$
	LD	BC,(SPADDR)
	CALL	SETDMA		;SET CPM BUFFER
	CALL	WRFS		;WRITE BUFFER
	LD	BC,FBUFF
	CALL	SETDMA		;RESTORE DMA
	CALL	FLSP		;COPY OLD BUFFER
	CALL	RDFS		;RE READ SECTOR
FXSP04	EQU	$		;ENDIF
FXSP02	EQU	$		;ENDIF
	RET
;
; FLSP - LOAD SCRATCHPAD (LOGICAL)
;
	$RTN	FLSP
	LD	HL,FBUFF
	LD	DE,(SPADDR)
	LD	BC,128
	LDIR			;COPY THE BUFFER
	LD	A,(CURAN)
	LD	(SPDRIV),A	;SET DRIV
	LD	HL,FILENM
	LD	DE,SPNAME
	LD	BC,12
	LDIR			;COPY FILE NAME
	LD	HL,(RELREC)
	LD	(SPSECT),HL
	LD	A,2
	LD	(SPTYPE),A	;SET THE TYPE
	RET
;
; DFSI - DISPLAY FILE SECTOR INFORMATION
;
	$RTN	DFSI
	$FLD	WRSNFL		;POSITION FOR SECTOR NUMBER
	$HEXW	RELREC		;DISPLAY RECORD NUMBER
	$FLD	WRFOFL		;POSITION FOR FILE OFFSET
	LD	HL,(RELREC)	;GET REC NO
	XOR	A
 	SRL	H
	RR	L
	RRA
	LD	(BASEAD+2),A
	LD	A,(COMFLG)
	OR	A
	JR	Z,DFSI01	;IF .COM FLAG
	INC	HL
DFSI01	EQU	$		;ENDIF
	LD	(BASEAD),HL	;SAVE REC/2
	CALL	PRTADR		;PRINT 3 BYTE ADDRESS
	RET

COMFLG:	DS	1		

;
; DRMD - DIRECTORY MODE
;
	$RTN	DRMD
	LD	HL,(DRMDEF)
	LD	(ERRFLD),HL	;SET PANEL ERROR FIELD
	LD	A,TRUE
	LD	(DRMDLD),A	;REQUEST LIST
DRMD01	EQU	$		;LOOP
	LD	A,(DRMDLD)
	OR	A
	JR	Z,DRMD02	;IF LIST REQUIRED
	$NPANEL	DRMDPN		;DISPLAY DIRECTORY LIST PANEL
	CALL	DLST		;DO DIRECTORY LIST
	XOR	A
	LD	(DRMDLD),A	;RESET LIST REQUEST
DRMD02	EQU	$		;ENDIF
DRMD06	EQU	$		;LOOP
	CALL	ERRP		;PROCESS ERRORS
	LD	A,(SELDE)
	CALL	DIRPOS		;POSITION OVER CURRENT ENTRY
	CALL	CHRF
	$MTCH	DRMDLS
	JR	Z,DRMD05	;EXITIF VALID
	CALL	ALRM		;SOUND ALARM
	JR	DRMD06
DRMD05	EQU	$		;ENDLOOP
	$EXVA	DRMDVC		;PERFORM ACTION
	LD	A,(WTG)
	CP	'D'	
	JR	NZ,DRMD07	;EXIT IF MODE NO LONGER D
	JP	DRMD01
DRMD07	EQU	$		;ENDLOOP
	RET

;
; DIRECTORY MODE PANEL AND VECTOR
;
DRMDPN:	DB	12
	DB	02,00,'^',$LEFT+040H,'  Cursor left',0
	DB	03,00,'^',$RIGHT+040H,'  Cursor right',0
	DB	04,00,'^',$UP+040H,'  Cursor up',0
	DB	05,00,'^',$DOWN+040H,'  Cursor down',0
	DB	02,22,'P  Previous directory page',0
	DB	03,22,'N  Next directory page',0
	DB	02,54,'Z  Exit from Superzap',0
	DB	03,54,'C  Change disk',0
	DB	04,54,'S  Select track / sector',0
	DB	05,54,'M  Set directory selection',0

	DB	07,00,'E  Edit file',0
	DB	07,22,'T  Type file',0

DRMDLS:	DB	13,$LEFT,$RIGHT,$UP,$DOWN,CR,'EZCSMPNT'

DRMDVC:	DW	FBS
	DW	FFS
	DW	FUP
	DW	FDN
	DW	FNL
	DW	STFL
	DW	SETX
	DW	CHDD
	DW	SETP
	DW	SAFN
	DW	DIRP
	DW	DIRN
	DW	TYPE

DRMDEF:	DB	9,0
NRFMSG:	DB	'** No records in file',0
FNFMSG:	DB	'** File not found',0

DRMDLD:	DS	1		;LIST DIRECTORY REQUEST FLAG

;
; DIRP - PAGE UP DIRECTORY
;
	$RTN	DIRP
	LD	A,(DIROFF)
	OR	A
	JR	Z,DIRP01	;IF NOT PAGE 0
	SUB	32
	LD	(DIROFF),A	;SET PREV PAGE
	XOR	A
	LD	(SELDE),A	;FIRST ENTRY ON PAGE
	CALL	ERRP
	LD	HL,DRAREA
	CALL	CLRA		;CLEAR AREA
	CALL	DLST		;DISPLAY PAGE
	JR	DIRP02
DIRP01	EQU	$		;ELSE
	CALL	ALRM		;RING BELL
DIRP02	EQU	$		;ENDIF
	RET
;
; DIRN - PAGE DOWN DIRECTORY
;
	$RTN	DIRN
	LD	A,(DIROFF)
	ADD	A,32		;POINT TO NEXT PAGE
	LD	HL,DECNT
	CP	(HL)
	JR	NC,DIRN01	;IF AVAILABLE
	LD	(DIROFF),A	;SAVE NEW POINTER
	XOR	A
	LD	(SELDE),A	;SET FIRST ENTRY ON PAGE
	CALL	ERRP
	LD	HL,DRAREA
	CALL	CLRA		;CLEAR DIRECTORY AREA
	CALL	DLST		;DISPLAY DIRECTORY
	JR	DIRN02
DIRN01	EQU	$		;ELSE
	CALL	ALRM		;ALARM
DIRN02	EQU	$		;ENDIF
	RET

;
; FBS - BACKSPACE ID DIRECTORY
;
	$RTN	FBS
	LD	A,(DIROFF)
	LD	B,A
	LD	HL,DECNT
FBS01	EQU	$		;REPEAT
	LD	A,(SELDE)
	DEC	A
	AND	31
	LD	(SELDE),A	;SELECT PREVIOUS
	JR	Z,FBS02		;EXIT IF FIRST POSN
	ADD	A,B
	CP	(HL)
	JR	NC,FBS01	;UNTIL NEW<=MAX
FBS02	EQU	$
	RET
;
; FUP - CURSOR UP IN DIRECTORY
;
	$RTN	FUP
	LD	A,(DIROFF)
	LD	B,A
	LD	HL,DECNT
FUP01	EQU	$		;REPEAT
	LD	A,(SELDE)
	SUB	4
	AND	31
	LD	(SELDE),A	;1 LINE UP
	JR	Z,FUP02		;EXIT IF FIRST POSN
	ADD	A,B
	CP	(HL)
	JR	NC,FUP01	;UNTIL NEW<=MAX
FUP02	EQU	$
	RET
;
; FDN - CURSOR DOWN IN DIRECTORY
;
	$RTN	FDN
	LD	A,(DIROFF)
	LD	B,A
	LD	HL,DECNT
FDN01	EQU	$		;REPEAT
	LD	A,(SELDE)
	ADD	A,4
	AND	31
	LD	(SELDE),A	;1 LINE DOWN
	JR	Z,FDN02
	ADD	A,B
	CP	(HL)
	JR	NC,FDN01	;UNTIL NEW<=MAX
FDN02	EQU	$
	RET
;
; FNL - C/R IN DIRECTORY
;
	$RTN	FNL
	LD	A,(DIROFF)
	LD	B,A
	LD	HL,DECNT
FNL01	EQU	$		;REPEAT
	LD	A,(SELDE)	;PICK UP CURRENT
	ADD	A,4		;MOVE TO NEXT LINE
	AND	01CH
	LD	(SELDE),A	;START OF NEXT LINE
	JR	Z,FNL02
	ADD	A,B
	LD	HL,DECNT
	CP	(HL)
	JR	NC,FNL01	;UNTIL NEW<=MAX
FNL02	EQU	$
	RET
;
; FFS - CURSOR FORWARD IN DIRECTORY
;
	$RTN	FFS
	LD	A,(DIROFF)
	LD	B,A		;GET START OF DISPLAY
	LD	HL,DECNT
FFS01	EQU	$		;REPEAT
	LD	A,(SELDE)
	INC	A
	AND	31
	LD	(SELDE),A	;NEXT ENTRY
	JR	Z,FFS02
	ADD	A,B
	CP	(HL)
	JR	NC,FFS01	;UNTIL NEW<=MAX
FFS02	EQU	$
	RET
;
; DIRPOS - POSITION TO PRINT DIRECTORY ENTRY
;
DIRPOS	EQU	$
	LD	(DIRNUM),A	;SAVE ENTRY POSITION
	LD	HL,LPTAB
	RRCA
	RRCA			;DIVIDE COUNT BY 4
	AND	0FH		;MAKE IT LINE COUNT
	CALL	AAHL
	LD	B,(HL)		;PICK UP LINE POSN
	LD	HL,DCTAB
	LD	A,(DIRNUM)	;PICK UP ENTRY AGAIN
	AND	03		;MAKE COUNT INTO COLUM NUMBER
	CALL	AAHL
	LD	H,(HL)		;GET COLUMN POSITION
	LD	L,B		;AND LINE NUMBER
	CALL	CURS		;POSITION CURSOR
	RET
DIRNUM:	DS	1

;
; STFL - SELECT FILE
;
	$RTN	STFL
	CALL	CFCB		;COPY FCB FROM DIR LIST
	CALL	SETF		;SET FILE MODE
	RET
;
; CFCB - COPY FCB FROM DIRECTORY LIST
;
	$RTN	CFCB
	LD	A,(DECNT)
	OR	A
	JR	NZ,CFCB01	;IF NO FILES
	CALL	ALRM		;SOUND ALARM
	LD	HL,FNFMSG
	LD	(ERRTXT),HL	;SET FILE NOT FOUND ERROR
	JR	CFCB02
CFCB01	EQU	$		;ELSE
	LD	A,(SELDE)	;GET SELECTED ENTRY NUMBER
	LD	B,A
	LD	A,(DIROFF)
	ADD	A,B		;ADD DISPLAY START
	LD	H,0
	LD	L,A
	LD	DE,(MEMRY)	;BASE OF TABLE
	CALL	H16D		;HL=HL*16+DE
	LD	DE,WRKFN	;START OF FILE NAME
	LD	BC,11
	LDIR			;MOVE DE OVER TO FCB
	XOR	A
	LD	(WRKEX),A
CFCB02	EQU	$		;ENDIF
	RET

;
; TYPE - TYPE SELECTED FILE
;
	$RTN	TYPE
	CALL	CFCB		;SET UP FCB
	CALL	TFLE		;TEST FILE
	LD	A,(FLERR)
	OR	A
	JP	NZ,TYPE01	;IF FILE FOUND
	XOR	A
	LD	(BUFPOS),A	;BUFFER OFFSET 0
	LD	(BASEAD+1),A
	INC	A
	LD	(BASEAD),A	;INITIALISE PAGE NUMBER 1
	CALL	TGET		;PRIME FIRST CHARACTER
	LD	HL,(PGEPTR)
	LD	(CURPG@),HL	;SET CURRENT PAGE ENTRY TO FIRST
	LD	(MAXPG@),HL	;AND LAST
	LD	A,0FFH
	LD	(TYPEX),A	;SET NO EXIT
	LD	(TYDSP),A	;REQUEST DISPLAY
TYPE03	EQU	$		;LOOP
	LD	A,(TYDSP)
	OR	A
	JR	Z,TYPE09	;IF DISPLAY REQUIRED
	XOR	A
	LD	(TYDSP),A	;RESET REQUEST
	$NPANEL	TYPEPN		;DISPLAY PANEL
	$FLD	PGENUM
	$HEXW	BASEAD		;DISPLAY PAGE NUMBER
	$FLD	TYPEFN
	$STRO	DRIVNM		;DISPLAY FILE NAME
	$FLD	RECNUM
	$HEXW	RELREC		;DISPLAY RECORD NUMBER
	CALL	TYPG		;DISPLAY PAGE
TYPE09	EQU	$		;ENDIF
TYPE06	EQU	$		;LOOP
	$IFLD	TYPIP		;GET COMMAND
	$MTCH	TYPLST
	JR	Z,TYPE05	;EXITIF VALID
	CALL	ALRM		;SOUND ALARM
	JR	TYPE06
TYPE05	EQU	$		;ENDLOOP
	$EXVA	TYPVEC		;EXEC COMMAND
	LD	A,(TYPEX)
	OR	A
	JR	Z,TYPE04	;EXITIF FLAG SET
	JR	TYPE03
TYPE04	EQU	$		;ENDLOOP
TYPE01	EQU	$		;ENDIF
	LD	A,TRUE
	LD	(DRMDLD),A	;REQUEST DIRECTORY LIST
	RET

TYPEPN:	DB	6
	DB	01,00,'N  Next page',0
	DB	01,22,'R  Return after Paging',0
	DB	01,50,'L  Exit to file list',0
	DB	02,00,'P  Previous page',0
	DB	02,22,'T  Top of file',0
	DB	02,50,'Z  Exit from Superzap',0

PGENUM:	DB	4,66,'Page ',0
RECNUM:	DB	4,32,'Sector ',0
TYPEFN:	DB	4,0,0
TYPIP:	DB	02,77,'>',0		;INPUT POSITION
TYPFL:	DB	6,0,0			;FIRST CHR POSITION

TYPLST:	DB	6,'NRLPTZ'
TYPVEC:	DW	TYPF
	DW	TYPR
	DW	TYPL
	DW	TYPB
	DW	TYPT
	DW	TYPZ

TYPEX:	DS	1		;EXIT FLAG
TYDSP:	DS	1		;DISPLAY REQUEST
TYPEOP:	DS	1		;END OF PAGE

;
; TYPF - FORWARD PAGE
;
	$RTN	TYPF
	LD	A,(READST)
	OR	A
	JR	Z,TYPF01	;IF EOF
	CALL	ALRM
	JR	TYPF02
TYPF01	EQU	$		;ELSE
	LD	HL,(CURPG@)
	LD	DE,6
	ADD	HL,DE
	LD	(CURPG@),HL	;UPDATE CURRENT POINTER
	LD	A,0FFH
	LD	(TYDSP),A	;REQUEST DISPLAY
TYPF02	EQU	$
	RET

;
; TYPR - REURN AFTER PAGING
;
	$RTN	TYPR
	LD	HL,(CURPG@)
	LD	DE,(MAXPG@)
	XOR	A
	SBC	HL,DE
	JR	Z,TYPR01	;IF NOT END OF FILE
	EX	DE,HL		;RESTORE TOP OF QUEUE
	LD	DE,6
	XOR	A
	SBC	HL,DE
	CALL	LPGE		;LOAD LAST PAGE
	LD	A,0FFH
	LD	(TYDSP),A	;REQUEST DISPLAY
TYPR01	EQU	$		;ENDIF
	RET

;
; TYPL - EXIT TYPE TO DIR LIST
;
	$RTN	TYPL
	XOR	A
	LD	(TYPEX),A	;REQUEST EXIT
	RET

;
; TYPB - PAGE BACKWARD
;
	$RTN	TYPB
	LD	DE,(CURPG@)
	LD	HL,(PGEPTR)
	XOR	A
	SBC	HL,DE
	JR	Z,TYPB01	;IF NOT TOP OF FILE
	EX	DE,HL
	LD	DE,6
	XOR	A
	SBC	HL,DE
	CALL	LPGE		;LOAD PAGE DATA
	LD	A,0FFH
	LD	(TYDSP),A	;REQUEST DISPLAY
TYPB01	EQU	$		;ENDIF
	RET

;
; TYPT - PAGE TO TOP OF FILE
;
	$RTN	TYPT
	LD	HL,(PGEPTR)
	CALL	LPGE		;LOAD FIRST PAGE
	LD	A,0FFH
	LD	(TYDSP),A	;REQUEST DISPLAY
	RET

;
; TYPZ - EXIT TYPE TO CM/M
;
	$RTN	TYPZ
	CALL	SETX		;EXIT SUPERZAP
	XOR	A
	LD	(TYPEX),A	;REQUEST EXIT
	RET

;
; TYPG - TYPE PAGE
;
	$RTN	TYPG
	CALL	QPGE		;PUT PAGE ON QUEUE
	$FLD	TYPFL		;POSITION FOR FIST CHAR
	$STRO	TYNPRF		;RIGHT MARGIN
	XOR	A
	LD	(TYPEOP),A	;RESET END OF PAGE
	LD	(PGECOL),A
	LD	(PGELNE),A	;LINE 0 COL 0
TYPG01	EQU	$		;LOOP
	LD	A,(TYPEOP)
	OR	A
	JR	NZ,TYPG02	;EXIT IF EOP
	LD	A,(COMFLG)
	OR	A
	LD	A,(TYCURC)
	JR	NZ,TYPG08	;IF NOT COM FILE
	CP	009H
	JR	NZ,TYPG04	;IF TAB
TYPG05	EQU	$		;REPEAT
	LD	A,' '
	CALL	TPUT		;PUT SPACE
	LD	A,(PGECOL)
	AND	7
	JR	NZ,TYPG05	;UNTIL TAB STOP
	JR	TYPG07
TYPG04	EQU	$
	CP	CR
	JR	NZ,TYPG08	;ELSE IF C/R
	LD	A,(READST)
	OR	A
	JR	NZ,TYPG11	;IF EOF
	LD	A,(BUFPOS)
	LD	HL,FBUFF
	CALL	AAHL
	LD	A,(HL)
	CP	00AH
	JR	NZ,TYPG11	;OR NOT LINE FEED
	JR	TYPG09
TYPG11	EQU	$
	LD	A,CR
	CALL	TPUT		;PUT CHAR
	JR	TYPG10
TYPG09	EQU	$		;ELSE
	CALL	TYNL		;TAKE NEW LINE
	CALL	TGET		;SKIP L/F IN FILE
TYPG10	EQU	$		;ENDIF
	JR	TYPG07
TYPG08	EQU	$		;ELSE
	CALL	TPUT		;PRINT CHR
TYPG07	EQU	$		;ENDIF
	LD	A,(READST)
	OR	A
	JR	NZ,TYPG02	;EXIT IF EOF
	CALL	TGET		;GET NEXT CHR
	JR	TYPG01
TYPG02	EQU	$		;ENDLOOP
	LD	HL,(BASEAD)
	LD	A,1
	ADD	A,L
	DAA
	LD	L,A
	LD	A,0
	ADC	A,H
	DAA
	LD	H,A
	LD	(BASEAD),HL	;INC PAGE NUMBER
TYPG03	EQU	$		;ENDIF
	RET
PGECOL:	DS	1
PGELNE:	DS	1
TYNPRF:	DB	'   ',0
;
; QPGE - PUT PAGE DATA ON QUEUE
;
	$RTN	QPGE
	LD	HL,(MAXPG@)
	LD	DE,(CURPG@)
	XOR	A
	SBC	HL,DE
	JR	NZ,QPGE01	;IF AT END OF Q
	LD	HL,TYCURC
	LD	DE,(MAXPG@)
	LD	BC,6
	LDIR			;COPY PAGE DATA
	LD	(MAXPG@),DE	;UPDATE MAX PTR
QPGE01	EQU	$		;ENDIF
	RET

;
; LPGE - LOAD PAGE DATA FROM QUEUE AT (HL)

	$RTN	LPGE
	LD	(CURPG@),HL	;SET CURRENT POINTER
	LD	DE,TYCURC
	LD	BC,6
	LDIR			;COPY PAGE DATA
	CALL	RDFS		;READ FIRST SECTOR OF PAGE
	RET

;
; TGET - GET CHARACTER FOR TYPE
;
	$RTN	TGET
	LD	A,(READST)
	OR	A
	JR	NZ,TGET02	;IF NOT EOF
	LD	HL,BUFPOS
	LD	A,(HL)		;GET CURRENT OFFSET
	INC	(HL)		;INC FOR NEXT GET
	LD	HL,FBUFF
	CALL	AAHL		;POINT TO CURRENT CHARACTER
	LD	A,(HL)
	LD	(TYCURC),A	;GET CHARACTER
	LD	A,(BUFPOS)
	CP	080H
	JR	NZ,TGET01	;IF BUFPOS=80
	LD	HL,(RELREC)
	INC	HL
	LD	(RELREC),HL	;SET NEXT SECTOR
	XOR	A
	LD	(BUFPOS),A	;BUFFER OFFSET=0
	CALL	RDFS		;READ SECTOR
TGET01	EQU	$		;ENDIF
TGET02	EQU	$		;ENDIF
	LD	A,(TYCURC)	;RETURN CHARACTER
	RET

;
; TPUT - TYPE A CHARACTER
;
	$RTN	TPUT
	LD	B,A
	LD	A,(PGECOL)
	CP	72
	JR	NZ,TPUT01	;IF COL=72
	CALL	TYNL		;TAKE NEW LINE
TPUT01	EQU	$		;ENDIF
	LD	A,(TYPEOP)
	OR	A
	JR	NZ,TPUT02	;IF NOT EOP
	LD	A,B
	CALL	ASCO		;OUTPUT CHARACTER
	LD	HL,PGECOL
	INC	(HL)		;INC COL COUNT
TPUT02	EQU	$		;ENDIF
	RET

;
; TYNL - TYPE NEW LINE
;
	$RTN	TYNL
	XOR	A
	LD	(PGECOL),A	;SET COL 0
	LD	HL,PGELNE
	INC	(HL)		;INC LINE
	LD	A,18
	CP	(HL)
	JR	NZ,TYNL01	;IF LINE = 18
	LD	A,0FFH
	LD	(TYPEOP),A	;SET END OF PAGE
	JR	TYNL02
TYNL01	EQU	$		;ELSE
	LD	A,00DH
	CALL	CHRO
	LD	A,00AH
	CALL	CHRO		;OTPUT CRLF
	$STRO	TYNPRF		;RIGHT MARGIN
TYNL02	EQU	$		;ENDIF
	RET

;
; CHDD - CHANGE DIRECTORY DRIVE
;
	$RTN	CHDD
	LD	HL,DSKMSG
	CALL	CFLD		;CLEAR PROMPT FIELD
	LD	A,TRUE
	LD	(DRMDLD),A	;REQUEST LIST ON RETURN
	$IFLD	DSKMSG		;PROMPT FOR DRIVE
	CP	$ESC
	JR	Z,CHDD03	;IF NOT ESC
	SUB	041H		;MAKE DRIVE ID
	CALL	CHDR		;CHANGE DISK
	JR	NZ,CHDD04	;IF ILLEGAL DISK
	CALL	ALRM		;SOUND ALARM
	JR	CHDD05
CHDD04	EQU	$		;ELSE
	XOR	A
	LD	(SELDE),A	;SELECT FIRST ENTRY
CHDD05	EQU	$		;ENDIF
CHDD03	EQU	$		;ENDIF
	RET

DSKMSG:	DB	12,20,'Enter Drive Name or press ESC ===>',0
NFDMSG:	DB	'** No Files on Drive',0

;
; SAFN - SET DIRECTORY LIST AFN
;
	$RTN	SAFN
	$NPANEL	AFNPNL		;DISPLAY SET AFN PANEL
	LD	A,TRUE
	LD	(DRMDLD),A	;REQUEST DIRECTORY LIST
	LD	HL,LMDFCB+1
	LD	DE,CPYAFN
	LD	BC,11
	LDIR			;TAKE LOCAL COPY OF DIR SEARCH NAME
	CALL	DAFN		;DISPLAY CURRENT MASK
	XOR	A
	LD	(IMODE),A	;RESET INSERT MODE
	LD	(NMODE),A	;SET FOR NAME PART
	LD	(AFNCNT),A	;SET COUNT=0
	LD	HL,(AFNPNM)
	LD	(AFNCUR),HL	;SET START ADDRESS ON SCREEN
	LD	A,8
	LD	(AFNMAX),A	;SET LENGTH OF FIELD
	LD	HL,CPYAFN
	LD	(AFNCHP),HL	;SAVE START ADDRESS IN MEMORY
SAFN01	EQU	$		;LOOP
	CALL	AFNC		;POSITION CURSOR
	CALL	CHRF		;GET A CHARACTER
	CP	CR
	JR	Z,SAFN02	;EXITIF C/R
	CP	$ESC
	JR	Z,SAFN02	;OR ESCAPE
	$MTCH	AFNACD
	JR	NZ,SAFN03	;IF VALID CONTROL
	$EXVA	AFNAVC		;PERFORM ACTION
	JR	SAFN04
SAFN03	EQU	$		;ELSE
	$MTCH	AFNINV
	JR	Z,SAFN05	;IF NOT IN ILLEGAL CHARACTER SET
	CP	020H
	JP	C,SAFN05	;AND NOT CONTROL CHARACTER
	CALL	PAFN		;PUT CHARACTER IN STRING
	JR	SAFN06
SAFN05	EQU	$		;ELSE
	CALL	ALRM		;RING BELL
SAFN06	EQU	$		;ENDIF
SAFN04	EQU	$		;ENDIF
	JR	SAFN01
SAFN02	EQU	$		;ENDLOOP
	CP	$ESC
	JR	Z,SAFN99	;IF EXIT BY C/R
	LD	HL,CPYAFN
	CALL	LSEL		;COPY NEW NAME TO FCB
	CALL	RDIR		;READ DIRECTORY
	XOR	A
	LD	(SELDE),A	;RESET CURRENT SELECTION
SAFN99	EQU	$		;ENDIF
	RET

AFNINV:	DB	7,07FH,':;<>ÆÅ'	;INVALID FILENAME CHARACTERS
IMODE:	DS	1		;INSERT ON/OFF
NMODE:	DS	1		;IN NAME/EXT PART
AFNCNT:	DS	1		;CURENT POSITION IN NAME
AFNCUR:	DS	2		;CURSOR POSITION OF CURRENT FIELD
AFNCHP:	DS	2		;ADDRESS OF CURRENT FIELD
AFNMAX:	DS	1		;LENGTH OF CURRENT PART
CPYAFN:	DS	11

AFNPNL	EQU	$
	DB	10		;FIELD COUNT
	DB	02,00,'^',$LEFT+040H,'  Cursor Left',0
	DB	02,27,'^',$RIGHT+040H,'  Cursor Right',0
	DB	03,00,'^',$DELETE+040H,'  Delete Character',0
	DB	03,27,'^',$INSRT+040H,'  Insert On/Off',0  
	DB	02,54,'^',$TAB+040H,'  Edit Name/Type',0
	DB	03,54,'ESC Use Current Selection',0
AFNMSG:	DB	7,08,'Edit File Name ===>',0
	DB	7,37,'<=',0			;FILENAME END MARKER
	DB	9,13,'File Type ===>',0
	DB	9,32,'<=',0			;FILE TYPE END MARKER
AFNPNM:	DB	7,28,0				;POSITION OF FILE NAME
AFNPEX:	DB	9,28,0				;POSITION OF FILE TYPE

INSMSG:	DB	05,29,'Insert',0

AFNACD:	DB	8,$LEFT,$RIGHT,$DELETE,$INSRT,$TAB,' .*'

AFNAVC:	DW	AFNL		;CURSROR LEFT
	DW	AFNR		;CURSOR RIGHT
	DW	AFND		;DELETE CHAR
	DW	AFNI		;TOGGLE INSERT MODE
	DW	AFNT		;TOGGLE NAME MODE
	DW	AFNS		;SPACE FILL FIELD
	DW	AFNP		;PERIOD
	DW	AFNQ		; "?" FILL (USED BY "*")
;
; AFNP - PERIOD IN AFN
;
	$RTN	AFNP
	LD	A,(NMODE)
	OR	A
	JR	NZ,AFNP01	;IF IN NAME
	CALL	AFNS		;SPACE FILL
AFNP01	EQU	$		;ENDIF
	RET
;
; AFND - DELETE CHARACTER IN AFN
;
	$RTN	AFND
	LD	HL,(AFNCHP)	;ADDRESS OF CURRENT FIELD
	LD	A,(AFNCNT)
	LD	C,A		;SAVE COUNT
	CALL	AAHL		;ADDRESS OF CURRENT CHARACTER
	LD	D,H
	LD	E,L		;DEST IN DE
	INC	HL		;SOURCE IN HL
	LD	A,(AFNMAX)	;LENGTH OF FIELD
	SUB	C		;LENGTH REMAINING
	DEC	A		;LENGTH TO MOVE
	JR	Z,AFND01	;IF SOMETHING TO MOVE
	LD	B,0
	LD	C,A		;SET UP COUNT
	LDIR			;MOVE FIELD LEFT
AFND01	EQU	$		;ENDIF
	LD	A,' '
	LD	(DE),A		;BLANK LAST CHARACTER
	CALL	DAFN		;DISPLAY NEW AFN
	RET
;
; AFNS - SPACE FILL AFN
;
	$RTN	AFNS
	LD	A,' '
	LD	(FILLCH),A
	CALL	AFNF
	RET
;
; AFNQ - "?" FILL AFN
;
	$RTN	AFNQ
	LD	A,'?'
	LD	(FILLCH),A
	CALL	AFNF
	RET

FILLCH:	DS	1		;CHARACTER TO FILL AFN

;
; AFNF - FILL AFN FIELD
;
	$RTN	AFNF
	LD	HL,(AFNCHP)
	LD	A,(AFNCNT)
	LD	B,A		;SAVE COUNT
	CALL	AAHL		;POSITION IN FIELD
	LD	A,(AFNMAX)
	SUB	B
	LD	B,A		;SAVE COUNT
	LD	A,(FILLCH)
AFNF01	EQU	$		;REPEAT
	LD	(HL),A		;INSERT SPACE
	INC	HL		;POINT NEXT CHARACTER
	DJNZ	AFNF01		;UNTIL END OF FIELD
	CALL	DAFN		;DISPLAY FIELD
	CALL	AFNT		;POSITION IN OTHER HALF
	RET

;
; DAFN - DISPLAY DIRECTORY SEARCH NAME
;
	$RTN	DAFN
	$FLD	AFNPNM		;POSITION FOR NAME
	LD	B,8
	LD	HL,CPYAFN
DAFN01	EQU	$		;LOOP
	LD	A,(HL)
	CALL	CHRO		;PRINT A CHARCTER
	INC	HL		;POINT TO NEXT
	DJNZ	DAFN01		;UNTIL END OF FIELD
	$FLD	AFNPEX		;POSITION FOR TYPE
	LD	HL,CPYAFN+8
	LD	B,3
DAFN02	EQU	$		;REPEAT
	LD	A,(HL)
	CALL	CHRO		;PRINT CHAR
	INC	HL		;POINT TO NEXT
	DJNZ	DAFN02		;UNTIL END OF FIELD
	RET

;
; PAFN - PUT CHARACTER IN STRING
;
	$RTN	PAFN
	PUSH	AF		;SAVE CHARACTER
	LD	A,(IMODE)
	OR	A	
	JR	Z,PAFN01	;IF INSERT ON
	CALL	AFNM		;MAKE SPACE
PAFN01	EQU	$		;ENDIF
	LD	HL,(AFNCHP)	;GET CHARACTER POSITION
	LD	A,(AFNCNT)
	CALL	AAHL		;ADD COUNT TO HL
	POP	AF		;RESTORE CHARACTER
	LD	(HL),A		;PUT IT IN STRING
	CALL	CHRO		;DISPLAY CHARACTER
	LD	A,(IMODE)
	OR	A
	JR	Z,PAFN02	;IF INSERT ON
	CALL	DAFN		;DISPLAY FULL NAME
PAFN02	EQU	$		;ENDIF
	CALL	AFNR		;MOVE CURSOR
	RET
;
; AFNM - MAKE SPACE FOR INSERT
;
	$RTN	AFNM
	LD	HL,(AFNCHP)	;ADDRESS OF CURRENT FIELD
	LD	A,(AFNMAX)
	DEC	A		;ADJUST COUNT TO OFFSET
	CALL	AAHL		;ADDRESS OF LAST CHARACTER
	LD	D,H
	LD	E,L		;DEST IN DE
	DEC	HL		;SOURCE IN HL
	LD	A,(AFNCNT)	;CURRENT OFFSET
	LD	C,A
	LD	A,(AFNMAX)
	SUB	C		;LENGTH REMAINING
	DEC	A		;LENGTH TO MOVE
	JR	Z,AFNM01	;IF SOMETHING TO MOVE
	LD	B,0
	LD	C,A		;SET UP COUNT
	LDDR			;MOVE FIELD RIGHT
AFNM01	EQU	$		;ENDIF
	RET
;
; AFNL - CURSOR LEFT IN AFN
;
	$RTN	AFNL
	LD	A,(AFNCNT)
	OR	A
	JR	Z,AFNL01	;IF NOT START OF FIELD
	DEC	A		;POSITION TO PREVIOUS
	JR	AFNL02
AFNL01	EQU	$		;ELSE
	CALL	AFNT		;TOGGLE MODE
	LD	A,(AFNMAX)	;GET END OF FIELD COUNT
	DEC	A		;POINT TO LAST CHAR IN FIELD
	LD	B,A		;SET COUNT
	DEC	A		;POINT TO PREVIOUS
	LD	HL,(AFNCHP)
	CALL	AAHL
	LD	A,' '
AFNL03	EQU	$		;REPEAT
	CP	(HL)
	JR	NZ,AFNL04	;EXITIF PREVIOUS NOT SPACE
	DEC	HL
	DJNZ	AFNL03		;UNTIL END OF FIELD
AFNL04	EQU	$		;ENDLOOP
	LD	A,B		;RESTORE COUNT
AFNL02	EQU	$		;ENDIF
	LD	(AFNCNT),A	;BACKSPACE POSITION
	RET

;
; AFNR - CURSOR RIGHT IN AFN
;
	$RTN	AFNR
	LD	HL,(AFNCHP)
	LD	A,(AFNCNT)
	CALL	AAHL		;POINT TO CURRENT CHARACTER
	LD	A,(HL)
	CP	' '
	JR	NZ,AFNR02	;IF SPACE
	CALL	AFNT		;CHANGE MODE
	JR	AFNR03
AFNR02	EQU	$		;ELSE
	LD	A,(AFNMAX)	;GET FIELD MAX
	LD	HL,AFNCNT
	INC	(HL)		;INC POSITION
	CP	(HL)
	JP	NZ,AFNR01	;IF OUT OF RANGE
	CALL	AFNT		;TOGGLE MODE
AFNR01	EQU	$		;ENDIF
AFNR03	EQU	$		;ENDIF
	RET
;
; AFNI - TOGGLE AFN INSERT MODE
;
	$RTN	AFNI
	LD	A,(IMODE)
	CPL
	LD	(IMODE),A	;TOGGLE MODE FLAG
	LD	HL,INSMSG	;POINT TO INSERT MESSAGE
	OR	A
	JR	Z,AFNI01	;IF NOW INSERT MODE
	CALL	DFLD		;DISPLAY IT
	JR	AFNI02
AFNI01	EQU	$		;ELSE
	CALL	CFLD		;CLEAR IT
AFNI02	EQU	$		;ENDIF
	RET

;
; AFNT - TOGGLE AFN MODE
;
	$RTN	AFNT
	XOR	A
	LD	(AFNCNT),A	;RESET COUNT
	LD	A,(NMODE)
	CPL
	LD	(NMODE),A	;TOGLE MODE FLAG
	OR	A
	JR	NZ,AFNT01	;IF NOW NAME MODE
	LD	A,8		;GET MAX LENGTH
	LD	HL,(AFNPNM)	;GET START POSITION
	LD	DE,CPYAFN
	JR	AFNT02		
AFNT01	EQU	$		;ELSE
	LD	A,3		;GET MAX FOR EXTENSION
	LD	HL,(AFNPEX)	;GET POSITION FOR EXTENSION
	LD	DE,CPYAFN+8
AFNT02	EQU	$		;ENDIF
	LD	(AFNMAX),A	;SET MAX
	LD	(AFNCUR),HL	;SET START POSITION
	LD	(AFNCHP),DE	;SET START ADDRESS
	RET

;
; AFNC - POSITION CURSOR IN AFN
;
	$RTN	AFNC
	LD	HL,(AFNCUR)	;GET START OF FIELD
	LD	A,(AFNCNT)	;GET OFFSET
	ADD	A,H
	LD	H,A		;OFFSET CURSOR
	CALL	CURS		;POSITION CURSOR
	RET

;
; TFLE - TEST FILE
;
	$RTN	TFLE
	XOR	A
	LD	(FLERR),A	;RESET ERROR FLAG
	LD	DE,WRKFCB	;POINT TO WORK FCB
	LD	C,OPEN
	CALL	CPM		;ATTEMPT TO OPEN FILE
	INC	A
	JR	NZ,TFLE01	;IF OPEN ERROR
	LD	HL,FNFMSG
	LD	(ERRTXT),HL	;SET FILE NOT FOUND ERROR
	LD	A,0FFH
	LD	(FLERR),A	;SET ERROR FLAG
	JP	TFLE02
TFLE01	EQU	$		;ELSE
	LD	HL,0
	LD	(RELREC),HL	;INITIALISE RECORD COUNTER
	LD	(SAVFSC),HL
	LD	DE,WRKFN
	CALL	FMTN
	LD	A,(WRKDR)
	ADD	A,040H
	LD	(DRIVNM),A	;FORMAT NAME AND DRIVE
	CALL	RDFS		;READ SECTOR
	JR	Z,TFLE03	;IF READ BAD
	LD	HL,NRFMSG
	LD	(ERRTXT),HL	;SET NO RECORDS ON FILE ERROR
	LD	A,0FFH
	LD	(FLERR),A	;SET ERROR FLAG
TFLE03	EQU	$		;ENDIF
TFLE02	EQU	$		;ENDIF
	RET
FLERR:	DS	1

;
; PSMD - PHYSICAL SECTOR MODE
;
	$RTN	PSMD
	LD	HL,(PSMDER)
	LD	(ERRFLD),HL	;SET ERROR FIELD POINTER
	LD	A,0FFH
	LD	(PMNEWD),A	;FLAG NEW DISK
	LD	(RPANEL),A	;REQUEST PANEL
PSMD05	EQU	$		;LOOP 
	CALL	ZBSA		;CLEAR ADDRESS COUNTER
	LD	A,(PMNEWD)
	OR	A
	JP	Z,PSMD01	;IF NEW DISK
	XOR	A
	LD	(PMNEWD),A	;RESET FLAG
	LD	A,(CURAN)
	LD	C,A
	CALL	SELDSK		;SELECT PHYSICAL DISK
	CALL	HOME		;HOME THE DISK
	LD	HL,0
	LD	(PSMDTR),HL	;SET TRACK TO 0
	LD	(PSMDSC),HL	;SET SECTOR TO 0
PSMD01	EQU	$		;ENDIF
	LD	A,(RPANEL)
	OR	A
	JR	Z,PSMD06	;IF PANEL REQUIRED
	XOR	A
	LD	(RPANEL),A	;RESET FLAG
	$NPANEL	PSMDPN		;DISPLAY PHYSICAL MODE PANEL
	$FLD	PSPMSG
	CALL	DSPI		;DISPLAY SCRATCHPAD DATA
PSMD06	EQU	$
	CALL	PRDD		;READ AND DISPLAY SECTOR
	CALL	ERRP		;PROCESS ERROR MESSAGES
PSMD03	EQU	$		;LOOP
	$IFLD	SELMSG		;ISSUE SELMSG, GET COMMAND
	$MTCH	PSMDLS
	JR	Z,PSMD02	;EXITIF VALID
	CALL	ALRM		;SOUND THE ALARM
	JR	PSMD03
PSMD02	EQU	$		;ENDLOOP
	$EXVA	PSMDVC		;EXEC ACTION
	LD	A,(WTG)
	CP	'P'
	JR	NZ,PSMD04	;EXIT IF NEXT MODE <> P
	JP	PSMD05
PSMD04	EQU	$		;ENDLOOP
	RET
PMNEWD:	DS	1		;NEW DISK FLAG
;
; LOCAL DISK PARAMETER HEADER
;
DPHLCL	EQU	$
DPHXLT:	DS	2
	DS	6		;FILLER
DPHDIR:	DS	2
DPHDPB:	DS	2
DPHCSV:	DS	2
DPHALV:	DS	2
;
; LOCAL DISK PARAMETER BLOCK
;
DPBLCL	EQU	$
DPBSPT:	DS	2		;CP/M LOGICAL SECTORS PER TRACK
DPBBSH:	DS	1
DPBBLM:	DS	1		;LOGICAL SECTORS PER BLOCK - 1
DPBEXM:	DS	1
DPBDSM:	DS	2		;FILE BLOCKS PER DISK
DPBDRM:	DS	2
DPBAL0:	DS	1
DPBAL1:	DS	1
DPBCKS:	DS	2
DPBOFF:	DS	2
;
; LOCAL DISK PARAMETER EXTENSIONS
;
DPETPD:	DS	2		;TRACKS PER DISK
DPESPB:	DS	2		;SECTORS PER BLOCK
DPERSC:	DS	2		;RESERVED SECTORS


PSMDTR:	DS	2
PSMDSC:	DS	2
PSMDBL:	DS	2

;
; PHYSICAL DISK MODE MESSAGES, PANEL AND ACTION VECTOR
;
TRKMSG:	DB	11,04,'Enter Hex Track',0	;OVERLAID BY CTRMSG
SECMSG:	DB	11,23,'Enter Hex Sector',0	;OVERLAID BY CSCMSG
BLKMSG:	DB	11,42,'Enter Hex Block',0	;OVERLAID BY CBLMSG
DIDMSG:	DB	11,61,'Enter Drive ID',0	;OVERLAID BY CDKMSG

PSMDPN:	DB	16				;FIELD COUNT
	DB	02,00,'N  Next sector',0
	DB	03,00,'P  Previous sector',0
	DB	04,00,'I  Next track',0
	DB	05,00,'O  Previous track',0
	DB	02,27,'T  Select track',0
	DB	03,27,'S  Select sector',0
	DB	04,27,'B  Select block',0
	DB	05,27,'D  Select drive',0
	DB	02,54,'Z  Exit from Superzap',0
	DB	03,54,'L  Exit to file list',0
	DB	04,54,'X  Scratchpad operations',0
	DB	05,54,'C  Change sector',0

CTRMSG:	DB	11,04,'Current-Track  ',0	;OVERLAID BY TRKMSG
CSCMSG:	DB	11,23,'Current-Sector  ',0	;OVERLAID BY SECMSG
CBLMSG:	DB	11,42,'Current-Block  ',0	;OVERLAID BY BLKMSG
CDKMSG:	DB	11,61,'Current-Drive ',0	;OVERLAID BY DIDMSG

PSMDER:	DB	8,0		;ERROR FIELD
PSPMSG:	DB	07,00,'Scratchpad :- ',0
;
; FILE STATISTICS FIELDS
;
PSTRFL:	DB	12,11,0
PSTRIP:	DB	12,15,0
PSSCFL:	DB	12,28,0
PSSCIP:	DB	12,32,0 
PSBLFL:	DB	12,47,0
PSBLIP:	DB	12,51,0
PSDKFL:	DB	12,67,0

PSMDLS:	DB	12,'NCPSITOZLBDX'
PSMDVC	EQU	$
	DW	NXPS		;NEXT PHYSICAL SECTOR
	DW	PSCH		;PHYSICAL SECTOR CHNAGE MODE
	DW	PRPS		;PREVIOUS PHYSICAL SECTOR
	DW	SPSN		;SET PHYSICAL SECTOR
	DW	FRTR		;FORWARD TRACK
	DW	SPTN		;SET PHYSICAL TRACK
	DW	BWTR		;BACKWARD TRACK
	DW	SETX		;SET EXIT MODE
	DW	PTOD		;CHANGE TO DIRECTORY MODE
	DW	SPBL		;SET PHYSICAL BLOCK
	DW	CHPD		;CHANGE PHYSICAL DISK
	DW	PSPM		;PHYSICAL S/P MANAGER
;
; PTOD - CHANGE TO DIRECTORY
;
	$RTN	PTOD
	LD	A,(CURAN)
	CALL	CHDR		;RESET DISKS
	CALL	SETD		;SET D MODE
	RET
;
; CHPD - CHANGE PHYSICAL DISK
;
	$RTN	CHPD
	$FLD	DIDMSG		;DISPLAY PROMP
CHPD01	EQU	$		;LOOP
	$FLD	PSDKFL		;POSITION FOR DISK ID
	LD	A,(CURAN)	;GET ABSOLUTE DRIVE NUMBER
	ADD	A,041H		;MAKE IT ALPHA
	CALL	CHRO		;DISPLAY DRIVE ID
	CALL	CHRF
	CP	$ESC
	JR	Z,CHPD02	;EXIT IF ESCAPE
	CP	CR
	JR	Z,CHPD02	;OR CR
	SUB	041H		;MAKE IT DISK NUMBER
	CALL	CHDR		;CHANGE DRIVE
	JR	NZ,CHPD02	;EXITIF NON ZERO DPH
	CALL	ALRM		;RING BELL
	JR	CHPD01
CHPD02	EQU	$		;ENDLOOP
	CP	$ESC
	JR	Z,CHPD03	;IF NOT ESC
	LD	A,0FFH
	LD	(PMNEWD),A	;FLAG NEW DISK
CHPD03	EQU	$
	$FLD	CDKMSG		;REDISPLAY CURRENT
	RET

;
; PRDD - READ AND DISPLAY PHYSICAL SECTOR
;
	$RTN	PRDD
	CALL	PSRD		;READ PHYSICAL SECTOR
	LD	HL,FBUFF
	CALL	WRBF		;DISPLAY BUFFER CONTENTS
	CALL	UBLK		;UPDATE BLOCK
	CALL	DPSI		;DISPLAY PHYSICAL SECTOR INFO
	RET
;
; DPSI - DISPLAY SECTOR INFORMATION
;
	$RTN	DPSI
	$FLD	PSTRFL		;POSITION CURSOR FOR TRACK NUMBER
	$HEXW	PSMDTR		;DISPLAY TRACK
	$FLD	PSSCFL		;POSITION FOR SECTOR NUMBER
	$HEXW	PSMDSC		;DISPLAY SECTOR
	$FLD	PSBLFL		;POSITION FOR BLOCK NUMBER
	$HEXW	PSMDBL		;DISPLAY BLOCK
	$FLD	PSDKFL		;POSITION FOR DISK ID
	LD	A,(CURAN)	;GET ABSOLUTE DRIVE NUMBER
	ADD	A,041H		;MAKE IT ALPHA
	CALL	CHRO		;DISPLAY DRIVE ID
	RET

;
; UBLK - UPDATE BLOCK NUMBER
;
	$RTN	UBLK
	LD	DE,(PSMDTR)
	LD	BC,(DPBSPT)
	CALL	MULT
	LD	DE,(PSMDSC)
	ADD	HL,DE		;CALCULATE ABSOLUTE SECTOR
	LD	DE,(DPERSC)
	OR	A
	SBC	HL,DE
	JR	NC,UBLK01	;IF WITHIN SYSTEM AREA
	LD	DE,0		;SET BLOCK ZERO
	JR	UBLK02
UBLK01	EQU	$		;ELSE
	EX	DE,HL
	LD	BC,(DPESPB)
	CALL	DIVD		;CALCULATE BLOCK NUMBER
	LD	HL,(DPBDSM)
	OR	A
	SBC	HL,DE
	JR	NC,UBLK04	;IF BLOCK NOT IN RANGE
	LD	DE,0		;SET BLOCK ZERO
UBLK04	EQU	$		;ENDIF
UBLK02	EQU	$		;ENDIF
	LD	(PSMDBL),DE	;SET NEW BLOCK NUMBER
	RET

;
; NXPS - NEXT PHYSICAL SECTOR
;
	$RTN	NXPS
	LD	HL,(PSMDSC)
	INC	HL
	LD	(PSMDSC),HL	;INCREMENT PHYSICAL SECTOR
	LD	DE,(DPBSPT)
	OR	A
	SBC	HL,DE
	JR	C,NXPS01	;IF TRACK OVERFLOW
	LD	HL,0
	LD	(PSMDSC),HL	;SET TO FIRST SECTOR
	CALL	FRTR		;ADVANCE TRACK
NXPS01	EQU	$		;ENDIF
	RET

;
; PRPS - PREVIOUS PHSICAL SECTOR
;
	$RTN	PRPS
	LD	HL,(PSMDSC)
	LD	A,H
	OR	L
	JR	NZ,PRPS01	;IF SECTOR IS ZERO
	CALL	BWTR		;GO BACK A TRACK
	LD	HL,(DPBSPT)	;SET UP FOR DECREMENT
PRPS01	EQU	$		;ENDIF
	DEC	HL
	LD	(PSMDSC),HL	;DECREMENT TO PREVIOUS SECTOR
	RET

;
; SPSN - SET PHYSICAL SECTOR NUMBER
;
	$RTN	SPSN
	LD	HL,SELMSG
	CALL	CFLD
	LD	HL,(PSMDSC)
	LD	(SAVPSC),HL	;SAVE RECORD NUMBER
	$FLD	SECMSG		;DISPLAY SET SECTOR
	LD	HL,0
	LD	(PSMDSC),HL	;ZERO RECORD NUMBER
SPSN01	EQU	$
	CALL	UBLK
	CALL	DPSI		;DISPLAY PHYSICAL SECTOR INFO
	$IFLD	PSSCIP		;POSITION AND GET INPUT
	$MTCH	HEXCHR
	JR	NZ,SPSN02	;IF VALID HEX
	EX	DE,HL
	LD	HL,(PSMDSC)
	CALL	H16D		;HL=HL*16+DIGIT
	LD	(PSMDSC),HL	;SAVE NEW SECTOR NUMBER
	JR	SPSN03
SPSN02	EQU	$
	CP	$ESC
	JR	NZ,SPSN04	;ELSEIF ESCAPE
	LD	HL,(SAVPSC)
	LD	(PSMDSC),HL	;RESTORE SECTOR NUMBER
	JR	SPSN03
SPSN04	EQU	$
	CP	$LEFT
	JR	NZ,SPSN05	;ELSEIF BACKSPACE
	LD	HL,PSMDSC+1
	XOR	A
	RRD
	DEC	HL
	RRD			;SECTOR=SECTOR/16
	JR	SPSN03
SPSN05	EQU	$
	CP	CR
	JR	NZ,SPSN06	;ELSEIF CR
	OR	A
	LD	HL,(PSMDSC)
	LD	DE,(DPBSPT)
	SBC	HL,DE
	JR	C,SPSN07	;IF SECTOR OUT OF RANGE
	CALL	ALRM		;SIGNAL ERROR
	LD	HL,(SAVPSC)
	LD	(PSMDSC),HL	;RESTORE TO ORIGINAL
	XOR	A
	LD	(INCH),A	;DONT EXIT
SPSN07	EQU	$
	JR	SPSN03
SPSN06	EQU	$		;ELSE
	CALL	ALRM		;ERROR
SPSN03	EQU	$		;ENDIF
	LD	A,(INCH)
	CP	CR
	JR	Z,SPSN08	;EXIT IF CR
	CP	$ESC
	JR	Z,SPSN08	;EXIT IF ESC
	JP	SPSN01
SPSN08	EQU	$		;ENDLOOP
	$FLD	CSCMSG		;DISPLAY CURRENT SECTOR MESSAGE
	RET

SAVPSC:	DS	2

;
; FRTR - FORWARD TRACK
;
	$RTN	FRTR
	LD	HL,(PSMDTR)
	INC	HL
	LD	(PSMDTR),HL
	LD	DE,(DPETPD)
	OR	A
	SBC	HL,DE
	JR	C,FRTR01	;IF DISK OVERFLOW
	LD	HL,0
	LD	(PSMDTR),HL	;SET TO FIRST TRACK
FRTR01	EQU	$
	RET

;
; SPTN - SET PHYSICAL TRACK NUMBER
;
	$RTN	SPTN
	LD	HL,SELMSG
	CALL	CFLD
	LD	HL,(PSMDTR)
	LD	(SAVPTR),HL	;SAVE TRACK NUMBER
	$FLD	TRKMSG		;DISPLAY TRKMSG
	LD	HL,0
	LD	(PSMDTR),HL	;ZERO TRACK NUMBER
SPTN01	EQU	$
	CALL	UBLK
	CALL	DPSI		;DISPLAY PHYSICAL SECTOR INFO
	$IFLD	PSTRIP		;POSITION AND GET INPUT
	$MTCH	HEXCHR
	JR	NZ,SPTN02	;IF VALID HEX
	EX	DE,HL
	LD	HL,(PSMDTR)
	CALL	H16D		;HL=HL*16+DIGIT
	LD	(PSMDTR),HL	;SAVE NEW TRACK NUMBER
	JR	SPTN03
SPTN02	EQU	$
	CP	$ESC
	JR	NZ,SPTN04	;ELSEIF ESCAPE
	LD	HL,(SAVPTR)
	LD	(PSMDTR),HL	;RESTORE TRACK NUMBER
	JR	SPTN03
SPTN04	EQU	$
	CP	$LEFT
	JR	NZ,SPTN05	;ELSEIF BACKSPACE
	LD	HL,PSMDTR+1
	XOR	A
	RRD
	DEC	HL
	RRD			;TRACK=TRACK/16
	JR	SPTN03
SPTN05	EQU	$
	CP	CR
	JR	NZ,SPTN06	;ELSEIF CR
	OR	A
	LD	HL,(PSMDTR)
	LD	DE,(DPETPD)
	SBC	HL,DE
	JR	C,SPTN07	;IF TRACK OUT OF RANGE
	CALL	ALRM		;SIGNAL ERROR
	LD	HL,(SAVPTR)
	LD	(PSMDTR),HL	;RESTORE TO ORIGINAL
	XOR	A
	LD	(INCH),A	;DONT EXIT
SPTN07	EQU	$		;ENDIF
	JR	SPTN03
SPTN06	EQU	$		;ELSE
	CALL	ALRM		;ERROR
SPTN03	EQU	$		;ENDIF
	LD	A,(INCH)
	CP	CR
	JR	Z,SPTN08	;EXIT IF CR
	CP	$ESC
	JR	Z,SPTN08	;EXIT IF ESC
	JP	SPTN01
SPTN08	EQU	$		;ENDLOOP
	$FLD	CTRMSG		;REDISPLY TRACK MESSAGE
	RET

SAVPTR:	DS	2

;
; BWTR - BACKWARD TRACK
;
	$RTN	BWTR
	LD	HL,(PSMDTR)
	LD	A,H
	OR	L
	JR	NZ,BWTR01	;IF TRACK IS ZERO
	LD	HL,(DPETPD)	;SET UP FOR DECREMENT
BWTR01	EQU	$		;ENDIF
	DEC	HL
	LD	(PSMDTR),HL	;DECREMENT TO PREVIOUS TRACK
	RET

;
; SPBL - SET PHYSICAL BLOCK
;
	$RTN	SPBL
	LD	HL,SELMSG
	CALL	CFLD
	LD	HL,(PSMDBL)
	LD	(SAVPBL),HL	;SAVE BLOCK NUMBER
	$FLD	BLKMSG		;DISPLAY BLKMSG
	LD	HL,0
	LD	(PSMDBL),HL	;ZERO BLOCK NUMBER
SPBL01	EQU	$
	CALL	DPSI		;DISPLAY PHYSICAL SECTOR INFO
	$IFLD	PSBLIP		;POSITION AND GET INPUT
	$MTCH	HEXCHR
	JR	NZ,SPBL02	;IF VALID HEX
	EX	DE,HL
	LD	HL,(PSMDBL)
	CALL	H16D		;BLOCK=BLOCK*16+DIGIT
	LD	(PSMDBL),HL	;SAVE NEW BLOCK NUMBER
	JR	SPBL03
SPBL02	EQU	$
	CP	$ESC
	JR	NZ,SPBL04	;ELSEIF ESCAPE
	LD	HL,(SAVPBL)
	LD	(PSMDBL),HL	;RESTORE BLOCK NUMBER
	JR	SPBL03
SPBL04	EQU	$
	CP	$LEFT
	JR	NZ,SPBL05	;ELSEIF BACKSPACE
	LD	HL,PSMDBL+1
	XOR	A
	RRD
	DEC	HL
	RRD			;BLOCK=BLOCK/16
	JR	SPBL03
SPBL05	EQU	$
	CP	CR
	JR	NZ,SPBL06	;ELSEIF CR
	OR	A
	LD	DE,(PSMDBL)
	LD	HL,(DPBDSM)
	SBC	HL,DE
	JP	P,SPBL07	;IF BLOCK OUT OF RANGE
	CALL	ALRM		;SIGNAL ERROR
	LD	HL,(SAVPBL)
	LD	(PSMDBL),HL	;RESTORE TO ORIGINAL
	XOR	A
	LD	(INCH),A	;DONT EXIT
	JR	SPBL08
SPBL07	EQU	$		;ELSE
	LD	DE,(PSMDBL)
	LD	BC,(DPESPB)
	CALL	MULT
	LD	DE,(DPERSC)
	ADD	HL,DE		;CALCULATE ABSOLUTE SECTOR
	EX	DE,HL
	LD	BC,(DPBSPT)
	CALL	DIVD
	LD	(PSMDTR),DE	;SET TRACK
	LD	(PSMDSC),HL	;SET SECTOR
SPBL08	EQU	$		;ENDIF
	JR	SPBL03
SPBL06	EQU	$		;ELSE
	CALL	ALRM		;ERROR
SPBL03	EQU	$		;ENDIF
	LD	A,(INCH)
	CP	CR
	JR	Z,SPBL09	;EXIT IF CR
	CP	$ESC
	JR	Z,SPBL09	;EXIT IF ESC
	JP	SPBL01
SPBL09	EQU	$		;ENDLOOP
	$FLD	CBLMSG		;REDISPLAY CURRENT BLOCK MESSAGE
	RET

SAVPBL:	DS	2

;
; PSPM - PHYSICAL SCRATCHPAD MODE
;
	$RTN	PSPM
	$NPANEL	PSPMPN		;DISPLAY PANEL
	$FLD	PSPCUR		;POSITION FOR CURRENT INFO
	$STRO	SPDMSG
	LD	A,(CURAN)
	ADD	A,41H
	CALL	CHRO		;DISPLAY DRIVE
	$STRO	SPTMSG
	$HEXW	PSMDTR		;TRACK
	$STRO	SPSMSG
	$HEXW	PSMDSC		;SECTOR
	$FLD	PSPSPD		;POSITION FOR S/P DATA
	CALL	DSPD
	CALL	SPCI		;GET COMMAND
	$EXVA	PSPMV		;PROCESS COMMAND
	LD	A,0FFH
	LD	(RPANEL),A	;REQUEST PANEL
	RET

PSPMPN:	DB	3
	DB	2,0,'ESC Return to sector display',0
	DB	3,0,'C   Copy current sector to scratchpad',0
	DB	4,0,'E   Exchange current sector with scratchpad',0

PSPCUR:	DB	11,0,'Current    :- ',0
PSPSPD:	DB	12,0,'Scratchpad :- ',0

PSPML:	DB	3,$ESC,'CE'
PSPMV:	DW	PSPX
	DW	PLSP
	DW	PXSP

	$RTN	PSPX
	RET

;
; PXSP - EXCHANGE WITH SCRATCHPAD
;
	$RTN	PXSP
	LD	A,(SPTYPE)
	OR	A
	JR	NZ,PXSP01	;IF PAD EMPTY
	CALL	ALRM		;RING BELL
	JR	PXSP02
PXSP01	EQU	$		;ELSE
	LD	BC,(SPADDR)
	CALL	SETDMA		;SET CPM BUFFER
	CALL	PSWR		;WRITE BUFFER
	LD	BC,FBUFF
	CALL	SETDMA		;RESTORE DMA
	CALL	PLSP		;COPY OLD BUFFER
PXSP02	EQU	$		;ENDIF
	RET
;
; PLSP - LOAD SCRATCHPAD (PHYSICAL)
;
	$RTN	PLSP
	LD	HL,FBUFF
	LD	DE,(SPADDR)
	LD	BC,128
	LDIR			;COPY THE BUFFER
	LD	A,(CURAN)
	LD	(SPDRIV),A	;SET DRIV
	LD	HL,(PSMDTR)
	LD	(SPNAME),HL	;SET TRACK
	LD	HL,(PSMDSC)
	LD	(SPSECT),HL	;SET SECTOR
	LD	A,1
	LD	(SPTYPE),A	;SET THE TYPE
	RET

;
; DSPD DISPLAY S/P DATA
;
	$RTN	DSPD
	CALL	DSPI		;DISPLAY SP INFO
	LD	A,(SPTYPE)
	OR	A
	JR	Z,DSPD01	;IF SP NOT EMPTY
	CALL	ZBSA		;CLEAR ADDRESS COUNTER
	LD	HL,(SPADDR)
	CALL	WRBF		;DISPLAY IT
DSPD01	EQU	$		;ENDIF
	RET

;
; LSEL - LIST FILE SELECTION STUB MASK POINTED TO BY HL
;
	$RTN	LSEL
	LD	DE,LMDFN
	LD	BC,11
	LDIR
	RET
;
; PSCH - PHYSICAL SECTOR CHANGE
;
	$RTN	PSCH
	CALL	SCCH		;GO INTO SECTOR CHANGE MODE
	LD	A,(SCCHWR)
	OR	A
	JR	Z,PSCH03	;IF WRITE REQUIRED
	CALL	PSWR		;WRITE OUT SECTOR
PSCH03	EQU	$		;ENDIF
	LD	A,0FFH
	LD	(RPANEL),A	;REQUEST PANEL
	RET			

;
; SCCH - SECTOR CHANGE MODE
;
	$RTN	SCCH
	LD	HL,HLAREA
	CALL	CLRA		;CLEAR THE HELP AREA
	$PANEL	SCCHPN		;DISPLAY SECTOR CHANGE PANEL
	LD	A,FALSE
	LD	(SCCHWR),A	;WRITE FLAG FALSE
	LD	(ASCII),A	;ASCII FALSE
	LD	(SCCHEX),A	;EXIT FALSE
	LD	(LOORD),A	;START WITH HO HEX DIGIT
	XOR	A
	LD	(BUFPOS),A	;BUFFER POSITION 0
SCCH03	EQU	$		;LOOP
	CALL	SLCP
	CALL	UDCP		;POSITION CURSOR
	CALL	CHRI
	CP	020H
	JP	NC,SCCH04	;IF CONTROL CODE
	$MTCH	SCCHLS
	JR	Z,SCCH05	;IF NOT VALID
	CALL	ALRM		;SOUND THE ALARM
	JR	SCCH06
SCCH05	EQU	$		;ELSE
	$EXVA	SCCHVC		;ACTION CONTROL CODE
SCCH06	EQU	$		;ENDIF
	JR	SCCH08
SCCH04	EQU	$		;ELSE
	LD	A,(ASCII)
	OR	A
	JR	Z,SCCH09	;IF ASCII MODE
	CALL	MACH		;MAKE ASCII CHANGE
	JR	SCCH10
SCCH09	EQU	$		;ELSE
	CALL	MHCH		;MAKE HEX CHANGE
SCCH10	EQU	$		;ENDIF
SCCH08	EQU	$		;ENDIF
	LD	A,(SCCHEX)
	OR	A
	JR	NZ,SCCH11	;EXIT IF END OF UPDATES
	JR	SCCH03
SCCH11	EQU	$		;ENDLOOP
	RET

SCCHEX:	DB	0
SCCHWR:	DB	0

;
; SECTOR CHANGE MODE PANEL AND ACTION VECTOR
;
SCCHPN:	DB	8
	DB	2,0,'^',$LEFT+040H,'  Cursor left',0
	DB	2,40,'^',$RIGHT+040H,'  Cursor right',0
	DB	3,0,'^',$UP+040H,'  Cursor up',0
	DB	3,40,'^',$DOWN+040H,'  Cursor down',0
	DB	4,0,'^',$TAB+040H,'  Change Side',0
	DB	4,40,'CR  New Line',0
	DB	5,0,'^',$QUIT+040H,'  Cancel changes',0
	DB	5,40,'^',$END+040H,'  Save Changes',0

SCCHLS:	DB	8,$LEFT,$TAB,$DOWN,$UP,$RIGHT,CR,$END,$QUIT

SCCHVC	EQU	$
	DW	LEFT
	DW	TOGL
	DW	DOWN
	DW	UPWD
	DW	RGHT
	DW	NWLN
	DW	CHND
	DW	QUIT

;
; LEFT - MOVE CURSOR LEFT
;
	$RTN	LEFT
	LD	A,(LOORD)
	OR	A
	JR	NZ,LEFT01	;IF HIGH OR ASCII
	LD	A,(BUFPOS)
	DEC	A
	AND	07FH
	LD	(BUFPOS),A	;DECREMENT POSITION
LEFT01	EQU	$
	LD	A,(ASCII)
	OR	A
	JR	NZ,LEFT02	;IF HEX MODE
	LD	A,(LOORD)
	CPL
	LD	(LOORD),A	;TOGGLE DIGIT
LEFT02	EQU	$
	RET

;
; TOGL - TOGGLE BETWEEN HEX AND ASCII
;
	$RTN	TOGL
	LD	A,(ASCII)
	CPL
	LD	(ASCII),A	;TOGGLE MODE FLAG
	LD	A,FALSE
	LD	(LOORD),A	;INDICATE HO DIGIT
	RET

;
; DOWN - MOVE CURSOR DOWN ONE LINE
;
	$RTN	DOWN
	LD	A,(BUFPOS)
	ADD	A,16
	AND	07FH
	LD	(BUFPOS),A
	RET

;
; UPWD - MOVE CURSOR UP ONE LINE
;
	$RTN	UPWD
	LD	A,(BUFPOS)
	SUB	16
	AND	07FH		;MODULO 128
	LD	(BUFPOS),A
	RET

;
; RGHT - MOVE CURSOR RIGHT
;
	$RTN	RGHT
	LD	A,(ASCII)
	OR	A
	JR	NZ,RGHT01	;IF HEX MODE
	LD	A,(LOORD)
	CPL			;TOGGLE HEX DIGIT
	LD	(LOORD),A
RGHT01	EQU	$		;ENDIF
	LD	A,(LOORD)
	OR	A
	JR	NZ,RIGH02	;IF HIGH ORD OR ASCII
	LD	A,(BUFPOS)
	INC	A
	AND	07FH
	LD	(BUFPOS),A	;INCREMENT POSITION
RIGH02	EQU	$		;ENDIF
	RET

;
; NWLN - MOV CURSOR TO START OF NEW LINE
;
	$RTN	NWLN
	LD	A,FALSE
	LD	(LOORD),A	;INDICATE HO HEX DIGIT
	LD	A,(BUFPOS)
	ADD	A,16
	AND	070H
	LD	(BUFPOS),A	;NEW BUFFER ADDR
	RET

;
; CHND - CHANGE END AND WRITE
;
	$RTN	CHND
	LD	A,TRUE
	LD	(SCCHEX),A	;SIGNAL EXIT
	LD	(SCCHWR),A	;SIGNAL WRITE
	RET

;
; QUIT - END WITHOUT SAVING UPDATES
;
	$RTN	QUIT
	LD	A,TRUE
	LD	(SCCHEX),A	;SIGNAL EXIT
	RET

;
; WRBF - DISPLAY FILE DATA IN SECTOR BUFFER
;
	$RTN	WRBF
	EX	DE,HL
	XOR	A
	LD	(BUFPOS),A	;SET OFFSET TO 0
WRBF01	EQU	$		;LOOP (HEX AND ASCII LINE)
	PUSH	DE		;SAVE BUFFER POINTER
	PUSH	DE		;AND FOR ASCII
	XOR	A
	LD	(CPOS),A	;POSITION 1
	CALL	STLP		;SET LINE CURSOR POSITION
	CALL	UDCP		;UPDATE CURSOR
	CALL	PRTADR		;DISPLAY ADDRESS
	LD	A,(BASEAD+2)
	ADD	A,010H
	LD	(BASEAD+2),A	;INC ADDR FOR NEXT LINE
	CALL	SHCP		;SET UP CURSOR POSN IN HEX AREA
	CALL	UDCP		;UPDATE CURSOR
	POP	DE		;GET CURRENT ADDRESS
WRBF03	EQU	$		;LOOP (BYTES IN HEX)
	LD	A,(DE)		;GET CHARACTER THERE
	INC	DE		;INCREMENT BUFF POINTER
	CALL	HEXO		;PRINT BYTE
	CALL	SPCO		;PRINT SPACE
	LD	HL,BUFPOS
	INC	(HL)		;INC TO NEXT COL
	LD	A,3
	AND	(HL)
	JR	NZ,WRBF04	;IF END OF GROUP
	CALL	SPCO		;PRINT SPACE
WRBF04	EQU	$		;ENDIF
	LD	A,0FH
	AND	(HL)
	JR	NZ,WRBF03	;UNTIL 16 BYTES DISPLAYED

	LD	A,(HL)
	SUB	16
	LD	(HL),A		;RESET BUFFER OFFSET
	CALL	SACP		;POSITION FOR ASCII
	LD	HL,CPOS
	DEC	(HL)		;BACK OFF 1 FOR MARGIN
	CALL	UDCP		;POSITION CURSOR
	LD	A,'ø'
	CALL	CHRO		;PRINT MARGIN
	POP	DE		;RESTORE CHAR POINTER
WRBF02	EQU	$		;LOOP (BYTES IN ASCII)
	LD	A,(DE)		;GET CURRENT CHARACTER
	INC	DE		;INCREMENT POINTER
	CALL	ASCO		;PRINT CHAR
	LD	HL,BUFPOS
	INC	(HL)		;INCREMENT BUFFER OFFSET
	LD	A,0FH
	AND	(HL)
	JR	NZ,WRBF02	;UNTIL 16 BYTES DISPLAYED
	LD	A,'ø'
	CALL	CHRO		;PRINT MARGIN

	LD	A,(HL)
	AND	07FH
	JP	NZ,WRBF01	;UNTIL 128 BYTES DISPLAYED
	RET

;
; CURSOR POSITON TABLES FOR HEX AND ASCII DISPLAY
;
LPTAB:	DB	14,15,16,17,18,19,20,21

HCTAB:	DB	 9,12,15,18,22,25,28,31,35,38,41,44,48,51,54,57
ACTAB:	DB	63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78

DCTAB:	DB	00,20,40,60 

;
; ZBSA - ZERO BASE ADDRESS
;
	$RTN	ZBSA
	XOR	A
	LD	(BASEAD),A
	LD	(BASEAD+1),A
	LD	(BASEAD+2),A
	RET

;
; PRTADR - PRINT FILE ADDRESS
;
	$RTN	PRTADR
	$HEXW	BASEAD		;DISPLAY 2 BYTES
	LD	A,(BASEAD+2)
	CALL	HEXO
	RET

;
; SLCP - SET CURSOR TO CURRENT LINE AND COLUMN POSITION IN BUFFER
;
	$RTN	SLCP
	CALL	STLP
	CALL	STCP
	RET

;
; STLP - SET UP LINE POSITION
;
	$RTN	STLP
	LD	HL,LPTAB	;GET BASE OF LINE TABLE
	LD	A,(BUFPOS)
	RRA
	RRA
	RRA
	RRA
	AND	0FH		;MOV TO LOW ORDER
	CALL	AAHL
	LD	A,(HL)		;GET VALUE
	LD	(LPOS),A	;SET UP FOR UDCP
	RET

;
; STCP - SET UP COLUMN POSITION IN BUFFER
;
	$RTN	STCP
	LD	A,(ASCII)
	OR	A
	JR	Z,STCP01	;IF IN ASCII DISPLAY MODE
	CALL	SACP		;SET UP ASCII DISPLAY
	JR	STCP02
STCP01	EQU	$		;ELSE
	CALL	SHCP		;SET UP FOR HEX DISPLAY
	LD	A,(LOORD)
	OR	A
	JR	Z,STCP03	;IF LOW ORDER DIGIT
	LD	HL,CPOS
	INC	(HL)		;INCREMENT COLUMN POS
STCP03	EQU	$		;ENDIF
STCP02	EQU	$		;ENDIF
	RET
;
ASCII:	DB	0
LOORD:	DB	0

;
; SHCP - SET CURSOR ADDRESS FOR HEX DISPLAY
;
	$RTN	SHCP
	LD	HL,HCTAB
	LD	A,(BUFPOS)
	AND	0FH
	CALL	AAHL
	LD	A,(HL)		;PICK UP VALUE
	LD	(CPOS),A	;SET POSITION
	RET

;
; SACP - SET CURSOR ADDRESS FOR ASCII DISPLAY
;
	$RTN	SACP
	LD	HL,ACTAB
	LD	A,(BUFPOS)
	AND	0FH
	CALL	AAHL
	LD	A,(HL)
	LD	(CPOS),A
	RET

;
; MACH - UPDATE BUFFER IN ASCII FORMAT
;
	$RTN	MACH
	LD	A,(INCH)
	CP	020H
	JR	C,MACH01
	CP	080H
	JR	C,MACH02	;IF CHARACTER OUT OF RANGE
MACH01	EQU	$
	CALL	ALRM		;SOUND THE ALARM
	JR	MACH03
MACH02	EQU	$		;ELSE
	PUSH	AF
	PUSH	AF		;SAVE CHAR
	LD	A,(BUFPOS)	;GET BUFFER OFFSET
	LD	HL,FBUFF
	CALL	AAHL		;POINT TO CHARACTER
	POP	AF		;RESTORE CHAR
	LD	(HL),A		;CHARACTER TO BUFFER
	CALL	ASCO		;ECHO IT
	CALL	SHCP		
	CALL	UDCP		;POSITION IN HEX AREA
	POP	AF		;RESTORE CHAR
	CALL	HEXO
	CALL	RGHT		;MOVE CURSOR FOR NEXT
MACH03	EQU	$		;ENDIF
	RET

;
; MHCH - UPDATE BUFFER CONTENTS IN HEX
;
	$RTN	MHCH
	LD	A,(INCH)	;GET INPUT CHARACTER
	CALL	FOLD
	LD	(INCH),A	;SAVE FOLDED VERSION
	$MTCH	HEXCHR
	JR	Z,MHCH02	;IF NOT VALID HEX
	CALL	ALRM		;SOUND THE ALARM
	JR	MHCH03
MHCH02	EQU	$
	LD	C,L		;SET HEX VALUE OF NIBBLE IN C
	LD	A,(INCH)
	CALL	ASCO		;ECHO IT
	LD	A,(BUFPOS)	;GET OFFSET
	LD	HL,FBUFF	;BASE OF BUFFET
	CALL	AAHL		;HL=A(CURRENT CHAR)
	LD 	B,(HL)		;B = CURRENT CHARACTER
	LD	A,(LOORD)
	OR	A
	JR	Z,MHCH04	;IF LO ORDER NIBBLE
	LD	A,0F0H		;SET MASK
	JR	MHCH05
MHCH04	EQU	$		;ELSE
	LD	A,C		;CHAR TO A REG
	RLCA
	RLCA
	RLCA
	RLCA			;HEX=HEX*16
	AND	0F0H		;CLEAR ANY MINCE LEFT
	LD	C,A		;BACK TO C REG
	LD	A,00FH		;SET MASK
MHCH05	EQU	$		;ENDIF
	AND	B		;MASK NIBBLE
	OR	C		;INSERT NEW VALUE
	LD	(HL),A		;REPLACE IN BUFFER
	PUSH	AF		;SAVE IT FOR ASCII
	CALL	SACP
	CALL	UDCP		;TOGGLE TO ASCII DISP
	POP	AF		;PICK UP NEW CHAR
	CALL 	ASCO		;DISPLAY IT
	CALL	RGHT		;ADVANCE CURSOR
MHCH03	EQU	$		;ENDIF
	RET

HEXCHR:	DB	16,'0123456789ABCDEF'	;VALID HEX CHARACTERS

;
; CHDR - CHANGE TO DRIVE IN A
;
	$RTN	CHDR
	LD	(SAVDRV),A	;SAVE REQUESTED DRIVE
	LD	C,A
	CALL	SELDSK		;LOCATE DPH
	LD	A,H
	OR	L
	JR	NZ,CHDR01	;IF INVALID DISK
	LD	A,(CURAN)	;GET CURRENT ID
	LD	C,A
	CALL	SELDSK		;RE-SELECT IT
	XOR	A
	JP	CHDR02
CHDR01	EQU	$		;ELSE
	PUSH	HL		;SAVE DPH
	LD	C,RESET
	CALL	CPM		;RESET DISKS
	POP	HL		;RESTORE DPH
				;INITIALISE PHYSICAL CONTROL BLOCKS
	LD	DE,DPHLCL
	LD	BC,16
	LDIR			;TAKE LOCAL COPY OF DPH
	LD	HL,(DPHDPB)
	LD	DE,DPBLCL
	LD	BC,15
	LDIR			;TAKE LOCAL COPY OF DPB
	LD	DE,(DPBSPT)
	LD	BC,(DPBOFF)
	CALL	MULT		;HL RETURNS NUMBER OF SYSTEM SECTORS
	PUSH	HL
	LD	(DPERSC),HL	;SAVE RESERVED SECTORS
	LD	A,(DPBBLM)
	LD	D,0
	LD	E,A
	INC	DE
	LD	(DPESPB),DE	;SAVE SECTORS PER BLOCK
	LD	BC,(DPBDSM)
	CALL	MULT		;HL RETURNS NUMBER OF FILE SECTORS
	POP	DE
	ADD	HL,DE		;HL CONTAINS SECTORS PER DISK
	LD	DE,(DPBSPT)
	DEC	DE
	ADD	HL,DE		;READY TO ROUND UP
	EX	DE,HL
	LD	BC,(DPBSPT)
	CALL	DIVD		;DE RETURNS TRACKS PER DISK
	LD	(DPETPD),DE	;SAVE TRACKS PER DISK
				;INITIALISE FILE CONTROL BLOCKS
	LD	A,(SAVDRV)	;RESTORE REQUESTED DRIVE
	LD	(CURAN),A	;SAVE AS ABSOLUTE DISK NUMBER
	INC	A	
	LD	(WRKDR),A	;PUT IT IN WORK FCB
	LD	(LMDDR),A	;AND DIRECTORY FCB
	CALL	RDIR		;READ DIRECTORY
	LD	A,0FFH
	OR	A		;SET NON-ZERO FLAGS
CHDR02	EQU	$		;ENDIF
	RET

SAVDRV:	DS	1

;
; DLST - DIRECTORY LISTING
;
	$RTN	DLST
	$FLD	DDLMSG
	LD	A,(CURAN)	;GET DISK ID
	ADD	A,41H		;CONVERT TO ASCII LETTER
	LD	(DRIVNM),A	;PUT DRIVE NAME IN MESSAGE
	LD	DE,LMDFN
	CALL	FMTN
	$STRO	DRIVNM
	LD	DE,(FSTDE@)
	LD	A,(DIROFF)	;GET STARTING ENTRY
	LD	H,0
	LD	L,A
	CALL	H16D		;HL=COUNT*LENGTH+FIRST
	LD	(NXTDE@),HL	;POINT TO FIRST DISPLAY
	XOR	A
	LD	(PRTCNT),A
DLST02	EQU	$		;LOOP
	LD	A,(DIROFF)
	LD	B,A
	LD	A,(DECNT)
	SUB	B
	LD	HL,PRTCNT
	CP	(HL)
	JR	Z,DLST03	;EXIT IF ALL ENTRIES PROCESSED
	LD	A,(HL)		;GET DISPLAY COUNTER
	CALL	DIRPOS		;POSITION TO DISPLAY
	LD	A,(FLAGCH)	;LOAD FLAG CHARACTER
	CALL	CHRO		;PRINT IT
	CALL	SPCO		;AND SPACE
	LD	DE,(NXTDE@)	;POINT ENTRY TO PRINT
	CALL	FMTN		;FORMAT FILE NAME
	$STRO	FILENM		;PRINT NAME
	LD	HL,(NXTDE@)
	LD	DE,16
	ADD	HL,DE
	LD	(NXTDE@),HL	;UPDATE TABLE POINTER
	LD	HL,PRTCNT
	INC	(HL)		;INCREMENT DISPLAY COUNTER
	LD	A,32
	CP	(HL)
	JR	Z,DLST03	;EXIT DISPLAY FULL
	JR	DLST02
DLST03	EQU	$		;ENDLOOP
	RET

DDLMSG:	DB	12,20,'Directory list - ',0

;
; RDIR - READ DIRECTORY
;
	$RTN	RDIR
	XOR	A
	LD	(DECNT),A	;NO ENTRIES IN TABLE
	LD	(SELDE),A	;SELECT LIST ENTRY 0
	LD	(DIROFF),A	;DISPLAY STARTS AT 0
	LD	HL,(MEMRY)
	LD	(NXTDE@),HL	;WHERE TO INSERT POINTER
	LD	(FSTDE@),HL	;START OF TABLE POINTER
	DEC	HL
	LD	(TOPDE@),HL	;TOP OF TABLE
	LD	DE,LMDFCB
	LD	C,FNDFST
	CALL	CPM		;GET FIRST DIRECTORY ENTRY
	CP	0FFH
	JR	Z,RDIR01	;QUIT IF NO FILE MATCHED
	RRCA
	RRCA
	RRCA			;MULTIPY BY 32
	LD	HL,FBUFF	;POINT TO RECORD
	CALL	AAHL		;ADDRESS OF CURRENT ENTRY
	LD	(NEWDE@),HL	;SAVE IT
	CALL	INSRT		;PUT MATCHED ENTRY IN TABLE
	LD	HL,(TOPDE@)
	LD	DE,16
	ADD	HL,DE
	LD	(TOPDE@),HL	;MARK TOP OF TABLE
RDIR02	EQU	$		;LOOP
	LD	DE,LMDFCB
	LD	C,FNDNXT
	CALL	CPM		;FIND NEXT MATCH
	CP	0FFH
	JR	Z,RDIR03	;EXITIF NO MORE
	RRCA
	RRCA
	RRCA			;MULTIPLY DIR CODE BY 32
	LD	HL,FBUFF	;POINT TO RECORD
	CALL	AAHL
	LD	(NEWDE@),HL	;SAVE IT
	CALL	ORDER		;FIND OUT WHERE TO PUT IT
	CALL	INSRT		;PUT ENTRY IN TABLE
	JR	RDIR02
RDIR03	EQU	$		;ENDLOOP
RDIR01	EQU	$		;ENDIF
	LD	HL,(TOPDE@)
	INC	HL
	LD	(PGEPTR),HL	;MARK START OF PAGING POINTERS
	RET
;
; INSRT - PUT DIRECTORY ENTRY IN TABLE
;
INSRT	EQU	$
	LD	DE,(NXTDE@)	;GET TABLE POINTER
	LD	HL,(NEWDE@)	;GET ADDRESS OF NEW ENTRY
	INC	HL		;DONT COPY DRIVE BYTE
	LD	BC,16		;LENGTH OF ENTRY
	LDIR			;SAVE ENTRY
	LD	HL,DECNT
	INC	(HL)		;ADD ONE TO ENTRY COUNT
	RET
;
; ORDER - UPDATE THE DIRECTORY TABLE
;
;
ORDER	EQU	$
	LD	HL,(FSTDE@)
ORDER1	EQU	$		;LOOP
	LD	DE,(TOPDE@)
	EX	DE,HL
	OR	A
	SBC	HL,DE
	JP	M,ORDER2	;EXIT IF END OF TABLE
	PUSH	DE		;SAVE CURRENT POINTER
	LD	HL,(NEWDE@)	;POINT TO NEW ENTRY
	INC	HL		;IGNORE DRIVE ID FIELD
	LD	BC,11		;LENGTH OF FILE NAME
	CALL	CPST		;COMPARE FILENAME
	POP	DE		;RESTORE CURRENT POINTER
	JP	M,ORDER2	;EXIT IF CURRENT>NEW
	LD	HL,16
	ADD	HL,DE		;POINT TO NEXT ENTRY
	JP	ORDER1
ORDER2	EQU	$		;ENDLOOP
	LD	(NXTDE@),DE	;SAVE INSERT ADDRESS
	LD	HL,(TOPDE@)
	INC	HL
	OR	A
	SBC	HL,DE
	LD	B,H
	LD	C,L		;LENGTH TO MOVE
	LD	HL,(TOPDE@)	;CURRENT TOP OF TABLE
	PUSH	HL		;SAVE CURRENT TOP
	LD	DE,16
	ADD	HL,DE		;NEW TOP OF TABLE
	LD	(TOPDE@),HL	;SAVE NEW TOP
	POP	DE		;RESTORE OLD TOP
	LD	A,B
	OR	C
	JP	Z,ORDER3	;QUIT IF NOTHING TO MOVE
	EX	DE,HL		;DEST=NEW,SRC=OLD TOP ADDRESS
	LDDR			;MOVE TABLE UP 16 BYTES
ORDER3	EQU	$		;ENDIF
	RET

;
; CPST - COMPARE STRING (HL)0:6 WITH (DE)0:6 LENGTH (BC) 
;
	$RTN	CPST
	XOR	A
	LD	(CPSTCN),A	;COMPARE CONDITION IS =
CPST01	EQU	$		;LOOP
	LD	A,C
	OR	B
	JR	Z,CPST02	;EXITIF DONE
	PUSH	BC		;SAVE COUNTER
	LD	A,(DE)		;GET 2ND STR CHAR
	AND	07FH		;IGNORE HIGH BIT
	LD	B,A		;SAVE IT
	LD	A,(HL)		;GET 1ST STR CHAR
	AND	07FH		;IGNORE HI BIT
	SUB	B		;COMPARE CURRENT CHARS
	LD	(CPSTCN),A	;SAVE RESULT
	POP	BC		;RETRIEVE COUNTER
	JR	NZ,CPST02	;EXITIF NOT EQUAL
	INC	HL
	INC	DE
	DEC	BC		;POINT TO NEXT CHARS
	JR	CPST01
CPST02	EQU	$		;ENDLOOP
	LD	A,(CPSTCN)	;PICK UP CONDITIONS
	OR	A		;SET CPU FLAGS
	RET

CPSTCN:	DS	1		;COMPARE CONDITION

; CLRA - CLEAR AREA FROM LINE H FOR L
;
	$RTN	CLRA
	LD	A,H
	LD	B,L
CLRA01	EQU	$
	CALL	CLRL
	INC	A
	DJNZ	CLRA01
	LD	HL,0
	LD	(PRVERR),HL	;NO ERROR NOW DISPLAYED
	RET

;
; FMTN - FORMAT FILE NAME FROM FCB POINTED TO BY DE INTO FILENM
;
	$RTN	FMTN
	LD	HL,FILENM
	LD	B,8		;LENGTH 8
FMTN01	EQU	$		;LOOP
	LD	A,(DE)
	AND	07FH		;STRIP OFF HIGH BIT
	LD	(HL),A		;COPY CHARACTER
	INC	HL
	INC	DE
	DJNZ	FMTN01		;UNTIL NAME DONE
	LD	(HL),'.'	;INSERT SEPERATOR
	INC	HL
	LD	A,(DE)
	AND	80H
	LD	(RO),A		;SET RO FLAG
	LD	B,3		;LENGTH 3
FMTN02	EQU	$		;REPEAT
	LD	A,(DE)
	AND	07FH		;STRIP OFF HIGH BIT
	LD	(HL),A		;COPY CHARACTER
	INC	HL
	INC	DE		;POINT TO NEXT
	DJNZ	FMTN02		;UNTIL TYPE DONE
	LD	A,(RO)
	OR	A		;TEST RO FLAG
	LD	A,'W'		;ASSUME R/W MODE
	JR	Z,FMTN03	;IF READ ONLY
	LD	A,'O'		;SELECT R/O MODE
FMTN03	EQU	$		;ELSE 
	LD	(FDMDRS),A	;SET MODE
	XOR	A
	LD	(COMFLG),A	;CLEAR .COM FLAG
	LD	HL,COMSTR
	LD	DE,FILENM+9	;POINT TO TYPE
	LD	BC,3
	CALL	CPST
	JR	NZ,FMTN04	;IF .COM FILE
	LD	A,0FFH
	LD	(COMFLG),A	;SET FLAG
FMTN04	EQU	$		;ENDIF
	RET

;
; UDCP - UPDATE CURSOR POSITION TO LPOS/CPOS
;

UDCP	EQU	$
	PUSH	HL
	PUSH	AF
	LD	A,(LPOS)	;GET LINE NUMBER
	LD	L,A
	LD	A,(CPOS)	;GET COLUM POSITION
	LD	H,A
	CALL	CURS		;PUT CURSOR THERE
	POP	AF
	POP	HL
	RET

LPOS:	DB	0
CPOS:	DB	0

;---------------
; FILE I/O ROUTINES
;---------------
;
; RDFS - READ FILE RELATIVE SECTOR
;
	$RTN	RDFS
	XOR	A
	LD	(WRKOV),A	;CLEAR OVERFLOW FLAG
	LD	HL,(WRKRR)
	LD	(SAVFSC),HL	;SAVE CURRENT RECORD
	LD	HL,(RELREC)
	LD	(WRKRR),HL	;SET RECORD NUMBER
	LD	DE,WRKFCB	;POINT TO FCB
	LD	C,READRN
	CALL	CPM		;READ THE RECORD
	LD	(READST),A	;SAVE STATUS
	OR	A
	JR	Z,RDFS01	;IF BAD READ
	LD	HL,(SAVFSC)
	LD	(RELREC),HL	;RESTORE RECORD NUMBER
	LD	(WRKRR),HL	
RDFS01	EQU	$
	RET

;
; WRFS - WRITE FILE RELATIVE SECTOR BACK TO DISK
;

	$RTN	WRFS
	LD	DE,WRKFCB	;POINT TO FCB
	LD	C,WRITRN	;RANDOM WRITE
	CALL	CPM		;GO DO IT
	RET

;
; PSRD - READ PHYSICAL SECTOR
;
	$RTN	PSRD
	LD	BC,(PSMDTR)
	CALL	SETTRK		;SELECT TRACK
	LD	BC,(PSMDSC)
	LD	HL,(PSMDTR)
	LD	DE,(DPBOFF)
	OR	A
	SBC	HL,DE
	JR	C,STSA01	;IF NOT SYSTEM TRACK
	LD	DE,(DPHXLT)
	CALL	SECTRN		;DO SECTOR TRANSLATION
	LD	B,H
	LD	C,L
STSA01	EQU	$
	CALL	SETSEC
	CALL	READ		;READ SECTOR
	RET

;
; PSWR - WRITE PHYSICAL SECTOR
;
	$RTN	PSWR
	LD	C,WRDIR		;USE WRITE DIRECTORY TO FORCE WRITE
	CALL	WRITE		;WRITE SECTOR
	RET

WRDIR	EQU	1		;BIOS DIRECTORY WRITE CODE

;----------------
; UTILITY ROUTINES
;----------------
;
; H16D - HL * 16 + DE
;
	$RTN	H16D
	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,HL		;HL=HL*16
	ADD	HL,DE		; + DE
	RET
;
; ERRP - PROCESS ERROR DISPLAYS
;
	$RTN	ERRP
	LD	HL,(PRVERR)
	LD	A,H
	OR	L
	JR	Z,ERRP01	;IF PREVIOS ERROR
	PUSH	HL		;SAVE TEXT ADDRESS
	$FLD	ERRFLD		;POSITION CURSOR
	POP	HL
	CALL	CSTR		;CLEAR STRING
	LD	HL,0
	LD	(PRVERR),HL	;CLEAR POINTER
ERRP01	EQU	$		;ENDIF
	LD	HL,(ERRTXT)
	LD	A,H
	OR	L
	JR	Z,ERRP02	;IF ERROR SET
	PUSH	HL		;SAVE TEXT POINTER
	$FLD	ERRFLD		;POSITION CURSOR
	POP	HL
	LD	(PRVERR),HL	;SAVE TEXT ADDRESS
	CALL	STRO		;OUTPUT TEXT
	CALL	ALRM		;SOUND ALARM
	LD	HL,0
	LD	(ERRTXT),HL	;CLEAR TEXT POINTER
ERRP02	EQU	$		;ENDIF
	RET

;
; MTCH - BYTE LIST MATCHER
;
	$RTN	MTCH
	PUSH	BC		;SAVE BC
	LD	B,0
	LD	C,(HL)		;BC=LENGTH
	INC	HL		;POINT TO START OF LIST
	PUSH	BC		;SAVE LENGTH
	CPIR			;SCAN LIST
	POP	HL		;RESTORE LENGTH TO HL
	JR	NZ,MTCH01	;IF FOUND
	OR	A
	SBC	HL,BC		;SUBTRACT RESIDUE TO GIVE OFFSET+1
	DEC	HL		;HL IS OFFSET
	CP	A		;SET Z FLAG
MTCH01	EQU	$
	POP	BC		;RESTORE BC
	RET

;
; DOIT - JUMP TO ROUTINE AT OFFSET 2*HL FROM DE
;
	$RTN	DOIT
	ADD	HL,HL
	ADD	HL,DE		;DERIVE ACTION ADDR
	CALL	LDHL
	JP	(HL)

;
; LDHL - LOAD HL WITH (HL)
;
	$RTN	LDHL
	PUSH	AF
	LD	A,(HL)
	INC	HL
	LD	H,(HL)
	LD	L,A		;HL = (HL)
	POP	AF
	RET

;
; AAHL - ADD A TO HL
;
	$RTN	AAHL
	PUSH	DE		;SAVE DE
	LD	E,A
	LD	D,0
	ADD	HL,DE
	POP	DE		;RESTORE DE
	RET
;
; MULT - MULTIPLY DE BY BC TO GIVE RESULT IN HL AND OVERFLOW IN DE
;
	$RTN	MULT
	LD	A,16		;SET A TO LOOP COUNT
	LD	HL,0		;ZERO RESULT
	OR	A		;CLEAR CARRY
MULT01	EQU	$		;LOOP
	EX	DE,HL
	ADC	HL,HL		;SHIFT DE LEFT 1 (AND INTO CARRY)
	EX	DE,HL
	JP	NC,MULT02	;IF BIT SHIFTED OUT OF DE IS SET
	ADD	HL,BC		;ADD MULTIPLICAND TO RESULT
	JP	NC,MULT03	;IF RESULT OVERFLOWED
	INC	DE		;PROPAGATE INTO DE
MULT03	EQU	$		;ENDIF
MULT02	EQU	$		;ENDIF
	DEC	A		;DECREMENT LOOP COUNT
	JP	Z,MULT04	;IF LOOP COUNT IS ZERO EXIT
	ADD	HL,HL		;SHIFT LEFT 1 (OVERFLOW ADDED BY ADC)
	JP	MULT01
MULT04	EQU	$		;ENDLOOP
	RET
;
; DIVD - DIVIDE DE BY BC TO GIVE REMAINDER IN HL AND QUOTIENT IN DE
;
	$RTN	DIVD
	LD	A,16		;SET A TO LOOP COUNT
	LD	HL,0		;ZERO REMAINDER
DIVD01	EQU	$		;LOOP
	ADD	HL,HL		;SHIFT REMAINDER LEFT 1
	EX	DE,HL
	ADD	HL,HL		;SHIFT DIVISOR LEFT 1
	EX	DE,HL
	JP	NC,DIVD02	;IF CARRY SET
	INC	HL		;INCREMENT RESULT
DIVD02	EQU	$		;ENDIF
	OR	A		;RESET CARRY FLAG
	SBC	HL,BC		;SUBTRACT DIVISOR
	INC	DE		;INCREMENT QUOTIENT
	JP	P,DIVD03	;IF RESULT IS NEGATIVE
	ADD	HL,BC		;BACK OFF SUBTRACT
	DEC	DE		;DECREMENT QUOTIENT
DIVD03	EQU	$		;ENDIF
	DEC	A		;DECREMENT LOOP COUNT
	JP	Z,DIVD04	;IF LOOP COUNT ZERO EXIT
	JP	DIVD01
DIVD04	EQU	$		;ENDLOOP
	RET

;
; SETD - SET DIRECTORY MODE
;
	$RTN	SETD
	LD	A,'D'
	LD	(WTG),A		;NEXT MODE IS DIRECTORY
	RET

;
; SETF - SET FILE MODE
;
	$RTN	SETF
	LD	A,'F'
	LD	(WTG),A		;NEXT MODE IS FILE
	RET

;
; SETP - SET PHYSICAL SECTOR MODE
;
	$RTN	SETP
	LD	A,'P'
	LD	(WTG),A		;NEXT MODE IS PHYSICAL SECTOR
	RET

;
; SETX - SET EXIT MODE
;
	$RTN	SETX
	LD	A,'X'
	LD	(WTG),A		;NEXT MODE IS EXIT
	RET

;----------------
; SCREEN I/O ROUTINES
;----------------
;
; CHRI - INPUT CHARACTER INTO A WITHOUT ECHO
;
	$RTN	CHRI
	PUSH	HL
	PUSH	DE
	PUSH	BC
CHRI01	EQU	$
	LD	E,0FFH		;INDICATE INPUT FUNCTION
	LD	C,CONIO		;DIRECT I/O
	CALL	CPM		;ISSUE CALL
	OR	A
	JR	Z,CHRI01	;UNTIL CHAR RECEIVED
	LD	(INCH),A
	POP	BC
	POP	DE
	POP	HL
	RET

;
; FOLD - FOLD CHARACTER IN A TO UPPER CASE IF REQUIRED
;
	$RTN	FOLD
	CP	'a'
	JR	C,FOLD01
	CP	'z'+1
	JR	NC,FOLD01	;IF NOT UPPER CASE
	AND	05FH		;FOLD CHARACTER
FOLD01	EQU	$		;ENDIF
	RET

;
; CHRF - GET FOLDED CHARACTER
;
	$RTN	CHRF
	CALL	CHRI
	CALL	FOLD
	RET
;
; CHRO - OUTPUT CHARACTER IN A 
;
	$RTN	CHRO
	PUSH	BC
	PUSH	DE
	PUSH	HL
	PUSH	AF
	LD	E,A		;INPUT TO PARM REG
	LD	C,CONIO		;DIRECT OUTPUT
	CALL	CPM		;CALL CPM 
	POP	AF
	POP	HL
	POP	DE
	POP	BC
	RET

;
; ALRM - SOUND THE CONSOLE BELL
;
	$RTN	ALRM
	PUSH	AF
	LD	A,07H
	CALL	CHRO
	POP	AF
	RET

;
; SPCO - OUTPUT SPACE TO SCREEN
;
	$RTN	SPCO
	PUSH	AF
	LD	A,' '
	CALL	CHRO
	POP	AF
	RET

;
; CLRS - CLEAR SCREEN AND HOME CURSOR
;
	$RTN	CLRS
	PUSH	AF
	PUSH	HL
	$STRO	CLSSTR		;PRINT CLEAR SCREEN STRING
	LD	HL,0
	LD	(PRVERR),HL	;CLEAR PREV ERROR
	POP	HL
	POP	AF
	RET

;
; DHDR - CLEAR SCREEN AND DISPLAY HEADER
;
	$RTN	DHDR
	CALL	CLRS
	$FLD	HDRMSG
	RET
;
; CLRL - CLEAR LINE CONTAINED IN A
;
	$RTN	CLRL
	PUSH	AF
	PUSH	HL
	LD	H,0		;COLUMN ZERO
	LD	L,A		;LINE (A)
	CALL	CURS		;POSITION TO LINE
	$STRO	CLLSTR		;PRINT CLEAR LINE STRING
	POP	HL
	POP	AF
	RET

;
; CURS - SET CURSOR POSITION TO LINE L COLUMN H
;
	$RTN	CURS
	PUSH	AF
	PUSH	HL
	$STRO	CRPSTR		;OUTPUT CURSOR POSITION PREFIX
	POP	HL
	LD	A,L
	ADD	A,20H
	CALL	CHRO		;OUTPUT LINE COORDINATE
	LD	A,H
	ADD	A,20H
	CALL	CHRO		;OUTPUT COLUMN COORDINATE
	POP	AF
	RET

;
; DPNL - DISPLAY PANEL
;
	$RTN	DPNL
	LD	B,(HL)
	INC	HL
DPNL01	EQU	$
	PUSH	BC
	CALL	DFLD		;DISPLAY FIELD
	POP	BC
	DJNZ	DPNL01
	RET

;
; DFLD - DISPLAY FIELD
;
	$RTN	DFLD
	PUSH	HL
	CALL	LDHL
	CALL	CURS		;SET CURSOR POSITION
	POP	HL
	INC	HL
	INC	HL
	CALL	STRO		;OUPUT STRING
	RET
;
; CFLD - CLEAR FIELD
;
	$RTN	CFLD
	PUSH	HL
	CALL	LDHL
	CALL	CURS		;SET CURSOR POSITION
	POP	HL
	INC	HL
	INC	HL
	CALL	CSTR		;CLEAR STRING
	RET
;
; CSTR - CLEAR STRING POINTED TO BY HL
;
	$RTN	CSTR
CSTR01	EQU	$		;LOOP
	LD	A,(HL)		;PICK UP FIELD CHARACTER
	OR	A
	JR	Z,CSTR02	;EXIT IF NULL
	CALL	SPCO		;OUTPUT BLANK
	INC	HL		;POINT TO NEXT CHARACTER
	JR	CSTR01
CSTR02	EQU	$		;ENDLOOP
	INC	HL
	RET
;
; STRO - OUTPUT STRING POINTED TO BY HL AND DELIMITED BY A NULL
;
	$RTN	STRO
STRO01	EQU	$
	LD	A,(HL)
	OR	A
	JR	Z,STRO02
	CALL	CHRO
	INC	HL
	JR	STRO01
STRO02	EQU	$
	INC	HL
	RET

;
; ASCO - OUTPUT ASCII CHARACTER OR '.' TO SCREEN
;
	$RTN	ASCO
	PUSH	AF
	CP	7FH
	JR	NC,ASCO01
	CP	20H
	JR	NC,ASCO02
ASCO01	EQU	$
	LD	A,'.'
ASCO02	EQU	$
	CALL	CHRO
	POP	AF
	RET

;
; HEXO - OUTPUT BYTE IN A IN HEX TO SCREEN
;
	$RTN	HEXO
	PUSH	AF
	RRA
	RRA
	RRA
	RRA			;REVERSE NIBBLES
	CALL	HEXC		;PRINT HO NIBBLE
	POP	AF
	CALL	HEXC		;PRINT LO NIBBLE
	RET

;
; HEXW - OUTPUT WORD IN HL TO SCREEN
;
	$RTN	HEXW
	PUSH	AF
	LD	A,H
	CALL	HEXO
	LD	A,L
	CALL	HEXO
	POP	AF
	RET

;
; HEXC - OUTPUT LO NIBBLE IN A IN HEX TO SCREEN
;
	$RTN	HEXC
	AND	0FH		;LOSE HO NIBBLE
	ADD	A,90H
	DAA
	ADC	A,40H
	DAA
	CALL	CHRO		;OUTPUT HEX CHARACTER
	RET

;		END OF CODE

ENDCDE	EQU	$
	END	INIT
«eof»