; 03/01/85 Richard Conn: Replaced fixed in EDPLOT that was somehow lost ; (see lines suffixed by ; ; 01/18/85 Modified by Jay Sage to incorporate a set of permanent ; macros. These macros can be invoked by the command tail ; when DU is invoked. They are copied from a space of 128 ; bytes near the beginning of the code. The area is ; identified by a string of text to facilitate patching. ; The macros are listed one after another, separated by ; carriage return characters. Macros that are not to be ; defined must be present as carriage returns alone or the ; program will fail. ; ; PROGRAM: DU3 ; AUTHOR: RICHARD CONN ; DERIVATION: DUTIL is derived from DU Version 7.5 ; DU2 is derived from DUTIL Version 1.1 ; DU3 is derived from DU2 Version 1.1 ; VERSION: 1.0 ; DATE: 20 June 84 ; PREVIOUS VERSIONS: None ; NOTE: DU3 must be assembled using M80 (or equiv) ; VERS EQU 13 Z3ENV EQU 0F400H ; ; DU3 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 DU3 follow -- ; ;This version of DU is compatible with CP/M 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. ; ;************************************************* ;* * ;* This program has been heavily modified * ;* to allow it to work without modification * ;* on 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. * ;* * ;* Ron Fowler * ;* * ;************************************************* ; ; ; SYSLIB and Z3LIB References ; ext z3vinit,envptr,cls,at,tinit,dinit,stndout,stndend,gotoxy ext getspeed,getcrt,getmdisk,getmuser ext codend ; ;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 DU3 ; EOLCH equ ',' ;Marks logical end of line SEPCH equ ' ' ;Argument Separator MULCH equ '*' ;Multiplication Command DIM equ 1 ;Enter DIM Mode for ILPRT BRIGHT equ 2 ;Enter BRIGHT Mode for ILPRT ; ;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 SRCHN EQU 18 ;SEARCH NEXT 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 INCLUDE: ; ; DJNZ - DECREMENT B AND JUMP RELATIVE IF NO ZERO ; DJNZ MACRO ?N ;;DECREMENT B AND JUMP ON NO ZERO DCR B JNZ ?N ENDM ; ; END OF MACROS ; ; ;Beginning of Program ; ; ; Environment Definition ; if z3env ne 0 ; ; External ZCPR3 Environment Descriptor ; jmp start db 'Z3ENV' ;This is a ZCPR3 Utility db 1 ;External Environment Descriptor z3eadr: dw z3env ; ; Space Added for Initial Macro Definitions -- block added by ; ;label to help locate when patching db 'INITIAL MACROS:' imac0: db 'G0,D',cr ;macro 0 db '-D',cr ;macro 1 db '+D',cr ;macro 2 db cr ;macro 3 db cr ;macro 4 db cr ;macro 5 db cr ;macro 6 db cr ;macro 7 db cr ;macro 8 db cr ;macro 9 ;fill rest of 128 bytes with nulls if imac0 + 128 - $ gt 0 rept imac0 + 128 - $ db 0 endm endif ; End of Block Added by start: lhld z3eadr ;pt to ZCPR3 environment ; else ; ; Internal ZCPR3 Environment Descriptor ; MACLIB Z3BASE.LIB MACLIB SYSENV.LIB z3eadr: jmp start SYSENV start: lxi h,z3eadr ;pt to ZCPR3 environment endif ; ; Start of Program -- Initialize ZCPR3 Environment ; call z3vinit ;initialize the ZCPR3 Env and the VLIB Env call tinit ;init terminal LXI H,0 ;GET PTR TO CP/M STACK DAD SP ;HL=SP SHLD DUTSTK ;SAVE IT ; call codend ;get free space lxi d,100h ;open area dad d ;large stack area shld savbuf dad d ;100H for SAVBUF push h ;save ptr mvi m,126 ;allow 126-char input line inx h inx h ;ptr to INBUF shld inbuf pop h ;pt to beginning lxi d,400h ;large area for expansion dad d shld pinbuf ;ptr to PINBUF dad d shld ctemp ;ptr to CTEMP dad d shld ctempx ;ptr to CTEMPX shld mtabl ;ptr to MACRO TABLE lxi d,100h*10 ;10 macros dad d shld gbuff ;group save buffer shld direct ;directory load buffer ; lhld savbuf ;top of stack sphl ; SET STACK ; call getspeed sta clock ;set clock speed call getcrt ;get CRT data inx h ;pt to screen size mov a,m ;get it sta pagsiz ;set page size call getmdisk ;get max disk sta mdisk ;and set it call getmuser ;get max user sta muser ;and set it ; ;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 ; JMP 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 'DU3 - Disk Utility III, Version ' DB VERS/10+'0','.',(VERS MOD 10)+'0' DB CR,LF,CR,LF DB DIM,'Type ? for Help',BRIGHT DB CR,LF,0 ; ;Clear Editor Reference ; XRA A STA EDRUN ;EDITOR NOT RUNNING ; ;Save initial command line in INBUF ; LXI H,TBUFF ;PT TO COMMAND LINE BUFFER MOV A,M ;GET CHAR COUNTER ora a ;check for no tail jnz ctail ;if not, no need to increment inr a ;allow for blank otherwise present ctail: ; INX H ;PT TO FIRST CHAR ADD L ;COMPUTE LOCATION OF AFTER LAST CHAR MOV L,A MOV A,H ACI 0 MOV H,A MVI M,CR ;SET ENDING CR LHLD INBUF ;PT TO BUFFER XCHG ;... IN DE LXI H,TBUFF+2 ;PT TO INPUT LINE (1 changed to 2 ) MVI B,128 ;COPY BUFFER CALL MOVE ; ;Establish Initial Position ; LXI D,0 ;GROUP 0 CALL DEGROUP ;POSITION TO GROUP CALL INQSUB ;PRINT POSITION ; ;Check for initial command ; LHLD INBUF ;INPUT BUFFER MOV A,M CPI CR JZ PRMPTR ;NO INITIAL COMMAND FROM COMMAND LINE INX H ;PT TO FIRST CHAR ; ;Got initial command, set it up ; MOV A,M ;GET FIRST CHAR CPI '/' ;IF SLASH, PRINT INITIAL HELP (TOOLSET CONVENTION) JZ IHELP ;PRINT INITIAL HELP INFO XRA A STA IHFLG ;SET NO INITIAL HELP ; line replaced ; JMP PRMPTI ;PROCESS AS THOUGH COMMAND LINE WAS TYPED jmp prmpts ;allow processing of macros in command line ; ;Input Command Line From User at Console ; PRMPTR: XRA A ;A=0 STA IHFLG ;Set No Initial Help LDA EDRUN ;Check for Editor Running ORA A JNZ EDIT0 ;Reenter Editor CALL SINBUF ;Save old INBUF into PINBUF PRMPTE: CALL RDBUF ;Read Input Line PRMPTS: ;Entry when Command Line has Input 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: SHLD STKSAV ;SAVE HL FOR STACK LOAD LHLD SAVBUF ;RESET STACK SPHL LHLD STKSAV ;RESTORE HL 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? JZ 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? JZ PRMPTR ;INPUT NEW COMMAND LINE IF SO CPI EOLCH ;END OF LINE LOGICALLY? JZ PROMPT ;PROCESS NEXT ELEMENT IF SO CALL UPCASE ;CAPITALIZE COMMAND STA DUMTYP ;TYPE OF DUMP (A,D,H) LXI D,CMDTBL ;PT TO COMMAND TABLE CALL CMD ;PROCESS JMP WHAT ;ERROR RETURN ; ;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 ; CMD: PUSH H ;SAVE HL MOV B,A ;COMMAND IN B XCHG ;HL PTS TO COMMAND TABLE CMDLP: MOV A,M ;GET COMMAND ORA A ;0=END OF TABLE JZ CMDER CMP B ;COMPARE COMMAND JZ CMDGO INX H ;PT TO ADR INX H INX H ;PT TO NEXT CMND JMP CMDLP CMDGO: INX H ;PT TO ADDRESS LOW MOV E,M INX H ;PT TO ADDRESS HIGH MOV D,M POP H ;RESTORE HL POP PSW ;CLEAR RETURN ADDRESS MOV A,B ;COMMAND BACK INTO A PUSH D ;PLACE ADDRESS ON STACK RET ;"RUN COMMAND" CMDER: POP H ;RESTORE HL MOV A,B ;RESTORE COMMAND CHAR IN CASE CMD RUN RET ;... IMMEDIATELY AGAIN ON A NEW TABLE ; ;Macro Expansion Routine -- Expand Macros ; EXMAC: LHLD CTEMP ;BUILD INTO TEMPORARY BUFFER XCHG LHLD INBUF ;PT TO INPUT LINE EXMAC1: MOV A,M ;GET CHAR CPI '0' ;SKIP IF LESS THAN '0' JC EXMAC2 CPI '9'+1 ;CHECK FOR RANGE JNC 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 LHLD 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? JZ EXMAC3 CPI EOLCH ;LOGICAL EOL? JNZ EXMAC2 JMP EXMAC1 ;PROCESS NEXT COMMAND EXMAC3: LHLD CTEMP ;COPY COMMAND LINE BACK XCHG LHLD INBUF ;INTO INBUF XCHG CALL COPYCR ;COPY TO LHLD 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? JNZ COPYM RET ; ;Test for Buffer Full ; MTEST: PUSH H ;SAVE HL PUSH PSW ;SAVE A LHLD CTEMPX ;CHECK FOR END OF BUFFER MOV A,H ;GET PAGE CMP D ;CHECK PAGE JZ 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: LHLD PINBUF ;PT TO PINBUF (PREVIOUS INBUF) XCHG LHLD INBUF ;PT TO 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? JNZ COPYCR RET ; ;Command Not Found Error ; WHAT: POP H ; RESTORE HL CALL ILPRT DB DIM,'Invalid Command at or after ',BRIGHT,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: E ;Edit Current Block ; EROW EQU 6 ;FIRST ROW OF EDITOR DISPLAY ECOL EQU 4 ;FIRST COL OF EDITOR DISPLAY ECOLC EQU ECOL+16*3+2 ;FIRST COL OF EDITOR CHAR DISPLAY ECURS EQU '>' ;EDITOR CURSOR ; EDIT: CALL SINBUF ;SAVE COMMAND LINE AS PREVIOUS MVI A,0FFH STA EDRUN ;EDITOR IS RUNNING ; ; SET UP ARROW KEYS ; LHLD ENVPTR ;PT TO ENVIRONMENT DESCRIPTOR LXI D,80H+10H ;PT TO ARROW KEY INFO DAD D LXI D,EDCURT ;PT TO CURSOR TABLE MVI B,4 ;4 ARROW KEYS EDITA: MOV A,M ;GET CHAR STAX D ;STORE CHAR INX H ;PT TO NEXT INX D ;PT TO NEXT ENTRY INX D INX D DJNZ EDITA ;COUNT DOWN ; ; REENTER EDIT WITH PTRS RESET ; REFRESH EDIT SCREEN ; EDIT0: CALL CLS ;NEW SCREEN CALL AT DB 2,32 ;ROW 2, COL 32 CALL ILPRT ;BANNER DB 'DU3 Block Editor',0 MVI H,EROW+9 ;POSITION FOR COMMAND DISPLAY MVI L,1 CALL GOTOXY ;POSITION CURSOR CALL ILPRT ;PRINT COMMAND SUMMARY DB ' -- Movement --' DB ' -------------- Operation ---------------',CR,LF DB ' ^E ' DB DIM,'Enter: ',BRIGHT,'A',DIM,' ASCII Chars',BRIGHT DB ' +',DIM,' Next Sector',BRIGHT,CR,LF DB ' ^ ' DB DIM,' ',BRIGHT,'H',DIM,' Hex Numbers',BRIGHT DB ' -',DIM,' Last Sector',BRIGHT,CR,LF DB ' ^S <-+-> ^D ' DB ' ' DB ' ^C',DIM,' Exit DU3 ',BRIGHT DB CR,LF DB ' v ' DB 'C',DIM,' DU3 Command Line ',BRIGHT DB ' ^R',DIM,' Rescreen ',BRIGHT,CR,LF DB ' ^X ' DB 'X',DIM,' Exit Editor to DU3',BRIGHT DB ' ^W',DIM,' Write Block',BRIGHT DB 0 CALL AT DB 2,65 CALL ILPRT DB DIM,'Position:',BRIGHT,0 ; JMP EDITCMD ; ; REFRESH SCREEN DISPLAY DATA ONLY ; EDITR: XRA A ;A=0 STA EINDEX ;SET INDEX TO 0 (FIRST ELEMENT) STA EDERR ;SET NO PREVIOUS ERROR CALL AT ;POSITION CURSOR DB EROW-2,ECOL CALL INQSUB ;PRINT POSITION DATA CALL EDPLOT ;PLOT BUFFER DATA ; ; INPUT EDITOR COMMAND ; EDITCMD: CALL EDERCL ;CLEAR EDITOR INVALID COMMAND MESSAGE EDITCMD1: CALL AT ;POSITION FOR COMMAND LINE DB 22,10 CALL ILPRT DB DIM,'Edit Command? ',BRIGHT,BS,0 CALL CONIN ;GET CHAR CALL UPCASE ;CAPITALIZE MOV B,A ;COMMAND IN B LXI D,EDCURT ;PROCESS CURSOR COMMANDS FIRST CALL CMD ;PROCESS COMMAND LXI D,ECMDTBL ;EDITOR COMMAND TABLE CALL CMD ;PROCESS COMMAND MVI A,0FFH ;SET ERROR FLAG STA EDERR CALL AT ;CLEAR ERROR MESSAGE DB 23,15 CALL ILPRT DB 'Invalid Command',0 JMP EDITCMD1 ; ;Clear Editor Invalid Command Message ; EDERCL: LDA EDERR ;PREVIOUS ERROR? ORA A ;0=NO RZ XRA A ;CLEAR FLAG STA EDERR CALL AT ;CLEAR ERROR MESSAGE DB 23,15 CALL ILPRT DB ' ',0 RET ; ;PLOT BUFFER DATA ; EDPLOT: MVI H,EROW ;SET ROW MVI L,ECOL-1 ;SET COLUMN CALL GOTOXY ;POSITION CURSOR XCHG ;POSITION IN DE LXI H,TBUFF ;PT TO DATA MVI B,8 ;8 LINES EDIT00: MVI C,16 ;16 ELEMENTS CALL SPACE ;PRINT LEADING SPACE EDIT01: MOV A,M ;GET BYTE CALL HEX ;PRINT AS HEX CALL SPACE ;PRINT 1 SPACE INX H ;PT TO NEXT DCR C ;COUNT DOWN JNZ EDIT01 XCHG ;POSITION AGAIN INR H ;NEXT ROW CALL GOTOXY XCHG DCR B ;COUNT DOWN JNZ EDIT00 MVI H,EROW ;RESET ROW MVI L,ECOLC ;RESET COL CALL GOTOXY ;POSITION CURSOR XCHG ;POSITION IN DE LXI H,TBUFF ;PT TO DATA MVI B,8 ;8 LINES EDIT02: CALL ASTER ;PRINT BAR MVI C,16 ;16 ELEMENTS EDIT03: MOV A,M ;GET BYTE ANI 7FH ;MASK MSB CPI 7FH ;7FH IS DOT JZ EDIT7F CPI ' ' ;SPACE OR MORE? JNC EDIT04 EDIT7F: MVI A,'.' ;PRINT DOT EDIT04: CALL TYPE ;PRINT BYTE INX H ;PT TO NEXT DCR C ;COUNT DOWN JNZ EDIT03 CALL ASTER ;PRINT ENDING BAR XCHG ;POSITION AGAIN INR H ;NEXT ROW CALL GOTOXY XCHG DCR B ;COUNT DOWN JNZ EDIT02 CALL EDCUR ;POSITION CURSOR RET ; ;EDITOR COMMAND TABLE ; ECMDTBL: DB CR ;NOP DW EDITCMD DB 'C'-'@' ;^C = EXIT DU3 DW EDCC DB 'R'-'@' ;^R = REFRESH DW EDIT0 DB 'E'-'@' ;^E=UP DW EDUP DB 'X'-'@' ;^X=DOWN DW EDDOWN DB 'D'-'@' ;^D=RIGHT DW EDRIGHT DB 'S'-'@' ;^S=LEFT DW EDLEFT DB 'W'-'@' ;WRITE BLOCK DW EDITWR DB ' ' ;NOP DW EDITCMD DB '+' ;ADVANCE DW EDITPLUS DB '-' ;BACKUP DW EDITMINUS DB 'A' ;CHANGE ALPHA DW EDITALP DB 'C' ;COMMAND LINE DW EDITCL DB 'H' ;CHANGE HEX DW EDITHEX DB 'X' ;EXIT DW EDITX DB 0 ;END OF TABLE ; ; ARROW KEY DEFINITONS FROM TCAP ; EDCURT: DB 0 ;0 INDICATES NO ARROW KEYS DW EDUP DB 0 DW EDDOWN DB 0 DW EDRIGHT DB 0 DW EDLEFT DB 0 ;END OF TABLE ; ;EDITOR BUFFERS ; EINDEX: DS 1 ;INDEX ENTRY EDERR: DS 1 ;ERROR FLAG EDRUN: DS 1 ;FLAG SAYING THAT EDITOR IS RUNNING ; ;Write Block to Disk ; EDITWR: CALL EDERCL ;CLEAR ERROR LINE CALL WRITE ;WRITE BLOCK CALL AT DB 23,15 ;MESSAGE CALL ILPRT DB 'Block Written',0 MVI A,0FFH ;SET ERROR STA EDERR JMP EDITCMD1 ; ;Enter ASCII Chars ; EDITALP: CALL EDERCL ;CLEAR ERROR LINE CALL AT DB 22,35 CALL ILPRT DB DIM,'Enter Text ( for Hex)',BRIGHT DB CR,LF,' --> ',0 CALL RDBUF1 ;INPUT TEXT WITHOUT PROMPT CALL EDPRCL ;CLEAR PROMPT LINE LDA EINDEX ;PT TO POSITION LXI D,TBUFF ;COMPUTE OFFSET ADD E MOV E,A MOV A,D ACI 0 MOV D,A ;DE PTS TO BYTE, HL PTS TO TEXT EDITA1: MOV A,M ;GET CHAR CPI CR ;EOL? JZ EDITA2 ;REFRESH SCREEN CALL GETVAL ;GET ASCII OR VALUE STAX D ;UPDATE BYTE INX H ;PT TO NEXT INPUT CHAR INR E ;PT TO NEXT BUFFER BYTE JNZ EDITA1 EDITA2: CALL EDPLOT ;REPLOT JMP EDITCMD1 ;DONE-REFRESH SCREEN ; ;Enter Numbers ; EDITHEX: CALL EDERCL ;CLEAR ERROR LINE CALL AT DB 22,35 CALL ILPRT DB DIM,'Enter Hex Numbers (#nn for Dec)' DB BRIGHT DB CR,LF,' --> ',0 CALL RDBUF1 ;INPUT TEXT WITHOUT PROMPT CALL EDPRCL ;CLEAR PROMPT LINE LDA EINDEX ;PT TO POSITION LXI D,TBUFF ;COMPUTE OFFSET ADD E MOV E,A MOV A,D ACI 0 MOV D,A ;DE PTS TO BYTE, HL PTS TO TEXT EDITH1: MOV A,M ;GET HEX DIGIT CPI CR ;EOL? JZ EDITA2 ;REFRESH SCREEN CPI ' ' ;SKIP SPACES JNZ EDITH2 INX H ;SKIP SPACE JMP EDITH1 EDITH2: PUSH D ;SAVE PTR CALL HEXIN ;GET VALUE AND POSITION HL MOV A,E ;... IN A POP D ;GET PTR STAX D ;PUT BYTE INR E ;ADVANCE TO NEXT BYTE JNZ EDITH1 JMP EDITA2 ;DONE-REFRESH ; ;CLEAR PROMPT LINE ; EDPRCL: CALL AT ;PROMPT LINE DB 22,35 MVI B,40 ;40 POSITIONS CALL EDPCL CALL AT ;USER INPUT DB 23,1 MVI B,79 ;79 POSITIONS EDPCL: CALL SPACE ;CLEAR PROMPT LINE WITH SPACES DCR B JNZ EDPCL RET ; ;Enter Command Line from Editor ; EDITCL: CALL EDERCL ;CLEAR ERROR LINE CALL CRLF ;NEW LINE JMP PRMPTE ;GET COMMAND LINE FROM USER ; ;Advance to Next Block ; EDITPLUS: CALL NXTSEC ;ADVANCE SECTORS EDITP1: PUSH H LHLD CURSEC XCHG CALL SETSEC ;SET SECTOR LHLD CURTRK XCHG CALL SETTRK ;SET TRACK POP H CALL READ ;READ IN BLOCK CALL CLCSUB ;CALCULATE GROUP DATA JMP EDITR ;REFRESH DATA ; ;Backup to Last Block ; EDITMINUS: CALL LSTSEC ;BACKUP BLOCK JMP EDITP1 ; ;Exit EDIT Mode ; EDITX: XRA A STA EDRUN ;EDITOR IS NOT RUNNING NOW CALL EDERCL ;CLEAR ERROR LINE JMP PRMPTR ; ;Exit DU3 ; EDCC: CALL EDERCL ;CLEAR ERROR LINE JMP EXIT ; ;EDIT MOVE: UP ; EDUP: CALL EDCCUR ;CLEAR CURSOR LDA EINDEX ;BACKUP INDEX BY 16 SUI 16 ; ;Common EDIT MOVE Routine - on input, A=new index ; EDMOVE: ANI 7FH ;MOD 128 STA EINDEX CALL EDCUR ;SET CURSOR JMP EDITCMD ; ;EDIT MOVE: DOWN ; EDDOWN: CALL EDCCUR ;CLEAR CURSOR LDA EINDEX ;INCREMENT INDEX BY 16 ADI 16 JMP EDMOVE ;COMMON ROUTINE ; ;EDIT MOVE: RIGHT ; EDRIGHT: CALL EDCCUR ;CLEAR CURSOR LDA EINDEX ;INCREMENT INDEX BY 1 INR A JMP EDMOVE ;COMMON ROUTINE ; ;EDIT MOVE: LEFT ; EDLEFT: CALL EDCCUR ;CLEAR CURSOR LDA EINDEX ;DECREMENT INDEX BY 1 DCR A JMP EDMOVE ;COMMON ROUTINE ; ;EDIT SUBROUTINE: EDCUR ; Position Editor Cursor at EINDEX ;EDIT SUBROUTINE: EDCCUR ; Clear Editor Cursor at EINDEX ; EDCUR: PUSH H ;SAVE HL MVI C,ECURS ;CURSOR CHAR CALL EDSETCUR CALL AT ;UPDATE DATA DB 2,75 LDA EINDEX ;PT TO BYTE AT CURSOR LXI H,TBUFF ADD L MOV L,A MOV A,H ACI 0 MOV H,A ;HL PTS TO BYTE AT CURSOR MOV A,M ;GET BYTE CALL HEX ;PRINT AS HEX CALL SPACE MOV A,M ;GET BYTE POP H ;RESTORE HL ANI 7FH ;MASK CPI 7FH ;7FH IS DOT JZ EDC7F CPI ' ' ;OUTPUT CHAR OR DOT JNC TYPE EDC7F: MVI A,'.' ;DOT JMP TYPE EDCCUR: MVI C,' ' ;CLEAR CURSOR EDSETCUR: CALL EDROW ;COMPUTE ROW ANI 0FH ;COMPUTE COL MOD 16 MOV B,A ;RESULT IN B ADD A ;*2 ADD B ;*3 ADI ECOL ;ADD IN COL DCR A ;SUBTRACT 1 MOV L,A ;COL POSITION SET CALL GOTOXY ;POSITION CURSOR MOV A,C ;OUTPUT CHAR JMP TYPE ; ;Compute Row from EINDEX ; EDROW: LDA EINDEX ;GET INDEX MOV B,A ;SAVE IN B RRC ;DIVIDE BY 16 RRC RRC RRC ANI 0FH ;MASK FOR LSB ONLY ADI EROW ;COMPUTE ROW MOV H,A ;ROW SET MOV A,B ;GET INDEX RET ; ;COMMAND: @ ;Repeat Previous Command Line ; PCMD: MOV A,M ;GET NEXT CHAR CPI CR ;SHOULD BE JZ PCMD1 CALL ILPRT DB CR,LF,'Warning: Remainder of Command Line after "@" Deleted',0 PCMD1: CALL ILPRT DB CR,LF,DIM,'Command --',BRIGHT,CR,LF,0 LHLD INBUF ;COPY INTO INBUF XCHG LHLD PINBUF ;GET PREVIOUS COMMAND 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 JNZ PCMD2 MVI A,LF ; CALL TYPE LHLD 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? JZ PCPR PUSH PSW ;SAVE A call cls cz crlf CALL ILPRT DB DIM,'Macro Definitions --',BRIGHT,0 POP PSW ;GET A CPI 'A' ;PRINT ALL MACROS? JZ 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 DIM,'Previous Command Line Definition --',BRIGHT DB CR,LF,'@: ',0 LHLD 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? JNZ 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,DIM,0 MOV A,D ;GET NUMBER ADI '0' ;CONVERT TO ASCII CALL TYPE ;PRINT CALL ILPRT DB ': ',BRIGHT,0 LHLD 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 JNZ 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 JC MNERR ;ERROR IF LESS CPI 10 ;RANGE? JNC 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 LHLD 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 cls cz crlf CALL ILPRT DB DIM DB ' -- Queue Information --',BRIGHT,CR,LF DB CR,LF DB 0 CALL QSTATS ;PRINT STATUS INFO CALL ILPRT DB CR,LF DB DIM DB ' -- Disk Information --',BRIGHT,CR,LF DB CR,LF DB DIM,'Disk Drive: ',BRIGHT,0 LDA DRIVE ADI 'A' ;CONVERT TO ASCII CALL TYPE ;PRINT DRIVE LETTER CALL ILPRT DB CR,LF,DIM,'Tracks: ',BRIGHT,0 LHLD MAXTRK ;PRINT NUMBER OF TRACKS INX H CALL DEC CALL ILPRT DB CR,LF,DIM,'Sectors/Track: ',BRIGHT,0 LHLD SPT ;PRINT NUMBER OF SECTORS/TRACK CALL DEC CALL ILPRT DB CR,LF,DIM,'Group Size: ',BRIGHT,0 LDA BLM ;PRINT SIZE OF A GROUP INR A MOV L,A MVI H,0 CALL DEC CALL ILPRT DB DIM,' Blocks/Group',BRIGHT DB CR,LF,DIM,'Total Groups: ',BRIGHT,0 LHLD DSM ;PRINT TOTAL NUMBER OF GROUPS ON A DISK CALL DEC CALL ILPRT DB CR,LF,DIM,'Directory Entries: ',BRIGHT,0 LHLD DRM ;PRINT NUMBER OF DIRECTORY ENTRIES INX H CALL DEC CALL ILPRT DB CR,LF,DIM,'System Tracks: ',BRIGHT,0 LHLD SYSTRK ;PRINT NUMBER OF SYSTEM TRACKS CALL DEC CALL SWAIT 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? JZ QSTAT ;STATUS REPORT CPI CR ;END OF LINE? JZ QSTAT INX H ;PT TO AFTER KEY CHAR PUSH H ;SAVE PTR CPI 'Z' ;ZERO QUEUE? JZ 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: LHLD 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 cls cz crlf CALL ILPRT DB DIM DB '** Queue Status Summary **' DB BRIGHT DB 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 CR,LF DB DIM,'Group Save Buffer Address: ',BRIGHT,0 PUSH H LHLD GBUFF ;BC=ADDRESS MOV B,H MOV C,L POP H CALL HEXB1 ;PRINT AS HEX CALL ILPRT DB ' Hex',CR,LF DB 0 CALL ILPRT DB DIM,'Address of Head of Queue: ',BRIGHT,0 LHLD QNXT ;PRINT ADDRESS OF HEAD OF QUEUE MOV B,H ;... ADDRESS IN BC MOV C,L CALL HEXB1 ;PRINT IN HEX CALL ILPRT DB ' Hex',CR,LF DB DIM,'Address of Tail of Queue: ',BRIGHT,0 LHLD QLST ;PRINT ADDRESS OF TAIL OF QUEUE MOV B,H MOV C,L CALL HEXB1 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 JNZ QSTAT1 MOV A,L CMP E JNZ QSTAT1 MOV H,B ;HL=BLOCK COUNT MOV L,C CALL DEC ;PRINT AS DECIMAL CALL ILPRT DB DIM,' Blocks Left in Queue',BRIGHT,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 JNZ 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 JZ 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 JNZ NNN ;NO: COUNTING XCHG ;GET COUNT SHLD TOGO ;SET COUNT ; NNN: LHLD TOGO ;GET CURRENT COUNT XCHG ;DE=CURRENT COUNT, HL=COUNT LIMIT LHLD 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 JNZ 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 JNZ 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 LHLD PINBUF ;SET PREVIOUS COMMAND TO NIL MVI M,CR ;CLEAR PREVIOUS COMMAND LHLD DIRECT ;SET FIRST AND LAST QUEUE ELEMENT PTRS SHLD QNXT SHLD QLST ; Initialize Default Macros -- new block by LHLD MTABL ;CLEAR MACRO TABLE MVI B,10 ;10 ENTRIES lxi d,imac0 ;point to beginning of default macro table initp1: push h ;save pointer to start of each macro initp2: ldax d ;get next initial macro character mov m,a ;store it in macro table inx d inx h cpi cr ;end of macro? jnz initp2 pop h ;retrieve pointer to start of this macro dcr b ;see if we've done all macros rz ;if so, return inr h ;point to next macro jmp initp1 ;INITP1: ; MVI M,CR ;STORE ; INR H ;PT TO NEXT PAGE ; DJNZ INITP1 ; RET ; End of Block Changed by ; ;Set up flags, etc, at initialization ;Find our way at initialization ; GETSTP: PUSH H LHLD INBUF ;PT TO INPUT BUFFER MVI M,CR ;INITIALIZE INPUT BUFFER POP H 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 JZ LGNODK CPI EOLCH ;NO REQUEST IF LOGICAL EOL JZ 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 JC 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 XCHG LHLD DIRECT ;DMA ADDR XCHG ;... IN DE ; ;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 JNZ 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? JZ 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.. JNZ MAPC1 ;..THE DISK CAPACITY.. MOV A,H CMP B ; MAPC1: POP H JZ MAPEND ;..AND WE ARE DONE PUSH H CALL GETGRP ;GET ANOTHER POP D ;SEE IF SAME CALL CTLCS ;ABORT? JZ MAPND2 MOV A,D CMP H JNZ MAPDIF MOV A,E CMP L JZ 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 JNZ MAPND1 JMP 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 JNZ 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 JMP FLIP ; NONAME: CALL ILPRT DB DIM,' ++ Free ++ ',BRIGHT,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? JC MAPN2H ;..NO, IN HEX CPI 7EH ;7E IS LEADIN ON SOME CRTS JC 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 LHLD DIRECT ;PT TO DIRECTORY ; GETGLP: PUSH H ;SAVE POINTER TO NAME MOV A,M ;PICK UP DN BYTE CPI 0E5H ;ERASED? JZ 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 JZ 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 JNZ 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 JZ 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 JNZ 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 JNZ 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? JZ QRESTOR CPI 'G' ;GROUP SAVE? JZ RESTRG LDA SAVEFL ;SAVE DONE PREVIOUSLY? ORA A JZ NOSAVE ;NONE TO SAVE PUSH H LHLD 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 JZ 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? JNZ SEARCH ;..YES LHLD 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 JZ 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? JZ SREQU CPI EOLCH ;LOGICAL EOL? JNZ 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 JNZ 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 JNZ VIEWLP INR E ;DFLT=1 ; VIEWLP: LXI H,TBUFF ;TO DATA ; VEWCHR: CALL CTLCS ;ABORT? JZ VEWEND MOV A,M ;GET NEXT CHAR CPI 1AH ;EOF? JZ VEWEOF ANI 7FH ;MASK CPI 7EH ;ESC CHAR FOR H1500 JNC VIEWHX ;SHOW RUBOUT AND TILDE AS HEX CPI ' ' JNC VIEWPR CPI CR ;CR PASS JZ VIEWPR CPI LF ;LF PASS JZ VIEWPR CPI TAB ;TAB PASS JZ VIEWPR ; VIEWHX: MOV A,M ;NOT ASCII...PRINT AS CALL BHEX JMP VIEWNP ; VIEWPR: CALL TYPE ; VIEWNP: INR L JNZ VEWCHR DCR E JZ VEWEND PUSH D ;SAVE COUNT CALL NXTSEC LHLD CURSEC XCHG CALL SETSEC LHLD CURTRK XCHG CALL SETTRK CALL READ POP D ;RESTORE COUNT JMP VIEWLP ; VEWEOF: CALL ILPRT DB CR,LF,DIM,' ++ EOF ++',BRIGHT,CR,LF,0 ; VEWEND: POP H CALL CRLF JMP CLCGRP ; ;COMMAND: A or D ;Dump in hex or ASCII ; DUMP: LDA WRFLG ORA A JNZ 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? JZ DUMPDF ;DFLT CPI CR ;PHYSICAL EOL? JNZ DMPNDF ; ;Use default ; DUMPDF: LXI B,TBUFF LXI D,0FFH JMP DUMP1 ; DMPNDF: CALL DISP MOV B,D MOV C,E CPI CR JZ DUMP1 CPI EOLCH JZ DUMP1 INX H ;SKIP SEPCH CALL DISP ; ;BC = start, DE = end ; DUMP1: PUSH H ;SAVE COMMAND POINTER MOV H,B MOV L,C ; DUMPLP: CALL DUMPHL ;PERFORM DUMP OF DIR ENTRY AT HL POP H ;RESTORE HL JMP PROMPT ; ; PERFORM DUMP AT HL ; DUMPHL: CALL STNDOUT ;DIM MOV A,L ANI 7FH CALL HEX ;PRINT HEX VALUE CALL STNDEND ;BRIGHT CALL SPACE CALL SPACE LDA DUMTYP CPI 'A' JZ DUMPAS PUSH H ;SAVE START ; ; DUMP 16 BYTES STARTING AT HL (CHECK FOR DE TERMINATION) ; 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 ;CHECK FOR END OF BYTES TO DUMP CMP L JZ DPOP INX H MOV A,L ;CHECK FOR END OF 16 BYTES ANI 0FH JNZ DHEX ; DPOP: CALL CTLCS ;ABORT? JZ PRMPTR LDA DUMTYP ;CHECK FOR ASCII ALSO CPI 'H' JZ DNOAS ;HEX ONLY POP H ;GET START ADDR ; ; DUMP ASCII CHARS - HL PTS TO FIRST BYTE ; DUMPAS: CALL ASTER ;PRINT FIRST ASTERISK TO SEPARATE TEXT ; DCHR: MOV A,M ;GET CHAR ANI 7FH CPI ' ' JC DPER CPI 7FH ;TRAP DEL JC DOK ; DPER: MVI A,'.' ;PRINT PRINTING CHAR ; DOK: CALL TYPE ;PRINT CHAR MOV A,E ;CHECK FOR END OF DUMP CMP L JZ DEND INX H MOV A,L ;CHECK FOR END OF 16 BYTES ANI 0FH JNZ DCHR ; ; END OF ASCII DUMP ; DEND: CALL ASTER ;PRINT ENDING ASTERISK CALL CRLF ;NEW LINE PUSH D CALL CTLCS ;ABORT? POP D JZ PRMPTR MOV A,E ;DONE WITH DUMP? CMP L JNZ DUMPHL RET ; ; NO ASCII DUMP ; DNOAS: POP B ;CLEAR STACK (START ADDRESS OF DUMP) CALL CRLF ;NEW LINE MOV A,E ;DONE WITH DUMP? CMP L JNZ DUMPHL RET ; ;COMMAND: G ;Position ; POS: PUSH PSW MOV A,M CPI EOLCH ;LOGICAL EOL? JZ POSINQ CPI CR ;PHYSICAL EOL? JNZ POSOK ; POSINQ: POP PSW JMP INQ ; POSOK: POP PSW CPI 'T' ;TRACK? JZ POSTKD CPI 'S' ;SECTOR? JZ 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 JMP 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 JNZ POSDLP ANI 1 ;GET GROUP MOV L,A ;SETUP FOR POSGP2 MVI H,0 SHLD GROUP XCHG ; 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 ; ;Position to Group ; POSGPH: CALL HEXIN ;GET PARAMETER ; ;Position to Group Numbered in DE and Print Position ; POSGRP: CALL DEGROUP ;GOTO GROUP JC OUTLIM JMP INQ ;PRINT POSITION ; ;Position to Group Numbered in DE ; Return with Carry Set if Out of Limits ; DEGROUP: PUSH H LHLD DSM ;CHECK FOR WITHIN BOUNDS CALL SUBDE POP H RC PUSH H ;SAVE HL XCHG SHLD GROUP ;SET GROUP NUMBER XCHG XRA A STA GRPDIS ;SET ZERO DISPLACEMENT CALL GTKSEC ;CONVERT GROUP TO SECTOR/TRACK CALL SETTRK ;SET TRACK XCHG CALL SETSEC ;SET SECTOR CALL READ ;READ BLOCK XRA A ;SET NC AND FLAG STA NOTPOS ;NOW POSITIONED POP H RET ; ;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 JNZ 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 JC 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 MVI A,'?' STAX D ;LOOK IN ALL EXTENTS MVI A,'D' ;SET TYPE OF DUMP TO FULL STA DUMTYP PUSH H ;SAVE PTR TO NEXT CHAR LXI D,FCB MVI C,SRCHF CALL BDOS INR A JNZ FLOK STA DIRPOS ;GRP 0 IF NOT FOUND CALL ILPRT DB '++ File Not Found ++',CR,LF,0 POP H ;RESTORE PTR TO NEXT CHAR 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 CALL DUMPHL ;PRINT DIR ENTRY LXI D,FCB ;LOOK FOR NEXT EXTENT MVI C,SRCHN CALL BDOS INR A JNZ FLOK POP H ;RESTORE PTR TO NEXT CHAR JMP PROMPT ; MVNAME: MOV A,M ;GET NEXT CHAR OF FILE NAME/TYPE CPI '.' ;END OF FILE NAME? JZ MVIPAD ;PAD OUT IF SO CPI CR ;END OF ENTRY? JZ PAD ;PAD OUT IF SO CPI EOLCH ;END OF ENTRY? JZ 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? JZ PLUSGO ;..YES, DFLT TO 1 CPI EOLCH JZ PLUSGO CALL DECIN ;GET # MOV A,D ORA E JNZ 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 JNZ 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? JZ MINGO ;..YES, DFLT=1 CPI EOLCH JZ MINGO CALL DECIN ;..NO, GET ## MOV A,D ORA E JNZ MINGO LXI D,1 ;ASSUME 1 ; MINGO: CALL LSTSEC ;BACK UP ONE SECTOR DCX D ;COUNT DOWN ON NUMBER OF TIMES TO BACKUP MOV A,D ORA E JNZ MINGO JMP PLUSMI ;READ BLOCK ; ;Go to last sector ; Wrap around to last sector of previous track or last sector of ; last track, as necessary ; LSTSEC: PUSH H LHLD CURSEC ;BACK UP SECTOR DCX H MOV A,H ORA L JNZ LSEC1 LHLD CURTRK ;BEYOND SECTOR ZERO, SO BACK UP TRACK MOV A,H ORA L JNZ LSEC0 LHLD MAXTRK ;WRAP TO END OF DISK SHLD CURTRK LHLD MAXSEC JMP LSEC1 ; LSEC0: DCX H SHLD CURTRK LHLD SPT ;GET NUMBER OF SECTORS/TRACK ; LSEC1: SHLD CURSEC ;SET NEW CURRENT SECTOR POP H RET ; ;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 JNC NEXTOK LHLD CURTRK ;BEYOND END OF TRACK, SO INCR CURRENT TRACK INX H XCHG LHLD MAXTRK ;SEE IF BEYOND END OF DISK CALL SUBDE JNC 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 JC NOGRP CALL ILPRT ;PRINT GROUP NUMBER IF NOT IN SYSTEM TRACKS DB DIM,'Group = ',BRIGHT,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 DIM,' Track = ',BRIGHT,0 LHLD CURTRK CALL DEC ;TRACK NUMBER IN DECIMAL CALL ILPRT ;PRINT SECTOR NUMBER DB DIM,', Sector = ',BRIGHT,0 LHLD CURSEC CALL DEC ;SECTOR NUMBER IN DECIMAL CALL ILPRT ;PRINT PHYSCIAL SECTOR NUMBER DB DIM,', Physical Sector = ',BRIGHT,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 JNZ 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 JMP CHGAH ; CHGNTH: CPI SEPCH JNZ WHAT ; CHGAH: POP PSW CPI 'H' ;HEX? JZ 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 JZ 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? JZ 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 JZ CHHNTH ;..NO. CMP E ;..YES, DONE? JZ PROMPT LHLD HEXAD ;..NO: MORE ; CHHNTH: INR E JNZ 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 JNZ 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 does not print MS Byte if DSM shows small disk size ; HEXB1 prints BC regardless ; HEXB: LDA DSM+1 ORA A JZ HEXX HEXB1: 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? JC 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 JNC 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 a dim '|' ; ASTER: CALL STNDOUT ;DIM MVI A,'|' CALL TYPE JMP STNDEND ;BRIGHT ; ;Inline print routine ; Print Chars ending in 0 pted to by Return Address; return to byte after ; ILPRT: XTHL ;PT TO STRING ILPLP: CALL CTLCS ;ABORT? JZ PRMPTR MOV A,M ;GET CHAR ; CPI 1 ;PAUSE? -- ^A ; JNZ ILPOK ; CALL CONIN ;WAIT FOR ANY CHAR ; CPI 3 ;ABORT? ; JZ PRMPTR ; JMP ILPNX ; ;ILPOK: CPI DIM ;GOTO DIM? JZ ILPDIM CPI BRIGHT ;GOTO BRIGHT? JZ ILPBRI CALL TYPE ;PRINT CHAR JMP ILPNX ILPDIM: CALL STNDOUT ;ENTER STANDOUT MODE JMP ILPNX ILPBRI: CALL STNDEND ;EXIT STANDOUT MODE ; ILPNX: INX H ;PT TO NEXT MOV A,M ;GET IT ORA A ;DONE? JNZ 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 JNZ 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 ;INIT VALUE MOV A,M CPI '#' ;DECIMAL? JZ HDIN ;MAKE DECIMAL ; HINLP: MOV A,M ;GET CHAR CALL UPCASE ;CAPITALIZE CPI CR ;EOL? RZ CPI EOLCH ;EOL? RZ CPI SEPCH RZ CPI ' ' ;SPACE? RZ CPI '-' ;'THRU'? RZ CPI '>' RZ INX H ;PT TO NEXT CHAR CPI '0' ;RANGE? JC WHAT CPI '9'+1 ;RANGE? JC 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 JMP 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? JNZ DINLP INX H ; PT TO DIGIT JMP 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 JMP DINLP ; ;Read in a console buffer ; RDBUF: CALL ILPRT ;PRINT PROMPT DB CR,LF,'DU3 ',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 ; ;ENTRY POINT TO READ BUFFER WITHOUT PROMPT ; RDBUF1: LHLD INBUF ;USE CP/M READLN DCX H DCX H XCHG MVI C,10 PUSH D CALL BDOS POP D INX D ;PT TO CHAR COUNT LDAX D ;GET CHAR COUNT MOV B,A ;CHAR COUNT IN B INX D ;PT TO INPUT LINE XCHG ;... IN HL ADD L ;ADD CHAR COUNT TO HL MOV L,A MOV A,H ACI 0 MOV H,A MVI A,CR ;STORE ENDING CR MOV M,A ;SET CR CALL TYPE ;ECHO IT MVI A,LF ;ECHO.. CALL TYPE ;..LF LHLD 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? JZ WAIT ;SAME AS USER DELAY DCR A ;COUNT DOWN STA PAGFLG JMP CRLF ; ;Delay Routine ; SWAIT: CALL AT DB 23,5 ;POSITION CURSOR JMP WAIT0 WAIT: CALL CRLF ;NEW LINE WAIT0: PUSH H CALL ILPRT DB DIM,'Type Any Character to Continue or ^C to Abort - ',BRIGHT,0 POP H CALL CONIN ;GET RESPONSE CPI 'C'-40H ;^C? JZ 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 JNZ TYPE2 ;Tabulate TYPTAB: MVI A,' ' ;PRINT SPACE CALL TYPE LDA TABCOL ;GET COL COUNT ANI 7 ;DONE? JNZ TYPTAB JMP TYPRET ; ;Filter out control characters to ;prevent garbage during view of file ; TYPE2: CPI ' ' JNC TYPEQ CPI CR JZ TYPEQ CPI LF JNZ 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 JNZ TYPNCR MVI A,0 ;RESET TAB COLUMN IF STA TABCOL JMP TYPLST ; TYPNCR: CPI ' ' ;CTL CHAR? JC 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 JNC NOTSYS ;IF NO CARRY FOR SUBDE, WE ARE NOT IN SYSTEM TRACKS LDA FIRST0 ;SEE IF FIRST SEC 0 ORA A JNZ GSTSEC ;NO, JUMP AWAY DCX H ;YES, SO DECREMENT JMP 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 JNZ 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? JZ 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 JNZ 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? JZ 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 cls cz crlf call helpban CALL ILPRT DB DIM,'Introductory HELP on DU3 (Disk Utility)',BRIGHT,CR,LF DB ' The DU3 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 DU3 user. This same list is invoked internally by the' DB CR,LF DB '? Command of DU3. For additional information on disk' DB CR,LF DB 'structures and how to use DU3 in general, refer to the' DB CR,LF DB 'file DU3.HLP.',CR,LF,0 MVI A,0FFH ;A=0FFH STA IHFLG ;SET INITIAL HELP CALL SWAIT JMP HELP1 ;PROCESS NORMALLY HELP: XRA A ;A=0 STA IHFLG ;SET NO INITIAL HELP HELP1: call cls cz crlf call helpban ;print help banner CALL ILPRT DB 'Operands in brackets [...] are optional' DB CR,LF,CR,LF DB ' @ ',DIM,'Repeat Previous Non-@ Command Line' DB BRIGHT,CR,LF DB ' +[nn] ',DIM,'Step In [nn (decimal)] Sectors' DB BRIGHT,CR,LF DB ' -[nn] ',DIM,'Step Out [nn (decimal)] Sectors' DB BRIGHT,CR,LF DB DIM DB ' Note: + or - need not be followed by a "," to ' DB 'delimit commands.' DB BRIGHT DB CR,LF DB ' # ',DIM,'Print Disk Parameters for Current Drive' DB BRIGHT DB CR,LF DB ' =xxx ',DIM DB 'Search for ASCII xxx from Current Sector' DB BRIGHT DB CR,LF DB DIM DB ' Note: upper/lower case matters. Use for hex:' DB BRIGHT DB CR,LF DB DIM DB ' To find "IN 0" use: =<0> or' DB BRIGHT DB CR,LF DB DIM DB ' "(tab)H,0(CR)(LF)" use: =<9>H,0' DB BRIGHT DB CR,LF DB ' *[nn] ',DIM,'Repeat [nn (decimal) times]' DB BRIGHT,CR,LF DB ' ! ',DIM,'Pause for User',BRIGHT,CR,LF DB ' :ntext ',DIM,'Define ''text'' to be Macro n' DB BRIGHT,CR,LF DB ' n ',DIM,'Perform Macro n, 0<=n<=9',BRIGHT,CR,LF DB ' :Pn ',DIM,'Print Macro n, 0<=n<=9',BRIGHT DB CR,LF DB ' :Px ',DIM DB 'Print All Macros if x=A or Print Prev Line if x=@' DB BRIGHT DB 0 CALL SWAIT call cls cz crlf call helpban CALL ILPRT DB ' A[ff,tt] ',DIM,'ASCII Dump',BRIGHT DB CR,LF DB ' C ',DIM,'Change:',BRIGHT DB CR,LF DB ' CHaddr byte byte... (hex)' DB CR,LF DB ' ',DIM,'or',BRIGHT DB ' CAaddr data... (Ascii)' DB CR,LF DB DIM DB ' Allowed for imbedded hex.' DB BRIGHT DB CR,LF DB ' ',DIM,'or',BRIGHT DB ' CHfrom-thru byte e.g. ch0-7f e5' DB CR,LF DB ' ',DIM,'or',BRIGHT,' CAfrom-thru byte' DB CR,LF DB ' D[ff,tt] ',DIM,'Dump (Hex and ASCII)',BRIGHT DB CR,LF DB ' E ',DIM,'DU3 Editor',BRIGHT,CR,LF DB ' ',DIM,' Note: Rest of Command Line ' DB 'is Flushed',BRIGHT,CR,LF DB ' Ffn.ft ',DIM,'Find File',BRIGHT DB CR,LF DB ' Gnn ',DIM,'CP/M Allocation Group nn (hex)' DB BRIGHT,CR,LF DB ' H[ff,tt] ',DIM,'Hex Dump',BRIGHT DB CR,LF DB ' L[d] ',DIM,'Log in Current Drive or Drive d' DB BRIGHT,CR,LF DB ' M[nn] ',DIM,'Map [from group nn (hex)]' DB BRIGHT DB 0 CALL SWAIT call cls cz crlf call helpban CALL ILPRT DB ' N ',DIM,'Load New Disk',BRIGHT,CR,LF DB ' P ',DIM,'Toggle Printer Switch',BRIGHT,CR,LF DB ' Q ',DIM,'Queue Status;',BRIGHT,CR,LF DB ' QZ ',DIM,'Zero (Empty) Queue',BRIGHT,CR,LF DB ' QSfn.ft ',DIM,'Save Queue as a File on Disk',BRIGHT DB CR,LF DB ' < ',DIM,'Save Current Block into Temp',BRIGHT DB CR,LF DB ' > ',DIM,'Restore Temp Block',BRIGHT,CR,LF DB ' B ',DIM,'Restore Queue Block',BRIGHT,CR,LF DB ' G[n] ',DIM,'Restore Queue Group',BRIGHT,CR,LF DB ' Snn ',DIM,'Sector nn (decimal)',BRIGHT,CR,LF DB ' Tnn ',DIM,'Track nn (decimal)',BRIGHT,CR,LF DB ' Unn ',DIM,'Set User nn (decimal) for Find command' DB BRIGHT,CR,LF DB ' V[nn] ',DIM,'View [nn (decimal)] ASCII Blocks',BRIGHT DB CR,LF DB ' R ',DIM,'Read Current Block',BRIGHT,CR,LF DB ' W ',DIM,'Write Current Block',BRIGHT,CR,LF DB ' X ',DIM,'Exit Program',BRIGHT,CR,LF DB ' Z[nn] ',DIM,'Sleep [nn (decimal) seconds]',BRIGHT DB 0 CALL SWAIT call cls cz crlf call helpban CALL ILPRT DB DIM,'Command Line is of the form: ',BRIGHT,'DU3 du?',CR,LF DB ' ',DIM,'"d" is Logged-In Disk, "u" is Current User' DB BRIGHT,CR,LF DB CR,LF DB 'Ctrl-C ',DIM,'Cancel a function',BRIGHT,CR,LF DB 'Ctrl-S ',DIM,'Suspend output',BRIGHT,CR,LF DB '"," ',DIM,'Separate commands',BRIGHT,CR,LF DB CR,LF DB DIM,'Examples:',BRIGHT,' g0 ',DIM,'and',BRIGHT DB ' +,d,z2,*' DB CR,LF DB DIM,'Causes:',BRIGHT,CR,LF DB ' 1. Position to group 0',CR,LF DB ' 2. Loops on step in, dump, sleep 2 sec',CR,LF DB ' until control-c is typed',CR,LF,CR,LF DB '"nn" usage varies with command as follows:',CR,LF DB ' +, -, *, T, S, U, V, Z ',DIM,'nn in Decimal' DB BRIGHT,CR,LF DB ' ',DIM,'(use #nn for Hex)' DB BRIGHT,CR,LF DB ' G, M ',DIM,'nn in Hexadecimal' DB BRIGHT,CR,LF DB ' ',DIM,'(use #nn for Decimal)' DB BRIGHT,CR,LF DB CR,LF DB '"ff" and "tt" are in Hexadecimal (use #ff or #tt for Decimal)' DB 0 CALL SWAIT LDA IHFLG ;INITIAL HELP? ORA A ;0=NO JNZ EXIT1 ;RETURN TO CP/M IF SO JMP PRMPTR ;NEW LINE INPUT IF NOT helpban: call ilprt DB ' ',DIM,'-- DU3 Command Summary --',BRIGHT DB CR,LF,CR,LF,0 ret ; ;COMMAND: X ;Exit to CP/M ; EXIT: call dinit ;deinit terminal JMP BASE ;WARM BOOT ; ;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 JZ 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 JNC COSKIP INR C ; COSKIP: DCR B JNZ 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 JNZ MULCON LXI H,0 ;FILTER SPECIAL CASE JMP MLDONE ; OF MULTIPLY BY 0 ; MULCON: DCX B MOV D,H MOV E,L ; MULTLP: MOV A,B ORA C JZ MLDONE DAD D DCX B JMP 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 ;*********************************** ; ; DU3 Command Table ; ;*********************************** CMDTBL: DB ' ' ;null command DW PROMPT ; 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 'E' DW EDIT ; 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' 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 ; clock: ds 1 ;clock speed pagsiz: ds 1 ;page size muser: ds 1 ;max user mdisk: ds 1 ;max disk STKSAV: DS 2 ;SAVE HL VALUE DUTSTK: DS 2 ;OLD CP/M STACK POINTER; TOP OF DU3 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 2 INBUF: DS 2 ;INPUT LINE BUFFER PINBUF: DS 2 ;PREVIOUS CONTENTS OF INPUT BUFFER CTEMP: DS 2 ;BUILD NEW COMMAND LINE BUFFER CTEMPX: DS 2 ;END OF CTEMP MTABL: DS 2 ;10 PAGES FOR 10 MACROS GBUFF: DS 2 DIRECT: DS 2 ; END