; ; PROGRAM: DU2 ; AUTHOR: RICHARD CONN ; DERIVATION: DUTIL is derived from DU Version 7.5 ; DU2 is derived from DUTIL Version 1.1 ; VERSION: 1.0 ; DATE: 10 JAN 83 ; PREVIOUS VERSIONS: None ; NOTE: DU2 must be assembled using MAC (or equiv) and will only run on ; a Z80 ; VERS EQU 10 ; ; DU2 is derived from -- ; DU.ASM V7.5 Revised 1/23/81 ; DISK UTILITY - By Ward Christensen ; ; Principal Authors of DU V7.5 are -- ; WLC KBP RGF BRR ; ; Key comments from DU V7.5 and DU2 follow -- ; ;This version of DU is compatible with CP/M 1.4 and 2.x ;and does not require alteration for various hardware ;configurations. It adjusts itself automatically to ;the correct number of sectors, tracks, directory size, ;etc. It has been tested on 5-1/4" and 8" floppy, and ;10 megabyte hard disk systems. ; ;Because of the automatic adaption feature, no conditional ;assembly options are included. The only alteration that ;needs to be done is to use DDT to set the byte at 103h ;to zero for systems using a 2 mHz clock or non-zero for ;4 mHz clock. This only affects the time delay used in ;the 'sleep' command. ; ;For DU2, the additional value of PAGSIZ at 104h should ;be set for the size of the display (in lines) on the user's ;CON: device. Under DU2, all output is paged, and this ;determines the page limit. ; ;************************************************* ;* * ;* This program has been heavily modified * ;* to allow it to work without modification * ;* on most versions of CP/M 1.4 and, hopefully, * ;* all versions of CP/M 2.x. * ;* One known possible problem involves the * ;* system tracks on some systems, and results * ;* from the system sectors being skewed. There * ;* is NO way for a program executing under CP/M * ;* to know about this. This program assumes the * ;* standard convention of no skew being used on * ;: the system tracks. This usually isn't a prob- * ;* lem because the SYSGEN program can be used to * ;* get the system from the disk so that it can * ;* be modified. * ;* This program should work under standard * ;* versions of CP/M 1.4. The only requirement * ;* is that the BIOS "SETSEC" routine not modify * ;* the sector number passed to it in the B * ;* register. Again, system tracks with skewed * ;* sectors will be a problem. * ;* If you add any features or make any useful * ;* changes to this program, please modem a copy * ;* to the above CBBS, so the currency of the * ;* program can be maintained. * ;* * ;* Ron Fowler * ;* * ;************************************************* ; ; The last few revision notes for note are -- ; ; ;System equates ; BASE EQU 0 ;SET TO 4200H FOR HEATH OR TRS-80 ALTCPM ; ;CP/M Key Areas ; FCB EQU BASE+5CH ;CP/M FCB BDOS EQU BASE+5 ;CP/M BDOS ENTRY POINT TBUFF EQU BASE+80H ;CP/M TEMPORARY DISK I/O BUFFER TPA EQU BASE+100H ;CP/M TRANSCIENT PROGRAM AREA ; ; Some Key Variables in DU2 ; EOLCH equ ',' ;Marks logical end of line SEPCH equ ' ' ;Argument Separator MULCH equ '*' ;Multiplication Command ; ;CP/M BDOS Function Codes ; PRINT EQU 9 GVERS EQU 12 RESETDK EQU 13 ;RESET SYSTEM SELDK EQU 14 ;SELECT DISK CLOSEF EQU 16 ;CLOSE FILE SRCHF EQU 17 ;SEARCH FIRST DELF EQU 19 ;DELETE FILE WRITEF EQU 21 ;WRITE BLOCK TO FILE MAKEF EQU 22 ;CREATE FILE SUSER EQU 32 ;SELECT USER GETDSK EQU 25 GETDPB EQU 31 ; ;CP/M 1.4 Offsets and Some Key Values ; TRNOFF EQU 15 ;CP/M 1.4 OFFSET FROM BASE ;OF BDOS TO SECTRAN ROUTINE SKWOFF EQU 1AH ;CP/M 1.4 OFFSET TO SKEW TABLE S2OFF EQU 14 ;OFFSET INTO FCB FOR S2 BYTE DPBOFF EQU 3AH ;CP/M 1.4 OFFSET TO DPB WITHIN BDOS S2MASK EQU 0FH ;MASK FOR EXTENDED RC BITS OF S2 DPBLEN EQU 15 ;SIZE OF CP/M 2.x DISK PARM BLOCK ; ;Define ASCII characters ; CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED TAB EQU 09H ;TAB BS EQU 08H ;BACKSPACE ; ; MACROS TO PROVIDE Z80 EXTENSIONS ; MACROS INCLUDE: ; $-MACRO ;FIRST TURN OFF THE EXPANSIONS ; ; JR - JUMP RELATIVE ; JRC - JUMP RELATIVE IF CARRY ; JRNC - JUMP RELATIVE IF NO CARRY ; JRZ - JUMP RELATIVE IF ZERO ; JRNZ - JUMP RELATIVE IF NO ZERO ; DJNZ - DECREMENT B AND JUMP RELATIVE IF NO ZERO ; LDIR - MOV @HL TO @DE FOR COUNT IN BC ; LXXD - LOAD DOUBLE REG DIRECT ; SXXD - STORE DOUBLE REG DIRECT ; EXX - EXCHANGE BC, DE, HL WITH BC', DE', HL' ; ; ; ; @GENDD MACRO USED FOR CHECKING AND GENERATING ; 8-BIT JUMP RELATIVE DISPLACEMENTS ; @GENDD MACRO ?DD ;;USED FOR CHECKING RANGE OF 8-BIT DISPLACEMENTS IF (?DD GT 7FH) AND (?DD LT 0FF80H) DB 100H ;Displacement Range Error on Jump Relative ELSE DB ?DD ENDIF ;;RANGE ERROR ENDM ; ; ; Z80 MACRO EXTENSIONS ; JR MACRO ?N ;;JUMP RELATIVE DB 18H @GENDD ?N-$-1 ENDM ; JRC MACRO ?N ;;JUMP RELATIVE ON CARRY DB 38H @GENDD ?N-$-1 ENDM ; JRNC MACRO ?N ;;JUMP RELATIVE ON NO CARRY DB 30H @GENDD ?N-$-1 ENDM ; JRZ MACRO ?N ;;JUMP RELATIVE ON ZERO DB 28H @GENDD ?N-$-1 ENDM ; JRNZ MACRO ?N ;;JUMP RELATIVE ON NO ZERO DB 20H @GENDD ?N-$-1 ENDM ; DJNZ MACRO ?N ;;DECREMENT B AND JUMP RELATIVE ON NO ZERO DB 10H @GENDD ?N-$-1 ENDM ; LDIR MACRO ;;LDIR DB 0EDH,0B0H ENDM ; LDED MACRO ?N ;;LOAD DE DIRECT DB 0EDH,05BH DW ?N ENDM ; LBCD MACRO ?N ;;LOAD BC DIRECT DB 0EDH,4BH DW ?N ENDM ; SDED MACRO ?N ;;STORE DE DIRECT DB 0EDH,53H DW ?N ENDM ; SBCD MACRO ?N ;;STORE BC DIRECT DB 0EDH,43H DW ?N ENDM ; EXX MACRO ;;EXCHANGE PRIMARY AND ALTERNATE REGISTERS DB 0D9H ENDM ; ; END OF Z80 MACRO EXTENSIONS ; ; ;Beginning of Program ; ORG TPA jmp start ; ;****************************************************************** ; ; SINSFORM -- ZCPR2 Utility Standard General Purpose Initialization Format ; ; This data block precisely defines the data format for ; initial features of a ZCPR2 system which are required for proper ; initialization of the ZCPR2-Specific Routines in SYSLIB. ; ; ; EXTERNAL PATH DATA ; EPAVAIL: DB 0FFH ; IS EXTERNAL PATH AVAILABLE? (0=NO, 0FFH=YES) EPADR: DW 40H ; ADDRESS OF EXTERNAL PATH IF AVAILABLE ; ; INTERNAL PATH DATA ; INTPATH: DB 0,0 ; DISK, USER FOR FIRST PATH ELEMENT ; DISK = 1 FOR A, '$' FOR CURRENT ; USER = NUMBER, '$' FOR CURRENT DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 ; DISK, USER FOR 8TH PATH ELEMENT DB 0 ; END OF PATH ; ; MULTIPLE COMMAND LINE BUFFER DATA ; MCAVAIL: DB 0FFH ; IS MULTIPLE COMMAND LINE BUFFER AVAILABLE? MCADR: DW 0FF00H ; ADDRESS OF MULTIPLE COMMAND LINE BUFFER IF AVAILABLE ; ; DISK/USER LIMITS ; MDISK: DB 4 ; MAXIMUM NUMBER OF DISKS MUSER: DB 31 ; MAXIMUM USER NUMBER ; ; FLAGS TO PERMIT LOG IN FOR DIFFERENT USER AREA OR DISK ; ;DOK: DB 0FFH ; ALLOW DISK CHANGE? (0=NO, 0FFH=YES) ;UOK: DB 0FFH ; ALLOW USER CHANGE? (0=NO, 0FFH=YES) ; ; PRIVILEGED USER DATA ; PUSER: DB 10 ; BEGINNING OF PRIVILEGED USER AREAS PPASS: DB 'chdir',0 ; PASSWORD FOR MOVING INTO PRIV USER AREAS DS 41-($-PPASS) ; 40 CHARS MAX IN BUFFER + 1 for ending NULL ; ; CURRENT USER/DISK INDICATOR ; CINDIC: DB '$' ; USUAL VALUE (FOR PATH EXPRESSIONS) ; ; DMA ADDRESS FOR DISK TRANSFERS ; DMADR: DW 80H ; TBUFF AREA ; ; NAMED DIRECTORY INFORMATION ; NDRADR: DW 00000H ; ADDRESS OF MEMORY-RESIDENT NAMED DIRECTORY NDNAMES: DB 64 ; MAX NUMBER OF DIRECTORY NAMES DNFILE: DB 'NAMES ' ; NAME OF DISK NAME FILE DB 'DIR' ; TYPE OF DISK NAME FILE ; ; REQUIREMENTS FLAGS ; EPREQD: DB 000H ; EXTERNAL PATH? MCREQD: DB 000H ; MULTIPLE COMMAND LINE? MXREQD: DB 0FFH ; MAX USER/DISK? UDREQD: DB 000H ; ALLOW USER/DISK CHANGE? PUREQD: DB 000H ; PRIVILEGED USER? CDREQD: DB 000H ; CURRENT INDIC AND DMA? NDREQD: DB 000H ; NAMED DIRECTORIES? Z2CLASS: DB 6 ; CLASS 6 DB 'ZCPR2' DS 10 ; RESERVED ; ; END OF SINSFORM -- STANDARD DEFAULT PARAMETER DATA ; ;****************************************************************** ; ; ; Extra Buffers et al ; CLOCK: DB 2 ;<---Put Processor Speed Here (1=1MHZ, 2=2MHZ, etc) PAGSIZ: DB 24 ;<---Put CRT Screen Size Here (24 Lines default) DB 'DU2.COM from DU.COM ver 7.5 1/23/81 by RLC' ; ; Start of Program ; START: LXI H,0 ;GET PTR TO CP/M STACK DAD SP ;HL=SP SHLD DUTSTK ;SAVE IT ; LXI SP,DUTSTK ; SET STACK ; MVI C,GVERS ;GET CP/M VERSION NR CALL BDOS MOV A,H ;MUST NOT BE VERSION 1.4 ORA L JRNZ START1 CALL ILPRT DB CR,LF,'DU2 cannot run on CP/M Version 1.4 -- Aborting',0 JMP EXIT1 ; ;Set up local jumps to BIOS ; START1: LHLD BASE+1 ;WARM BOOT POINTER LXI D,3 ;READY FOR ADD DAD D SHLD VCONST+1 ;CON: Status DAD D SHLD VCONIN+1 ;CON: Input DAD D SHLD VCONOT+1 ;CON: Output DAD D SHLD VLIST+1 ;LST: Output DAD D ;Skip PUNCH DAD D ;Skip RDR DAD D SHLD VHOME+1 ;Home Disk DAD D SHLD VSELDK+1 ;Select Disk DAD D SHLD VSETRK+1 ;Set Track DAD D SHLD VSTSEC+1 ;Set Sector DAD D SHLD SETDMA+1 ;Set DMA Address DAD D SHLD VREAD+1 ;Read Block From Disk DAD D SHLD VWRITE+1 ;Write Block To Disk DAD D ;Skip LISTST DAD D SHLD VSCTRN+1 ;CP/M 2.x Sector Translation Table JR HELLO ; ;Initialization Complete -- Print Signon Message and Begin Command Processing ; HELLO: CALL GETSTP ;SET UP CP/M PARAMETERS CALL INITP ;INITIALIZE BUFFER PARAMETERS CALL ILPRT DB CR,LF,'DU2 - Disk Utility II, Version ' DB VERS/10+'0','.',(VERS MOD 10)+'0' DB CR,LF DB 'Type ? for Help' DB CR,LF,0 LXI H,TBUFF ;TO INPUT BUFF MOV A,M ORA A JRZ PRMPTR ;NO INITIAL COMMAND FROM COMMAND LINE ; ;Got initial command, set it up ; MOV B,A ;SAVE LENGTH DCR B ;JUST A SPACE? JRZ PRMPTR ;GOTO COMMAND PROCESSOR IF SO LXI D,INBUF ;PT TO INLINE BUFFER INX H ;SKIP LEN INX H ;SKIP ' ' MOV A,M ;GET FIRST CHAR CPI '/' ;IF SLASH, PRINT INITIAL HELP (TOOLSET CONVENTION) JZ IHELP ;PRINT INITIAL HELP INFO CALL MOVE ;COPY INPUT LINE INTO INLINE BUFFER MVI A,CR ;STORE ENDING STAX D LXI H,INBUF ;PT TO FIRST BYTE OF INLINE BUFFER JR PRMPTI ;PROCESS AS THOUGH IT WAS TYPED ; ;Input Command Line From User at Console ; PRMPTR: XRA A ;A=0 STA IHFLG ;Set No Initial Help CALL SINBUF ;Save old INBUF into PINBUF CALL RDBUF ;Read Input Line CALL EXMAC ;Expand Macros ; ;Begin Processing Command Line in INBUF ; At this point, HL points to next character to process ; PRMPTI: MVI A,0FFH ;SET INFINITE LOOP COUNT STA TOGO ;LOOP COUNT FOR MULTIPLE LOOPS STA TOGO+1 ; ;Minor Command Loop; This is the entry point for each individual command in ; a Command Line; Commands may be separated by semicolons in this manner ; PROMPT EQU $ SETSTK: LXI SP,DUTSTK ;RESET STACK XRA A ;ZERO 2-UP PRINT FOR DUAL-COLUMN PRINT STA TWOUP ;..SWITCH MVI A,1 STA FTSW ;TELL SEARCH NOT TO INCR PUSH H LXI H,TBUFF ;SET NO-READ INPUT BUFFER ADDRESS SHLD BUFAD ;FOR RDBYTE POP H CALL CTLCS ;ABORT? JRZ PRMPTR ;..YES, READ BUFFER ; ;Do we have to position in directory after find? ; LDA FINDFL ORA A JNZ POSDIR ;POSITION IN DIRECTORY ; ;Begin Command Evaluation -- Check for EOL and Capitalize ; MOV A,M ;GET NEXT CHAR IN COMMAND LINE INX H ;POINT TO FOLLOWING CHAR CPI CR ;END OF LINE PHYSICALLY? JRZ PRMPTR ;INPUT NEW COMMAND LINE IF SO CPI EOLCH ;END OF LINE LOGICALLY? JRZ PROMPT ;PROCESS NEXT ELEMENT IF SO CALL UPCASE ;CAPITALIZE COMMAND STA DUMTYP ;TYPE OF DUMP (A,D,H) ; ;Command dispatcher ; If command not found, abort with error message ; If command file, process command with HL pting to next command char and ; A containing command letter ; PUSH H ;SAVE HL MOV B,A ;COMMAND IN B LXI H,CMDTBL ;SCAN COMMAND TABLE FOR USER COMMAND CMDLP: MOV A,M ;GET COMMAND ORA A ;0=END OF TABLE JZ WHAT CMP B ;COMPARE COMMAND JRZ CMDGO INX H ;PT TO ADR INX H INX H ;PT TO NEXT CMND JR CMDLP CMDGO: INX H ;PT TO ADDRESS LOW MOV E,M INX H ;PT TO ADDRESS HIGH MOV D,M MOV A,B ;COMMAND BACK INTO A POP H ;RESTORE HL PUSH D ;PLACE ADDRESS ON STACK RET ;"RUN COMMAND" ; ;Macro Expansion Routine -- Expand Macros ; EXMAC: LXI H,INBUF ;PT TO INPUT LINE LXI D,CTEMP ;BUILD INTO TEMPORARY BUFFER EXMAC1: MOV A,M ;GET CHAR CPI '0' ;SKIP IF LESS THAN '0' JRC EXMAC2 CPI '9'+1 ;CHECK FOR RANGE JRNC EXMAC2 INX H ;PT TO NEXT CHAR PUSH H ;SAVE PTR TO NEXT CHAR IN LINE SUI '0' ;CONVERT TO BINARY (0-9) MOV B,A ;RESULT IN B MVI C,0 LXI H,MTABL ;PT TO BASE OF MACROS DAD B ;PT TO MACRO CALL COPYM ;COPY MACRO INTO LINE DCX D ;BACK UP OVER POP H ;GET PTR TO NEXT CHAR IN COMMAND LINE EXMAC2: MOV A,M ;GET CHAR STAX D ;PUT CHAR INX H ;PT TO NEXT INX D CALL MTEST ;TEST FOR END OF BUFFER CPI CR ;DONE? JRZ EXMAC3 CPI EOLCH ;LOGICAL EOL? JRNZ EXMAC2 JR EXMAC1 ;PROCESS NEXT COMMAND EXMAC3: LXI H,CTEMP ;COPY COMMAND LINE BACK LXI D,INBUF ;INTO INBUF CALL COPYCR ;COPY TO LXI H,INBUF ;PT TO INBUF RET ;EXPANSION COMPLETE ; ;Copy Macro Into Command Line Buffer ; COPYM: MOV A,M ;GET CHAR STAX D ;PUT CHAR INX H ;PT TO NEXT INX D CALL MTEST ;CHECK FOR LIMIT CPI CR ;END OF MACRO? JRNZ COPYM RET ; ;Test for Buffer Full ; MTEST: PUSH H ;SAVE HL PUSH PSW ;SAVE A LXI H,CTEMPX ;CHECK FOR END OF BUFFER MOV A,H ;GET PAGE CMP D ;CHECK PAGE JRZ MACERR POP PSW ;GET A POP H ;GET HL RET ; ;Macro Command Expansion Error ; MACERR: CALL ILPRT DB CR,LF,'Error -- Macro Expanded Command Line too Long',0 JMP PRMPTR ;NEW COMMAND ; ;Save INBUF into PINBUF for later processing by '@' command ; SINBUF: LXI H,INBUF ;PT TO INBUF LXI D,PINBUF ;PT TO PINBUF (PREVIOUS INBUF) ; ;Copy (HL) to (DE) until Encountered ; COPYCR: MOV A,M ;GET CHAR STAX D ;PUT CHAR INX H ;PT TO NEXT INX D CPI CR ;DONE? JRNZ COPYCR RET ; ;Command Not Found Error ; WHAT: POP H ; RESTORE HL CALL ILPRT DB 'Invalid Command at or after ',0 MOV A,B ;GET COMMAND LETTER CALL TYPE ;PRINT IT JMP PRMPTR ; ;Memory full error ; MEMFUL: CALL ILPRT DB '+++ Out of memory +++' DB CR,LF,0 JMP PRMPTR ; ;COMMAND: @ ;Repeat Previous Command Line ; PCMD: MOV A,M ;GET NEXT CHAR CPI CR ;SHOULD BE JRZ PCMD1 CALL ILPRT DB CR,LF,'Warning: Remainder of Command Line after "@" Deleted',0 PCMD1: CALL ILPRT DB CR,LF,'Command --',CR,LF,0 LXI H,PINBUF ;GET PREVIOUS COMMAND LXI D,INBUF ;COPY INTO INBUF PCMD2: MOV A,M ;GET CHAR STAX D ;PUT CHAR INX H ;PT TO NEXT INX D CPI CR ;END OF LINE? PUSH PSW ;SAVE FLAG CALL TYPE ;PRINT CHAR POP PSW ;GET FLAG JRNZ PCMD2 MVI A,LF ; CALL TYPE LXI H,INBUF ;RESTART COMMAND PROCESSING JMP PRMPTI ;INCLUDE LOOP CAPABILITY ; ;COMMAND: : ;Define or Print Macro ;:n Defines Macro n, 0<=n<=9; ::n Prints Macro n, 0<=n<=9 ; MAC: MOV A,M ;GET NEXT CHAR CALL UPCASE ;CAPITALIZE CPI 'P' ;PRINT MACRO? JNZ MACROD ;IF NOT, DEFINE MACRO INX H ;PT TO MACRO NUMBER MOV A,M ;GET IT CALL UPCASE ;CAPITALIZE CPI '@' ;PRINT PREVIOUS COMMAND? JRZ PCPR PUSH PSW ;SAVE A CALL ILPRT DB 'Macro Definitions --',0 POP PSW ;GET A CPI 'A' ;PRINT ALL MACROS? JRZ AMACPR CALL MNUM ;CHECK FOR VALID NUMBER AND RETURN # IN D INX H ;PT TO CHAR AFTER MACRO NUMBER CALL MACPR ;PRINT MACRO WHOSE NUMBER IS IN D JMP PROMPT ; ;Print Previous Command ; PCPR: INX H ;PT TO CHAR AFTER '@' LXI D,PROMPT ;SET UP RET ADR PUSH D ;RETURN ADR ON STACK PUSH H ;SAVE PTR CALL ILPRT DB 'Previous Command Line Definition --' DB CR,LF,'@: ',0 LXI H,PINBUF ;PT TO PREVIOUS COMMAND JMP MPRINT ;USE MACRO PRINT FACILITY ; ;Print All Macros ; AMACPR: INX H ;PT TO CHAR AFTER 'A' MVI D,0 ;SET FOR FIRST MACRO AMPRL: CALL MACPR ;PRINT MACRO WHOSE NUMBER IS IN D INR D ;INCREMENT MACRO NUMBER MOV A,D ;GET VALUE CPI 10 ;DONE? JRNZ AMPRL JMP PROMPT ;CONTINUE PROCESSING ; ;Print Macro Whose Number (0-9) is in D ; MACPR: PUSH H ;SAVE PTR CALL ILPRT ;PRINT HEADER DB CR,LF,0 MOV A,D ;GET NUMBER ADI '0' ;CONVERT TO ASCII CALL TYPE ;PRINT CALL ILPRT DB ': ',0 LXI H,MTABL ;PT TO TABLE OF MACROS MVI E,0 ;PAGE OFFSET OF ZERO; MACRO NUMBER ALREADY IN D DAD D ;PT TO MACRO MPRINT: MOV A,M ;GET CHAR INX H ;PT TO NEXT CPI CR ;END OF MACRO? PUSH PSW ;SAVE FLAG CALL TYPE ;PRINT CHAR POP PSW ;GET FLAG JRNZ MPRINT MVI A,LF ; CALL TYPE POP H ;GET PTR TO NEXT CHAR RET ; ;Check char in A for valid Macro Number (0-9), print error message if ; not, return number in D if so ; MNUM: SUI '0' ;CONVERT TO 0-9 JRC MNERR ;ERROR IF LESS CPI 10 ;RANGE? JRNC MNERR MOV D,A ;RESULT IN D RET MNERR: CALL ILPRT DB CR,LF,'Invalid Macro Number Specified in Command',0 JMP PRMPTR ;NEW COMMAND ; ;Define Macro ; MACROD: CALL MNUM ;CHECK NUMBER AND RETURN IN D INX H ;PT TO CHAR AFTER MACRO NUMBER PUSH H ;SAVE PTR LXI H,MTABL ;PT TO MACRO TABLE MVI E,0 ;SET EVEN PAGE DAD D ;PT TO MACRO ENTRY IN HL XCHG ;... IN DE POP H ;PT TO MACRO TEXT CALL COPYCR ;COPY TO JMP PRMPTR ;NEW COMMAND ; ;COMMAND: ! ;Delay for user input ; UWAIT: CALL WAIT ; USE WAIT ROUTINE JMP PROMPT ; ;COMMAND: # ;Print disk statistics ; STATS: PUSH H ;SAVE POINTER TO NEXT COMMAND CALL ILPRT DB '+=============================+',CR,LF DB '| -- Queue Information -- |',CR,LF DB '+-----------------------------+',CR,LF DB 0 CALL QSTATS ;PRINT STATUS INFO CALL ILPRT DB CR,LF,CR,LF DB '+=============================+',CR,LF DB '| -- Disk Information -- |',CR,LF DB '+-----------------------------+',CR,LF DB CR,LF,'Disk Drive: ',0 LDA DRIVE ADI 'A' ;CONVERT TO ASCII CALL TYPE ;PRINT DRIVE LETTER CALL ILPRT DB CR,LF,'Tracks: ',0 LHLD MAXTRK ;PRINT NUMBER OF TRACKS INX H CALL DEC CALL ILPRT DB CR,LF,'Sectors/Track: ',0 LHLD SPT ;PRINT NUMBER OF SECTORS/TRACK CALL DEC CALL ILPRT DB CR,LF,'Group Size: ',0 LDA BLM ;PRINT SIZE OF A GROUP INR A MOV L,A MVI H,0 CALL DEC CALL ILPRT DB ' Blocks/Group' DB CR,LF,'Total Groups: ',0 LHLD DSM ;PRINT TOTAL NUMBER OF GROUPS ON A DISK CALL DEC CALL ILPRT DB CR,LF,'Directory Entries: ',0 LHLD DRM ;PRINT NUMBER OF DIRECTORY ENTRIES INX H CALL DEC CALL ILPRT DB CR,LF,'System Tracks: ',0 LHLD SYSTRK ;PRINT NUMBER OF SYSTEM TRACKS CALL DEC CALL ILPRT DB CR,LF DB '===============================',CR,LF,0 POP H ;RESTORE POINTER TO NEXT COMMAND JMP PROMPT ; ;COMMAND: N ;The following command resets the disk ;system thru CP/M, and may be usable for ;changing the disk density or format. ;This can only be done if your BIOS resets ;the auto-density select parameters at ;every track-zero access. ; NEWDSK: PUSH H ;SAVE POINTER TO NEXT LETTER MVI C,RESETDK ;BDOS RESET DISK FUNCTION CALL BDOS LDA DRIVE ;RESELECT CURRENT DRIVE MOV C,A POP H CALL SELECT JMP PROMPT ; ;COMMAND: Q ;Queue Control ; QUEUER: MOV A,M ;GET 2ND ARGUMENT CALL UPCASE ;CAPITALIZE CPI EOLCH ;END OF LINE? JRZ QSTAT ;STATUS REPORT CPI CR ;END OF LINE? JRZ QSTAT INX H ;PT TO AFTER KEY CHAR PUSH H ;SAVE PTR CPI 'Z' ;ZERO QUEUE? JRZ QZERO CPI 'S' ;SAVE QUEUE? JZ QFSAVE POP H ;GET PTR CALL ILPRT DB 'Invalid Queue Command',CR,LF,0 JMP PRMPTR ;ABORT LINE ON ERROR ; ; Zero the Queue ; QZERO: LXI H,DIRECT ;ZERO QUEUE SHLD QNXT ;SET NEXT SHLD QLST ;SET LAST LXI H,0 ;ZERO COUNT SHLD QCNT POP H ;GET PTR AND FALL THRU TO QSTAT ; ; Print Status of Queue ; QSTAT: PUSH H ;SAVE PTR TO NEXT CHAR CALL ILPRT DB '** Queue Status Summary **',CR,LF,0 CALL QSTATS ;PRINT STATUS POP H ;RESTORE PTR JMP PROMPT QSTATS: LHLD QCNT ;GET SIZE OF QUEUE CALL PRQCNT ;PRINT DATA CALL PRQSPAC ;PRINT SPACE AVAILABLE INFO CALL ILPRT DB 'Address of Head of Queue: ',0 LHLD QNXT ;PRINT ADDRESS OF HEAD OF QUEUE MOV B,H ;... ADDRESS IN BC MOV C,L CALL HEXB ;PRINT IN HEX CALL ILPRT DB ' Hex',CR,LF DB 'Address of Tail of Queue: ',0 LHLD QLST ;PRINT ADDRESS OF TAIL OF QUEUE MOV B,H MOV C,L CALL HEXB CALL ILPRT DB ' Hex',CR,LF,0 RET ; ; Print Amount of Space Left in Queue ; PRQSPAC: LXI B,-1 ;SET COUNT LHLD QLST ;GET PTR TO QUEUE TAIL QSTAT1: INX B ;INCREMENT COUNT LXI D,80H ;PT TO NEXT QUEUE ELEMENT DAD D XCHG ;WRAP AROUND CALL QWRAP LHLD QNXT ;GET PTR TO FIRST ELEMENT XCHG MOV A,H ;COMPARE CMP D JRNZ QSTAT1 MOV A,L CMP E JRNZ QSTAT1 MOV H,B ;HL=BLOCK COUNT MOV L,C CALL DEC ;PRINT AS DECIMAL CALL ILPRT DB ' Blocks Left in Queue',CR,LF,0 RET ; ; Save Queue as a File ; QFSAVE: MOV A,M ;GET FIRST CHAR OF FILE NAME CPI EOLCH ;EOL? JZ WHAT CPI CR ;EOL? JZ WHAT LXI D,FCB ;START TO FILL FCB XRA A ;A=0 STAX D ;SELECT DEFAULT DRIVE INX D ;PT TO FILE NAME MVI B,8 ;SAVE FILE NAME CALL MVNAME MVI B,3 ;SAVE FILE TYPE CALL MVNAME PUSH H ;SAVE PTR TO NEXT CHAR LHLD QCNT ;ANY ELEMENTS IN QUEUE? MOV A,H ORA L JZ QEMPTY PUSH H ;SAVE QUEUE COUNT CALL NORITE ;CAN'T WRITE NOW LXI D,FCB ;PT TO FCB CALL FCBINIT ;INIT FCB MVI C,DELF ;DELETE FILE PUSH D ;SAVE DE CALL BDOS POP D CALL FCBINIT ;INIT FCB AGAIN MVI C,MAKEF ;CREATE FILE CALL BDOS POP B ;GET QUEUE COUNT IN BC LHLD QNXT ;PT TO NEXT BLOCK IN QUEUE QFS1: PUSH B ;SAVE COUNT LXI D,TBUFF ;COPY INTO TBUFF MVI B,128 ;128 BYTES CALL MOVE XCHG ;PT TO NEXT QUEUE BLOCK IN DE CALL QWRAP ;WRAP AROUND PUSH D ;SAVE PTRS LXI D,FCB ;PT TO FCB MVI C,WRITEF ;WRITE BLOCK TO FILE CALL BDOS POP H ;GET PTR TO NEXT BLOCK POP B ;GET COUNT DCX B ;COUNT DOWN MOV A,B ;DONE? ORA C JRNZ QFS1 LXI D,FCB ;CLOSE FILE MVI C,CLOSEF CALL BDOS CALL ILPRT DB 'Queue Saved in File',CR,LF,0 POP H ;PT TO NEXT CHAR JMP PROMPT FCBINIT: PUSH D ;SAVE PTR LXI H,12 ;SKIP TO EX FIELD DAD D MVI B,24 ;ZERO 36 BYTES XRA A ;A=0 FCBIN1: MOV M,A ;STORE ZEROES INX H DJNZ FCBIN1 POP D ;RESTORE PTR RET ; ;COMMAND: * ;Repeat buffer contents ; REPEAT: CALL DECIN ;NN SPECIFIED? MOV A,D ORA E JRZ NNN ;NO -- SET FOR INFINITE LOOP OR SIMPLE REPEAT LHLD TOGO ;LOAD LOOP FLAG INX H ;TEST FOR FIRST TIME MOV A,H ORA L ;WAS IT 0FFFFH?; IF SO, WE HAVE NEW VALUE JRNZ NNN ;NO: COUNTING XCHG ;GET COUNT SHLD TOGO ;SET COUNT ; NNN: LHLD TOGO ;GET CURRENT COUNT XCHG ;DE=CURRENT COUNT, HL=COUNT LIMIT LXI H,INBUF ;PT TO FIRST CHAR FOR REPEAT INX D ;TEST FOR 0FFFFH MOV A,D ;IF 0FFFFH, INX D MADE DE=0 ORA E JZ PROMPT ;CONTINOUS LOOP IF 0FFFFH DCX D ;COUNT DOWN DCX D ;MAKE UP FOR PREV INX D XCHG SHLD TOGO ;SET NEW COUNT (1 LESS THAN BEFORE) MOV A,H ;ALL DONE? ORA L XCHG ;GET BACK INBUF PTR IN HL JNZ PROMPT ;KEEP GOING IF NOT YET ZERO JMP PRMPTR ;ALL DONE ; ;COMMAND: U ;Set CP/M 2.x user number ; USER: CALL DECIN ;GET REQUESTED USER NO. LDA MUSER ;GET MAX USER MOV B,A ;... IN B MOV A,E CMP B ;VALID? JNC USRERR MOV A,D ;HIGH-ORDER BYTE MUST BE ZERO FOR VALID NUMBER ORA A JNZ USRERR MOV A,E ;SAVE USER NUMBER STA UNUM MVI C,SUSER ;SET USER NUMBER PUSH H ;SAVE CHAR POINTER CALL BDOS ;SET USER NO. POP H JMP PROMPT USRERR: CALL ILPRT DB 'User Number Out of Range',CR,LF,0 JMP PRMPTR ; ;COMMAND: P ;Toggle print flag ; PRNTFF: LDA PFLAG ;TOGGLE PRINT FLAG XRI 1 STA PFLAG JMP PROMPT ; ;COMMAND: Z ;Sleep routine, in seconds ; SLEEP: CALL DECIN ;GET COUNT IF ANY MOV A,E ;ANY? ORA A JRNZ SLEPLP MVI E,1 ; 1 SEC DEFAULT ; SLEPLP: LDA CLOCK ; GET CLOCK SPEED MOV D,A ; SLEEP1: LXI B,41700 ; APPROX 1 SEC @ 1MHz ; SLEEP2: DCX B ;COUNT DOWN FOR 1 MHz [5 CYCLES] MOV A,B ;[5 CYCLES] <-- TOTAL TIME: 24 CYCLES ORA C ;[4 CYCLES] <-- (24 MU-SECS AT 1MHz) JNZ SLEEP2 ;[10 CYCLES] PUSH D CALL CTLCS ;ABORT? POP D JZ PRMPTR DCR D ;COUNT DOWN FOR CLOCK SPEED JNZ SLEEP1 DCR E ;COUNT DOWN NUMBER OF REQUESTED SECONDS JNZ SLEPLP JMP PROMPT ; ;Check for control-C or S ; CTLCS: CALL CONST ;CHAR AVAILABLE? ORA A JRNZ GETC ORI 1 ;NO CHAR, RETURN NZ RET ; GETC: CALL CONIN ;INPUT CHAR ANI 1FH ;ALLOW ASCII CPI 'S'-40H ;WAIT FOR NEXT CHAR IF ^S OR S OR s CZ CONIN CPI 'C'-40H ;CHECK FOR ^C OR C OR c RET ;0 SET IF CTL-C ; ;Initialize Memory Buffers ; INITP: XRA A ;A=0 STA HEXAD ;CLEAR ADDRESS STA HEXAD+1 STA PFLAG ;SET NO PRINT STA SAVEFL ;SET NO SAVE DONE STA WRFLG ;MAY NOT WRITE STA DIRPOS ;SET NO DIRECTORY POSITION STA FINDFL ;SET NO POSITION INR A ;A=1 STA FTSW ;SET SEARCH WITHOUT INCREMENT STA NOTPOS ;NOT POSITIONED LXI H,0 ;HL=0 SHLD QCNT ;SET NO ELEMENTS IN QUEUE SHLD MFPTR ;SET NO MULTI FILE PTR SHLD CURTRK ;SET TRACK 0 INX H ;HL=1 SHLD CURSEC ;SET LOGICAL SECTOR 1 SHLD PHYSEC ;SET PHYSICAL SECTOR 1 MVI A,CR ;CLEAR PREVIOUS COMMAND STA PINBUF ;SET PREVIOUS COMMAND TO NIL LXI H,DIRECT ;SET FIRST AND LAST QUEUE ELEMENT PTRS SHLD QNXT SHLD QLST LXI H,MTABL ;CLEAR MACRO TABLE MVI B,10 ;10 ENTRIES INITP1: MVI M,CR ;STORE INR H ;PT TO NEXT PAGE DJNZ INITP1 RET ; ;Set up flags, etc, at initialization ;Find our way at initialization ; GETSTP: MVI A,CR ;INITIALIZE INPUT BUFFER STA INBUF ;EMPTY BUFFER MVI C,SUSER ;GET USER NUMBER MVI E,0FFH ;GET USER CALL BDOS STA UNUM ;SET USER NUMBER MVI C,GETDSK CALL BDOS ;GET CURRENT DISK MOV C,A ;WE HAVE TO SELECT JMP SELECT ;TO GET THE DPH ; ;COMMAND: L ;Log in the selected disk ; LOGIN: CALL DOLOG JMP PROMPT ; DOLOG: MOV A,M ;DISK REQUESTED? LXI D,0 CPI CR ;NO REQUEST OF PHYSICAL EOL JRZ LGNODK CPI EOLCH ;NO REQUEST IF LOGICAL EOL JRZ LGNODK CALL UPCASE ;CAPITALIZE INX H ;POINT TO NEXT CHAR SUI 'A' ;CONVERT TO 0-15 MOV C,A ;DISK NUMBER IN C LDA MDISK ;GET MAX DISK MOV B,A ;... IN B MOV A,C CMP B JRC SELECT CALL ILPRT DB 'Disk Letter Out of Range',CR,LF,0 JMP PRMPTR ; ;Select Disk Whose Number is in C (A=0, B=1, etc) ; SELECT: PUSH H ;SAVE PTR TO NEXT COMMAND LETTER MOV A,C STA DRIVE ;REMEMBER LATER WHERE WE ARE ; VSELDK: CALL $-$ ;ADDR FILLED IN BY 'INIT' MOV A,H ORA L JZ WHAT ;SELECT ERROR MOV E,M ;GET THE SECTOR TABLE PNTR INX H MOV D,M INX H XCHG SHLD SECTBL ;SET THE SECTOR TABLE PTR LXI H,8 ;OFFSET TO DPBPTR DAD D MOV A,M ;PICK UP DPB POINTER INX H ; TO USE MOV H,M ; AS PARAMETER MOV L,A ; TO LOGIT CALL LOGIT LHLD SYSTRK ;RESET TRACK AND SECTOR XCHG ; TO DIRECTORY CALL SETTRK ; ON EVERY LXI D,1 ; LOGIN CALL SETSEC ; CHANGE LHLD PHYSEC ;THIS LOGIC WILL TELL MOV A,H ; IF FIRST SEC ORA L ; IS PHYSICAL 0 STA FIRST0 CALL CLCSUB ;CALCULATE WHAT GROUP/GRPDISP WE ARE IN POP H ;GET PTR TO NEXT LETTER ; LGNODK: CALL NORITE ;SET NO DISK I/O DONE (NO POSITION) RET ; ;Read in the disk directory ; REDDIR: PUSH H ;SAVE PTR TO NEXT LETTER CALL NORITE ;POSITIONING LOST LHLD SYSTRK ;SAVE CURRENT TRACK SHLD CURTRK LXI H,1 ;SET SECTOR 1 SHLD CURSEC LHLD DRM ;GET DIR SIZE FROM DPB INX H ;MAKE 1-RELATIVE CALL ROTRHL CALL ROTRHL ;DIVIDE BY 4 (4 NAMES/SECTOR) MOV B,H ;BC=NUMBER OF BLOCKS TO READ MOV C,L LXI D,DIRECT ;DMA ADDR ; ;Read Disk Directory Loop ; RDIRLP: PUSH B ;SAVE REGS PUSH D MOV B,D ;BC=DMA ADDRESS MOV C,E LDA BDOS+2 ;CHECK MEM AVAIL DCR A ;ARE WE RNNING INTO BDOS? CMP D JC MEMFUL ;MEMORY FULL ERROR IF SO CALL SETDMA ;SET DMA ADDRESS TO THAT IN BC LHLD CURTRK ;SET TRACK XCHG CALL SETTRK LHLD CURSEC ;SET SECTOR XCHG CALL SETSEC CALL READ ;READ DIRECTORY BLOCK CALL NXTSEC ;INCREMENT TO NEXT SECTOR POP D POP B LXI H,80H ;ADVANCE TO NEXT DMA ADDRESS DAD D XCHG ;DE=NEXT DMA ADDRESS DCX B ;COUNT DOWN DIRECTORY BLOCKS MOV A,B ORA C JRNZ RDIRLP LXI B,TBUFF ;RESET DMA ADDRESS TO TBUFF CALL SETDMA POP H ;GET PTR TO NEXT CHAR RET ; ;COMMAND: M ;Map the directory ; MAP: PUSH H ;SAVE PTR LHLD QCNT ;GET COUNT MOV A,H ORA L POP H JZ MAP1 ;PROCEED IF QUEUE EMPTY CALL ILPRT ;PRINT ABORT MESSAGE DB CR,LF,'MAP not permitted -- Block Queue would be overlaid',0 JMP PRMPTR MAP1: CALL PAGSET ;SET PAGING COUNTER XRA A STA ONLY1 ;SET FLAG FOR ALL GROUPS (NOT ONLY 1) CALL REDDIR ;READ IN DIRECTORY MVI C,0 ;INIT START GRP # LDA AL0 ;READ DIR GRP BITS CALL COLECT ;COLLECT COUNT OF DIR GRPS.. LDA AL1 ;..IN REGISTER C CALL COLECT MVI B,0 ;BC NOW HAS A DEFAULT START GRP # CALL HEXIN ;GET SPECIFIED GROUP IF ANY PUSH H ;SAVE INBUF PTR MOV A,E ;GET START ORA D ;NOTHING? JRZ MAPDF ;..YES, DFLT MVI A,0FFH ;SET FLAG FOR ONLY 1 GROUP STA ONLY1 MOV B,D ;GET VALUE IN BC MOV C,E ; MAPDF: CALL HEXB ;PRINT FIRST GROUP NUMBER MVI A,'-' ;PRINT SEPARATOR CALL TYPE MVI A,' ' ;SET NO DUPLICATES STA DUPFLG CALL GETGRP ;GET GRP(C) TO HL ; MAPCNT: INX B ;NEXT GRP # PUSH H LHLD DSM ;GET HIGHEST GRP # INX H ;PLUS 1 FOR COMPARISON MOV A,L ;WHEN BC REACHES DSM+1.. CMP C ;..THEN WE HAVE EXCEEDED.. JRNZ MAPC1 ;..THE DISK CAPACITY.. MOV A,H CMP B ; MAPC1: POP H JRZ MAPEND ;..AND WE ARE DONE PUSH H CALL GETGRP ;GET ANOTHER POP D ;SEE IF SAME CALL CTLCS ;ABORT? JRZ MAPND2 MOV A,D CMP H JRNZ MAPDIF MOV A,E CMP L JRZ MAPCNT ;SAME, CONTINUE ; ;Different file encountered ; MAPDIF: DCX B CALL HEXB ;PRINT ENDING GROUP NUMBER INX B XCHG CALL MAPNAM ;PRINT FILE NAME LDA ONLY1 ;ONLY 1 NAME TO BE PRINTED? ORA A ;0=NO JRNZ MAPND1 JR MAPDF ; ;End of map ; MAPEND: DCX B ;GET LAST CALL HEXB ;PRINT LAST GROUP NUMBER CALL MAPNAM ;PRINT FILE NAME CALL WAIT ;DELAY FOR USER MAPND1: POP H CALL CRLF ;NEW LINE ; ;End of map - reposition to previous group ; MAPND2: PUSH H LHLD GROUP ;POINT TO GROUP IN DE XCHG JMP POSGP2 ; ;Print file name pointed to by HL ; MAPNAM: CALL SPACE ;LEADING SPACE MOV A,H ORA L ;NONE? JZ NONAME MOV A,M ;SEE IF ALLOC CPI 0E5H ;FREE? MVI A,' ' ;MARK ALLOCATED JRNZ MPNSP1 MVI A,'(' ;MARK NOT ALLOCATED (ERASED FILE) ; MPNSP1: CALL TYPE ;PRINT ALLOCATION INDICATOR (SPACE OR '(') PUSH H ;SAVE POINTER MOV A,M CALL HEX ;SHOW USER NUMBER CALL SPACE INX H ;SKIP USER BYTE PUSH B MVI B,8 ;PRINT FILE NAME CALL MAPN2 MVI A,'.' ;PRINT DECIMAL SEPARATOR CALL TYPE MVI B,3 ;PRINT FILE TYPE CALL MAPN2 LDA DUPFLG ;DUPLICATE? CALL TYPE ;SPACE OR STAR POP B MOV A,M ;GET EXT CALL HEX ;PRINT EXTENT NUMBER POP H MOV A,M CPI 0E5H ;DELETED ENTRY? MVI A,' ' ;PRINT ENDING SPACE JNZ MPNSP2 MVI A,')' ;PRINT ALLOCATION FLAG ; MPNSP2: CALL TYPE ;")" IF ERASED FILE OR SPACE IF NOT JR FLIP ; NONAME: CALL ILPRT DB ' ++ Free ++ ',0 ; FLIP: LDA TWOUP ;FLIP FLAG FOR TWO ENTRIES PER LINE XRI 1 STA TWOUP JZ PAGER ;NEW LINE WITH PAGING IF REQUIRED ; DELIM: MVI A,':' ;PRINT DELIMITER BETWEEN ADJACENT ENTRIES ON LINE CALL TYPE JMP SPACE ; ;Print name pted to by HL, length in B ; MAPN2: MOV A,M ANI 7FH ;STRIP POSSIBLE 2.x ATTRIBUTE BIT INX H CPI ' ' ;PRINTABLE? JRC MAPN2H ;..NO, IN HEX CPI 7EH ;7E IS LEADIN ON SOME CRTS JRC MAPN2A ; MAPN2H: CALL BHEX ;PRINT A AS HEX CHARS JMP MAPN2Z ; MAPN2A: CALL TYPE ;PRINT AS CHAR ; MAPN2Z: DJNZ MAPN2 RET ; ;Find which file group (BC) belongs to ; GETGRP: LHLD DRM ;MAX DIR ENTRY # INX H ;MAKE 1-RELATIVE SHLD FILECT LXI H,0 SHLD MFPTR ;SET MULTI-FILE (MORE THAN ONE USER) PTR LXI H,DIRECT ;PT TO DIRECTORY ; GETGLP: PUSH H ;SAVE POINTER TO NAME MOV A,M ;PICK UP DN BYTE CPI 0E5H ;ERASED? JRZ GETGNF LXI D,14 ;NOW GET RECORD COUNT DAD D ; S2 PORTION .. MOV A,M ; IS 0 IN CP/M 1.4 ANI 0FH MOV E,A INX H MOV A,M ORA E JZ GETGNF MVI E,16 ;FIRST SET FOR 8-BIT GRPS LDA DSM+1 ORA A JRZ SMALGP MVI E,8 ;NOPE, BIG GROUPS ; SMALGP: MOV D,A ;SAVE GRP SIZE INDICATOR ; GETGL2: INX H ;POINTING INTO DM FIELD CALL GRPCMP ;COMPARE BC GP # AGAINST 1 DM FLD JRNZ NOTGOT ;JUMP IF NOT FOUND ; ;Found the file ; PUSH H ;SAVE GROUP PTR LHLD MFPTR MOV A,H ;ANY ENTRIES? ORA L POP H ;GET PTR XTHL ;SAVE ENTRY START AND SAVE PTR JRZ MPFRST ;IF ZERO, THEN FIRST ENTRY MVI A,'*' ;SET MULTI FLAG STA DUPFLG MPFRST: SHLD MFPTR ;SAVE POINTER XTHL ;RESTORE ENTRY START AND GET PTR NOTGOT: DCR E ;COUNT DOWN JRNZ GETGL2 ;GO TEST SOME MORE ; GETGNF: POP H ;NOT THIS ONE LXI D,32 ;SO GO TO NEXT DAD D XCHG LHLD FILECT ;THERE IS LIMIT TO EVERYTHING DCX H SHLD FILECT MOV A,H ORA L XCHG ;RE-ALIGN JRNZ GETGLP ; ;Set the allocation address, if any ; LHLD MFPTR ;GET ADDRESS RET ; ;COMMAND: < ;Save the current sector ; Special Form of ;Restore the current sector ; Special Form >S gets next block from queue ; Special Form >G gets next group from queue ; RESTOR: MOV A,M ;CHECK FOR SPECIAL FORM CALL UPCASE ;CAPITALIZE CPI 'B' ;BLOCK SAVE? JRZ QRESTOR CPI 'G' ;GROUP SAVE? JZ RESTRG LDA SAVEFL ;SAVE DONE PREVIOUSLY? ORA A JZ NOSAVE ;NONE TO SAVE PUSH H LXI H,SAVBUF ;COPY FROM SAVBUF LXI D,TBUFF ;INTO TBUFF MVI B,128 ;128 BYTES CALL MOVE POP H ;GET PTR TO NEXT CHAR JMP PROMPT ; ; Restore Sector from Queue ; QRESTOR: INX H ;PT TO NEXT CHAR PUSH H ;SAVE PTR ON STACK LHLD QCNT ;GET ELEMENT COUNT MOV A,H ;EMPTY? ORA L JRZ QEMPTY ;ABORT IF EMPTY DCX H ;COUNT DOWN SHLD QCNT CALL PRQCNT ;PRINT COUNT LHLD QNXT ;PT TO NEXT ELEMENT IN QUEUE LXI D,TBUFF ;COPY INTO TBUFF MVI B,128 ;128 BYTES CALL MOVE XCHG ;DE=PTR TO NEXT ELEMENT IN QUEUE CALL QWRAP ;CHECK FOR WRAP AROUND XCHG ;HL PTS TO NEXT ELEMENT IN QUEUE SHLD QNXT ;SAVE PTR POP H ;RESTORE PTR JMP PROMPT QEMPTY: CALL ILPRT DB 'Error -- Queue Empty',CR,LF,0 POP H ;RESTORE NEXT CHAR PTR JMP PRMPTR ; ;Write Group Loaded in GBUFF to Disk ; RESTRG: CALL COMG ;GET GROUP NUMBER FROM COMMAND LINE AND POS PUSH H CALL ILPRT DB 'Writing to Group ',0 LHLD GROUP ;GET GROUP NUMBER MOV B,H ;VALUE IN BC MOV C,L CALL HEXB ;PRINT IN HEX CALL ILPRT DB CR,LF,0 LHLD QNXT ;NEXT PTR USED FOR WRITE SHLD QPTR POP H MVI A,0FFH ;WRITE FUNCTION STA CPYFCT ;COPY FUNCTION FOR GROUP COPY ROUTINE JMP COPYG ;GROUP COPY ROUTINE ; NOSAVE: CALL ILPRT DB '++ No "<" Save Command Issued ++' DB CR,LF,0 JMP PRMPTR ; ;Move (HL) to (DE) length in B ; MOVE: MOV A,M STAX D INX H INX D DJNZ MOVE RET ; NORITE: XRA A ;GET 0 STA WRFLG ;CAN'T WRITE NOW RET ; ;No match in search, try next char ; SRNOMT: POP H CALL CTLCS ;ABORT? JRNZ SEARCH ;..YES LXI H,INBUF MVI M,CR JMP CLCGRP ;SHOW WHERE STOPPED ; ;COMMAND: = ;Search for character string ; SEARCH: PUSH H ;SAVE STRING POINTER ; SRCHL: CALL RDBYTE ;GET A BYTE MOV B,A ;SAVE IT MOV A,M ;CHECK NEXT MATCH CHAR. CPI '<' ;WILL IT BE HEX? MOV A,B ;RESTORE DISK CHAR JRZ SRCHL1 ANI 7FH ;NEXT CHAR IS ASCII...STRIP BIT 7 ; SRCHL1: PUSH PSW CALL GETVAL ;GET SEARCH VALUE MOV B,A POP PSW CMP B ;MATCH? JNZ SRNOMT ;NO MATCH INX H MOV A,M ;DONE? CPI CR ;END OF LINE? JRZ SREQU CPI EOLCH ;LOGICAL EOL? JRNZ SRCHL ; ;Got match ; SREQU: CALL ILPRT DB '= at ',0 LDA BUFAD ANI 7FH CALL HEX CALL CRLF JMP CLCGRP ; ;Get value from input buffer ; GETVAL: MOV A,M ;GET NEXT CHAR CPI '<' ;HEX ESCAPE? RNZ ;NO, RETURN ;"<<" means one "<" INX H MOV A,M CPI '<' RZ ;Got hex PUSH D CALL HEXIN ;GET VALUE CPI '>' ;PROPER DELIM? MOV A,E ;GET VALUE POP D JNZ WHAT ;ERROR RET ; ;Read a byte at a time from disk ; RDBYTE: PUSH H LDA FTSW ;FIRST READ? ORA A JRNZ READ1 LHLD BUFAD MOV A,L ORA A ;IN BUFFER? JM NORD ;YES, SKIP READ ; ;Have to read ; CALL NXTSEC ;ADVANCE TO NEXT BLOCK ; READ1: XRA A STA FTSW ;NOT FIRST READ LHLD CURSEC XCHG CALL SETSEC LHLD CURTRK XCHG CALL SETTRK CALL READ CALL CLCSUB LXI H,TBUFF ; NORD: MOV A,M INX H SHLD BUFAD POP H RET ; ;COMMAND: V ;View the file in ASCII starting at ;current sector, stepping thru the disk ; VIEW: LDA WRFLG ORA A JZ BADDMP CALL DECIN ;GET DISPL IF ANY PUSH H MOV A,E ORA A JRNZ VIEWLP INR E ;DFLT=1 ; VIEWLP: LXI H,TBUFF ;TO DATA ; VEWCHR: CALL CTLCS ;ABORT? JRZ VEWEND MOV A,M ;GET NEXT CHAR CPI 1AH ;EOF? JRZ VEWEOF ANI 7FH ;MASK CPI 7EH ;ESC CHAR FOR H1500 JRNC VIEWHX ;SHOW RUBOUT AND TILDE AS HEX CPI ' ' JRNC VIEWPR CPI CR ;CR PASS JRZ VIEWPR CPI LF ;LF PASS JRZ VIEWPR CPI TAB ;TAB PASS JRZ VIEWPR ; VIEWHX: MOV A,M ;NOT ASCII...PRINT AS CALL BHEX JR VIEWNP ; VIEWPR: CALL TYPE ; VIEWNP: INR L JRNZ VEWCHR DCR E JRZ VEWEND PUSH D ;SAVE COUNT CALL NXTSEC LHLD CURSEC XCHG CALL SETSEC LHLD CURTRK XCHG CALL SETTRK CALL READ POP D ;RESTORE COUNT JR VIEWLP ; VEWEOF: CALL ILPRT DB CR,LF,' ++ EOF ++',CR,LF,0 ; VEWEND: POP H CALL CRLF JMP CLCGRP ; ;COMMAND: A or D ;Dump in hex or ASCII ; DUMP: LDA WRFLG ORA A JRNZ DUMPOK ; BADDMP: CALL ILPRT DB '++ Can''t dump, no sector read ++',CR,LF,0 ; EXPL: CALL ILPRT DB 'Use G command following F,',CR,LF DB 'or R or S following T',CR,LF,0 JMP PRMPTR ; DUMPOK: MOV A,M ;GET NEXT CHAR CPI EOLCH ;LOGICAL EOL? JRZ DUMPDF ;DFLT CPI CR ;PHYSICAL EOL? JRNZ DMPNDF ; ;Use default ; DUMPDF: LXI B,TBUFF LXI D,0FFH JR DUMP1 ; DMPNDF: CALL DISP MOV B,D MOV C,E CPI CR JRZ DUMP1 CPI EOLCH JRZ DUMP1 INX H ;SKIP SEPCH CALL DISP ; ;BC = start, DE = end ; DUMP1: PUSH H ;SAVE COMMAND POINTER MOV H,B MOV L,C ; DUMPLP: MOV A,L ANI 7FH CALL HEX ;PRINT HEX VALUE CALL SPACE CALL SPACE LDA DUMTYP CPI 'A' JRZ DUMPAS PUSH H ;SAVE START ; DHEX: MOV A,M CALL HEX ;PRINT HEX VALUE PTED TO BY HL MOV A,L ANI 3 CPI 3 ;EXTRA SPACE EVERY 4 CZ SPACE MOV A,L ANI 7 CPI 7 ;TWO EXTRA SPACES EVERY 8 CZ SPACE MOV A,E CMP L JRZ DPOP INX H MOV A,L ANI 0FH JRNZ DHEX ; DPOP: CALL CTLCS ;ABORT? JZ PRMPTR LDA DUMTYP CPI 'H' JRZ DNOAS ;HEX ONLY POP H ;GET START ADDR ; DUMPAS: CALL ASTER ;PRINT FIRST ASTERISK TO SEPARATE TEXT ; DCHR: MOV A,M ;GET CHAR ANI 7FH CPI ' ' JRC DPER CPI 7EH ;TRAP ESC FOR H1500 JRC DOK ; DPER: MVI A,'.' ;PRINT PRINTING CHAR ; DOK: CALL TYPE ;PRINT CHAR MOV A,E CMP L JRZ DEND INX H MOV A,L ANI 0FH JRNZ DCHR ; DEND: CALL ASTER ;PRINT ENDING ASTERISK CALL CRLF ;NEW LINE PUSH D CALL CTLCS ;ABORT? POP D JZ PRMPTR MOV A,E CMP L JRNZ DUMPLP POP H JMP PROMPT ; DNOAS: POP B CALL CRLF MOV A,E CMP L JRNZ DUMPLP POP H JMP PROMPT ; ;COMMAND: G ;Position ; POS: PUSH PSW MOV A,M CPI EOLCH ;LOGICAL EOL? JRZ POSINQ CPI CR ;PHYSICAL EOL? JRNZ POSOK ; POSINQ: POP PSW JMP INQ ; POSOK: POP PSW CPI 'T' ;TRACK? JRZ POSTKD CPI 'S' ;SECTOR? JRZ POSSCD CPI 'G' ;GROUP? JZ POSGPH JMP WHAT ;ERROR OTHERWISE ; ;Position to Track ; POSTKD: CALL DECIN ;GET NUMBER IN DECIMAL ; POSTRK: PUSH H LHLD MAXTRK ;CHECK FOR BEYOND END OF DISK CALL SUBDE POP H JC OUTLIM CALL SETTRK ;SET TRACK CALL NORITE ;TRACK DOESN'T READ MVI A,1 STA NOTPOS ;SHOW NOT POSITIONED JR CLCGRP ; ;Position to Sector ; POSSCD: CALL DECIN ;GET NUMBER IN DECIMAL MOV A,D ORA E JZ WHAT ;DON'T ALLOW SECTOR 0 ; POSSEC: PUSH H LHLD SPT ;CHECK FOR WITHIN RANGE CALL SUBDE POP H JC WHAT CALL SETSEC ;SET SECTOR CALL READ ;READ XRA A STA NOTPOS ;POSITIONED OK ; ;Calculate Group Number/Group Displacement and Print ; CLCGRP: CALL CLCSUB JMP INQ ; ;Calculate group from track and sector ; On exit, GROUP = Group Number and GRPDIS = Displacement within Group ; CLCSUB: PUSH H LHLD SYSTRK XCHG LHLD CURTRK CALL SUBDE ;COMPUTE RELATIVE TRACK NUMBER (SKIP SYSTEM TRACKS) XCHG LHLD SPT ;MULTIPLY BY NUMBER OF SECTORS/TRACK CALL MULT XCHG ;DE=TOTAL NUMBER OF SECTORS IN TRACKS LHLD CURSEC ;GET SECTOR OFFSET FROM BEGINNING OF TRACK DCX H DAD D ;HL=TOTAL NUMBER OF SECTORS WITH OFFSET LDA BLM MOV B,A MOV A,L ANA B STA GRPDIS ;DISPLACEMENT WITHIN GROUP LDA BSH MOV B,A ; CLCLOP: CALL ROTRHL DJNZ CLCLOP SHLD GROUP ;GROUP NUMBER POP H RET ; ;Position in the directory after a find ;(Does not work in CP/M-2.x) ; POSDIR: PUSH H ;SAVE INBUF LHLD BSH XRA A STA FINDFL ;CANCEL POS REQ LDA DIRPOS ;GET POSITION RAR RAR PUSH PSW ANA H STA GRPDIS POP PSW ; POSDLP: RAR DCR L JRNZ POSDLP ANI 1 ;GET GROUP MOV L,A ;SETUP FOR POSGP2 MVI H,0 SHLD GROUP XCHG JR POSGP2 ;POSITION TO IT ; ;Position to Group ; POSGPH: CALL HEXIN ;GET PARAMETER ; ;Position to Group Numbered in DE and Print Position ; POSGRP: PUSH H LHLD DSM ;CHECK FOR WITHIN BOUNDS CALL SUBDE POP H JC OUTLIM XCHG SHLD GROUP ;SET GROUP NUMBER XCHG XRA A STA GRPDIS ;SET ZERO DISPLACEMENT PUSH H ; POSGP2: CALL GTKSEC ;CONVERT GROUP TO SECTOR/TRACK CALL SETTRK ;SET TRACK XCHG CALL SETSEC ;SET SECTOR CALL READ ;READ BLOCK XRA A STA NOTPOS ;NOW POSITIONED POP H JMP INQ ; ;Convert Group Number in DE to Sector and Track; also, GRPDIS = Offset in Grp ; On exit, DE = Track Number, HL = Sector Number ; GTKSEC: MOV H,D ;HL=GROUP NUMBER MOV L,E LDA BSH ;GET NUMBER OF SECTORS IN GROUP ; GLOOP: DAD H DCR A JRNZ GLOOP LDA GRPDIS ;ADD IN DISPLACEMENT WITHIN GROUP ADD L ;CAN'T CARRY MOV L,A ; ;Divide by number of sectors, quotient=track, remainder=sector ; XCHG ;DE=TOTAL NUMBER OF SECTORS LHLD SPT ;GET NUMBER OF SECTORS/TRACK CALL NEG ;HL = -SECTORS/TRACK XCHG LXI B,0 ;SET TRACK COUNTER TO ZERO ; DIVLP: INX B ;INCREMENT TRACK COUNT DAD D ;SUBTRACT SECTORS/TRACK FROM SECTORS TOTAL JRC DIVLP DCX B ;ADJUST TRACK COUNT XCHG LHLD SPT ;ADD SECTORS/TRACK BACK IN TO ADJUST DAD D ;HL=NUMBER OF SECTORS ON LAST TRACK OF GROUP PUSH H LHLD SYSTRK ;ADD IN NUMBER OF SYSTEM TRACKS DAD B XCHG ;DE=TRACK NUMBER POP H INX H ;HL=SECTOR NUMBER RET ; ;COMMAND: F ;Find Directory Entry for specified file ; POSFIL: CALL NORITE MVI A,1 STA FINDFL ;SO WE POSITION LATER LXI D,FCB XRA A ;LOGGED IN DISK STAX D INX D MVI B,8 CALL MVNAME MVI B,3 CALL MVNAME LXI D,FCB MVI C,SRCHF PUSH H CALL BDOS INR A JRNZ FLOK STA DIRPOS ;GRP 0 IF NOT FOUND CALL ILPRT DB '++ File Not Found ++',CR,LF,0 POP H JMP PROMPT ; FLOK: DCR A STA DIRPOS ;SAVE POS. IN DIR ANI 3 MOV L,A MVI H,0 DAD H ;X32 BYTES/ENTRY DAD H DAD H DAD H DAD H LXI D,TBUFF DAD D ;HL POINTS TO ENTRY LXI D,32 XCHG DAD D XCHG MVI A,'D' STA DUMTYP JMP DUMPLP ;WHICH POPS H ; MVNAME: MOV A,M ;GET NEXT CHAR OF FILE NAME/TYPE CPI '.' ;END OF FILE NAME? JRZ MVIPAD ;PAD OUT IF SO CPI CR ;END OF ENTRY? JRZ PAD ;PAD OUT IF SO CPI EOLCH ;END OF ENTRY? JRZ PAD ;PAD OUT IF SO CALL UPCASE ;CAPITALIZE STAX D ;STORE INX H ;PT TO NEXT INX D DJNZ MVNAME MOV A,M ;CHECK FOR ERROR CPI CR ;OK IF EOL RZ CPI EOLCH ;OK IF LOGICAL EOL RZ INX H CPI '.' ;OK IF DECIMAL RZ JMP WHAT ; MVIPAD: INX H ; PAD: MVI A,' ' ;PRINT PADDING SPACES STAX D INX D DJNZ PAD RET ; ;COMMAND: + ;Advance to Next Logical Sector ; PLUS: LXI D,1 ;DFLT TO 1 SECT MOV A,M ;GET NEXT CHAR CPI CR ;CR? JRZ PLUSGO ;..YES, DFLT TO 1 CPI EOLCH JRZ PLUSGO CALL DECIN ;GET # MOV A,D ORA E JRNZ PLUSGO LXI D,1 ;SET 1 IF VALUE OF ZERO ; PLUSGO: CALL NXTSEC ;ADVANCE TO NEXT LOGICAL SECTOR DCX D ;MORE TO GO? MOV A,D ORA E JRNZ PLUSGO ;..YES ; ;Ok, incremented to sector. Setup and read ; PLUSMI: PUSH H LHLD CURSEC XCHG CALL SETSEC ;SET SECTOR LHLD CURTRK XCHG CALL SETTRK ;SET TRACK POP H CALL READ ;READ IT JMP CLCGRP ;CALCULATE GROUP AND DISPLAY ; ;COMMAND: - ;Back up to previous sector ; MINUS: LXI D,1 ;SET DFLT MOV A,M ;GET CHAR CPI CR ;CR? JRZ MINGO ;..YES, DFLT=1 CPI EOLCH JRZ MINGO CALL DECIN ;..NO, GET ## MOV A,D ORA E JRNZ MINGO LXI D,1 ;ASSUME 1 ; MINGO: PUSH H LHLD CURSEC ;BACK UP SECTOR DCX H MOV A,H ORA L JRNZ MINOK LHLD CURTRK ;BEYOND SECTOR ZERO, SO BACK UP TRACK MOV A,H ORA L JRNZ SEASH LHLD MAXTRK ;WRAP TO END OF DISK SHLD CURTRK LHLD MAXSEC JR MINOK ; SEASH: DCX H SHLD CURTRK LHLD SPT ;GET NUMBER OF SECTORS/TRACK ; MINOK: SHLD CURSEC ;SET NEW CURRENT SECTOR POP H DCX D ;COUNT DOWN ON NUMBER OF TIMES TO BACKUP MOV A,D ORA E JRNZ MINGO JR PLUSMI ;READ BLOCK ; ;Go to next sector ; On exit, CURSEC = Current Sector and CURTRK = Current Track ; NXTSEC: PUSH H PUSH D LHLD CURSEC ;INCREMENT CURRENT SECTOR INX H XCHG LHLD SPT ;CHECK TO SEE IF BEYOND END OF TRACK CALL SUBDE XCHG JRNC NEXTOK LHLD CURTRK ;BEYOND END OF TRACK, SO INCR CURRENT TRACK INX H XCHG LHLD MAXTRK ;SEE IF BEYOND END OF DISK CALL SUBDE JRNC TRASK LXI D,0 ;WRAP TO START OF DISK ; TRASK: XCHG SHLD CURTRK ;SET NEW CURRENT TRACK LXI H,1 ;SET SECTOR 1 ; NEXTOK: SHLD CURSEC ;SET NEW CURRENT SECTOR POP D POP H RET ; ;Tell what group, displacement, track, sector, physical sector ; INQ: CALL INQSUB JMP PROMPT ; ;Position inquiry subroutine ;Executed via: G S or T (with no operands) ; INQSUB: PUSH H LHLD SYSTRK ;CHECK IF IN SYSTEM TRACKS XCHG LHLD CURTRK CALL SUBDE JRC NOGRP CALL ILPRT ;PRINT GROUP NUMBER IF NOT IN SYSTEM TRACKS DB 'Group = ',0 LHLD GROUP MOV B,H MOV C,L CALL HEXB ;PRINT GROUP NUMBER IN BC MVI A,':' CALL TYPE LDA GRPDIS CALL HEX ;PRINT GROUP DISPLACEMENT IN A MVI A,',' CALL TYPE ; NOGRP: CALL ILPRT ;PRINT TRACK NUMBER DB ' Track = ',0 LHLD CURTRK CALL DEC ;TRACK NUMBER IN DECIMAL CALL ILPRT ;PRINT SECTOR NUMBER DB ', Sector = ',0 LHLD CURSEC CALL DEC ;SECTOR NUMBER IN DECIMAL CALL ILPRT ;PRINT PHYSCIAL SECTOR NUMBER DB ', Physical Sector = ',0 LHLD PHYSEC CALL DEC ;PHYSICAL SECTOR NUMBER IN DECIMAL CALL CRLF POP H RET ; ;COMMAND: C ;Change Contents of Current Block ; CHG: MOV A,M ;GET TYPE (HEX, ASCII) CALL UPCASE PUSH PSW ;SAVE "H" OR "A" INX H CALL HEXIN ;GET DISP IN HEX CALL DISP1 ;VALIDATE DISP TO DE INX H LXI B,0 ;SHOW NO 'THRU' ADDR CPI '-' ;TEST DELIM FR. DISP JRNZ CHGNTH ;NO THRU PUSH D ;SAVE FROM CALL HEXIN CALL DISP1 ;GET THRU INX H ;SKIP END DELIM MOV B,D MOV C,E ;BC = THRU POP D ;GET FROM JR CHGAH ; CHGNTH: CPI SEPCH JNZ WHAT ; CHGAH: POP PSW CPI 'H' ;HEX? JRZ CHGHEX CPI 'A' ;ASCII? JNZ WHAT ; ;Change ASCII ; CHGALP: MOV A,M ;GET CHAR CPI CR JZ PROMPT CPI EOLCH JZ PROMPT ; ;The following print of the deleted byte is commented out; if leading ; semicolons are removed, deleted bytes will be printed ; ; LDAX D ;GET BYTE THAT IS REPLACED ; CPI ' ' ; JC CHGAHX ; CPI 7EH ;DON'T PRINT ESC CHAR FOR H1500 ; JNC CHGAHX ; JMP CHGA2 ; ;CHGAHX: ; CALL BHEX ; JMP CHGA3 ; ;CHGA2: ; CALL TYPE ; ;End of print of delete bytes ; CHGA3: SHLD BACK ;IN CASE "THRU" CALL GETVAL ;GET ASCII OR VALUE STAX D ;UPDATE BYTE INX H ;PT TO NEXT INPUT CHAR ; ;See if 'THRU' requested ; MOV A,C ORA A JRZ CHANTH CMP E ;DONE?.. JZ PROMPT ;..YES LHLD BACK ; CHANTH: INR E JNZ CHGALP MOV A,M CPI CR JZ PROMPT CPI EOLCH JZ PROMPT JMP WHAT ; ;Change hex ; CHGHCM: INX H ; CHGHEX: MOV A,M ;GET HEX DIGIT CPI CR JZ PROMPT CPI EOLCH JZ PROMPT CPI SEPCH ;DELIM? JRZ CHGHCM PUSH D SHLD HEXAD ;IN CASE 'THRU' CALL HEXIN ;POSITIONS TO DELIM MOV A,E ;GET VALUE POP D ;..ADDR ; ;The following comments out the echo of the deleted byte; removing the ; leading semicolons restores the echo ; ; PUSH PSW ;SAVE VALUE ; LDAX D ;GET OLD ; CALL HEX ;ECHO IN HEX ; POP PSW ;GET NEW ; ;End of echo of bytes ; STAX D ;SAVE NEW BYTE MOV A,C ;SEE IF 'THRU' ORA A JRZ CHHNTH ;..NO. CMP E ;..YES, DONE? JZ PROMPT LHLD HEXAD ;..NO: MORE ; CHHNTH: INR E JRNZ CHGHEX MOV A,M CPI CR JZ PROMPT CPI EOLCH JZ PROMPT JMP WHAT ; ;COMMAND: R ;Read Current Block into TBUFF ;COMMAND: RG ;Read Specified Group into GBUFF ; DOREAD: LDA NOTPOS ;POSITIONED? ORA A JRNZ CANTRD CALL READ ;READ BLOCK JMP PROMPT ; CANTRD: CALL ILPRT DB '++ Can''t read - not positioned ++',CR,LF DB 'Position by:',CR,LF DB ' Track then Sector, or',CR,LF DB ' Group',CR,LF,0 JMP PROMPT ; ;COMMAND: W ;Write Current Block to Disk ;COMMAND: WG ;Write Specified Group from GBUFF ; DORITE: CALL WRITE ;DO WRITE JMP PROMPT ; ;Print Byte in A as Hex Digits ; BHEX: PUSH PSW MVI A,'<' CALL TYPE POP PSW CALL HEX MVI A,'>' CALL TYPE RET ; ;Print Number in BC as Hex Digits ; HEXB: LDA DSM+1 ORA A JZ HEXX MOV A,B CALL HEX ; HEXX: MOV A,C ; ;Print Byte in A as 2 Hex Digits ; HEX: PUSH PSW RAR ;GET HIGH NYBBLE RAR RAR RAR CALL NIBBL ;PRINT IT POP PSW ;GET LOW NYBBLE ; NIBBL: ANI 0FH ;MASK LOW NYBBLE CPI 10 ;0-9? JRC HEXNU ADI 7 ;CONVERT TO A-F ; HEXNU: ADI '0' ;CONVERT TO ASCII JMP TYPE ;PRINT IT ; ;Decimal output routine ; Print Number in HL as decimal digits ; DEC: PUSH B PUSH D PUSH H XRA A ;SET NO LEADING DIGIT STA DDIG LXI B,10000 CALL DPRT DAD B LXI B,1000 CALL DPRT DAD B LXI B,100 CALL DPRT DAD B LXI B,10 CALL DPRT DAD B MOV A,L ;ALWAYS PRINT LSD ADI '0' ;ASCII CALL TYPE POP H POP D POP B RET DPRT: PUSH B ;SAVE BC MVI D,0FFH ;SET -1 DPRTL: INR D ;ADD 1 TO OUTPUT DIGIT MOV A,L ;L-C SUB C MOV L,A MOV A,H ;H-B SBB B MOV H,A JRNC DPRTL POP B ;RESTORE BC LDA DDIG ;GET LEADING DIGIT FLAG ORA D ;CHECK FOR ZERO STILL STA DDIG ;SET FLAG MOV A,D ;GET DIGIT TO PRINT RZ ;ABORT IF BOTH ZERO ADI '0' ;ASCII JMP TYPE DDIG: DS 1 ;TEMP FOR DEC USE ONLY ; ;Print ; SPACE: MVI A,' ' JMP TYPE ; ;Print '*' ; ASTER: MVI A,'*' JMP TYPE ; ;Inline print routine ; Print Chars ending in 0 pted to by Return Address; return to byte after ; ILPRT: XTHL ;GET PTR AND SAVE HL ; ILPLP: CALL CTLCS ;ABORT? JZ PRMPTR MOV A,M ;GET CHAR CPI 1 ;PAUSE? -- ^A JRNZ ILPOK CALL CONIN ;WAIT FOR ANY CHAR CPI 3 ;ABORT? JZ PRMPTR JR ILPNX ; ILPOK: CALL TYPE ;PRINT CHAR ; ILPNX: INX H ;PT TO NEXT MOV A,M ;GET IT ORA A ;DONE? JRNZ ILPLP INX H ;PT TO BYTE AFTER ENDING 0 XTHL ;RESTORE HL AND RET ADR RET ; ;DISP calls DECIN, and validates a sector ;displacement, then converts it to an address ; DISP: CALL DECIN DISP1: PUSH PSW ;SAVE DELIMITER MOV A,D ORA A JRNZ BADISP MOV A,E ORA A JM BADISP ADI 80H ;TO POINT TO BUFFER AT BASE+80H MOV E,A MVI D,BASE/256 POP PSW ;GET DELIM RET ; BADISP: CALL ILPRT DB '++ Bad Displacement (Not 0-7FH) ++' DB CR,LF,0 JMP PRMPTR ; ;Input Number from Command Line -- Assume it to be Hex ; Number returned in DE ; HEXIN: LXI D,0 MOV A,M CPI '#' ;DECIMAL? JRZ HDIN ;MAKE DECIMAL ; HINLP: MOV A,M ;GET CHAR CALL UPCASE ;CAPITALIZE CPI CR ;EOL? RZ CPI EOLCH ;EOL? RZ CPI SEPCH RZ CPI '-' ;'THRU'? RZ CPI '>' RZ INX H ;PT TO NEXT CHAR CPI '0' ;RANGE? JC WHAT CPI '9'+1 ;RANGE? JRC HINNUM CPI 'A' ;RANGE? JC WHAT CPI 'F'+1 ;RANGE? JNC WHAT SUI 7 ;ADJUST FROM A-F TO 10-15 ; HINNUM: SUI '0' ;CONVERT FROM ASCII TO BINARY XCHG DAD H ;MULT PREVIOUS VALUE BY 16 DAD H DAD H DAD H ADD L ;ADD IN NEW DIGIT MOV L,A XCHG JR HINLP ; HDIN: INX H ;SKIP '.' ; ;Input Number in Command Line as Decimal ; Number is returned in DE ; DECIN: LXI D,0 MOV A,M ; GET 1ST CHAR CPI '#' ; HEX? JRNZ DINLP INX H ; PT TO DIGIT JR HINLP ; DO HEX PROCESSING ; DINLP: MOV A,M ;GET DIGIT CALL UPCASE ;CAPITALIZE CPI '0' ;RANGE? RC CPI '9'+1 ;RANGE? RNC SUI '0' ;CONVERT TO BINARY INX H ;PT TO NEXT PUSH H MOV H,D MOV L,E DAD H ;X2 DAD H ;X4 DAD D ;X5 DAD H ;X10 ADD L ;ADD IN DIGIT MOV L,A MOV A,H ACI 0 MOV H,A XCHG ;RESULT IN DE POP H JR DINLP ; ;Read in a console buffer ; RDBUF: CALL ILPRT ;PRINT PROMPT DB CR,LF,'DU2 ',0 LDA DRIVE ;GET DRIVE NUMBER ADI 'A' ;CONVERT TO ASCII CALL TYPE LDA UNUM ;DISPLAY USER NUMBER MOV L,A ;VALUE IN HL MVI H,0 CALL DEC ;PRINT IN DECIMAL CALL ILPRT ;PRINT PROMPT DB '? ',0 LXI D,INBUF-2 ;USE CP/M READLN MVI C,10 CALL BDOS LDA INBUF-1 ;GET CHAR COUNT MOV B,A ;CHAR COUNT IN B LXI H,INBUF ;STORE ENDING ADD L ;ADD CHAR COUNT TO HL MOV L,A MOV A,H ACI 0 MOV H,A MVI A,CR ;STORE ENDING MOV M,A ;SAVE IT CALL TYPE ;ECHO IT MVI A,LF ;ECHO.. CALL TYPE ;..LF LXI H,INBUF ;SET PTR TO FIRST CHAR IN LINE RET ; ;Set paging flag for page routine ; PAGSET: LDA PAGSIZ ;GET SIZE OF PAGE STA PAGFLG ;SET FLAG RET ; ;Page output ; PAGER: LDA PAGFLG ;GET FLAG CPI 2 ;2 LINES LEFT? JRZ WAIT ;SAME AS USER DELAY DCR A ;COUNT DOWN STA PAGFLG JMP CRLF ; ;Delay Routine ; WAIT: PUSH H CALL ILPRT DB CR,LF,'Type Any Character to Continue or ^C to Abort - ',0 POP H CALL CONIN ;GET RESPONSE CPI 'C'-40H ;^C? JRZ WAIT1 CALL CRLF ;NEW LINE CALL PAGSET ;RESET PAGE COUNT RET WAIT1: LDA IHFLG ;INITIAL HELP? ORA A ;0=NO JZ PRMPTR ;ABORT TO COMMAND PROMPT JMP EXIT1 ;ABORT TO CP/M ; ;CRLF Routine ; CRLF: MVI A,CR CALL TYPE MVI A,LF JMP TYPE ; ;Convert to Upper Case ; UPCASE: ANI 7FH ;MASK OUT MSB CPI 60H ;LESS THAN SMALL A? RC ;RETURN IF SO ANI 5FH ;MAKE UPPER CASE RET ; ;CON: Status Routine ; CONST: PUSH B PUSH D PUSH H VCONST: CALL $-$ ;ADDR FILLED IN BY 'INIT' POP H POP D POP B RET ; ;CON: Input Routine ; CONIN: PUSH B PUSH D PUSH H VCONIN: CALL $-$ ;ADDR FILLED IN BY 'INIT' POP H POP D POP B RET ; ;Console out with TAB expansion ; Char in A ; TYPE: PUSH B ;SAVE REGS PUSH D PUSH H MOV C,A ;FOR OUTPUT ROUTINE CPI TAB JRNZ TYPE2 ;Tabulate TYPTAB: MVI A,' ' ;PRINT SPACE CALL TYPE LDA TABCOL ;GET COL COUNT ANI 7 ;DONE? JRNZ TYPTAB JR TYPRET ; ;Filter out control characters to ;prevent garbage during view of file ; TYPE2: CPI ' ' JRNC TYPEQ CPI CR JRZ TYPEQ CPI LF JRNZ TYPNCR ; TYPEQ: ; ;CON: Output Routine ; VCONOT: CALL $-$ ;ADDR FILLED IN BY 'INIT' ; ;Update column used in tab expansion ; MOV A,C ;GET CHAR CPI CR JRNZ TYPNCR MVI A,0 ;RESET TAB COLUMN IF STA TABCOL JR TYPLST ; TYPNCR: CPI ' ' ;CTL CHAR? JRC TYPLST ;..NO CHANGE IN COL LDA TABCOL ;INCR TAB COUNT INR A STA TABCOL ; TYPLST: LDA PFLAG ;CHECK FOR PRINTER OUTPUT ANI 1 CNZ LIST ;FROM C REG ; TYPRET: POP H ;RESTORE REGS POP D POP B RET ; ;LST: Output Routine ; Char in C ; LIST: PUSH B ;SAVED REGS PUSH D PUSH H VLIST: CALL $-$ ;ADDR FILLED IN BY 'INIT' POP H POP D POP B RET ; ;Home Disk Routine ; HOME: PUSH H VHOME: CALL $-$ ;ADDR FILLED IN BY 'INIT' POP H RET ; ;Set track # in DE ; SETTRK: PUSH H LHLD MAXTRK ;CHECK FOR WITHIN BOUNDS CALL SUBDE ;IF TRACK # IN DE > MAX, THEN ERROR POP H JC OUTLIM XCHG ;RESET CURRENT TRACK SHLD CURTRK XCHG MOV B,D ;BC=TRACK NUMBER MOV C,E PUSH H ; VSETRK: CALL $-$ ;ADDR FILLED IN BY 'INIT' POP H RET ; ;Set Sector Number in DE ; SETSEC: PUSH H PUSH D LHLD SYSTRK ;GET NUMBER OF SYSTEM TRACKS XCHG SHLD CURSEC ;SET CURRENT SECTOR LHLD CURTRK ;GET CURRENT TRACK CALL SUBDE ;SEE IF WE ARE IN THE SYSTEM TRACKS POP B ;BC=SECTOR NUMBER MOV H,B ;HL=SECTOR NUMBER MOV L,C JRNC NOTSYS ;IF NO CARRY FOR SUBDE, WE ARE NOT IN SYSTEM TRACKS LDA FIRST0 ;SEE IF FIRST SEC 0 ORA A JRNZ GSTSEC ;NO, JUMP AWAY DCX H ;YES, SO DECREMENT JR GSTSEC ;REQUESTED, THEN GO ; ;Not in System Tracks, so Skew Factor is effective ; NOTSYS: LHLD SECTBL ;GET PTR TO SECTOR TABLE XCHG ;... IN DE DCX B ;DECREMENT SECTOR NUMBER BY 1 ; VSCTRN: CALL $-$ ;ADDR FILLED IN BY 'INIT' LDA SPT+1 ;IF SPT<256 (HI-ORD = 0) ORA A ; THEN FORCE 8-BIT TRANSLATION JRNZ GSTSEC ; ELSE KEEP ALL 16 BITS MOV H,A GSTSEC: SHLD PHYSEC MOV B,H MOV C,L ; VSTSEC: CALL $-$ ;ADDR FILLED IN BY 'INIT' POP H ;RESTORE PTR TO NEXT CHAR RET ; ;Out of Disk Track Limit ; OUTLIM: CALL ILPRT DB '++ Not Within Tracks 0-',0 PUSH H LHLD MAXTRK ;PRINT MAX TRACK NUMBER CALL DEC POP H CALL ILPRT DB ' ++',CR,LF,0 CALL NORITE ;NOT POSITIONED JMP PRMPTR ; ;Set DMA Address ; SETDMA: JMP $-$ ;ADDR FILLED IN BY 'INIT' ; ;Read Next Block into DMA Address ; READ: MVI A,1 ;SET FLAG STA WRFLG PUSH H ;SAVE PTR TO NEXT CHAR ; VREAD: CALL $-$ ;ADDR FILLED IN BY 'INIT' ORA A ;ERROR? JRZ READOK CALL ILPRT DB '++ READ Failed, Sector may be Invalid ++' DB CR,LF,0 ; READOK: POP H ;GET PTR TO NEXT CHAR RET ; ;Write Block in DMA Address to Disk ; WRITE: LDA WRFLG ;READ ALREADY PERFORMED? ORA A ;ERROR IF NOT JRNZ PWRITE ; BADW: CALL ILPRT DB '++ Cannot Write Unless Read Issued ++' DB CR,LF,0 JMP EXPL ; ;Do Write ; PWRITE: PUSH H ;SAVE PTR TO NEXT CHAR MVI C,1 ;FORCE WRITE TYPE 1 IN CASE 2.x DEBLOCK USED ; VWRITE: CALL $-$ ;ADDR FILLED IN BY 'INIT' ORA A ;ERROR? JRZ WRITOK CALL ILPRT DB '++ WRITE Failed ++',CR,LF,0 ; WRITOK: POP H RET ; ;Help; HELP is entry point for HELP (?) command, HELP1 is entry point for ; Initial Help Command, and IHELP is entry point for HELP (/) from command ; line ; IHELP: CALL ILPRT DB 'Introductory HELP on DU2 (Disk Utility)',CR,LF DB ' The DU2 program is designed to provide the user with' DB CR,LF DB 'the ability to manipulate information on the disk as easily' DB CR,LF DB 'as the DDT and SID utilities allow the user to manipulate' DB CR,LF DB 'information in memory.',CR,LF DB ' The following is a summary of the commands available to' DB CR,LF DB 'the DU2 user. This same list is invoked internally by the' DB CR,LF DB '? Command of DU2. For additional information on disk' DB CR,LF DB 'structures and how to use DU2 in general, refer to the' DB CR,LF DB 'files DU2.DOC and DU2.HLP.',CR,LF,0 MVI A,0FFH ;A=0FFH STA IHFLG ;SET INITIAL HELP CALL WAIT JR HELP1 ;PROCESS NORMALLY HELP: XRA A ;A=0 STA IHFLG ;SET NO INITIAL HELP HELP1: CALL ILPRT DB '=======================================================',CR,LF DB ' -- Command Summary -- ',CR,LF DB '-------------------------------------------------------',CR,LF DB CR,LF DB 'Operands in brackets [...] are optional' DB CR,LF,CR,LF DB '@ Repeat Previous Non-@ Command Line' DB CR,LF DB '+[nn] Step In [nn (decimal)] Sectors; -[nn] Step Out ' DB 'Sectors' DB CR,LF DB ' Note: + or - need not be followed by a "," to ' DB 'delimit commands.' DB CR,LF DB '# Print Disk Parameters for Current Drive' DB CR,LF DB '=xxx Search for ASCII xxx from Current Sector' DB CR,LF DB ' Note: upper/lower case matters. Use for hex:' DB CR,LF DB ' To find "IN 0" use: =<0> or' DB CR,LF DB ' "(tab)H,0(CR)(LF)" use: =<9>H,0' DB CR,LF DB '*[nn] Repeat [nn (decimal) times]; ! Pause for User' DB CR,LF DB ':ntext Define ''text'' to be Macro n; n Perform Macro' DB ' n, 0<=n<=9' DB CR,LF DB ':Pn Print Macro n, 0<=n<=9' DB CR,LF DB ':Px Print All Macros if x=A or Print Prev Line if x=@' DB CR,LF,CR,LF,0 CALL WAIT CALL ILPRT DB '-------------------------------------------------------',CR,LF DB 'A[ff,tt] ASCII Dump' DB CR,LF DB 'C Change:' DB CR,LF DB ' CHaddr byte byte... (hex)' DB CR,LF DB ' or CAaddr data... (Ascii)' DB CR,LF DB ' Allowed for imbedded hex.' DB CR,LF DB ' or CHfrom-thru byte e.g. ch0-7f,e5' DB CR,LF DB ' or CAfrom-thru byte' DB CR,LF DB 'D[ff,tt] Dump (Hex and ASCII)' DB CR,LF DB 'Ffn.ft Find File' DB CR,LF DB 'Gnn CP/M Allocation Group nn (hex)' DB CR,LF DB 'H[ff,tt] Hex Dump' DB CR,LF DB 'L[d] Log in Current Drive or Drive d' DB CR,LF DB 'M[nn] Map [from group nn (hex)]' DB CR,LF,CR,LF,0 CALL WAIT CALL ILPRT DB '-------------------------------------------------------',CR,LF DB CR,LF DB 'N Load New Disk; P Toggle Printer Switch' DB CR,LF DB 'Q Queue Status; QZ Zero (Empty) Queue' DB CR,LF DB 'QSfn.ft Save Queue as a File on Disk' DB CR,LF DB '< Save Current Block into Temp; > Restore Temp ' DB 'Block' DB CR,LF DB 'B Restore Queue ' DB 'Block' DB CR,LF DB 'G[n] Restore Queue ' DB 'Group' DB CR,LF DB 'Snn Sector nn (decimal)' DB CR,LF DB 'Tnn Track nn (decimal)' DB CR,LF DB 'Unn Set User nn (decimal) for Find command (CP/M-2 only)' DB CR,LF DB 'V[nn] View [nn (decimal)] ASCII Blocks' DB CR,LF DB 'R Read Current Block; W Write Current Block' DB CR,LF DB 'X Exit Program' DB CR,LF DB 'Z[nn] Sleep [nn (decimal) seconds]' DB CR,LF,CR,LF,0 CALL WAIT CALL ILPRT DB '-------------------------------------------------------',CR,LF DB CR,LF DB 'Command Line is of the form: DU2 du?',CR,LF DB ' "d" is Logged-In Disk, "u" is Current User',CR,LF DB CR,LF DB 'Cancel a function with C or Ctrl-C.' DB CR,LF DB 'Suspend output with S or Ctrl-S.' DB CR,LF DB 'Separate commands with ",".' DB CR,LF DB ' Example: g0' DB CR,LF DB ' +,d,z2,*' DB CR,LF DB ' would step in, dump, sleep 2 sec, ' DB CR,LF DB ' and repeat until control-c typed.' DB CR,LF DB '"nn" usage varies with command as follows:',CR,LF DB ' +, -, *, T, S, U, V, Z nn in Decimal',CR,LF DB ' (use #nn for Hex)',CR,LF DB ' G, M nn in Hexadecimal',CR,LF DB ' (use #nn for Decimal)' DB CR,LF DB '"ff" and "tt" are in Hexadecimal (use #ff or #tt for Decimal)' DB CR,LF,CR,LF DB '=======================================================',CR,LF DB 0 CALL WAIT CALL ILPRT DB '=======================================================',CR,LF DB 'DU2 Status Information',CR,LF DB '-------------------------------------------------------',CR,LF DB 'Processor Speed: ',0 LDA CLOCK ;GET CLOCK SPEED ADI '0' ;CONVERT TO ASCII CALL TYPE ;PRINT CALL ILPRT DB ' MHz',CR,LF DB 'Number of Lines on CON: ',0 LDA PAGSIZ ;GET PAGE SIZE MOV L,A ;NUMBER IN HL MVI H,0 CALL DEC ;PRINT NUMBER IN DECIMAL CALL ILPRT DB CR,LF,'Group Save Buffer Address: ',0 LXI B,GBUFF ;BC=ADDRESS CALL HEXB ;PRINT AS HEX CALL ILPRT DB ' Hex',CR,LF DB '=======================================================',CR,LF DB 0 LDA IHFLG ;INITIAL HELP? ORA A ;0=NO JRNZ EXIT1 ;RETURN TO CP/M IF SO JMP PRMPTR ;NEW LINE INPUT IF NOT ; ;COMMAND: X ;Exit to CP/M ; EXIT: CALL ILPRT ;PRINT DB CR,LF,'Exit to CP/M -- Do you wish to Warm Boot (Y/N/=N)?' DB ' ',0 CALL CONIN ;GET RESPONSE CALL UPCASE ;CAPITALIZE CPI 'Y' ;YES? JZ BASE ;WARM BOOT IF SO ; ;Quick Exit to CP/M ; EXIT1: LHLD DUTSTK ;GET CP/M STACK PTR SPHL ;SET SP RET ; ;******************************** ;* * ;* Utility Subroutines * ;* * ;******************************** ; GRPCMP: MOV A,C INR D DCR D JRZ CMP8 CMP M INX H RNZ MOV A,B ; CMP8: CMP M RET ; ;2's complement HL ==> HL ; NEG: MOV A,L CMA MOV L,A MOV A,H CMA MOV H,A INX H RET ; ;HL/2 ==> HL ; ROTRHL: ORA A MOV A,H RAR MOV H,A MOV A,L RAR MOV L,A RET ; ;Collect the number of '1' bits ;in A as a count in C ; COLECT: MVI B,8 ;NUMBER OF BITS ; COLOP: RAL JRNC COSKIP INR C ; COSKIP: DCR B JRNZ COLOP RET ; ;HL-DE ==> HL ; Carry Flag is Significant ; SUBDE: MOV A,L SUB E MOV L,A MOV A,H SBB D MOV H,A RET ; ;Quick Kludge multiply ;HL*DE ==> HL ; MULT: PUSH B PUSH D XCHG MOV B,D MOV C,E MOV A,B ORA C JRNZ MULCON LXI H,0 ;FILTER SPECIAL CASE JR MLDONE ; OF MULTIPLY BY 0 ; MULCON: DCX B MOV D,H MOV E,L ; MULTLP: MOV A,B ORA C JRZ MLDONE DAD D DCX B JR MULTLP ; MLDONE: POP D POP B RET ; ;Routine to fill in disk params ;with every drive change ; LOGIT: LXI D,DPB ; THEN MOVE TO LOCAL MVI B,DPBLEN ; WORKSPACE CALL MOVE LXI H,GRPDIS MOV A,M PUSH PSW LDA BLM MOV M,A PUSH H LHLD DSM XCHG CALL GTKSEC SHLD MAXSEC XCHG SHLD MAXTRK POP H POP PSW MOV M,A RET ;*********************************** ; ; DU2 Command Table ; ;*********************************** CMDTBL: DB ':' DW MAC ; DB '@' DW PCMD ; DB '+' DW PLUS ; DB '-' DW MINUS ; DB '=' DW SEARCH ; DB '<' DW SAVE ; DB '>' DW RESTOR ; DB '#' DW STATS ; DB '?' DW HELP ; DB MULCH DW REPEAT ; DB '!' DW UWAIT ; DB 'A' DW DUMP ; DB 'C' DW CHG ; DB 'D' DW DUMP ; DB 'F' DW POSFIL ; DB 'G' DW POS ; DB 'H' DW DUMP ; DB 'L' DW LOGIN ; DB 'M' DW MAP ; DB 'N' DW NEWDSK ; DB 'P' DW PRNTFF ; DB 'Q' DW QUEUER ; DB 'R' DW DOREAD ; DB 'S' DW POS ; DB 'T' DW POS ; DB 'U' ;******CP/M 2.x ONLY****** DW USER ; DB 'V' DW VIEW ; DB 'W' DW DORITE ; DB 'X' DW EXIT ; DB 'Z' DW SLEEP ; DB 0 ; End of Table ;************************************* ; ;Temporary storage area ; DS 100 ;50-ELT STACK DUTSTK: DS 2 ;OLD CP/M STACK POINTER; TOP OF DU2 STACK BUFAD: DS 2 ;FORCES INITIAL READ QCNT: DS 2 ;NUMBER OF SECTORS IN QUEUE QNXT: DS 2 ;PTR TO NEXT SECTOR IN QUEUE QLST: DS 2 ;PTR TO LAST SECTOR IN QUEUE QPTR: DS 2 ;G-P QUEUE PTR HEXAD: DS 2 ;TO RE-FETCH A VALUE TOGO: DS 2 ;REPEAT COUNT (FFFF=CONT) TWOUP: DS 1 UNUM: DS 1 ;NUMBER OF CURRENT USER ONLY1: DS 1 ;FLAG TO PRINT ONLY 1 MAP ENTRY (0=NO) MFPTR: DS 2 ;MULTI FILE PTR FOR GETGRP PAGFLG: DS 1 ;LINE COUNTER FOR PAGING PFLAG: DS 1 ;1=PRINT GROUP: DS 2 ;GROUP NUMBER GRPDIS: DS 1 ;DISPLACEMENT INTO GROUP SAVEFL: DS 1 ;SAVE FLAG CURTRK: DS 2 ;CURRENT TRACK NUMBER CURSEC: DS 2 ;CURRENT SECTOR NUMBER PHYSEC: DS 2 ;CURRENT PHYSICAL SECTOR NUMBER TABCOL: DS 1 ;TAB COLUMN CPYFCT: DS 1 ;GROUP COPY FUNCTION; 0=READ, 0FFH=WRITE FILECT: DS 2 ;FILE COUNT DIRPOS: DS 1 ;POSITION IN DIRECTORY FINDFL: DS 1 ;1=MUST POSITION AFTER FIND FTSW: DS 1 ;SEARCH W/O INCREMENT NOTPOS: DS 1 ;INITIALLY NOT POSITIONED WRFLG: DS 1 ;MAY NOT WRITE UNTIL '+', '-', ; OR 'G' COMMAND TGRP: DS 2 ;TEMPORARY GROUP FLAG FIRST0: DS 1 ;SETS TO 0 IF FIRST SEC # IS 0 DRIVE: DS 1 ;DRIVE NUMBER MAXTRK: DS 2 ;MAX TRACK NUMBER MAXSEC: DS 2 ;MAX SECTOR NUMBER SECTBL: DS 2 ;POINTER TO SECTOR SKEW TABLE ; IHFLG: DS 1 ;0=NOT AT INITIAL HELP, 0FFH=AT INITIAL HELP DUPFLG: DS 1 ;SPACE OR STAR TO INDICATE MULTIPLE USERS BACK: DS 2 ;TO BACK UP IN "CA0-7F,X" DUMTYP: DS 1 ; ;The disk parameter block ;is moved here from CP/M ; DPB EQU $ ;DISK PARAMETER BLOCK (COPY) SPT: DS 2 BSH: DS 1 BLM: DS 1 EXM: DS 1 DSM: DS 2 DRM: DS 2 AL0: DS 1 AL1: DS 1 CKS: DS 2 SYSTRK: DS 2 ; ;End of disk parameter block ; SAVBUF: DS 128+2+2 ; ;Set INBUF to a Page Boundary ; ORG $/100H*100H+100H-2 DB 126 ; SIZE OF BUFFER FOR CP/M DS 1 INBUF: DS 400H ;EXTRA SPACE FOR MACRO EXPANSION PINBUF: DS 400H ;PREVIOUS CONTENTS OF INPUT BUFFER CTEMP: DS 400H ;BUILD NEW COMMAND LINE BUFFER CTEMPX EQU $ ;END OF CTEMP ; ;Directory read in here; also loaded group area and Macros ; MTABL: DS 100H*10 ;10 PAGES FOR 10 MACROS GBUFF EQU $ DIRECT EQU $ ; END