;DISK UTILITY - By Ward Christensen ;DU.ASM V6.1 EDIT 00 ; FALSE EQU 0 TRUE EQU NOT FALSE ; STDCPM EQU TRUE ;<---- HEATH EQU NOT STDCPM ; IF STDCPM MAXTRK EQU 77 ;MAX TRK # BASE EQU 0 ;BASE ADDR OF CP/M TRKSIZE EQU 26 ;SECTORS PER TRACK SYSTRK EQU 2 ;# OF SYSTEM TRACKS ENDIF ; IF HEATH MAXTRK EQU 40 BASE EQU 4200H ;0 FOR REGULAR CP/M TRKSIZE EQU 20 ;SECTORS/TRACK SYSTRK EQU 3 ;# OF SYSTEM TRACKS ENDIF ; ;N-O-T-E IF YOU HAVE A SYSTEM WITH ;OTHER THAN 76 OR 40 TRACKS, (WHICH ARE ;AUTOMATICALLY HANDLED) YOU MIGHT WANT ;TO CHANGE THE ERROR MESSAGE "NOT IN ;TRKS 0-76" AT LABEL "SETTRK". ; ; 8/6/78 ;ORIGINALLY WRITTEN TO RECONSTRUCT BLOWN ;DISKS ON CBBS VIA REMOTE ACCESS ; ; ---------------- ;Sorry for the lack of comments in the code ;portion of this program - it was just hacked ;together to satisfy my needs, but lots of ;other people found it useful. Its external ;documentation is good, but its sadly lacking ;comments on the instructions. ; ---------------- ; ; 11/12/78 WLC ;ADD LOGIN COMMAND ; ; 11/26/78 WLC ;ADD DISK # TO LOGIN COMMAND ; ; 02/25/79 WLC ;PUT SECTOR READ INTO "S" COMMAND ; ; 10/10/79 WLC ;SAVE REGS IN BIOS CALLS ;TRANSLATE INPUT TO UPPER CASE ;ADD COMMANDS: < SAVE SECTOR ; > RESTORE SECT ; / REPEAT ;ALLOW CHANGE FROM-THRU ; 01/06/80 WLC ;REWRITE "F" COMMAND ; 01/07/79 ;ADD VIEW COMMAND ; 01/08/80 ;REPOSITION AFTER "M" COMMAND ; 02/12/80 ;MOD FOR HEATH CP/M ; 02/24/80 ;MOD LOGIN COMMAND TO NOT REALLY DO LOG, JUST ;DRIVE SELECT ; 05/21/80 ;MAKE SECTOR, TRACK, BE DECIMAL, NOT HEX. ;ALSO DIS-ALLOW A READ UNTIL POSITIONED. ;(DU OTHERWISE NOT IN SYNC WITH CP/M) ; 06/22/80 ;Put in "Q" command. Fix so "P" (printer) ;mode outputs L/F's. ; CR EQU 0DH LF EQU 0AH TAB EQU 09H ; ;Any valid command string may be placed as an ;operand of the original DU command, i.e.: ; ; DU G0;D;G2;=OK<1A>;D ; ;Functions supported: ; ; Tnn Seek to track nn (Decimal) (no read) ; Snn Position to sector nn (decimal), and read ; Gnn Position to group nn and read. ; G Shows current position ; V Views the current sector. ; (assumes ASCII data) ; Vnn Views nn sectors ; Fname print directory for file "name", ; then positions to it's directory ; sector. (does N-O-T position correctly ; with CP/M 2.0: use G0;=FOO ASM ; for example, to find the file. ; ; =string Ascii search, starting at current ; sector. hex may be imbedded, ; or used alone: To find "IN 0FEH": ; = ; ; L Re-logs in the current disk. You may pull ; out a disk, put in a new, and "L" just ; to log it in (prevents CP/M 1.4 ; from getting R/O errors). (hmmm, on second ; thought, I'm not doing any BDOS calls ; anyway, so no R/O errors COULD occur.. ; owell, better safe than sorry) ; ; Lx Logs in disk 'x', such as: LB ; ; D Dump sector, hex + ASCII ; A Dump sector, ASCII only ; H Dump sector, hex only ; ;note all dump commands (D, A, H) may be optionally ; followed by a starting and ending address: ; D0,7F is the same as just D ; D3,5 ; A20,3F ; ; CHaddr,val,val,val... change hex in sector ; CAaddr,char string... change ASCII in sector ; NOTE that may be hex imbedded ; in the Ascii: ca0,OK<1a> ; ; ----> Use W to write changes to disk. ; Note that the C command echoes ; the overlaid data for verification. ; ; CHaddr-addr,byte ; or CAaddr-addr,byte repeats a change ; ; # (Used by Ward to set the sector ; order table to 1,2,3,4,5... ; for my strange disks) ; ; + advance 1 sector (if below track 2, ; this advances to next numerical, if ; 2 or >, advances based on CP/M's normal ; sector scrambling algorithm, i.e. so + ; will get the next logical sector of the file ; ; - backs up 1 logical sector ; ; note + and - may take an amount: ; for example, +F steps in 15 sectors ; ; ? Gives command summary ; ; M Dumps a map of the group allocations ; for files. ; Mn Shows which file is allocated to ; group "n". ; ; Q Preceeding any command makes DU run ; in "Quiet" mode - no msgs to console ; except in case of a disk error. ; ; R Reads the sector currently positioned to ; into memory. Note R (Read) is implicit in ; the G, +, and - commands, but N-O-T in the ; S and T commands (I did it because I was ; tired of disk reading after T command before ; I had a chance to issue the S command) ; ; W Write back the current sector (N-O-T-E may ; not be used after an F command, as CP/M was ; used to find the file in the directory ; ; X Exit back to CP/M (Must press return). Ctl-c ; was too easy to hit over modem lines, so I ; decided on 2-byte (X, CR) to exit. ; ; P Toggle printer switch on/off ; ; Z Sleep - causes the program to pause, such ; as to look at a dump. Z is 1 sec. Znn ; is nn tenths of a second on a 2 MHz 8080. ; ; < Saves current sector in a save buffer ; ; > Gets saved buffer. < and > may be used ; to move a sector to another place. ; ; / Repeats entire command. Defaults ; or /nn to "forever". NN may be 2 to 254 ; ;multiple commands may be separated by ";" ; ;Example: the following commands will erase the ; b disk directory to all E5's: ; ; lb log in b drive ; g0 position to directory. ; ch0-7f,e5 fill with e5 ; < save the sector ; >;w;+;/16 restore, write, next, ; repeat 16 ; ;----This could be shortened to: ; ; lb;g0;ch0-7f,e5;< ; >;w;+;/16 ; ORG BASE+100H LXI SP,STACK ;EXITS VIA JMP 0 ;SET UP LOCAL JMPS TO BIOS LHLD BASE+1 ;WARM BOOT POINTER LXI D,3 DAD D SHLD VCONST+1 DAD D SHLD VCONIN+1 DAD D SHLD VCONOUT+1 DAD D ;LIST SHLD VLIST+1 DAD D ;PUNCH DAD D ;RDR DAD D SHLD VHOME+1 DAD D SHLD VSELDK+1 DAD D SHLD VSETTRK+1 DAD D SHLD VSETSEC+1 DAD D SHLD VSETDMA+1 DAD D SHLD VREAD+1 DAD D SHLD VWRITE+1 CALL ILPRT DB 'DISK UTILITY (DU) V6.1 06/22/80',CR,LF DB CR,LF,'Type ? for help' DB CR,LF,'Type X to exit' DB CR,LF,0 LXI H,BASE+80H ;TO INPUT BUFF MOV A,M ORA A JZ PROMPTR ;NO COMMAND ; ;GOT INITIAL COMMAND, SET IT UP ; MOV B,A ;SAVE LENGTH DCR B JZ PROMPTR LXI D,INBUF INX H ;SKIP LEN INX H ;SKIP ' ' CALL MOVE MVI A,CR STAX D LXI H,INBUF JMP PROMPTI ; PROMPTR XRA A STA QFLAG ;NOT QUIET CALL RDBUF PROMPTI MVI A,255 STA TOGO ;LOOP COUNT FOR "/" PROMPT LXI SP,STACK XRA A ;ZERO 2-UP PRINT STA TWOUP ;..SWITCH MVI A,1 STA FTSW ;TELL SEARCH NOT TO INCR PUSH H LXI H,BASE+100H SHLD BUFAD ;FOR RDBYTE POP H CALL CTLCS ;ABORT? JZ PROMPTR ;..YES, READ BUFFER ;DO WE HAVE TO POSITION IN DIRECTORY AFTER FIND? LDA FINDFLG ORA A JNZ POSDIR ;POSITION IN DIRECTORY MOV A,M CPI CR JZ PROMPTR CPI ';' ;LOGICAL CR? INX H JZ PROMPT CALL UPCASE STA DUMTYPE ;TYPE OF DUMP (A,D,H) CPI '!' ! JZ WARDSK ;<----DON'T USE CPI '+' ! JZ PLUS CPI '-' ! JZ MINUS CPI '=' ! JZ SEARCH CPI '<' ! JZ SAVE CPI '>' ! JZ RESTORE CPI '?' ! JZ HELP CPI 'A' ! JZ DUMP CPI 'C' ! JZ CHG CPI 'D' ! JZ DUMP CPI 'F' ! JZ POSFIL CPI 'G' ! JZ POS CPI 'H' ! JZ DUMP CPI 'L' ! JZ LOGIN CPI 'M' ! JZ MAP CPI 'P' ! JZ PRINTFF CPI 'Q' ! JZ QUIET CPI 'R' ! JZ DOREAD CPI 'S' ! JZ POS CPI 'T' ! JZ POS CPI 'V' ! JZ VIEW CPI 'W' ! JZ DOWRITE CPI 'X' ! JZ BASE CPI 'Z' ! JZ SLEEP CPI '/' ! JZ REPEAT ; WHAT XRA A STA QFLAG ;NOT QUIET CALL ILPRT DB '?',0 JMP PROMPTR ; ;QUIET MODE ; QUIET STA QFLAG ;NOW QUIET JMP PROMPT ; ;REPEAT BUFFER CONTENTS ; REPEAT CALL DECIN ;NN SPECIFIED? MOV A,E ORA A JZ NNN ;NO. LDA TOGO ;FIRST TIME? CPI 0FFH ;WAS IT 0FFH? JNZ NNN ;NO: COUNTING MOV A,E ;GET COUNT STA TOGO ;SET COUNT NNN LXI H,INBUF ;READY TO REPEAT LDA TOGO CPI 0FFH JZ PROMPT ;CONTINUOUS DCR A ;COUNT DOWN STA TOGO JNZ PROMPT JMP PROMPTR ;RESET ; ;TOGGLE PRINT FLAG ; PRINTFF LDA PFLAG XRI 1 STA PFLAG JMP PROMPT ; ;SLEEP ROUTINE, IN TENTHS OF A SEC ; SLEEP CALL HEXIN ;GET COUNT IF ANY MOV A,E ;ANY? ORA A JNZ SLEEPLP MVI E,10 SLEEPLP LXI B,8000 ;APPROX .1 SEC @ 2MHz SLEEP2 DCX B MOV A,B ORA C JNZ SLEEP2 PUSH D CALL CTLCS POP D JZ PROMPTR DCR E JNZ SLEEPLP JMP PROMPT ; ;CHECK FOR CONTROL-C OR S ; CTLCS CALL CONST INR A RNZ ;NO CHAR CALL CONIN ANI 1FH ;ALLOW ASCII CPI 'S'-40H CZ CONIN CPI 'C'-40H RET ;0 SET IF CTL-C ; LOGIN EQU $ ; MVI C,RESETDK ;COMMENTED OUT- ; PUSH H ;DON'T BOTHER.. ; CALL BDOS ;TELLING CP/M ; POP H MOV A,M ;DISK REQ? LXI D,0 CPI CR JZ LGNODK CPI ';' JZ LGNODK CALL UPCASE INX H SUI 'A' MOV C,A PUSH H VSELDK CALL $-$ ;ADDR FILLED IN BY INIT JMP LOGGED ; LGNODK EQU $ ; MVI C,SELDK PUSH H ; CALL BDOS LOGGED POP H CALL NOWRITE JMP PROMPT ; ;READ IN THE DISK DIRECTORY ; READDIR PUSH H CALL NOWRITE ;POSITIONING LOST MVI A,SYSTRK STA CURTRK MVI A,1 STA CURSEC MVI B,16 ;# OF SECTORS LXI D,DIRECT ;DMA ADDR RDIRLP PUSH B PUSH D MOV B,D MOV C,E CALL VSETDMA LDA CURTRK CALL SETTRK LDA CURSEC CALL SETSEC CALL READ CALL NEXTSEC POP D POP B LXI H,80H DAD D XCHG DCR B JNZ RDIRLP LXI B,BASE+80H CALL VSETDMA POP H RET ; ;MAP THE DIRECTORY ; MAP CALL READDIR ;READ IN DIRECTORY MVI C,2 ;DFLT START CALL HEXIN PUSH H ;SAVE INBUF PTR MOV A,E ;GET START ORA A ;NOTHING? JZ MAPDF ;..YES, DFLT MOV C,E MAPDF MOV A,C CALL HEX MVI A,'-' CALL TYPE CALL GETGRP ;GET GRP(C) TO HL MAPCONT INR C ;NEXT GRP JZ MAPEND ;DONE PUSH H CALL GETGRP ;GET ANOTHER POP D ;SEE IF SAME CALL CTLCS JZ MAPEND2 MOV A,D CMP H JNZ MAPDIFF MOV A,E CMP L JNZ MAPDIFF ;SAME, CONTINUE JMP MAPCONT ; ;DIFFERENT FILE ENCOUNTERED ; MAPDIFF MOV A,C DCR A CALL HEX XCHG CALL MAPNAME JMP MAPDF ; ;END ; MAPEND MOV A,C ;GET LAST DCR A CALL HEX CALL MAPNAME POP H CALL CRLF ; ;END OF MAP - REPOSITION TO PREVIOUS GROUP ; MAPEND2 LDA GROUP PUSH H MOV L,A JMP POSGRP2 ; ;PRINT FILE NAME POINTED TO BY HL ; MAPNAME CALL SPACE MOV A,H ORA L ;NONE? JZ NONAME MOV A,M ;SEE IF ALLOC ORA A ;ZERO? MVI A,' ' JZ MAPNSP1 MVI A,'(' MAPNSP1 CALL TYPE PUSH H ;SAVE POINTER INX H ;SKIP ALLOC BYTE MVI B,8 CALL MAPN2 MVI A,'.' CALL TYPE MVI B,3 CALL MAPN2 CALL SPACE MOV A,M ;GET EXT ORI '0' CALL TYPE POP H MOV A,M ORA A MVI A,' ' JZ MAPNSP2 MVI A,')' MAPNSP2 CALL TYPE ;")" IF ERASED FILE LDA TWOUP XRI 1 STA TWOUP JZ CRLF JMP DELIM ; NONAME CALL ILPRT DB '++FREE++ ',0 LDA TWOUP XRI 1 STA TWOUP JZ CRLF DELIM MVI A,':' JMP TYPE ; ;PRINT NAME, LENGTH IN B ; MAPN2 MOV A,M INX H CPI ' ' ;PRINTABLE? JC MAPN2H ;..NO, IN HEX CPI 7FH JC MAPN2A MAPN2H CALL BHEX JMP MAPN2Z MAPN2A CALL TYPE MAPN2Z DCR B JNZ MAPN2 RET ; ;FIND WHICH FILE GROUP(C) BELONGS TO ; GETGRP LXI H,DIRECT MVI A,64 ;# OF FILES STA FILECT GETGLP PUSH H ;SAVE POINTER LXI D,15 ;DISP TO LENGTH DAD D MOV A,M ;GET LENGTH ORA A ;ZERO? JZ GETGNF ;NO FILE CPI 0E5H ;UNUSED, FORMATTED DISK? JZ GETGNF MOV B,A ;SAVE COUNT DCR B ;ALLOW JP BELOW GETGL2 INX H ;TO NEXT MOV A,M ;GET GRP CMP C ;CORRECT ONE? JZ GETGOT ;YES, GOT IT. MOV A,B ;GET REC COUNT SUI 8 MOV B,A JP GETGL2 ;NO FILE GETGNF POP H LXI D,32 DAD D ;TO NEXT ENTRY LDA FILECT DCR A STA FILECT JNZ GETGLP ;MORE? LXI H,0 ;NO, NOT FOUND RET ; ;GOT THE FILE ; GETGOT POP H ;POINT TO NAME RET ; ;SAVE THE CURRENT SECTOR ; SAVE LDA WRFLG ORA A JZ BADW ;NONE TO SAVE PUSH H LXI H,BASE+80H LXI D,SAVEBUF MVI B,128 CALL MOVE MVI A,1 ;..SHOW STA SAVEFLG ;..SAVED EXISTS POP H JMP PROMPT ; ;RESTORE THE CURRENT SECTOR ; RESTORE LDA SAVEFLG ORA A JZ NOSAVE ;NONE TO SAVE PUSH H LXI H,SAVEBUF LXI D,BASE+80H MVI B,128 CALL MOVE POP H JMP PROMPT ; NOSAVE XRA A STA QFLAG ;NOT QUIET CALL ILPRT DB '++NO "<" SAVE COMMAND ISSUED' DB CR,LF,0 JMP PROMPTR ; ;MOVE (HL) TO (DE) LENGTH IN B ; MOVE MOV A,M STAX D INX H INX D DCR B JNZ MOVE RET ; NOWRITE XRA A ;GET 0 STA WRFLG ;CAN'T WRITE NOW RET ; ;NO MATCH IN SEARCH, TRY NEXT CHAR ; SRNOMAT POP H CALL CTLCS ;ABORT? JNZ SEARCH ;..YES LXI H,INBUF MVI M,CR JMP CALCGRP ;SHOW WHERE STOPPED ; ;SEARCH FOR CHARACTER STRING ; SEARCH PUSH H ;SAVE STRING POINTER SRCHL CALL RDBYTE ;GET A BYTE PUSH PSW CALL GETVAL ;GET SEARCH VALUE MOV B,A POP PSW CMP B ;MATCH? JNZ SRNOMAT ;NO MATCH INX H MOV A,M ;DONE? CPI CR JZ SREQU CPI ';' JNZ SRCHL ;GOT MATCH SREQU XRA A STA QFLAG ;NOT QUIET CALL ILPRT DB '= AT ',0 LDA BUFAD ANI 7FH CALL HEX CALL CRLF JMP CALCGRP ; ;GET VALUE FROM INPUT BUFFER ; GETVAL MOV A,M 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 ; 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 NEXTSEC READ1 XRA A STA FTSW ;NOT FIRST READ LDA CURSEC CALL SETSEC LDA CURTRK CALL SETTRK CALL READ CALL CALCSUB LXI H,BASE+80H NORD MOV A,M INX H SHLD BUFAD POP H RET ; ;VIEW THE FILE IN ASCII STARTING AT ;CURRENT SECTOR, STEPPING THRU THE DISK ; VIEW LDA WRFLG ORA A JZ BADDMP CALL DECIN ;GET # IF ANY PUSH H MOV A,E ORA A JNZ VIEWLP INR E ;DFLT=1 VIEWLP LXI H,BASE+80H ;TO DATA VIEWCHR CALL CTLCS JZ VIEWEND MOV A,M CPI 1AH JZ VIEWEOF CALL TYPE INR L JNZ VIEWCHR DCR E JZ VIEWEND PUSH D ;SAVE COUNT CALL NEXTSEC LDA CURSEC CALL SETSEC LDA CURTRK CALL SETTRK CALL READ POP D ;RESTORE COUNT JMP VIEWLP ; VIEWEOF CALL ILPRT DB CR,LF,TAB,'++EOF++',CR,LF,0 ; VIEWEND POP H CALL CRLF JMP CALCGRP ; ;DUMP IN HEX OR ASCII ; DUMP LDA WRFLG ORA A JNZ DUMPOK BADDMP XRA A STA QFLAG ;NOT QUIET CALL ILPRT DB '++Can''t dump, no sector read.',CR,LF,0 EXPL XRA A STA QFLAG ;NOT QUIET CALL ILPRT DB 'Use G command following F,',CR,LF DB 'or R or S following T',CR,LF,0 JMP PROMPTR ; DUMPOK MOV A,M CPI ';' JZ DUMPDF ;DFLT CPI CR JNZ DUMPNDF ;USE DEFAULT DUMPDF LXI B,BASE+80H LXI D,0FFH JMP DUMP1 DUMPNDF CALL DISP MOV B,D MOV C,E CPI CR JZ DUMP1 CPI ';' JZ DUMP1 INX H ;SKIP ',' 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 CALL SPACE CALL SPACE LDA DUMTYPE CPI 'A' JZ DUMPAS PUSH H ;SAVE START DHEX MOV A,M CALL HEX MOV A,L ANI 3 CPI 3 CZ SPACE MOV A,L ANI 7 CPI 7 CZ SPACE MOV A,E CMP L JZ DPOP INX H MOV A,L ANI 0FH JNZ DHEX DPOP CALL CTLCS JZ PROMPTR LDA DUMTYPE CPI 'H' JZ DNOAS ;HEX ONLY POP H ;GET START ADDR DUMPAS CALL ASTER DCHR MOV A,M CPI ' ' JC DPER CPI 7FH JC DOK DPER MVI A,'.' DOK CALL TYPE MOV A,E CMP L JZ DEND INX H MOV A,L ANI 0FH JNZ DCHR DEND CALL ASTER CALL CRLF PUSH D CALL CTLCS POP D JZ PROMPTR MOV A,E CMP L JNZ DUMPLP POP H JMP PROMPT ; DNOAS POP B CALL CRLF MOV A,E CMP L JNZ DUMPLP POP H JMP PROMPT ; ;POSITION ; POS PUSH PSW MOV A,M CPI ';' JZ POSINQ CPI CR JNZ POSOK POSINQ POP PSW JMP INQ ; POSOK POP PSW CPI 'T' JZ POSTRKD CPI 'S' JZ POSSECD CPI 'G' JZ POSGRPH JMP WHAT ; POSTRKD CALL DECIN POSTRK MOV A,E CALL SETTRK CALL NOWRITE ;TRACK DOESN'T READ MVI A,1 STA NOTPOS ;SHOW NOT POSITIONED JMP CALCGRP ; POSSECD CALL DECIN POSSEC MOV A,E ORA A JZ WHAT CPI 27 JNC WHAT CALL SETSEC CALL READ XRA A STA NOTPOS ; CALCGRP CALL CALCSUB JMP INQ ; CALCSUB PUSH H LDA CURTRK SUI SYSTRK ;GRP 0 IS TRK 2 MOV E,A MVI D,0 LXI H,0 MVI A,TRKSIZE C1LP DAD D DCR A JNZ C1LP LDA CURSEC DCR A ADD L MOV L,A MOV A,H ACI 0 MOV H,A MOV A,L ANI 7 STA GRPDISP DAD H DAD H DAD H DAD H DAD H MOV A,H STA GROUP POP H RET ; ;POSITION IN THE DIRECTORY AFTER A FIND ; POSDIR PUSH H ;SAVE INBUF XRA A STA FINDFLG ;CANCEL POS REQ LDA DIRPOS ;GET POSITION RAR RAR PUSH PSW ANI 7 ;GET GRP DISPLACEMENT STA GRPDISP POP PSW RAR RAR RAR ANI 1 ;GET GROUP STA GROUP MOV L,A ;SETUP FOR POSGRP2 JMP POSGRP2 ;POSITION TO IT ; POSGRPH CALL HEXIN POSGRP MOV A,E STA GROUP XRA A STA GRPDISP PUSH H MOV L,E ;MULTIPLY POSGRP2 MVI H,0 ;BY 8 DAD H DAD H DAD H LDA GRPDISP ;MAY BE >0 IF "F" CMD. ADD L ;CAN'T CARRY MOV L,A ;DIVIDE BY 26, QUOTIENT = TRK, REMAINDER = SECTOR LXI D,-TRKSIZE MVI B,0 ;TRK DIVLP INR B DAD D JC DIVLP DCR B LXI D,TRKSIZE DAD D MOV A,B ADI SYSTRK ;SYSTEM TRACKS TO GRP 0 CALL SETTRK MOV A,L INR A CALL SETSEC CALL READ POP H XRA A STA NOTPOS ;NOW POSITIONED JMP INQ ; POSFIL CALL NOWRITE MVI A,1 STA FINDFLG ;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 JNZ 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,BASE+80H DAD D ;HL POINTS TO ENTRY LXI D,32 XCHG DAD D XCHG MVI A,'D' STA DUMTYPE JMP DUMPLP ;WHICH POPS H ; MVNAME MOV A,M CPI '.' JZ MVIPAD CPI CR JZ PAD CPI ';' JZ PAD CALL UPCASE STAX D INX H INX D DCR B JNZ MVNAME MOV A,M CPI CR RZ CPI ';' RZ INX H CPI '.' RZ JMP WHAT ; MVIPAD INX H ; PAD MVI A,' ' STAX D INX D DCR B JNZ PAD RET ; PLUS LXI D,1 ;DFLT TO 1 SECT MOV A,M ;GET NEXT CHAR CPI CR ;CR? JZ PLUSGO ;..YES, DFLT TO 1 CPI ';' JZ PLUSGO CALL DECIN ;GET # MOV A,E ORA A JZ WHAT PLUSGO CALL NEXTSEC DCR E ;MORE TO GO? JNZ PLUSGO ;..YES ; ;OK, INCREMENTED TO SECTOR. SETUP AND READ ; PLUSMI LDA CURSEC CALL SETSEC LDA CURTRK CALL SETTRK CALL READ JMP CALCGRP ; MINUS LXI D,1 ;SET DFLT MOV A,M ;GET CHAR CPI CR ;CR? JZ MINGO ;..YES, DFLT=1 CPI ';' JZ MINGO CALL DECIN ;..NO, GET ## MOV A,E ORA A JZ WHAT MINGO LDA CURSEC ;GET CURR DCR A ;BACK UP JNZ MINOK ;TO 0? LDA CURTRK ;..YES, BACK.. DCR A ;..UP 1.. STA CURTRK ;..TRACK MVI A,TRKSIZE MINOK STA CURSEC DCR E JNZ MINGO JMP PLUSMI ; ;GO TO NEXT SECTOR ; NEXTSEC LDA CURSEC ;GET CURRENT INR A ;BUMP IT CPI TRKSIZE+1 ;NEXT TRACK? JNZ NEXTOK ;NO, CONI LDA CURTRK ;BUMP.. INR A ;..CURR.. STA CURTRK ;..TRK MVI A,1 ;SECT=1 NEXTOK STA CURSEC RET ; ;TELL WHAT GRP, DISPLACEMENT, TRK, SECT, PHY SECT ; INQ CALL INQSUB JMP PROMPT ; ;POSITION INQUIRY SUBROUTINE ; EXECUTED VIA: G S OR T (WITH NO OPERANDS) ; INQSUB LDA CURTRK CPI SYSTRK JC NOGRP CALL ILPRT DB 'G=',0 LDA GROUP CALL HEX MVI A,':' CALL TYPE LDA GRPDISP ORI '0' CALL TYPE MVI A,',' CALL TYPE NOGRP CALL ILPRT DB ' T=',0 LDA CURTRK CALL DEC CALL ILPRT DB ', S=',0 LDA CURSEC CALL DEC CALL ILPRT DB ', PS=',0 LDA PHYSEC CALL DEC CALL CRLF RET ; CHG MOV A,M ;GET TYPE (HEX, ASCII) CALL UPCASE PUSH PSW ;SAVE "H" OR "A" INX H CALL DISP ;GET, 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 DISP ;GET THRU INX H ;SKIP END DELIM MOV B,D MOV C,E ;BC = THRU POP D ;GET FROM JMP CHGAH CHGNTH CPI ',' JNZ WHAT CHGAH POP PSW CPI 'H' JZ CHGHEX CPI 'A' JNZ WHAT ;CHANGE ASCII CHGALP MOV A,M CPI CR JZ PROMPT CPI ';' JZ PROMPT LDAX D CPI ' ' JC CHGAHX CPI 7FH JNC CHGAHX JMP CHGA2 CHGAHX CALL BHEX JMP CHGA3 CHGA2 CALL TYPE CHGA3 SHLD BACK ;IN CASE "THRU" CALL GETVAL ;ASCII OR STAX D ;UPDATE CHAR INX H ;TO NEXT INPUT CHAR ;SEE IF 'THRU' REQUESTED MOV A,C ORA A JZ CHGANTH CMP E ;DONE?.. JZ PROMPT ;..YES LHLD BACK CHGANTH INR E JNZ CHGALP MOV A,M CPI CR JZ PROMPT CPI ';' JZ PROMPT JMP WHAT ; ;CHANGE HEX ; CHGHCOM INX H CHGHEX MOV A,M CPI CR JZ PROMPT CPI ';' JZ PROMPT CPI ',' ;DELIM? JZ CHGHCOM PUSH D SHLD HEXAD ;IN CASE 'THRU' CALL HEXIN ;POSITIONS TO DELIM MOV A,E ;GET VALUE POP D ;..ADDR PUSH PSW ;SAVE VALUE LDAX D ;GET OLD CALL HEX ;ECHO IN HEX POP PSW ;GET NEW STAX D ;SAVE NEW ; MOV A,C ;SEE IF 'THRU' ORA A JZ CHGHNTH ;..NO. CMP E ;..YES, DONE? JZ PROMPT LHLD HEXAD ;..NO: MORE CHGHNTH INR E JNZ CHGHEX MOV A,M CPI CR JZ PROMPT CPI ';' JZ PROMPT JMP WHAT ; DOREAD LDA NOTPOS ORA A JNZ CANTRD CALL READ JMP PROMPT ; CANTRD XRA A STA QFLAG ;NOT QUIET CALL ILPRT DB '++Can''t read - not positioned',CR,LF DB 'Position by:',CR,LF DB 9,'Track then Sector, or',CR,LF DB 9,'Group',CR,LF,0 JMP PROMPT ; DOWRITE CALL WRITE JMP PROMPT ; BHEX PUSH PSW MVI A,'<' CALL TYPE POP PSW CALL HEX MVI A,'>' CALL TYPE RET ; HEX PUSH PSW RAR RAR RAR RAR CALL NIBBL POP PSW NIBBL ANI 0FH CPI 10 JC HEXNU ADI 7 HEXNU ADI '0' JMP TYPE ; DEC MVI B,'0'-1 DEC10 INR B SUI 10 JNC DEC10 PUSH PSW MOV A,B CALL TYPE POP PSW ADI '0'+10 ;MAKE ASCII, ADD BACK LAST SUBTR. JMP TYPE ; SPACE MVI A,' ' JMP TYPE ASTER MVI A,'*' JMP TYPE ; ILPRT XTHL ILPLP CALL CTLCS ;ABORT? JZ PROMPTR MOV A,M CALL TYPE INX H MOV A,M ORA A JNZ ILPLP INX H XTHL RET ; ;DISP CALLS HEXIN, AND VALIDATES A SECTOR ;DISPLACEMENT, THEN CONVERTS IT TO AN ADDRESS ; DISP CALL HEXIN 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 80 MOV E,A MVI D,BASE/256 POP PSW ;GET DELIM RET ; BADISP XRA A STA QFLAG ;NOT QUIET CALL ILPRT DB '++BAD DISPLACEMENT (NOT 0-7F)' DB CR,LF,0 JMP PROMPTR ; HEXIN LXI D,0 MOV A,M CPI '#' ;DECIMAL? JZ HDIN ;MAKE DECIMAL HINLP MOV A,M CALL UPCASE CPI CR RZ CPI ';' RZ CPI ',' RZ CPI '-' ;'THRU'? RZ CPI '>' RZ INX H CPI '0' JC WHAT CPI '9'+1 JC HINNUM CPI 'A' JC WHAT CPI 'F'+1 JNC WHAT SUI 7 HINNUM SUI '0' XCHG DAD H DAD H DAD H DAD H ADD L MOV L,A XCHG JMP HINLP ; HDIN INX H ;SKIP '.' DECIN LXI D,0 DINLP MOV A,M CALL UPCASE CPI CR RZ CPI ';' RZ CPI ',' RZ CPI '-' ;'THRU'? RZ INX H CPI '0' JC WHAT CPI '9'+1 JNC WHAT SUI '0' PUSH H MOV H,D MOV L,E DAD H ;X2 DAD H ;X4 DAD D ;X5 DAD H ;X10 ADD L MOV L,A MOV A,H ACI 0 MOV H,A XCHG POP H JMP DINLP ; ;READ IN A CONSOLE BUFFER FULL ; RDBUF CALL ILPRT DB CR,LF,':',0 LXI H,INBUF MVI B,0 RDBLP CALL CONIN MOV C,A ;SAVE FOR BS TEST CPI 'U'-40H ! JZ RDCTLU CPI CR ! JZ RDCR CPI 'H'-40H ! JZ RDBS CPI 7FH ! JZ RDBS CPI 'R'-40H ! JZ RDCTLR CPI ' ' ! JC RDBLP MOV M,A INX H INR B JM FULL CALL TYPE JMP RDBLP ; FULL DCR B DCX H MVI A,7 ;'DING' CALL TYPE JMP RDBLP ; ;GOT CR ; RDCR MOV M,A ;SAVE IT CALL TYPE ;ECHO IT MVI A,LF ;ECHO.. CALL TYPE ;..LF LXI H,INBUF RET ; ;GOT DELETE OR BS, ECHO IF BS ; RDBS XRA A ;AT FRONT.. ORA B ;..OF LINE? JZ RDCTLU ;..YES, ECHO ^U DCX H DCR B MOV A,C CPI 'H'-40H ;BS? JZ BACKUP ;ECHO THE BS MOV A,M ;ECHO.. CALL TYPE ;..DELETED CHAR JMP RDBLP ; BACKUP MVI A,'H'-40H CALL TYPE JMP RDBLP ; ;GOT CTL-R, RETYPE ; RDCTLR MVI M,CR CALL CRLF LXI H,INBUF MVI B,0 RDCRL MOV A,M CPI CR JZ RDBLP CALL TYPE INR B INX H JMP RDCRL ; ;GOT CTL-U OR BACKUP TO BEG. OF LINE. ; RDCTLU MVI A,'^' CALL TYPE MVI A,'U' CALL TYPE JMP RDBUF ; CRLF MVI A,CR CALL TYPE MVI A,LF JMP TYPE ; UPCASE CPI 60H RC ANI 5FH ;MAKE UPPER CASE RET ; CONST PUSH B PUSH D PUSH H VCONST CALL $-$ POP H POP D POP B RET ; CONIN PUSH B PUSH D PUSH H VCONIN CALL $-$ POP H POP D POP B RET ; ;CONSOLE OUT WITH TAB EXPANSION ; TYPE PUSH B PUSH D PUSH H MOV C,A ;FOR OUTPUT ROUTINE CPI TAB JNZ TYPEQ TYPETAB MVI A,' ' CALL TYPE LDA TABCOL ANI 7 JNZ TYPETAB JMP TYPERET ; TYPEQ LDA QFLAG ORA A VCONOUT CZ $-$ ;ADDR FILLED IN BY 'INIT' ; ;UPDATE COLUMN USED IN TAB EXPANSION ; MOV A,C ;GET CHAR CPI CR JNZ TYPENCR MVI A,0 STA TABCOL JMP TYPELST ; TYPENCR CPI LF JZ TYPELST CPI ' ' ;CTL CHAR? JC TYPERET ;..NO CHANGE IN COL LDA TABCOL INR A STA TABCOL TYPELST LDA PFLAG ANI 1 CNZ LIST ;FROM C REG. TYPERET POP H POP D POP B RET ; LIST: ;NO PUSH, TYPE SAVED THE REGS. VLIST JMP $-$ ; HOME PUSH H VHOME CALL $-$ POP H RET ; SETTRK CPI MAXTRK JC TRKOK XRA A STA QFLAG ;NOT QUIET CALL ILPRT DB '++not in tracks 0-' ; IF STDCPM DB '76' ENDIF ; IF HEATH DB '40' ENDIF ; DB '++' DB CR,LF,0 CALL NOWRITE JMP PROMPTR ; TRKOK STA CURTRK MOV C,A PUSH H VSETTRK CALL $-$ POP H RET ; SETSEC STA CURSEC ;LOGICAL MOV C,A LDA CURTRK CPI 2 JC GSETSEC ;DON'T SCRAMBLE TRK'S 0-1 PUSH H LXI H,SECTBL-1 MOV A,C ADD L MOV L,A MOV A,H ACI 0 MOV H,A MOV A,M POP H MOV C,A GSETSEC PUSH H MOV A,C ;GET PHYSICAL SECTOR STA PHYSEC VSETSEC CALL $-$ POP H RET ; SETDMA: VSETDMA JMP $-$ ; READ MVI A,1 STA WRFLG PUSH H VREAD CALL $-$ ORA A JZ READOK XRA A STA QFLAG ;NOT QUIET CALL ILPRT DB '++READ failed, sector may be invalid++' DB CR,LF,0 READOK POP H RET ; WRITE LDA WRFLG ORA A JNZ PWRITE BADW XRA A STA QFLAG ;NOT QUIET CALL ILPRT DB '++CANNOT WRITE UNLESS READ ISSUED' DB CR,LF,0 JMP EXPL PWRITE PUSH H VWRITE CALL $-$ ORA A JZ WRITEOK XRA A STA QFLAG ;NOT QUIET CALL ILPRT DB '++WRITE failed++',CR,LF,0 WRITEOK POP H RET ; ;'SCUSE THIS KLUDGE - IT'S TO SET THE SCRAMBLE ;TABLE TO 1,2,3,4,5.. FOR MY 3600 RPM "FLOPPY".. ; WARDSK PUSH H LXI H,SECTBL MVI B,1 MVI C,26 WARDLP MOV M,B INR B DCR C INX H JNZ WARDLP POP H JMP PROMPT ; ;HELP ; HELP CALL ILPRT DB 'Operands in brackets [...] are optional' DB CR,LF DB 'Numeric values: ''n'' are decimal, ''x'' hex' DB CR,LF,CR,LF DB '+[n] step in [n] sectors;' DB CR,LF DB '-[n] step out [n] sectors' DB CR,LF DB '=aaa search for ASCII aaa from curr sector.' DB CR,LF DB ' Caution: upper/lower case matters.' DB CR,LF DB ' 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 '< save current sector into mem. buff.' DB CR,LF DB '> restore saved sector' DB CR,LF DB '? give help' 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+ASCII)' DB CR,LF DB 'Fn.t Find file' DB CR,LF DB 'Gxx CP/M Allocation Group xx' DB CR,LF DB 'H[ff,tt] hex dump' DB CR,LF DB 'L Log in drive' DB CR,LF DB 'Lx Log in drive x' DB CR,LF DB 'M[xx] Map [from group xx]' DB CR,LF DB 'P Toggle printer switch' DB CR,LF DB 'Q Quiet mode (no msgs)' DB CR,LF DB 'R Read current sector' DB CR,LF DB 'Snn Sector nn' DB CR,LF DB 'Tnn Track nn' DB CR,LF DB 'V[nn] View [nn] ASCII sectors' DB CR,LF DB 'W Write current sector' DB CR,LF DB 'X Exit program' DB CR,LF DB 'Z[nn] Sleep [nn tenths]' DB CR,LF DB '/[nn] Repeat [nn (decimal) times]' DB CR,LF,CR,LF DB 'Cancel a function with C or Ctl-C.' DB CR,LF DB 'Suspend output with S or Ctl-S.' DB CR,LF DB 'Separate commands with ";".' DB CR,LF DB ' Example: g0' DB CR,LF DB ' +;d;z#20;/' 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 'To use "Q", preceed a command with it.' DB CR,LF DB 'Quiet mode is set off upon console input.' DB CR,LF,CR,LF DB 'See DU.DOC for complete examples.' DB CR,LF,0 JMP PROMPT ; ;DISK SECTOR ORDER - standard CP/M ; IF STDCPM SECTBL DB 1,7,13,19,25,5,11,17,23,3,09,15,21 DB 2,8,14,20,26,6,12,18,24,4,10,16,22 ENDIF IF HEATH SECTBL DB 1, 2, 9,10,17,18, 5, 6,13,14 DB 3, 4,11,12,19,20, 7, 8,15,16 ENDIF ; BUFAD DW BASE+100H ;FORCES INITIAL READ HEXAD DW 0 ;TO RE-FETCH A VALUE TOGO DB 0FFH ;REPEAT COUNT (FF=CONT) TWOUP DB 0 PFLAG DB 0 ;1=PRINT GROUP DB 0 GRPDISP DB 0 SAVEFLG DB 0 CURTRK DB 0 CURSEC DB 1 PHYSEC DB 1 TABCOL DB 0 FILECT DB 0 DIRPOS DB 0 FINDFLG DB 0 ;1=MUST POSITION AFTER FIND FTSW DB 1 ;SEARCH W/O INCREMENT NOTPOS DB 1 ;NOT POSITIONED YET (CAN'T READ) WRFLG DB 0 ;MAY NOT WRITE UNTIL '+', '-', ; OR 'G' COMMAND QFLAG DB 0 ;QUIET? (0=NO) DS 100 ;STACK SPACE STACK: BACK DS 2 ;TO BACK UP IN "CA0-7F,X" DUMTYPE DS 1 SAVEBUF DS 128 INBUF DS 128 ; ;DIRECTORY READ IN HERE; ALSO SEARCH WORKAREA ; WORK: DIRECT DS 32*64 ; FCB EQU BASE+5CH BDOS EQU BASE+5 RESETDK EQU 13 SELDK EQU 14 SRCHF EQU 17 ;SEARCH FIRST