home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
ENTERPRS
/
CPM
/
UTILS
/
S
/
SPZAP128.LZH
/
SUPERZAP.MAC
< prev
Wrap
Text File
|
1987-11-07
|
83KB
|
4,067 lines
.xlist ;Moved here to keep .PRN file short for Z8E
.Z80
TITLE SUPERZAP - CP/M DISK UTILITY
; (SUPERZAP v.3.3 PRECONFIGURED AND CORRECTED FOR C128)
;------------------------------------------------------------------------------
;
; SUPERZAP - A screen-oriented disk editor for CP/M-80
;
; Versions prior to 3.x by Davidson and Sheldrake
;
; Upgraded to CP/M+ operation by:
; John Hastwell-Batten,
; SYSOP, Tesseract RCPM+,
; P.O. Box 242,
; Dural, NSW 2158,
; AUSTRALIA.
;
; Hopefully, what we have now is a "universal" version that will run
; without change under CP/M 2.2 and CP/M 3.1 but since I do not have
; a CP/M 2.2 system there is the chance that I have screwed it up.
;
; All of Willie Davidson's code is in upper case. My changes are easy
; to identify because they are in lower case. JHB.
;
;------------------------------------------------------------------------------
;
; Update list (most recent first)
;
; 7 Nov 87 CONFIGURED FOR C128 BY M.D. GIRARDEAU
; *********THIS VERSION ONLY FOR THE C128*********
;
; 3.3 20 Mar 86 Willie Davidson (mods done by John Hastwell-Batten)
;
; - Incorporated Willie Davidson's updates to the CP/M 2.2 version into
; this universal version.
;
; 3.2 24 Feb 86 John Hastwell-Batten
;
; - Removed CP/M 3 configuration/implementation dependencies.
; SUPERZAP should now run on any CP/M 3 or 2.2 system with a Z80.
;
; 3.1 11 Jan 86 John Hastwell-Batten
;
; - Added ability to select user number (very crude).
; - Changed default track number to directory track
; - Made terminal functions more general and object-patchable.
;
; 3.0 9 Jan 86 John Hastwell-Batten
;
; - ASEG and ORG directives added, .LIST and .XLIST directives moved
; to simplify use with Z8E debugger.
; - Upgraded to be compatible with CP/M 3.1
; - Introduced inverse video display of characters with high bit set
; to make display of directory sectors more readable
;
; 2.1 Willie Davidson and H Sheldrake
;
; Original (as distributed by SIG/M)
;
;------------------------------------------------------------------------------
aseg ;For Z8E debugger symbol table alignment
org 100h ;(Just makes it a little easier)
;---------------- Entry point to program -----------------
jp init ;Now we have to do this ourselves
$VER DEFL '3' ;VERSION NUMBER
$MOD DEFL '3' ;MODIFICATION LEVEL
DB ' SUPERZAP 3 ' ;Deleted a few "blank" lines.
DB ' for CP/M 2.2 ' ;Screen controls now at 150h
DB ' and CP/M 3.1 ' ;instead of 180h
DB ' W.M.Davidson '
DB ' H.J.Sheldrake '
; DB '18 DEAN PARK CR.'
; DB ' EDINBURGH '
; DB ' EH4 1PH '
; DB ' SCOTLAND '
; CURSOR CHARACTER EQUATES (MUST BE 01H TO 01FH)
$LEFT EQU 013H ;CURSOR LEFT IS ^S
$RIGHT EQU 004H ;CURSOR RIGHT IS ^D
$UP EQU 005H ;CURSOR UP IS ^E
$DOWN EQU 018H ;CURSOR DOWN IS ^X
$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 'K'-040H ;END EDIT IS ^K
; SCREEN CONTROL (for Commodore 128)
CLSSTR: DB 1,1Ah,0,0,0,0,0,0 ;CLEAR SCREEN
CLLSTR: DB 2,1Bh,54h,0,0,0,0,0 ;CLEAR LINE
vInv: db 3,1Bh,47h,34h,0,0,0,0 ;Inverse video
vNorm: db 3,1Bh,47h,30h,0,0,0,0 ;Normal video
cpPref: DB 2,1Bh,3Dh,0,0,0,0,0 ;CURSOR POSITION PREFIX
cpMid: db 0,0,0,0,0,0,0,0 ;Cursor position infix
cpEnd: db 0,0,0,0,0,0,0,0 ;Cursor position suffix
row1st: db 1 ;1=row first, 0=column first. SEE NOTE!
rowOff: db 20h ;Offset for row
colOff: db 20h ;Offset for column
cpBin: db 1 ;0 for decimal cursor coordinates,
;Non-0 for binary.
maxASC: db 7Eh ;Set to 7Dh for stupid Hazeltines
; --- WARNING WARNING WARNING WARNING ---
; The value of row1st must not be set to any value other than 0 or 1.
FLAGCH: DB ' ' ;FLAG CHARACTER IN LIST MODE
;---------------- 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
; $strl - print string at (HL) where first byte is length
$strl macro $strnm
ld hl,$strnm
call strl
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 - EXECUTE VECTORED ACTION
$EXVA MACRO $LST
LD DE,$LST
CALL EXVA
ENDM
; $HEXW - DISPLAY HEX WORD
$HEXW MACRO $WORD
LD HL,($WORD)
CALL HEXW
ENDM
;---------------- GLOBAL EQUATES ----------------
CR EQU 0DH
LF EQU 0AH
FALSE EQU 000H
TRUE EQU 0FFH
CMD EQU 80H
FBUFF EQU 80H
;Note: The CP/M2.2-specific version of this program used the default
; file I/O buffer at 80H for all disk operations, i.e. for file-
; oriented AND physical I/O. Under CP/M 3.1 this is not tenable
; because the BIOS deals with physical sectors rather than 128-
; byte "logical" sectors and physical sectors can be much larger
; than 128 bytes.
;
; Physical disk I/O for CP/M 3.x now uses an area set aside at
; the end of this program, before the scratchpad. 2048 bytes has
; been reserved. That should be enough; I don't know of any
; system which supports physical sectors longer than 1024 bytes
; but the notes on the WD1797 FDC suggest that 2048 is possible.
;
; JHB January 1986
;
;---------------- CPM SYSTEM CALL CODES
CPM EQU 05H ;CPM CALL ADDRESS
CONIO EQU 06H ;DIRECT CONSOLE I/O
getVsn EQU 0Ch ;Get CP/M version number
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
sDMA equ 1Ah ;Set DMA address (Req'd for CP/M 3.1)
userNo equ 20h ;Get/Set user number
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,21,'SUPERZAP version ',$VER,'.',$MOD,0
;---------------- GLOBAL WORK AREAS
MEMRY: DS 2 ;FREE MEMORY SPACE
CPM3: DS 1 ;CP/M 3 flag
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: CALL BIOS3 ;For CP/M3 we make all of these
CONST: CALL BIOS3 ;branch to the same place. From
CONIN: CALL BIOS3 ;there we will do a "Come From"
CONOUT: CALL BIOS3 ;statement to figure out which
LIST: CALL BIOS3 ;routine was called.
PUNCH: CALL BIOS3
READER: CALL BIOS3 ;For CP/M 2.2 these CALLs will
HOME: CALL BIOS3 ;be overlaid with a copy of the
SELDSK: CALL BIOS3 ;JP table at the beginning of
SETTRK: CALL BIOS3 ;the BIOS.
SETSEC: CALL BIOS3
SETDMA: CALL BIOS3 ;JHB - January 1986
READ: CALL BIOS3
WRITE: CALL BIOS3
LISTST: CALL BIOS3
SECTRN: CALL BIOS3
; Note that the entire CP/M 3.x BIOS table is not represented here.
ELBIOS EQU $ ;END OF LOCAL BIOS
; INIT - SPZ INITIALISATION
$RTN INIT
LD HL,(6)
ld l,0 ;Don't interfere with any RSXs
LD SP,HL ;SET STACK TO BASE OF BDOS
ld c,getVsn ;Test CP/M version. Set
call cpm ;'cpm3' to zero if 2.x
ld a,2Fh ;or to 1 if 3.x
sub l
ld a,h ;Pull in MP/M flag too
jr nc,notPlus
inc a
notPlus:
ld (cpm3),a ;Zero if CP/M 2.x, Non-zero if MP/M or CP/M 3.x
or a ;Only copy BIOS vector if CP/M 2.x
jr nz,noLocal
LD HL,(1) ;LOAD BIOS VECTOR ADDRESS
LD DE,LBIOS
LD BC,ELBIOS-LBIOS
LDIR ;SET UP LOCAL BIOS VECTOR
noLocal:
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
ld c,reset ;Reset disk system
call cpm
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,' ',0 ;Deleted for C128
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
; FOLLOWING LINE CHANGED FOR C128 TO DELETE SECTOR CHANGE MODE COMMAND X
FDMDLS: DB 8,'NCPLTESZ'
;
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
; LINE DELETED HERE FOR C128 (SCRATCHPAD ACTION VECTOR DELETED)
;
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 dmaSet ;SET CPM BUFFER
CALL WRFS ;WRITE BUFFER
LD BC,FBUFF
CALL dmaSet ;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
;
; Updated Jan 86 by JHB to include user number selection
DRMDPN: DB 13 ;(Was 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 04,22,'U Change user number',0
DB 02,54,'Z Exit from Superzap',0
DB 03,54,'C Change disk',0
DB 04,54,'S Select track/sector',0
; FOLLOWING LINE CHANGED FOR C128
DB 05,54,' ',0 ;M option deleted
;
DB 07,00,'E Edit file',0
DB 07,22,'T Type file',0
; FOLLOWING LINE CHANGED FOR C128 TO DELETE M OPTION
DRMDLS: DB 14,$LEFT,$RIGHT,$UP,$DOWN,CR,'EZCSPNTU',$TAB
DRMDVC: DW FBS
DW FFS
DW FUP
DW FDN
DW FNL
DW STFL
DW SETX
DW CHDD
; 1 LINE DELETED HERE FOR C128 TO DELETE ACTION VECTORS FOR M
DW SETP
DW DIRP
DW DIRN
DW TYPE
dw chun
DW FFS
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 IN 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 CP/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 Z,TYPG12 ;IF COM FILE
CALL TPUT ;OUTPUT CHARACTER
LD A,(READST)
OR A
JR NZ,TYPG02 ;EXIT IF END OF FILE
LD A,(TYPEOP)
OR A
JR NZ,TYPG02 ;OR END OF PAGE
CALL TGET ;GET NEXT CHARACTER
JR TYPG13
TYPG12 EQU $ ;ELSE (NOT A 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
TYPG13 EQU $
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 76
JR NZ,TPUT01 ;IF COL=76
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
; chun - change user number (Code mostly copied from CHDD)
$rtn chun
ld hl,unMsg
call cfld
ld a,true
ld (drmdld),a
$ifld unMsg
cp $esc
ret z
sub 30h ;Make user number 0-9
jr c,chun04 ;If illegal user number
cp 10 ;Check for A..F
jr c,chun05
sub 7
chun02: cp 16
jr c,chun05
chun04: call alrm
ret
chun05: ld e,a
ld c,userNo
call cpm
ld c,GETDEF
call cpm
call chdr
xor a
ld (selde),a
ret
unMsg: defb 12,20,'Enter user number or press ESC ===>',0
; 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 (PSMDSC),HL ;SET SECTOR TO 0
; LD (PSMDTR),HL ;SET TRACK TO 0
; The above used to set the track to 0 but I found that is not very useful so
; I changed it to point to the beginning of the directory:-
ld hl,(dpbOff)
ld (psmdtr),hl
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
BIOS3: ;General BIOS entry for CP/M 3.1
ld (hlVal),hl ;Save caller's register values
ld (deVal),de ; in BIOS parameter block
ld (bcVal),bc ;
ld (aVal),a ;
pop hl ;Get return address for figuring which
; routine was called. (Also leaves proper
; return address on stack!)
ld de,LBIOS-3 ;Base of jump table
xor a ;Clear carry flag
sbc hl,de ;(BIOS function) * 3 now in HL
ld b,a
ld a,l
fnCalc:
sub 3 ;Figure out which BIOS function was called
jr z,gotFn
inc b
jr fnCalc
gotFn:
ld a,b ;Stash it in the BIOS parameter block
ld de,BIOSfn
ld (de),a
ld c,50 ;CP/M Plus direct BIOS call
call cpm
ret
BIOSfn: defs 1 ;CP/M Plus BIOS parameter block
aVal: defs 1
bcVal: defs 2
deVal: defs 2
hlVal: defs 2
; LOCAL DISK PARAMETER HEADER
;
; It seems that the DPH layouts for CP/M 2.x and CP/M 3.x are different.
; In particular, there are 10 bytes between DPHXLT and DPHDPB instead
; of the 8 shown here. We will correct for this when we are making a
; local copy of the DPB.
;
; Note that the labels DPHDIR, DPHCSV and DPHALV are not used anywhere.
DPHLCL EQU $
DPHXLT: DS 2
DS 6 ;FILLER
DPHDIR: DS 2
DPHDPB: DS 2
DPHCSV: DS 2
DPHALV: DS 2
dphdp3 equ dphdpb+2 ;Equivalence for CP/M 3.x
; 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
dpbPSH: DS 1 ;CP/M 3 only
dpbPSM: DS 1 ;CP/M 3 only
; 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
PhySec: 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 CHANGE 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 dmaSet ;SET CPM BUFFER
CALL PSWR ;WRITE BUFFER
LD BC,FBUFF
CALL dmaSet ;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
ld hl,-1 ;Clear prvTrk and prvSec to force
ld (prvTrk),hl ; physical I/O on next access
ld (prvSec),hl
; <<< INITIALISE PHYSICAL CONTROL BLOCKS >>>
; If CP/M 3.1 then the DPH is not necessarily in the same memory bank as
; this program but the banked BDOS does us the favour of making a local
; copy in common memory.
POP HL ;RESTORE DPH
LD DE,DPHLCL
LD BC,16
LDIR ;TAKE LOCAL COPY OF DPH
LD HL,(DPHDPB) ;DPB pointer for CP/M 2.x
ld a,(cpm3) ;Check which version of CP/M so we get
or a ; the DPB pointer right
jr z,copyDPB ;Skip reload if 2.2
ld hl,(dphdp3) ;Get CP/M 3 DPB pointer
copyDPB:
LD DE,DPBLCL
LD BC,17 ;Increased from 15 for CP/M+
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
; FOLLOWING CODE CALCULATES CORRECT NUMBER OF LOGICAL
; TRACKS/DISK FOR C128. ORIGINAL SUPERZAP CODE GETS WRONG NUMBER.
;
inc de ;Increment # tracks/disk
ld a,0
cp d ;Is disk double-sided?
jr z,single ;Jump if single-sided
inc de ;Increment again if double-sided
single equ $ ;Jump target
ld (dpetpd),de ;Now # of tracks/disk is correct
; END OF THIS CORRECTION SECTOR FOR C128
;
;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
;---------------
; IOaddr - Set the data transfer address for disk operations
$rtn IOaddr
ld de,(DMA)
ld c,sDMA
call cpm ;Could just JP CPM but this is
ret ;easier when using Z8E debugger
; DMAset - Record the data transfer address for disk operations
$rtn DMAset
ld (DMA),bc
ret
DMA: defw 80h ;(Default at entry to this program)
; 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
call IOaddr ;Set data pointer
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
call IOaddr ;Set data pointer
LD DE,WRKFCB ;POINT TO FCB
LD C,WRITRN ;RANDOM WRITE
CALL CPM ;GO DO IT
RET
; PHYS3 - Test if CP/M Plus and if so then change sector number to
; conform to physical sector size.
$rtn phys3
ld a,(cpm3)
or a
push af ;Save result for caller
jr z,pExit ;No transformation needed for 2.x
ld a,(dpbpsh) ;Pick up physical sector size from DPH
inc a ;Pre-increment for shift loop
pshift:
dec a ;Count down the number of shifts
jr z,pExit ;Exit when done
srl b ;BC := BC/2
sra c
jr pshift ;Around again
pExit:
pop af
ret
; secPnt Build address of 128-byte "logical" sector within psBuff
; On exit, HL holds required address and BC contains the
; value 128 (ready for an LDIR instruction)
$rtn secPnt
ld hl,(psmdsc) ;Get sector number
ld a,(dpbpsm) ;Get physical sector mask
and l ;Calculate which 128-byte chunk
ld hl,psBuff
ld bc,128 ;Chunk size
pOff: ret z ;Exit now if address calculated
add hl,bc ;Otherwise increment pointer
dec a
jr pOff
; PSRD - READ PHYSICAL SECTOR
$RTN PSRD
call IOaddr ;We'll override this later if CP/M 3.x
LD BC,(PSMDTR)
; FOLLOWING LINE ADDED FOR C128
ld (tmptrk),bc ;Temporary save of track #
;
CALL SETTRK ;SELECT TRACK
LD BC,(PSMDSC)
call phys3 ;If CP/M 3.x then change to physical
push bc ;Save sector number during tests
jr z,pRead ;If CP/M 2.x then do the read
ld hl,(prvSec) ;See if same physical sector as last time
sbc hl,bc ;(Carry flag is already clear)
jr nz,pRead ;Do read if different
ld bc,(prvTrk) ;Check track
ld hl,(psmdtr)
sbc hl,bc
jr nz,pRead ;Do read if different
;If we get here then we are running under CP/M+ and we already have the
;correct physical sector in memory. All we have to do is deliver the
;appropriate logical sector to the rest of the program.
pop bc ;Align stack
call secPnt ;Build pointer into psBuff
ld de,(DMA) ;Where to put the data
ldir ;Move 128 bytes
ret
pRead:
pop bc
ld (prvSec),bc ;Record sector ..
LD HL,(PSMDTR)
ld (prvTrk),hl ;.. and track
; 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 $
; FOLLOWING LINE ADDED FOR C128
ld (tmpsec),bc ;Temporary save of sector #
;
CALL SETSEC
ld a,(cpm3) ;If CP/M 3 then ..
or a
jr z,doRead
ld bc,psBuff ;.. use physical sector buffer
call setdma
doRead: CALL READ ;READ SECTOR
push af ;Preserve result
ld a,(cpm3)
or a
jr z,psrdx ;Exit if CP/M 2.2
call IOaddr ;Restore DMA
call secPnt ;Calculate address in psBuff
ld de,(DMA) ;Where to put the data
ldir ;Copy it
psrdx: pop af
RET
; PSWR - WRITE PHYSICAL SECTOR
$RTN PSWR
; FOLLOWING 4 LINES ADDED FOR C128
ld bc,(tmptrk)
call settrk ;Set track to value of previous read
ld bc,(tmpsec)
call setsec ;Set sector to value of previous read
;
ld a,(cpm3) ;Decide which method to use
or a
jr z,pswr2
call secPnt ;Calculate address within psBuff
ex de,hl ;Put destination address into DE
ld hl,(DMA) ;Where to put the data
ldir ;Move the data
ld bc,psBuff ;Set address for data transfer
call setdma
pswr2:
LD C,WRDIR ;USE WRITE DIRECTORY TO FORCE WRITE
CALL WRITE ;WRITE SECTOR
push af ;Save result
call IOaddr ;Restore data address
pop af
RET
WRDIR EQU 1 ;BIOS DIRECTORY WRITE CODE
; FOLLOWING 2 LINES ADDED FOR C128
tmptrk: dw 0 ;Temp. storage for track #
tmpsec: dw 0 ;Temp. storage for sector #
;
prvSec: defw -1
prvTrk: defw -1
;----------------
; 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
; EXVA - JUMP TO ROUTINE AT OFFSET 2*HL FROM DE
$RTN EXVA
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
; USE BIOS CALL TO SUPPORT SYSTEMS WITH SOFTWARE CURSOR
$RTN CHRI
PUSH HL
PUSH DE
PUSH BC
CALL CONIN
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
$strl 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
$strl 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
$strl cpPref ;OUTPUT CURSOR POSITION PREFIX
pop hl
push hl
ld a,(row1st) ;Row or column?
or a
push af ;Save row/column flag
call coord
$strl cpMid ;Output cursor position infix
pop af ;Recover row/column flag
dec a ;Toggle it for 2nd coordinate
POP HL
call coord
$strl cpEnd
POP AF
RET
; coord - outputs a cursor-position coordinate.
; H contains horizontal position
; L contains line number
; Z flag is set if H coord required, reset if L
$rtn coord
jr z,doHor
ld a,(rowOff)
add a,l
jr either
doHor: ld a,(colOff)
add a,h
either: ld e,a
ld a,(cpBin)
or a
jr nz,coBin
call decOut
ret
coBin: ld a,e
call chro
ret
; decOut - Convert 16-bit number in DE to decimal and output to the screen
; Leading zeros are suppressed. Number is treated as unsigned.
$rtn decOut
push hl
push de
push bc
ex de,hl
ld bc,-10 ;Radix
ld de,-1 ;Initialise quotient
dvlp: add hl,bc ;Subtract radix
inc de ;Increment quotient
jr c,dvlp ;(Slow way to divide)
sbc hl,bc ;Correct for extra subtract
ex de,hl
ld a,h
or l ;Test for zero
call nz,decOut ;Recursive call
ld a,'0' ;Convert digit for display
add a,e
call chro ;Write to screen
pop bc ;Restore stack
pop de
pop hl
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
; strl - Output length-prefixed string pointed to by HL
$rtn strl
push bc
ld b,(hl)
inc b
strllp: inc hl
dec b
jr z,strlxt
ld a,(hl)
push hl
call chro
pop hl
jr strllp
strlxt: pop bc
ret
; ASCO - OUTPUT ASCII CHARACTER OR '.' TO SCREEN
;
; Modified Jan 86 by JHB to display ASCII chars with high bit
; set in reverse video. The idea is to make displays of file
; names in directory sectors more readable.
$RTN ASCO
push hl
PUSH AF
bit 7,a ;Check high bit
push af ;Save high bit flag
push af ;Save character during video mode change
call nz,vmInv ;Turn on highlight
pop af ;Recover character for display
and 7Fh ;Mask off high bit
ld hl,maxASC ;Check for graphic
CP (hl)
JR NC,ASCO01
CP 20H
JR NC,ASCO02
ASCO01 EQU $
LD A,'.'
ASCO02 EQU $
CALL CHRO
pop af ;Did we highlight?
call nz,vmNorm ;If so then return to normal video
POP AF
pop hl
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
; Video functions
$rtn vmInv ;Inverse video
ld hl,vInv
jr vmSet
$rtn vmNorm ;Normal video
ld hl,vNorm
vmSet: call strl
ret
; END OF CODE
psBuff equ $ ;Physical sector I/O buffer
ENDCDE equ $+2048
.list ;Enable symbols for Z8E
END INIT