.xlist ;Moved here to keep .PRN file short for Z8E .Z80 TITLE SPZ - CP/M DISK UTILITY ;------------------------------------------------------------------------------ ; ; 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. ; (.. I changed MOST OF THEM TO UPPER -- TO DISTINGUISH ; RECENT ONES I MADE...... PGM. ;------------------------------------------------------------------------------ ; ; Update list (most recent first) ; ; 3.5 15 Sep 86 John T. Coburn ; ; Fixed 2 bugs in the cursor addressing routines when using ANSI ; terminal addressing. Insured that Row1st byte is a zero or one. ; Setup source to default to ANSI terminal cursor addressing. Set ; Peter's additions to the default case. Setup to be assembled by ; most assemblers - the ENTRY pseudoop is conditionalized. ; ; ; 3.4 11-24 Jul 86 Peter G. Martin ; ; Added hex & ascii searches in Edit mode, ; random sector/page/line access in Type mode,(rough) ; Alternative line-end interpretation for Type ; for word-processed ('document') files ; ; ; 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 '5' ;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 -- JHB 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 ANSI terminals) CLSSTR: DB 6,1bh,5Bh,48h,1Bh,5Bh,4Ah,0,0 ;CLEAR SCREEN CLLSTR: DB 3,1Bh,5Bh,4BH,0,0,0,0,0 ;CLEAR LINE vInv: db 4,1Bh,5Bh,37h,6Dh,0,0,0 ;Inverse video vNorm: db 3,1Bh,5Bh,6Dh,0,0,0,0 ;Normal video cpPref: DB 2,1Bh,5Bh,0,0,0,0,0 ;CURSOR POSITION PREFIX cpMid: db 1,3Bh,0,0,0,0,0,0 ;Cursor position infix cpEnd: db 1,48h,0,0,0,0,0,0 ;Cursor position suffix row1st: db 1 ;1=row first, 0=column first rowOff: db 1 ;Offset for row colOff: db 1 ;Offset for column cpBin: db 0 ;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 is set to 0 or 1 ( Odd numbers are 1 ) FLAGCH: DB ' ' ;FLAG CHARACTER IN LIST MODE ; NEW: word processor newline characters for typing of files ; Standard which should be harmless is to have all 'line end' chars ; set to 0DH, which is normally handled by the 'hard-wired' code... ; This means, you may insert UP TO 2 'soft' codes for those line-ends ; used by your word-processor files which ARE NOT NORMALLY FOLLOWED BY ; a LF and 2 'hard' codes for CRs normally followed by LFs such as ; Wordstar's 8D 0A combination. ; PGM 24 July 86 ; DEFAULT FOR ALL FOUR ENTRIES IS 0DH -- SELECT FOR WORD-PROCESSOR YOU USE ; OR LEAVE HARMLESS AS 0DH soft1: db 0dh ; CHANGE AS YOU WOULD OR LEAVE AS 0DH soft2: db 0dh ; for the default - No Action case hard1: db 0dh ; hard2: db 0dh ; SLR_Z80 equ 1 ; Ignore the ENTRY pseudo op ;---------------- MACRO DEFINITIONS ; NB: macro variables prefix of '#' are preferred for Z80MR macro assembler ; --- PGM. ; $RTN - STANDARD ROUTINE ENTRY $RTN MACRO $RTNN IfNDef SLR_Z80 ; Z80ASM doesn't allow in Absolute Mode ENTRY $RTNN EndIf $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 linesc: ds 2 ; line count for type display 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 a,(row1st) ; Insure that Row1st and 1 ; is a 1 or 0 ld (row1st),a 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 ld a,8 ; new display clear -- pgm call CLRL ; " " 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 ; -- under mod 4, july 86, new options added... PGM. 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 16 ;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 05,00,'A Find ASCII string',0 ; new one db 05,22,'H Find HEX sequence',0 ; new one 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 fndpmt: db 08,00,'Find :',$TAB,0 ; new strpos: db 08,08 ; new notfnd: db 08,00,'NOT FOUND - HIT FOR START ',0 ; new fndcon: db 13,64,'NEXT (Y/N) ? ',0 ; new ; FILE STATISTICS FIELDS WRSNFL: DB 12,41,0 WRFOFL: DB 12,55,0 SFSNIP: DB 12,45,0 FDMDLS: db 11,'NPTEZLCSXAH' ; new extra options added ...PGM. FDMDVC EQU $ dw NXFS ;NEXT FILE SECTOR dw PRFS ;PREVIOUS FILE SECTOR dw FRFS ;POSITION TO FIRST FILE SECTOR dw LSFS ;POSITION TO LAST FILE SECTOR dw SETX ;SET EXIT MODE dw SETD ;SELECT DIRECTORY MODE dw FSCH ;FILE SECTOR CHANGE dw SFSN ;SET FILE SECTOR NUMBER dw FSPM ;SCRATCHPAD MANAGER dw fasc ; find ascii string ; new dw fhex ; find hex sequence ; new FDMDSI: DS 1 ;SI REQUEST FLAG ; NXFS - READ NEXT FILE SECTOR ; Maybe it's just my caution or lack of complete comprehension ; of all of the code, but I DO think we could do with a deal ; more of register-preservation in many routines....pgm. $RTN NXFS push de ; new -- save some registers LD HL,(RELREC) INC HL LD (RELREC),HL ;INCREMENT RECORD NUMBER CALL RDFS ;ATTEMPT TO READ RECORD push af ; <= save file status (new) 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 pop af ; new -- return file status in A pop de ; new 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 ; New Section ; pattrn: ds 21 ; 20 bytes ought to be enough ? lasthl: ds 2 ; pointers for last 'lead' byte found lastbc: ds 2 ; prevhl: ds 2 ; pointers to find in earlier sector prevbc: ds 2 ; oerlap: db 0 ; pattrn overlaps buffers flag curch: ds 1 ; byte storage lsflg: ds 1 curct: ds 1 cuhx: ds 1 nib: ds 1 fndmk: db 2,'->' ; FASC -- GET ASCII PATTERN FOR SEARCH, FIND AND DISPLAY IT. $RTN fasc ld a,0ffh ld (ascii),a call asin ; < = prompt, get and check ascii pattrn ; and leave it in pattrn, null terminated. call find ; go find it, display it etc. ret ; FIND -- search for and display with pointers all instances of hex ; or ascii patterns in object file. Prompts for continuation, and ; continues if requested to end of file. Ends on display of end of ; file, last sector accessed, or top of file $RTN find ld a,(afncnt) or a jp z,cpout top equ $ xor a ; clear indicator of sector overlap ld (oerlap),a ld hl,fbuff ld bc,0080h ld (lasthl),hl ld (lastbc),bc ld (prevhl),hl ; storage for when we cross ld (prevhl),bc ; sector boundaries topres equ $ ld a,0ffh ; signal not lone last byte ld (lsflg),a ld hl,(lasthl) ld bc,(lastbc) topccp equ $ ld a,(afncnt) ld (curct),a ld de,pattrn ; get and look for 1st byte ld a,(de) cpir jp po,cplast ; if not overrun ld (lasthl),hl ; save pointers ld (lastbc),bc cprest equ $ ; check tail call DCCT ; next byte -- end of search pattern ? jr z,cpfnd ; yes -- go display find. dec c ; else are we at buffer end jp m,nbbitf ; yes cp (hl) ; no -- continue checking pattrn jr nz,topres ; failed -- restart search inc hl ; otherwise -- next buffer byte jr cprest ; and loop cplast equ $ ; was it a find on last byte jr z,cplfnd ; if not found on last byte call nxfs ; get another sector jp nz,cp99 ; aborting if none available jp top ; or looping if one is cplfnd equ $ ; else ld (lasthl),hl ; save these for screen ld (lastbc),bc call DCCT ; reached end ? jp nz,nbbitf ; if only byte in pattern ld a,c ; and it's at end of buffer ld (lsflg),a ; signal with c=0=lsflg and show it jp cpfnd ; endif nbbitf equ $ ; We found a bit, but reached end of sector ld (curch),a ; save current byte ld a,c ; use BC value as flag to show ld (lsflg),a ; whether found pattrn at very end ld hl,(lasthl) ld (prevhl),hl ld bc,(lastbc) ld (prevbc),bc ; save pointers for progress point ld a,0ffh ld (oerlap),a ; flagging that we have overlapped nbbit0 equ $ call nxfs ; get/check next sector jp nz,cp99 ; reached eof -- exit ld hl,fbuff ; point to start of next sector ld bc,80h ld a,(curch) ; restore byte nbbit1 equ $ cp (hl) jr nz,nbunf ; if found, call DCCT ; keep checking jr z,cpfnd inc hl jr nbbit1 nbunf equ $ ; tried the overlap, but no match.. ld a,(lsflg) ; was it on last byte anyway ? or a ; if so, loop jp z,top ; if not last byte call prfs ; go back a sector xor a ; establish we're back ld (oerlap),a ld hl,(prevhl) ; restore the sector's pointers ld bc,(prevbc) jp topccp ; and continue search on 1st sector cpfnd equ $ ; we found something ld bc,(lastbc) ; well get a pointer anyway ld a,(lsflg) or a jr nz,cpfnd0 ; if last char ld hl,fbuff ; reinitialise ptrs for new buffer ld (lasthl),hl ld bc,80h ld (lastbc),bc ; endif cpfnd0 equ $ ld a,(oerlap) ; was find in overlap? or a jr z,cpfnd2 ; if overlap ld bc,(prevbc) ; replace ptr with earlier one cpfnd1 equ $ call prfs ; and go back to start of find xor a ; remembering to flag that's done ld (oerlap),a cpfnd2 equ $ push bc ; are registers saved ? save bc anyway call DFSI ; show things ld hl,FBUFF call WRBF pop bc ; get back byte ptr ld hl,80h ; calculate equivalent or a ; of bufpos for display sbc hl,bc ld a,l or a jr nz,cpfnd3 ; if zero, it's last byte ld a,80h ; so set up to char in front cpfnd3 equ $ dec a ld (bufpos),a ; use that call slcp ; to update cursor and ld hl,(lpos) ; then fiddle dec h ; to go back a bit more dec h ; to allow room for visual ptr ld (lpos),hl call udcp ; point to that position call vmInv ld hl,fndmk ; and point to the find call strl call vmNorm $fld fndcon ; ask if we want next call chrf ; get answer to next query cp 'Y' push af ; save response call slcp ; reposition on display ld hl,(lpos) dec h ; back again dec h ld (lpos),hl call udcp ; for cursor update and call spco ; clear fndmk call spco pop af ; now check query answer jp nz,cpout ; if next wanted, do it jr nz,cp99 ld a,(lsflg) ; but check first or a ; if on last byte in buffer jp nz,topres ; not ? then loop call nxfs ; last byte? get new sector jp z,topres ; if its there, loop ; else cp99 equ $ ; clear pattrn input line ld hl,fndcon call cfld ld a,8 call CLRL $fld notfnd ; say eof and not found call chrf ; wait, displaying, for any input cp 'T' jr nz,cpout call frfs cpout equ $ ld a,0ffh ld (rpanel),a cpout1 equ $ ld (fdmdsi),a ret ; DDCT - GET NEXT PATTERN BYTE AND CHECK COUNT OF BYTES $RTN DCCT ; get next byte inc de ld a,(de) push hl ; and decrement count ld hl,curct dec (hl) ; did we get to end ? pop hl ret ; ASIN -- GETTING ASCII PATTERN INPUT FOR SEARCH $RTN asin call sstr asin01 equ $ call afnc ; position cursor call chri ; get a char (unfolded) cp CR JR Z,asin99 cp $ESC jr NZ,asin02 xor a ld (pattrn),a jp asin99 asin02 equ $ $MTCH asincd ; if scrn char control key jr nz,asin03 $EXVA asinvc ; do action required JR asin01 ; endif asin03 equ $ cp $TAB jr z,asin04 cp 20h ; else if not other ctrl key jr nc,asin04 call alrm jr asin01 asin04 equ $ call pastr ; output progress ld a,(afnmax) ld hl,afncnt inc (hl) cp (hl) jp nz,asin01 call alrm asin99 equ $ ret asincd: db 3,$LEFT,$RIGHT,$DELETE asinvc: dw afnl dw afnr dw afnd ; PASTR -- STORING BYTES OF PATTERN FOR SEARCH $RTN pastr push af ld hl,(afnchp) ld a,(afncnt) call aahl pop af ld (hl),a push af ld a,(ascii) or a jr z,pastr1 pop af call chro jr pastr2 pastr1 equ $ pop af call hexo pastr2 equ $ ret ; FHEX -- INPUT HEX SEQUENCE AND SEARCH FOR IT. $RTN fhex xor a ld (ascii),a call hxin call find ret ; ; SSTR -- INITIALISING PATTERN FOR SEARCH AND PROMPTING $RTN sstr ; initialise variables xor a ; and prompt for find input ld (afncnt),a ld (pattrn),a $fld fndpmt ld hl,(strpos) ld (afncur),hl ld a,20 ld (afnmax),a ld hl,pattrn ld (afnchp),hl ret ; HXIN -- GETTING INPUT OF HEX BYTE SEQUENCE FOR SEARCH $RTN hxin call sstr ; initialise hxnib1 equ $ xor a ; clear temporary byte hold ld (cuhx),a call hxsc ; position on screen $strl cllstr ; clear line beyond that call hxsc ; reposition call chrf ; get a nibble in $MTCH HEXCHR jr nz,hxino1 ld a,(cuhx) call hxad ld (cuhx),a call pastr ; now save byte and display ld hl,afncnt ; incrementing byte count inc (hl) hxnib2 equ $ call chrf $MTCH HEXCHR jr nz,hxino2 ld a,(cuhx) call hxad ld (cuhx),a ld hl,afncnt ; going back in byte count dec (hl) call hxsc ; to ensure save and screen right call pastr ld a,(afnmax) ; IF after 2 nibbles in, ld hl,afncnt ; we are at maximum byte count cp (hl) ; exit jp z,hxin99 ; ENDIF inc (hl) ; IF NOT jp hxnib1 ; loop for another byte ; ENDIF hxino1 equ $ ; IF NON-HEX CHARS ON 1st nibble, ld a,(inch) ; SWITCH CASE cp CR ; CASE cr input, jr z,hxin99 ; we're done cp $ESC ; CASE esc jp z,hxinX ; exit signalling no valid input cp $LEFT ; CASE left jr nz,hxinw1 ld a,(afncnt) ; IF still the 1st byte of input or a ; just restart //ENDIF jp z,hxnib1 ; ENDIF dec a ; IF not 1st byte,decrement count ld (afncnt),a ; and restart jp hxnib1 ; ENDIF hxinw1 equ $ ; DEFAULT: call alrm ; ring bell jp hxnib1 ; and try agin hxino2 equ $ ; NON-HEX INPUT 2nd nibble ld a,(inch) cp CR jr nz,hxino3 ld hl,afncnt ; decrement count dec (hl) ; before exit, but ... jr nz,hxin99 ; IF it's single 1st nibble inc (hl) ; don't signal no input jr hxin99 ; ENDIF hxino3 equ $ cp $ESC jr z,hxinX cp $LEFT jr nz,hxinw2 xor a ld hl,cuhx ; rotate byte back rrd ld a,(hl) or a ; IF still known relevant data jp nz,hxnib2 ; loop for 2nd nibble ld hl,afncnt ; ELSE reposition dec (hl) ; and loop for whole new byte jp hxnib1 ; ENDIF hxinw2 equ $ ; wrong input call alrm ; ring and loop jp hxnib2 hxinX equ $ ; exit -- cancel search xor a ld (afncnt),a hxin99 equ $ ; just exit ret ; HXSC -- POSITION CURSOR FOR HEX SCREEN INPUT -- EACH BYTE ; SEPARATED WITH SPACES $RTN hxsc push bc push af ld hl,(afncur) ld a,(afncnt) ld b,a add a,a add a,b add a,h ld h,a call curs pop af pop bc ret ; HXAD $RTN hxad ex de,hl ; move value into de ld l,a ; and current byte into L ld h,0 ; rotating and adding call h16d ld a,l ; and getting result in af ret ; End of New Section v.3 mod 4 pgm ; 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 DB 05,54,'M Set directory selection',0 DB 07,00,'E Edit file',0 DB 07,22,'T Type file',0 DRMDLS: DB 15,$LEFT,$RIGHT,$UP,$DOWN,CR,'EZCSMPNTU',$TAB 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 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 ; Second new section --main routine has bits and pieces added...PGM. ; 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 ld (tqued),a ; New -- reset already queued flag ld (linesc+1),a ; and line count ld (tsect),a ; and specific sector flag ld (tline),a ; and specific line flag INC A LD (BASEAD),A ;INITIALISE PAGE NUMBER 1 ld (linesc),a ; new -- line 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 TYPEFN $STRO DRIVNM ; new filename display $fld mxsnum ; and data on max sector $hexw maxrec $FLD PGENUM $HEXW BASEAD ;DISPLAY PAGE NUMBER $FLD RECNUM $HEXW RELREC ;DISPLAY RECORD NUMBER $fld linnum ; new line number display $hexw linesc CALL TYPG ;DISPLAY PAGE ld a,(tqued) ; new -- is data queued? or a ; (this probably should go elsewhere) call z,TYPQ ; if not, queue it xor a ; reinitialise flags ld (tsect),a ld (tline),a $fld recnm2 ; and then end of ranges $hexw relrec ; display range $fld linnm2 $hexw lastln 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 JP TYPE03 ; not relative any more TYPE04 EQU $ ;ENDLOOP TYPE01 EQU $ ;ENDIF LD A,TRUE LD (DRMDLD),A ;REQUEST DIRECTORY LIST RET TYPEPN: DB 11 ; new display and extra options 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 db 03,00,'S Sector to type',0 db 03,22,'G Goto Page No.',0 db 03,50,'W Select line',0 db 04,00,'Enter Selection ==>',0 mxsnum: db 05,50,'Max. Sector ',0 mxout: db 05,62,0 ; posn for max sector PGENUM: DB 6,0,'Page ',0 ; moved down & across RECNUM: DB 6,32,'Sectors ',0 recnm2: db 6,44,'-',0 tyfofl: db 6,44,0 ; input position for 1st sector linnum: db 6,60,'Lines ',0 linnm2: db 6,71,'-',0 loadin: db 4,22,'** LOADING FILE DATA **',0 TYPEFN: DB 5,22,'File : ',0 ; on diff line TYPIP: DB 4,19,0 ;new input position TYPFL: DB 8,0,0 ;FIRST CHR POSITION tcsend: db 6,44,' ',0 tclend db 6,71,' ',0 decs db 10,'0123456789' ; new data for decimal input TYPLST: db 9,'NRLPTZSGW' TYPVEC: DW TYPF DW TYPR DW TYPL DW TYPB DW TYPT DW TYPZ dw typs ; new options dw typp dw tpln TYPEX: DS 1 ;EXIT FLAG TYDSP: DS 1 ;DISPLAY REQUEST TYPEOP: DS 1 ;END OF PAGE target: DS 2 ; sector requested tqued: ds 1 ; queued flag tsect: ds 1 ; flag showing typs called tline: ds 1 ; flag showing tpln called maxrec: ds 2 ; last sector read savba: ds 2 ; temp storage, basead lastln: ds 2 ; 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,8 ADD HL,DE LD (CURPG@),HL ;UPDATE CURRENT POINTER LD A,0FFH LD (TYDSP),A ;REQUEST DISPLAY TYPF02 EQU $ RET ; TYPR - RETURN 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,8 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,8 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 ; alterations include renumbering of labels -- pgm. $RTN typg CALL QPGE ;PUT PAGE ON QUEUE $FLD TYPFL ;POSITION FOR FIRST CHAR ; $STRO TYNPRF ;LEFT MARGIN -- omitted 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 jp NZ,typg99 ; exit if eop (non-rel jump) LD A,(COMFLG) OR A LD A,(TYCURC) JR Z,typg02 ;IF COM FILE push af xor a ld (tsect),a ; not whole sector pop af CALL TPUT ;OUTPUT CHARACTER LD A,(READST) OR A jp NZ,typg99 ; exit if end of file (non-rel now) LD A,(TYPEOP) OR A jp NZ,typg99 ; or end of page CALL TGET ;GET NEXT CHARACTER jp typg12 typg02 EQU $ ;ELSE (NOT A COM FILE) push af ld a,(tsect) or a jr z,typg03 ld hl,(WRKRR) call tinv jr typg04 typg03 EQU $ ld hl,(LINESC) ld a,(tline) or a call nz,tinv typg04 EQU $ pop af CP 009H JR NZ,typg06 ;IF TAB typg05 EQU $ ;REPEAT LD A,' ' CALL TPUT ;PUT SPACE LD A,(PGECOL) AND 7 JR NZ,typg05 ;UNTIL TAB STOP jp typg11 typg06 EQU $ CP CR ; ELSE IF C/R JR Z,typg07 ; GO CHECK FOR TRAILING L/F ld hl,HARD1 cp (hl) ; do same for 'hard's jr z,typg07 ld hl,HARD2 cp (hl) jr z,typg07 ; (just do newline) ld hl,SOFT1 ; now process 'softs' cp (hl) jr z,typg09 ld hl,SOFT2 cp (hl) jr z,typg09 jr typg10 typg07 EQU $ LD A,(READST) OR A JR NZ,typg08 ;IF EOF LD A,(BUFPOS) LD HL,FBUFF CALL AAHL LD A,(HL) CP 00AH push AF ; save result call TYNL ; but do newline anyway pop AF call z,TGET ; and swallow char if L/F there JR typg11 typg08 EQU $ ; eof cr only LD A,CR CALL TPUT ;PUT CHAR JR typg11 typg09 EQU $ ;ELSE CALL TYNL ; newline for softs JR typg11 ;ENDIF typg10 EQU $ ;ELSE CALL TPUT ; just do a NORMAL char output typg11 EQU $ ;ENDIF LD A,(READST) OR A JR NZ,typg99 ;EXIT IF EOF CALL TGET ;GET NEXT CHR typg12 EQU $ jp typg01 ; non-relative jmp, now typg99 EQU $ ;ENDLOOP call vmNorm ; ensure enhancement off eof LD HL,(BASEAD) call BCDU ; do bcd incrementing LD (BASEAD),HL ;INC PAGE NUMBER RET ;ENDIF PGECOL: DS 1 PGELNE: DS 1 TUNPUT: db 0 ; flag for dummy paging ops ; TYNPRF: DB ' ',0 ; <= omitted left margin ; 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,8 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,8 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) ld a,(tqued) ; new -- check if queued or a jr nz,tget04 ; if not queued ld (maxrec),hl ; save last sector tget04 equ $ ; endif call tinv ; switch for enhanced display on/off INC HL LD (RELREC),HL ;SET NEXT SECTOR call tinv ; switch again XOR A tget03 equ $ LD (BUFPOS),A ;BUFFER OFFSET=0 CALL RDFS ;READ SECTOR TGET01 EQU $ ;ENDIF TGET02 EQU $ ;ENDIF LD A,(TYCURC) ;RETURN CHARACTER RET ; TINV -- ENHANCE SECTOR switch routine -- checks if needed. $RTN tinv ld a,(tsect) or a jr nz,tinv1 ld a,(tline) or a jr z,tinv4 tinv1 equ $ push hl push de ; preserve -- in case ld de,(TARGET) sbc hl,de jr NZ,tinv2 call vmInv jr tinv3 tinv2 equ $ call vmNorm tinv3 equ $ pop de ; and restore pop hl tinv4 equ $ ret ; TPUT - TYPE A CHARACTER $RTN TPUT LD B,A LD A,(PGECOL) CP 79 ; changed for 80 cols -- no left margin JR NZ,TPUT01 ; if COL=79 CALL TYNL ; TAKE NEW LINE TPUT01 EQU $ ; endif LD A,(TYPEOP) OR A JR NZ,TPUT02 ;IF NOT EOP ld a,(TUNPUT) ; if unput flagged or a ; then skip screen output jr nz,TPUT03 ; and just count lines LD A,B ; else CALL ASCO ;OUTPUT CHARACTER TPUT03 EQU $ ; endif 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,(LINESC) ; get file line count ld (LASTLN),hl call BCDU ; incremented ld (LINESC),hl call tinv ; switch if we've got to specified line LD HL,PGELNE INC (HL) ;NOW PAGE LINE COUNT UP LD A,16 CP (HL) JR NZ,TYNL01 ;if page line = 16 ld a,(tsect) ; check if page specified and done or a call nz,vmNorm ; switch enhanced off if it is LD A,0FFH LD (TYPEOP),A ;SET END OF PAGE JR TYNL02 TYNL01 EQU $ ;ELSE ld a,(TUNPUT) ; check if just counting lines or a jr nz,TYNL02 LD A,00DH ; if not, output newline CALL CHRO LD A,00AH CALL CHRO ;OUTPUT CRLF ; $STRO TYNPRF ; <= omitted left margin again TYNL02 EQU $ ;ENDIF RET ; all new option ; TYPS -- selecting sector for typing $RTN typs ld a,0ffh ld (tsect),a ; flag specific sector function ld hl,(RELREC) ; save current ld (SAVFSC),hl ld hl,0 ; set to start ld (RELREC),hl typs00 equ $ $fld tcsend ; clear end of range bit $fld recnum ; redisplay sector $hexw relrec call CHRF ; get folded input $MTCH HEXCHR jr nz,typs01 ex de,hl ld hl,(RELREC) call H16D ld (RELREC),hl jr typs05 typs01 equ $ cp $ESC jr nz,typs02 ld hl,(SAVFSC) ld (RELREC),hl jr typs05 typs02 equ $ cp $LEFT jr nz,typs03 ld hl,RELREC+1 xor a rrd dec hl rrd jr typs05 typs03 equ $ cp CR jr nz,typs04 ld hl,(RELREC) ; get sector target ld (TARGET),hl ; and save it for later ld hl,(PGEPTR) ld de,1 ; offset to 1st relrec instance call tloc ; look for and load data jr z,typs99 ; if actual read error xor a ld (INCH),a ; fall thru to alrm typs04 equ $ call ALRM ; endif typs05 equ $ ld a,(INCH) cp CR jr z,typs99 cp $ESC jr NZ,typs00 ; loop bottom typs99 equ $ ld a,0ffh ld (TYDSP),a ret ; New ; TYPQ -- COMPILE QUEUE OF DATA FOR WHOLE FILE typq equ $ ld a,0ffh ld (TUNPUT),a ; set unput flag ld hl,(SAVFSC) ; go back to where we were ld (RELREC),hl call TYPT ; start at top, typq01 equ $ call vmInv $FLD LOADIN call vmNorm call TYPG ; using dummy paging process $fld mxout $hexw maxrec call TYPF ; getting next page ld hl,loadin ; and flashing signal call cfld ld a,(READST) or a jr z,typq01 ; until eof ld hl,(CURPG@) ; insert null terminators ld de,8 add hl,de xor a ld b,e typq02 equ $ ld (hl),a inc hl djnz typq02 typq03 equ $ ld (tunput),a ; reset dummy run flag dec a ; set queued-already flag, ld (tqued),a call TYPT ; and call redisplay of 1st sector ret ; new option ; TYPP -- Select and find screen page within file to display $RTN typp ; select page number to type ld hl,(RELREC) ld (SAVFSC),hl ld hl,(BASEAD) ld (SAVBA),hl ld hl,0 ld (BASEAD),hl typp00 equ $ $fld PGENUM $hexw BASEAD call CHRF $MTCH DECS jr nz,typp01 ld a,l ld hl,(BASEAD) add hl,hl add hl,hl add hl,hl add hl,hl add a,l daa ld l,a ld a,h ld h,0 adc a,h daa ld h,a ld (BASEAD),hl jr typp00 typp01 equ $ cp $ESC jr nz,typp02 ld hl,(SAVFSC) ld (RELREC),hl ld hl,(SAVBA) ld (BASEAD),hl jp typp06 typp02 equ $ cp $LEFT jr nz,typp03 ld hl,BASEAD+1 xor a rrd dec hl rrd jr typp06 typp03 equ $ cp CR jr nz,typp05 ld hl,(BASEAD) ld a,l or h jr nz,typp04 ; if zero page inc a ; make it page 1 ld (BASEAD),a ; endif typp04 equ $ ld hl,(BASEAD) ld (TARGET),hl ld hl,(PGEPTR) ld de,6 ; offset to basead posn call tloc ; call routine to find target ; and test it for range jr z,typp99 ; if read error xor a ; signal ld (INCH),a ; and fall thru alarm typp05 equ $ call ALRM ; endif typp06 equ $ ld a,(INCH) cp CR jr z,typp99 cp $ESC jp nz,typp00 ; loop xor a ld (TYDSP),a typp99 equ $ ld a,0ffh ld (TYDSP),a ret ; 3rd new option under TYPE ; TPNL -- Select and display specified line within file $RTN tpln ld a,0ffh ld (tline),a ld hl,(RELREC) ld (SAVFSC),hl ld hl,(LINESC) ld (SAVBA),hl ld hl,0 ld (LINESC),hl tpln00 equ $ $fld tclend $fld linnum $hexw linesc call CHRF $MTCH DECS jr nz,tpln01 ld a,l ld hl,(LINESC) add hl,hl add hl,hl add hl,hl add hl,hl add a,l daa ld l,a ld a,h ld h,0 adc a,h daa ld h,a ld (LINESC),hl jr tpln00 tpln01 equ $ cp $ESC jr nz,tpln02 ld hl,(SAVFSC) ld (RELREC),hl ld hl,(SAVBA) ld (LINESC),hl jp tpln06 tpln02 equ $ cp $LEFT jr nz,tpln03 ld hl,LINESC+1 xor a rrd dec hl rrd jp tpln06 tpln03 equ $ cp CR jr nz,tpln05 ld hl,(LINESC) ld a,l ; minimum line is 0001 or h jr nz,tpln04 inc a ld (LINESC),a tpln04 equ $ ld hl,(LINESC) ld (TARGET),hl ld hl,(PGEPTR) ld de,4 ; offset to linesc posn call tloc ; call routine to find target ; and test it for range jr z,tpln99 ; if read error xor a ; signal ld (INCH),a ; and fall thru alarm ; to loop for other input tpln05 equ $ call ALRM ; endif tpln06 equ $ ld a,(INCH) cp CR jr z,tpln99 cp $ESC jp nz,tpln00 tpln99 equ $ ld a,0ffh ld (TYDSP),A ret ; Routine to support new options -- sequential search thru queued data ; TLOC -- find place in queue for match ; This REALLY should be a binary search, based on the assumption we ; save the address of the last queued entry, while pgeptr already should ; hold address of first. $RTN tloc ; sequential search in queue push de ; preserve offset to tycurc posn add hl,de ; point to field we want ld bc,8 ; sizeof the queue structure tloc00 equ $ ld de,(TARGET) ; get in what we're looking for push hl ; record where we're at call LDHL ; get the current field xor a sbc hl,de ; check against 'target' jr nc,tloc02 ; if not found yet pop hl ; get back where we're at pop de ; and offset to tycurc push de ; --- saving it again add hl,bc ; move to next queue item push hl ; save its address or a sbc hl,de ld de,06 ; now check its BASEAD value add hl,de ; (we're really hacking here ) call LDHL ; (binary srch WOULD be better) ld a,l ; ANYWAY... BECAUSE THIS IS AN UNTIL, or h ; zero BASEAD means endofq pop hl ; fall thru jr nz,tloc00 ; or loop if more tloc01 equ $ ; search failed pop de push af ; preserve z flag set call typr ; set up end of file parameters call alrm ; say it didn't really work pop af jr tloc99 ; but signal z set -- ok tloc02 equ $ pop hl jr z,tloc03 ; if past it, or a ; go back one sbc hl,bc ; endif tloc03 equ $ pop de or a sbc hl,de ; restore offset to top of entry call LPGE ; signals nz on bad read, z if found tloc99 equ $ ; endif ret ; routine separated -- increments packed BCD data in HL by one $RTN BCDU LD A,1 ADD A,L DAA LD L,A LD A,0 ADC A,H DAA LD H,A ret ; End of second new section v3 mod 4 -PGM. ; 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 ;CURSOR 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 (JHB) 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. ; --- (JHB) 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 ;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 push bc XOR A LD (WRKOV),A 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 TOFCB 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 $ pop bc 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) 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 $ 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 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 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 d,0 ; JTC be sure no extra values in D 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 ;JTC EX DE,HL ld a,d ; JTC or e ;Test for zero CALL NZ,DECOUT ;Recursive call LD A,'0' ;Convert digit for display add a,l ; JTC 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