; DU.ASM V7.5 Revised 1/23/81 ; DISK UTILITY - By Ward Christensen ; ;See DU.DOC for description and detailed instructions. ; ;This version of DU is compatible with CP/M 1.4 and 2.x ;and does not require alteration for various hardware ;configurations. It adjusts itself automatically to ;the correct number of sectors, tracks, directory size, ;etc. It has been tested on 5-1/4" and 8" floppy, and ;10 megabyte hard disk systems. ; ;Because of the automatic adaption feature, no conditional ;assembly options are included. The only alteration that ;needs to be done is to use DDT to set the byte at 103h ;to zero for systems using a 2 mHz clock or non-zero for ;4 mHz clock. This only affects the time delay used in ;the 'sleep' command. ; ;************************************************* ;* * ;* This program has been heavily modified * ;* to allow it to work without modification * ;* on most versions of CP/M 1.4 and, hopefully, * ;* all versions of CP/M 2.x. * ;* If you have difficulty getting this program * ;* to run, AND if you are using CP/M 2.x, AND * ;* if you know your BIOS to be bug-free, leave * ;* a message on Technical CBBS of Dearborn, * ;* Michigan (313)-846-6127 with a description * ;* of the problem and a summary of your hard- * ;* ware configuration. * ;* One known possible problem involves the * ;* system tracks on some systems, and results * ;* from the system sectors being skewed. There * ;* is NO way for a program executing under CP/M * ;* to know about this. This program assumes the * ;* standard convention of no skew being used on * ;: the system tracks. This usually isn't a prob- * ;* lem because the SYSGEN program can be used to * ;* get the system from the disk so that it can * ;* be modified. * ;* This program should work under standard * ;* versions of CP/M 1.4. The only requirement * ;* is that the BIOS "SETSEC" routine not modify * ;* the sector number passed to it in the B * ;* register. Again, system tracks with skewed * ;* sectors will be a problem. * ;* If you add any features or make any useful * ;* changes to this program, please modem a copy * ;* to the above CBBS, so the currency of the * ;* program can be maintained. * ;* * ;* Ron Fowler * ;* * ;************************************************* ; ;01/23/81 Changed SETSEC to ignore high-order result of ; SECTRN if SPT<256. This fixes some translation ; problems where the BIOS leaves garbage in H. (BRR) ; ;01/15/81 Changed labels to be no more than 6 characters ; long. Moved stack. Cleaned up file. (KBP) ; ;01/13/81 Updated help messages for '#' and 'N' commands. ; Modified sign-on message. (RGF) ; ;01/12/81 Fixed problem with sector translation under ; CP/M 1.4. (RGF) ; ;01/11/81 Fixed problem with CP/M 1.4. Added 'N' command. ; Hard-code 'FASTCLOCK' as a boolean at 103h. Add ; fix for sector number being 0 in system tracks, ; as suggested by Keith Petersen, W8SDZ. Added '#' ; command and memory-full check. Changed login to ; position to directory track at every log. This ; is necessary to set up the 'FIRST0' flag. (RGF) ; ;01/08/81 Corrected error in MAP routine that caused map ; to fail when >255 groups allocated. Changed ; 'REPEAT' to allow up to 65535 repeats. (RGF) ; ;01/06/81 Modified to allow use with ALL systems, without ; conditional assembly, thru use of disk parameter ; block. By Ron Fowler, Westland, Mich. ; ;01/05/81 Modified '+' and '-' commands as follows: ; 1) + at end of disk now wraps to start ; 2) - at start wraps back to end ; 3) argument for + & - now good to 65535 ; (RGF) ; ;01/03/81 Modified logic in console status test to allow ; any non-zero value to indicate char waiting. ; (RGF) ; ;01/02/81 Made compatible with MACRO80 assembler (labels ; made unique within 6 chars, and separated multi- ; statement lines). (RGF) ; ;11/14/80 Corrected missing conditional in CLCSUB routine ; for MICROP or DIGDBL. Cleaned up file. (KBP) ; ;11/04/80 Forced write type 1 (pre-read and immediate write) ; so deblocking BIOS's don't mess up. Ignore bit 7 ; in = command unless form was used. Display ; unprintables as in V command. Show user no. ; in M command (will always be 00 for 1.4) and only ; print parentheses if E5 present. (BRR) ; ;10/30/80 Fixed bug in backspace/control-X. Corrected more ; bit-7 stuff. Added 'U' command to change user no. ; under CP/M 2.x. Added pauses in help file. (BRR) ; ;10/27/80 Added Thinkertoys DBL DENS, Micromation DBL DENS, ; Industrial Micro Systems DBL and QUAD DENS. ; Fixed several bit-7 problems in MAP and DUMP logic. ; Added control-X (CRT erase line) to command input ; logic. (Bruce R. Ratoff, ACGNJ-SIG/M) ; ;09/16/80 Fix backspace in line enter routine, add MAXDIR ; equate, general cleanup of ASM file. (KBP) ; ;06/22/80 Put in 'Q' command. Fix so 'P' (printer) ; mode outputs L/F's. (WLC) ; ;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) (WLC) ; ;03/24/80 Mod for Micropolis, Digital Microsystems DD, ; and Northstar DD CP/M. Trap out garbage ; during VIEW of file. By Keith Petersen, W8SDZ ; ;02/24/80 Mod login command to not really do log, just ; drive select. (WLC) ; ;02/12/80 Mod for heath CP/M. (WLC) ; ;01/08/80 Reposition after 'M' command. (WLC) ; ;01/07/79 Add VIEW command. (WLC) ; ;01/06/80 Rewrite 'F' command. (WLC) ; ;10/10/79 Save regs in BIOS calls, translate input to upper case ; add commands: < save sector ; > restore sect ; / repeat ; allow change from-thru. (WLC) ; ;02/25/79 Put sector read into 'S' command. (WLC) ; ;11/26/78 Add disk # to login command. (WLC) ; ;11/12/78 Add login command. (WLC) ; ;08/06/78 Originally written to reconstruct blown ; disks on CBBS via remote access. (WLC) ; ; ; ---------------- ;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. (WLC) ; ---------------- ; ;System equates ; BASE EQU 0 ;SET TO 4200H FOR HEATH OR TRS-80 ALTCPM ; FCB EQU BASE+5CH BDOS EQU BASE+5 PRINT EQU 9 GVERS EQU 12 RESETDK EQU 13 SELDK EQU 14 SRCHF EQU 17 ;SEARCH FIRST SUSER EQU 32 GETDSK EQU 25 GETDPB EQU 31 ; 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 ; ORG BASE+100H ; JMP PASTCK ;JUMP OVER CLOCK BYTE AND I.D. ; CLOCK: DB 0 ;<---PUT NON-ZERO HERE FOR 4 MHZ CLOCK DB 'DU.COM ver 7.5 1/23/81' ; PASTCK: LHLD BDOS+1 ;GET POINTER TO BDOS ENTRY MVI L,0 ;SET HL=BASE OF BDOS SPHL ;PUT STACK THERE SHLD SETSTK+1 ;SAVE FOR LATER LXI SP INSTR. MVI C,GVERS ;GET CP/M VERSION NR CALL BDOS MOV A,H ;COMBINE THE TWO BYTE... ORA L ;...VERSION NR FOR A FLAG STA VER2FL ;SAVE IT ; ;Set up local jumps to BIOS LHLD BASE+1 ;WARM BOOT POINTER LXI D,3 ;READY FOR ADD DAD D SHLD VCONST+1 DAD D SHLD VCONIN+1 DAD D SHLD VCONOT+1 DAD D SHLD VLIST+1 DAD D ;PUNCH DAD D ;RDR DAD D SHLD VHOME+1 DAD D SHLD VSELDK+1 DAD D SHLD VSETRK+1 DAD D SHLD VSTSEC+1 DAD D SHLD SETDMA+1 DAD D SHLD VREAD+1 DAD D SHLD VWRITE+1 LDA VER2FL ORA A JZ DOCPM1 DAD D ;LISTST DAD D SHLD VSCTRN+1 JMP HELLO ; DOCPM1: LHLD BDOS+1 MVI L,0 ;BDOS ON PAGE BOUNDARY PUSH H LXI D,TRNOFF ;CP/M 1.4 SECTRAN ROUTINE OFFSET DAD D SHLD VSCTRN+1 POP H LXI D,SKWOFF ;CP/M 1.4 SKEW TABLE OFFSET DAD D SHLD SECTBL ;SET UP SKEW TABLE POINTER ; HELLO: CALL ILPRT DB CR,LF,'DISK UTILITY ver 7.5',CR,LF DB 'Universal Version',CR,LF DB CR,LF DB 'Type ? for help',CR,LF DB 'Type X to exit' DB CR,LF,0 CALL GETSTP ;SET UP PARAMETERS LXI H,BASE+80H ;TO INPUT BUFF MOV A,M ORA A JZ PRMPTR ;NO COMMAND ; ;Got initial command, set it up MOV B,A ;SAVE LENGTH DCR B JZ PRMPTR LXI D,INBUF INX H ;SKIP LEN INX H ;SKIP ' ' CALL MOVE MVI A,CR STAX D LXI H,INBUF JMP PRMPTI ; PRMPTR: XRA A STA QFLAG CALL RDBUF ; PRMPTI: MVI A,255 STA TOGO ;LOOP COUNT FOR "/" STA TOGO+1 ; PROMPT EQU $ SETSTK: LXI SP,$-$ ;MODIFIED AT INIT 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 PRMPTR ;..YES, READ BUFFER ; ;Do we have to position in directory after find? LDA FINDFL ORA A JNZ POSDIR ;POSITION IN DIRECTORY MOV A,M CPI CR JZ PRMPTR CPI ';' ;LOGICAL CR? INX H JZ PROMPT CALL UPCASE STA DUMTYP ;TYPE OF DUMP (A,D,H) ; ;Command dispatcher ; CPI '+' JZ PLUS ; CPI '-' JZ MINUS ; CPI '=' JZ SEARCH ; CPI '<' JZ SAVE ; CPI '>' JZ RESTOR ; CPI '#' JZ STATS ; 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 'N' JZ NEWDSK ; CPI 'P' JZ PRNTFF ; CPI 'Q' JZ QUIET ; CPI 'R' JZ DOREAD ; CPI 'S' JZ POS ; CPI 'T' JZ POS ; CPI 'U' ;******CP/M 2.x ONLY****** JZ USER ; CPI 'V' JZ VIEW ; CPI 'W' JZ DORITE ; CPI 'X' JZ BASE ; CPI 'Z' JZ SLEEP ; CPI '/' JZ REPEAT ; WHAT: XRA A STA QFLAG CALL ILPRT DB '?',0 JMP PRMPTR ; ;Memory full error ; MEMFUL: XRA A STA QFLAG CALL ILPRT DB '+++ Out of memory +++' DB CR,LF,0 JMP PRMPTR ; ;Print disk statistics ; STATS: PUSH H CALL ILPRT DB 'Disk Information:',CR,LF DB 'Tracks:',9,9,0 LHLD MAXTRK INX H CALL DEC CALL ILPRT DB CR,LF,'Sec/trk:',9,0 LHLD SPT CALL DEC CALL ILPRT DB CR,LF,'Grpsize:',9,0 LDA BLM INR A MOV L,A MVI H,0 CALL DEC CALL ILPRT DB ' (sectors per group)',CR,LF DB 'Tot grps:',9,0 LHLD DSM CALL DEC CALL ILPRT DB CR,LF,'Dir entries:',9,0 LHLD DRM INX H CALL DEC CALL ILPRT DB CR,LF,'Sys tracks:',9,0 LHLD SYSTRK CALL DEC CALL CRLF POP H JMP PROMPT ; ;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 MVI C,RESETDK CALL BDOS LDA DRIVE MOV C,A POP H CALL SELECT JMP PROMPT ; ;Quite mode ; QUIET: STA QFLAG ;NOW QUIET JMP PROMPT ; ;Repeat buffer contents ; REPEAT: CALL DECIN ;NN SPECIFIED? MOV A,D ORA E JZ NNN ;NO. LHLD TOGO INX H ;TEST FOR FIRST TIME MOV A,H ORA L ;WAS IT 0FFFFH? JNZ NNN ;NO: COUNTING XCHG ;GET COUNT SHLD TOGO ;SET COUNT ; NNN: LHLD TOGO XCHG LXI H,INBUF ;READY TO REPEAT INX D ;TEST FOR 0FFFFH MOV A,D ORA E JZ PROMPT ;CONTINOUS DCX D ;COUNT DOWN DCX D ;MAKE UP FOR PREV INX D XCHG SHLD TOGO MOV A,H ;ALL DONE? ORA L XCHG ;GET BACK INBUF PTR JNZ PROMPT ;NO, KEEP GOING JMP PRMPTR ;ALL DONE ; ;Set CP/M 2.x user number ; USER: LDA VER2FL ORA A JZ WHAT CALL DECIN ;GET REQUESTED USER NO. MOV A,E CPI 32 ;VALID? JNC WHAT MOV A,D ORA A JNZ WHAT MVI C,SUSER PUSH H ;SAVE CHAR POINTER CALL BDOS ;SET USER NO. POP H JMP PROMPT ; ;Toggle print flag ; PRNTFF: 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 SLEPLP MVI E,10 ; SLEPLP: LXI B,8000 ;APPROX .1 SEC @ 2MHz LDA CLOCK ORA A JZ SLEEP2 LXI B,16000 ;APPROX .1 SEC @ 4 MHz ; SLEEP2: DCX B MOV A,B ORA C JNZ SLEEP2 PUSH D CALL CTLCS POP D JZ PRMPTR DCR E JNZ SLEPLP JMP PROMPT ; ;Check for control-C or S ; CTLCS: CALL CONST ORA A JNZ GETC ORI 1 ;NO CHAR, RETN NZ RET ; GETC: CALL CONIN ANI 1FH ;ALLOW ASCII CPI 'S'-40H CZ CONIN CPI 'C'-40H RET ;0 SET IF CTL-C ; ;Find our way at initialization ; GETSTP: MVI C,GETDSK CALL BDOS ;GET CURNT DSK MOV C,A ; WE HAVE TO SELECT JMP SELECT ; TO GET THE DPH ; LOGIN: CALL DOLOG JMP PROMPT ; DOLOG: MOV A,M ;DISK REQ? LXI D,0 CPI CR JZ LGNODK CPI ';' JZ LGNODK CALL UPCASE INX H SUI 'A' MOV C,A ; SELECT: PUSH H MOV A,C STA DRIVE ;REMEMBER LATER WHERE WE ARE ; VSELDK: CALL $-$ ;ADDR FILLED IN BY 'INIT' LDA VER2FL ORA A ;IF NOT CP/M 2.x ... JZ SELSKP ;..THEN SKIP THIS JUNK 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 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 ; SELSKP: 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 POP H ; LGNODK: CALL NORITE RET ; ;Read in the disk directory ; REDDIR: PUSH H CALL NORITE ;POSITIONING LOST LHLD SYSTRK SHLD CURTRK LXI H,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 MOV C,L LXI D,DIRECT ;DMA ADDR ; RDIRLP: PUSH B PUSH D MOV B,D MOV C,E LDA BDOS+2 ;CHECK MEM AVAIL DCR A CMP D JC MEMFUL CALL SETDMA LHLD CURTRK XCHG CALL SETTRK LHLD CURSEC XCHG CALL SETSEC CALL READ CALL NXTSEC POP D POP B LXI H,80H DAD D XCHG DCX B MOV A,B ORA C JNZ RDIRLP LXI B,BASE+80H CALL SETDMA POP H RET ; ;Map the directory ; MAP: 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 PUSH H ;SAVE INBUF PTR MOV A,E ;GET START ORA D ;NOTHING? JZ MAPDF ;..YES, DFLT MOV B,D MOV C,E ; MAPDF: CALL HEXB MVI A,'-' CALL TYPE 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 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 INX B XCHG CALL MAPNAM JMP MAPDF ; ;End of map ; MAPEND: DCX B ;GET LAST CALL HEXB CALL MAPNAM POP H CALL CRLF ; ;End of map - reposition to previous group ; MAPND2: PUSH H LHLD GROUP XCHG JMP POSGP2 ; ;Print file name pointed to by HL ; MAPNAM: CALL SPACE MOV A,H ORA L ;NONE? JZ NONAME MOV A,M ;SEE IF ALLOC CPI 0E5H ;FREE? MVI A,' ' JNZ MPNSP1 MVI A,'(' ; MPNSP1: CALL TYPE PUSH H ;SAVE POINTER MOV A,M CALL HEX ;SHOW USER NUMBER CALL SPACE INX H ;SKIP USER BYTE PUSH B MVI B,8 CALL MAPN2 MVI A,'.' CALL TYPE MVI B,3 CALL MAPN2 POP B CALL SPACE MOV A,M ;GET EXT CALL HEX POP H MOV A,M CPI 0E5H MVI A,' ' JNZ MPNSP2 MVI A,')' ; MPNSP2: CALL TYPE ;")" IF ERASED FILE JMP FLIP ; NONAME: CALL ILPRT DB ' ++FREE++ ',0 ; FLIP: LDA TWOUP XRI 1 STA TWOUP JZ CRLF ; DELIM: MVI A,':' CALL TYPE JMP SPACE ; ;Print name, 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 JMP MAPN2Z ; MAPN2A: CALL TYPE ; MAPN2Z: DCR B JNZ MAPN2 RET ; ;Find which file group (BC) belongs to ; GETGRP: LHLD DRM ;MAX DIR ENTRY # INX H ;MAKE 1-RELATIVE SHLD FILECT LXI H,DIRECT ; GETGLP: PUSH H ;SAVE POINTER TO NAME MOV A,M ;PICK UP DN BYTE LXI D,14 ;NOW GET RECORD COUNT DAD D ; S2 PORTION .. MOV A,M ; IS 0 IN CP/M 1.4 CPI 0E5H JZ GETGNF 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 JZ GETGOT ;JUMP IF FOUND ONE DCR E ;ELSE 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 ; ;Group is not allocated to any file LXI H,0 ;SAY SO RET ; ;Found the file ; GETGOT: POP H RET ; ;Save the current sector ; SAVE: LDA WRFLG ORA A JZ BADW ;NONE TO SAVE PUSH H LXI H,BASE+80H LXI D,SAVBUF MVI B,128 CALL MOVE MVI A,1 ;..SHOW STA SAVEFL ;..SAVED EXISTS POP H JMP PROMPT ; ;Restore the current sector ; RESTOR: LDA SAVEFL ORA A JZ NOSAVE ;NONE TO SAVE PUSH H LXI H,SAVBUF LXI D,BASE+80H MVI B,128 CALL MOVE POP H JMP PROMPT ; NOSAVE: XRA A STA QFLAG 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 DCR B JNZ 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 LXI H,INBUF MVI M,CR JMP CLCGRP ;SHOW WHERE STOPPED ; ;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 JZ SREQU CPI ';' JNZ SRCHL ; ;Got match SREQU: XRA A STA QFLAG CALL ILPRT DB '= AT ',0 LDA BUFAD ANI 7FH CALL HEX CALL CRLF JMP CLCGRP ; ;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 NXTSEC ; READ1: XRA A STA FTSW ;NOT FIRST READ LHLD CURSEC XCHG CALL SETSEC LHLD CURTRK XCHG CALL SETTRK CALL READ CALL CLCSUB 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 HEXIN ;GET DISPL IF ANY PUSH H MOV A,E ORA A JNZ VIEWLP INR E ;DFLT=1 ; VIEWLP: LXI H,BASE+80H ;TO DATA ; VEWCHR: CALL CTLCS JZ VEWEND MOV A,M CPI 1AH JZ VEWEOF ANI 7FH CPI 7EH JNC VIEWHX ;SHOW RUBOUT AND TILDE AS HEX CPI ' ' JNC VIEWPR CPI CR JZ VIEWPR CPI LF JZ VIEWPR CPI TAB 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,TAB,'++EOF++',CR,LF,0 ; VEWEND: POP H CALL CRLF JMP CLCGRP ; ;Dump in hex or ASCII ; DUMP: LDA WRFLG ORA A JNZ DUMPOK ; BADDMP: XRA A STA QFLAG CALL ILPRT DB '++Can''t dump, no sector read.',CR,LF,0 ; EXPL: XRA A STA QFLAG 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 CPI ';' JZ DUMPDF ;DFLT CPI CR JNZ DMPNDF ; ;Use default DUMPDF: LXI B,BASE+80H LXI D,0FFH JMP DUMP1 ; DMPNDF: 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 DUMTYP 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 PRMPTR LDA DUMTYP CPI 'H' JZ DNOAS ;HEX ONLY POP H ;GET START ADDR ; DUMPAS: CALL ASTER ; DCHR: MOV A,M ANI 7FH CPI ' ' JC DPER CPI 7EH 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 PRMPTR 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 POSTKD CPI 'S' JZ POSSCD CPI 'G' JZ POSGPH JMP WHAT ; POSTKD: CALL DECIN ; POSTRK: PUSH H LHLD MAXTRK CALL SUBDE POP H JC OUTLIM CALL SETTRK CALL NORITE ;TRACK DOESN'T READ MVI A,1 STA NOTPOS ;SHOW NOT POSITIONED JMP CLCGRP ; POSSCD: CALL DECIN MOV A,D ORA E JZ WHAT ;DON'T ALLOW SECTOR 0 ; POSSEC: PUSH H LHLD SPT CALL SUBDE POP H JC WHAT CALL SETSEC CALL READ XRA A STA NOTPOS ;POSITIONED OK ; CLCGRP: CALL CLCSUB JMP INQ ; ;Calculate group from track and sector ; CLCSUB: PUSH H LHLD SYSTRK XCHG LHLD CURTRK CALL SUBDE XCHG LHLD SPT CALL MULT XCHG LHLD CURSEC DCX H DAD D LDA BLM MOV B,A MOV A,L ANA B STA GRPDIS LDA BSH MOV B,A ; CLCLOP: CALL ROTRHL DCR B JNZ CLCLOP SHLD GROUP POP H RET ; ;Position in the dorectory 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 JMP POSGP2 ;POSITION TO IT ; POSGPH: CALL HEXIN ; POSGRP: PUSH H LHLD DSM CALL SUBDE POP H JC OUTLIM XCHG SHLD GROUP XCHG XRA A STA GRPDIS PUSH H ; POSGP2: CALL GTKSEC CALL SETTRK XCHG CALL SETSEC CALL READ XRA A STA NOTPOS ;NOW POSITIONED POP H JMP INQ ; GTKSEC: MOV H,D MOV L,E LDA BSH ; GLOOP: DAD H DCR A JNZ GLOOP LDA GRPDIS ADD L ;CAN'T CARRY MOV L,A ; ;Divide by nr of sectors, quotient=track, remainder=sector ; XCHG LHLD SPT CALL NEG XCHG LXI B,0 ; DIVLP: INX B DAD D JC DIVLP DCX B XCHG LHLD SPT DAD D PUSH H LHLD SYSTRK DAD B XCHG POP H INX H RET ; POSFIL: CALL NORITE MVI A,1 STA FINDFL ;SO WE POSITION LATER LXI D,FCB XRA A ;LOGGED IN DISK STAX D INX D MVI B,8 CALL MVNAME MVI B,3 CALL MVNAME LXI D,FCB MVI C,SRCHF PUSH H CALL BDOS INR A 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 DUMTYP 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 HEXIN ;GET # MOV A,D ORA E JZ WHAT ; PLUSGO: CALL NXTSEC 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 LHLD CURTRK XCHG CALL SETTRK POP H CALL READ JMP CLCGRP ; MINUS: LXI D,1 ;SET DFLT MOV A,M ;GET CHAR CPI CR ;CR? JZ MINGO ;..YES, DFLT=1 CPI ';' JZ MINGO CALL HEXIN ;..NO, GET ## MOV A,D ORA E JZ WHAT ; MINGO: PUSH H LHLD CURSEC DCX H MOV A,H ORA L JNZ MINOK LHLD CURTRK MOV A,H ORA L JNZ SEASH LHLD MAXTRK ;WRAP TO END OF DISK SHLD CURTRK LHLD MAXSEC JMP MINOK ; SEASH: DCX H SHLD CURTRK LHLD SPT ; MINOK: SHLD CURSEC POP H DCX D MOV A,D ORA E JNZ MINGO JMP PLUSMI ; ;Go to next sector ; NXTSEC: PUSH H PUSH D LHLD CURSEC INX H XCHG LHLD SPT CALL SUBDE XCHG JNC NEXTOK LHLD CURTRK INX H XCHG LHLD MAXTRK CALL SUBDE JNC TRASK LXI D,0 ;WRAP TO START OF DISK ; TRASK: XCHG SHLD CURTRK LXI H,1 ; NEXTOK: SHLD CURSEC 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 XCHG LHLD CURTRK CALL SUBDE JC NOGRP CALL ILPRT DB 'G=',0 LHLD GROUP MOV B,H MOV C,L CALL HEXB MVI A,':' CALL TYPE LDA GRPDIS CALL HEX MVI A,',' CALL TYPE ; NOGRP: CALL ILPRT DB ' T=',0 LHLD CURTRK CALL DEC CALL ILPRT DB ', S=',0 LHLD CURSEC CALL DEC CALL ILPRT DB ', PS=',0 LHLD PHYSEC CALL DEC CALL CRLF POP H 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 7EH 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 CHANTH CMP E ;DONE?.. JZ PROMPT ;..YES LHLD BACK ; CHANTH: INR E JNZ CHGALP MOV A,M CPI CR JZ PROMPT CPI ';' JZ PROMPT JMP WHAT ; ;Change hex ; CHGHCM: INX H ; CHGHEX: MOV A,M CPI CR JZ PROMPT CPI ';' JZ PROMPT CPI ',' ;DELIM? JZ CHGHCM 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 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 ';' 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 ; DORITE: CALL WRITE JMP PROMPT ; BHEX: PUSH PSW MVI A,'<' CALL TYPE POP PSW CALL HEX MVI A,'>' CALL TYPE RET ; HEXB: LDA DSM+1 ORA A JZ HEXX MOV A,B CALL HEX ; HEXX: MOV A,C ; 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 ; ;Decimal output routine ; DEC: PUSH B PUSH D PUSH H LXI B,-10 LXI D,-1 ; DECOU2: DAD B INX D JC DECOU2 LXI B,10 DAD B XCHG MOV A,H ORA L CNZ DEC MOV A,E ADI '0' CALL TYPE POP H POP D POP B RET ; SPACE: MVI A,' ' JMP TYPE ; ASTER: MVI A,'*' JMP TYPE ; ;Inline print routine ; ILPRT: XTHL ; ILPLP: CALL CTLCS ;ABORT? JZ PRMPTR MOV A,M CPI 1 ;PAUSE? JNZ ILPOK CALL CONIN CPI 3 ;ABORT? JZ PRMPTR JMP ILPNX ; ILPOK: CALL TYPE ; ILPNX: 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 BASE+80H MOV E,A MVI D,BASE/256 POP PSW ;GET DELIM RET ; BADISP: XRA A STA QFLAG CALL ILPRT DB '++BAD DISPLACEMENT (NOT 0-7F)' DB CR,LF,0 JMP PRMPTR ; 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 ; RDBF1: LXI H,INBUF MVI B,0 ; RDBLP: CALL CONIN MOV C,A ;SAVE FOR BS TEST ; ;Evaluate control characters ; CPI 'U'-40H JZ RDCTLU ; CPI CR JZ RDCR ; CPI 'H'-40H JZ RDBS ; CPI 7FH JZ RDBS ; CPI 'R'-40H JZ RDCTLR ; CPI 'X'-40H JZ RDCTLX ; CPI ' ' JC RDBLP ; MOV M,A INX H INR B JM FULL CALL TYPE JMP RDBLP ; FULL: DCR B DCX H MVI A,'*' ;SIGNAL WE'RE FULL 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: CALL WIPER JMP RDBLP ; RDCTLX: INR B ; RDCX1: DCR B JZ RDBF1 CALL WIPER JMP RDCX1 ; WIPER: PUSH B PUSH D PUSH H LXI D,BSMSG ;BACKSPACE, SPACE, BACKSPACE MVI C,PRINT CALL BDOS POP H POP D POP B RET ; BSMSG: DB BS,' ',BS,'$' ; ;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 beginning 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 $-$ ;ADDR FILLED IN BY 'INIT' POP H POP D POP B RET ; 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 ; TYPE: PUSH B PUSH D PUSH H MOV C,A ;FOR OUTPUT ROUTINE CPI TAB JNZ TYPE2 ; TYPTAB: MVI A,' ' CALL TYPE LDA TABCOL ANI 7 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: LDA QFLAG ORA A VCONOT: CZ $-$ ;ADDR FILLED IN BY 'INIT' ; ;Update column used in tab expansion MOV A,C ;GET CHAR CPI CR JNZ TYPNCR MVI A,0 STA TABCOL JMP TYPLST ; TYPNCR: CPI ' ' ;CTL CHAR? JC TYPLST ;..NO CHANGE IN COL LDA TABCOL INR A STA TABCOL ; TYPLST: LDA PFLAG ANI 1 CNZ LIST ;FROM C REG. ; TYPRET: POP H POP D POP B RET ; LIST: PUSH B ;SAVED REGS PUSH D PUSH H VLIST: CALL $-$ ;ADDR FILLED IN BY 'INIT' POP H POP D POP B RET ; HOME: PUSH H VHOME: CALL $-$ ;ADDR FILLED IN BY 'INIT' POP H RET ; ;Set track # in DE ; SETTRK: PUSH H LHLD MAXTRK CALL SUBDE POP H JC OUTLIM XCHG SHLD CURTRK XCHG MOV B,D MOV C,E PUSH H VSETRK: CALL $-$ ;ADDR FILLED IN BY 'INIT' POP H RET ; SETSEC: PUSH H PUSH D LHLD SYSTRK XCHG SHLD CURSEC LHLD CURTRK CALL SUBDE POP B MOV H,B MOV L,C JNC NOTSYS LDA FIRST0 ;SEE IF FIRST SEC 0 ORA A JNZ GSTSEC ;NO, JUMP AWAY DCX H ;YES, SO DECREMENT JMP GSTSEC ; REQUESTED, THEN GO ; NOTSYS: LHLD SECTBL XCHG DCX B VSCTRN: CALL $-$ ;ADDR FILLED IN BY 'INIT' LDA SPT+1 ;IF SPT<256 (HI-ORD = 0) ORA A ; THEN FORCE 8-BIT TRANSLATION JNZ VSCTR1 ; ELSE KEEP ALL 16 BITS MOV H,A VSCTR1: LDA VER2FL ;SEE IF VERSION 2.x ORA A ;SET FLAGS JNZ GSTSEC ;JUMP IF CP/M 2.x MVI H,0 ;CP/M 1.4 GOOD TO ONLY 8 BITS MOV L,C ;MOST BIOS'S RETURN THE ; PHYSICAL SEC # IN REG C GSTSEC: SHLD PHYSEC ;THIS MAY BE REDUNTANT IN ; MOST 1.4 VERSIONS, BUT ; SHOULD CAUSE NO PROBLEMS MOV B,H MOV C,L VSTSEC: CALL $-$ ;ADDR FILLED IN BY 'INIT' POP H RET ; OUTLIM: XRA A STA QFLAG CALL ILPRT DB '++not within tracks 0-',0 PUSH H LHLD MAXTRK CALL DEC POP H CALL ILPRT DB '++' DB CR,LF,0 CALL NORITE JMP PRMPTR ; SETDMA: JMP $-$ ;ADDR FILLED IN BY 'INIT' ; READ: MVI A,1 STA WRFLG PUSH H VREAD: CALL $-$ ;ADDR FILLED IN BY 'INIT' ORA A JZ READOK XRA A STA QFLAG 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 CALL ILPRT DB '++CANNOT WRITE UNLESS READ ISSUED' DB CR,LF,0 JMP EXPL ; PWRITE: PUSH H MVI C,1 ;FORCE WRITE TYPE 1 IN CASE 2.x DEBLOCK USED VWRITE: CALL $-$ ;ADDR FILLED IN BY 'INIT' ORA A JZ WRITOK XRA A STA QFLAG CALL ILPRT DB '++WRITE failed++',CR,LF,0 ; WRITOK: POP H RET ; ;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 '# print disk parameters for curr drive.' DB CR,LF DB '=xxx search for ASCII xxx 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,CR,LF DB '(Type any char. to continue)' DB 1,CR,LF,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 'Gnn CP/M Allocation Group nn' 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[nn] Map [from group nn]' DB CR,LF,CR,LF DB '(Type any char. to continue)' DB 1,CR,LF,CR,LF DB 'N New disk' 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 'Unn Set User nn for Find command (CP/M-2 only)' 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 '(Type any char. to continue)' DB 1,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 'All "nn" usage except "/", "T", and "S" are' DB CR,LF DB ' HEX. Use #nn for decimal.' DB CR,LF,CR,LF DB 'See DU.DOC for complete examples.' DB CR,LF,CR,LF,0 JMP PROMPT ; ;******************************** ;* * ;* 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 ; COLOP: RAL JNC COSKIP INR C ; COSKIP: DCR B JNZ COLOP RET ; ;HL-DE ==> HL ; 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: LDA VER2FL ORA A ;IF NOT CP/M 2.x THEN JZ LOG14 ; DO IT AS 1.4 LXI D,DPB ; THEN MOVE TO LOCAL MVI B,DPBLEN ; WORKSPACE CALL MOVE JMP LOGCAL ; LOG14: LHLD BDOS+1 ;FIRST FIND 1.4 BDOS MVI L,0 LXI D,DPBOFF ;THEN OFFSET TO 1.4'S DPB DAD D MVI D,0 ;SO 8 BIT PARMS WILL BE 16 MOV E,M ;NOW MOVE PARMS INX H XCHG SHLD SPT XCHG MOV E,M INX H XCHG SHLD DRM XCHG MOV A,M INX H STA BSH MOV A,M INX H STA BLM MOV E,M INX H XCHG SHLD DSM XCHG MOV E,M INX H XCHG SHLD AL0 XCHG MOV E,M XCHG SHLD SYSTRK ; LOGCAL: 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 ; ;Temporary storage area ; BUFAD: DW BASE+100H ;FORCES INITIAL READ HEXAD: DW 0 ;TO RE-FETCH A VALUE TOGO: DW 0FFFFH ;REPEAT COUNT (FFFF=CONT) TWOUP: DB 0 PFLAG: DB 0 ;1=PRINT GROUP: DW 0 GRPDIS: DB 0 SAVEFL: DB 0 CURTRK: DW 0 CURSEC: DW 1 PHYSEC: DW 1 TABCOL: DB 0 FILECT: DW 0 DIRPOS: DB 0 FINDFL: DB 0 ;1=MUST POSITION AFTER FIND FTSW: DB 1 ;SEARCH W/O INCREMENT NOTPOS: DB 1 ;INITIALLY NOT POSITIONED WRFLG: DB 0 ;MAY NOT WRITE UNTIL '+', '-', ; OR 'G' COMMAND QFLAG: DB 0 ;QUIET? (0=NO) FIRST0: DB 0 ;SETS TO 0 IF FIRST SEC # IS 0 DRIVE: DB 0 MAXTRK: DW 0 MAXSEC: DW 0 VER2FL: DB 0 SECTBL: DW 0 ;POINTER TO SECTOR SKEW TABLE ; BACK: DS 2 ;TO BACK UP IN "CA0-7F,X" DUMTYP: DS 1 ; ;-------------------------------------------------- ;The disk parameter block ;is moved here from CP/M ; DPB EQU $ ;DISK PARAMETER BLOCK (COPY) SPT: DS 2 BSH: DS 1 BLM: DS 1 EXM: DS 1 DSM: DS 2 DRM: DS 2 AL0: DS 1 AL1: DS 1 CKS: DS 2 SYSTRK: DS 2 ; ;End of disk parameter block ;-------------------------------------------------- ; SAVBUF: DS 128 INBUF: DS 128 ; ;Directory read in here; also search work area ; WORK EQU $ DIRECT EQU $ ; END