;**************************************************************** ;* * ;* CP/M FILE DUMP UTILITY * ;* DUAL DENSITY VERSION * ;* * ;**************************************************************** ; ; History : Originally published through CPMUG as ; version 1.2 by Sam SINGER ; ; Updated to version 1.3 through CPMUG ; by Sam SINGER ; ; Updated to version 1.4 by Dave Hatch ; and published by GED ; ; FEB 1,1980 Revised and extended to version 1.5 ; for double density with static density ; allocation (two sector sizes) for CP/M ; 1.4 by Bill Bolton and published by 80AT ; ; JULY 11,1980 Revised and extended to version 2.0 ; for double density with dynamic density ; allocation (four sector sizes) for CP/M ; 2.2 by Bill Bolton and published by 80AT ; ; JULY 23,1980 Minor bugs exterminated and version updated ; to 2.1 ; ; AUGUST 26,1980 Sector translation for all disk operations ; and reserved track offset in block dump ; routine added, version updated to 2.2 ; ; OCT 23,1980 Bugs in the DIR and GRP2 routines which ; showed up when tried on an Morrow HDCA-3 ; were eliminated. Conditional assembly for ; hard disk added. Flag for sector display ; header and track 0 added. ; ; FEB 10, 1981 Macro library changed to MACRO3 and DJORG ; equate added for easier DJ2D address change, ; version updated to 2.3A ; ; FEB 11, 1981 Two sided status check changed to direct ; check on 1791 controller as Model DJ2Ds ; do not return a side bit in the disk status ; firmware call. Version updated to 2.4 ; ; NOV 25, 1981 Modified for use with Godbout Disk 1 and ; Morrow HDCA-3 controller, all track number ; references changed to 16 bit values. Version ; updated to 2.5 ; ; --- DDH --- ; TITLE 'Disk 1 + HDCA-3 Disk Dump DDH Ver 2.5' ; TRUE EQU 0FFH FALSE EQU 0 ; HARD EQU TRUE ;TRUE FOR MORROW HARD DISK FIRST EQU TRUE ;TRUE FOR MORROW HARD DISK A,B,C ; & FLOPPY DISKS D,E,F,G ; FALSE FOR FLOPPY DISKS A,B,C,D ; & MORROW HARD DISK E,F,G ; FCB EQU 0005CH ;CP/M FILE CONTROL BLOCK LOC. WBOOT EQU 00000H ;CP/M WARM BOOT ENTRY LOC. BDOS EQU 00005H ;CP/M BDOS ENTRY LOC. ST$OFFSET EQU 01EH ;Offset to set track routine in BIOS ; MACLIB MACRO3 ;INCLUDE MACRO LIBRARY ; ORG 100H ;SET PROG START ; BEGIN: LXI H,0 DAD SP ;GET STACK POINTER SHLD OLDSTK LXI SP,NEWSTK ;SET UP NEW STACK DISKIO ?DRIVE ;GET CURRENTLY LOGGED DRIVE NO STA DRVNO ;SAVE FOR EXIT STA NEWDRV ;ALSO SAVE IN NEW DRIVE NO MVI C,12 ;FIRST, CHECK VERSION NUMBER CALL BDOS MOV A,L ;A <--- VERSION NO. CPI 20H ;VERSION 2.0 OR LATER? JC VERSION$ERROR ;NO, ERROR MESSAGE CALL DISKDATA ;GET DISK PARAMETERS LDA 81H ;CONSOLE INPUT ALREADY HERE ? ORA A JZ SIGNON ;BUFFER EMPTY, INPUT FROM CONSOLE LDA 80H ;GET NO OF CHAR INPUT ORI 80H ;ADD 128 MOV L,A ;TO L XRA A ;ZERO MOV H,A ;HL CONTAINS ADDR OF END OF BUFFER ZBFF: INR L JZ START ;REMAINDER OF BUFFER ZEROED MOV M,A JMP ZBFF ;LOOP SIGNON: PRINT PRINT <'Copyright (C) 1978 By Sam Singer',CR,LF> PRINT <'Copyright (C) 1980 By Bill Bolton',CR,LF,LF> PRINT <'For Godbout Disk 1 Controller',CR,LF> IF HARD PRINT <'and Morrow HDCA-3 Hard Disk Controller',CR,LF> ENDIF IF HARD AND FIRST PRINT <'Hard Disk Logical Drives A,B,C',CR,LF> PRINT <'Floppy Drives D,E,F,G',CR,LF> ELSE PRINT <'Floppy Drives A,B,C,D,',CR,LF> ENDIF IF HARD AND NOT FIRST PRINT <'Hard Disk Logical Drives E,F,G',CR,LF> ENDIF NEWIN: PRINT MVI A,0FFH ;SET SWITCH TO RETURN HERE AGAIN STA INFLAG LXI SP,NEWSTK ;RESET STACK POINTER LXI H,0 SHLD LINE ;SET LINE COUNT TO ZERO FILL 80H,0FFH ;ZERO INPUT BUFFER INPUT 80H ;READ FILE NAME ; ; SELECT DISK DRIVE AND SET UP FILE CONTROL BLOCK ; START: FILL FCB,FCB+32 ;ZERO FILE CONTROL BLOCK MATCH 82H,'A:' ;DRIVE A JZ ADISK MATCH 82H,'B:' ;DRIVE B JZ BDISK MATCH 82H,'C:' ;DRIVE C JZ CDISK MATCH 82H,'D:' ;DRIVE D JZ DDISK MATCH 82H,'E:' ;DRIVE E JZ EDISK MATCH 82H,'F:' ;DRIVE F JZ FDISK MATCH 82H,'G:' ;DRIVE G JZ GDISK JMP GETNAM ;NO DRIVE SPECIFIED ; ADISK: XRA A ;SELECT DRIVE A JMP SETDRV ; BDISK: MVI A,1 ;SELECT DRIVE B JMP SETDRV ; CDISK: MVI A,2 ;SELECT DRIVE C JMP SETDRV ; DDISK: MVI A,3 ;SELECT DRIVE D JMP SETDRV ; EDISK: MVI A,4 ;SELECT DRIVE E JMP SETDRV ; FDISK: MVI A,5 ;SELECT DRIVE F JMP SETDRV ; GDISK: MVI A,6 ;SELECT DRIVE G SETDRV: STA NEWDRV ;STORE THE SELECTED DRIVE CALL DISKDATA ;GET DISK PARAMETERS MOVE 82H,80H,40H ;SHIFT BUFFER DOWN TWO BYTES ; ; SEARCH FOR DIRECT READ OF TRACK AND SECTOR OR VALIDATE ; GETNAM: INSTR 82H,40H,'GROUP' JC GROUP ;DISPLAY CPM ALLOCATION GROUP INSTR 82H,40H,'G ' ;SEARCH FOR 'G' JC GROUP ;DISPLAY GROUP INSTR 82H,40H,'MAP' ;ALLOCATION MAP JC MAP ;DISPLAY GROUP ALLOCATION MAP INSTR 82H,40H,'DIR' ;DIRECTORY REQUEST JC DIR ;DISPLAY DIRECTORY INSTR 82H,40H,'TRACK' ;SEARCH FOR TRACK JC TRK1 INSTR 82H,40H,'T ' ;SEARCH FOR 'T' JNC FILNAM ;NO TRACK GO TO READ FILE TRK1: SCAN ;FIND AND CONVERT NUMBER DECIN JC INERR ;INPUT ERROR ON CARRY LXI D,0 SHLD TRACK ;SAVE TRACK NO. CPHL ;TRACK 0? JNZ SECSCH ;NO, CONTINUE LDA HARD$D ;ON HARD DISK? ORA A JNZ SECSCH ;YES, TRACK 0 SAME AS OTHERS MVI A,TRUE ;NO, SET A FLAG STA TK0FLAG ; FOR TRACK 0 SECSCH: INSTR 82H,40H,'SECTOR';SEARCH FOR SECTOR JC SEC1 INSTR 82H,40H,'S ' ;TRY 'S' JNC WHLTRK ;DUMP ENTIRE TRACK SEC1: SCAN DECIN JC INERR ;INPUT ERROR ON CARRY SHLD BSEC ;BEGINNING SECTOR SHLD ESEC ;SAVE IN END SECTOR ALSO XCHG ;SET BUFFER POINTER FOR SCAN SHLD IPOINT ;SAVE BUFFER POINTER FOR EDIT INSTR ,40H,'-' ;SEARCH FOR '-' JNC EDIT ;CHECK FOR EDIT OF SECTOR SCAN DECIN ;SCAN AND CONVERT ANOTHER NO JC INERR ;ERROR IF CARRY SET SHLD ESEC ;SAVE IN END SECTOR PUSH H LHLD BSEC XCHG ;DE <--- START SECTOR NO. POP H ;HL <--- END SECTOR NO. CPHL ;COMPARE BEGIN AND END JP DOREAD ;OK IF END>=BEGIN SHLD BSEC ;OTHERWISE SWITCH THEM XCHG ;HL <--- NEW END SECTOR SHLD ESEC DOREAD: CALL RDISK ;READ DIRECT JMP ENDFIL ;BACK FOR MORE INPUT ; EDIT: LHLD IPOINT ;RESET BUFFER POINTER INSTR ,40H,'EDIT' ;CHECK EDIT FUNCTION JNC DOREAD ;GO TO DISPLAY SECTOR CALL RDISK ;DISPLAY SECTOR EDIT1: PRINT FILL INBUF,INBUF+9 INPUT INBUF,6 ;INPUT MAXIMUM 6 CHAR INSTR INBUF,8,'WRITE' ;WRITE EDITED SECTOR ON DISK? JC WRTDSK ;WRITE BUFFER BACK ON DISK INSTR INBUF,8,'STOP' ;STOP EDITING WITHOUT WRITING? JC ENDFIL ;EXIT HEXIN INBUF+2 ;CONV ASCII TO HEX JNC CKLIM ;IF NO ERROR, CHECK ADDR LDAX D ;GET ASCII CHAR CPI '.' ;CHECK FOR EXIT CHAR JZ EDIT3 ;BACK FOR MORE EDITING JMP ADERR ;ADDRESS ERROR CKLIM: LXI D,0080H ;CHECK ADDR LIMIT CPHL JP ADERR ;ADDRESS ERROR SHLD IPOINT ;SAVE ADDRESS PRINT CRLF,$ PTX: HEXOUT IPOINT+1 HEXOUT IPOINT ;ECHO THE ADDRESS PRINT SPACE,$ LHLD IPOINT ;ECHO PRESENT CONTENTS LXI D,080H DAD D ;COMPUTE MEMORY ADDR MOV A,M ;GET BYTE FROM MEMORY HEXOUT PRINT SPACE,$ FILL INBUF,INBUF+5 ;ZERO INPUT BUFFER INPUT INBUF,4 ;INPUT 4 CHAR MAX HEXIN INBUF+2 ;CONVERT JNC EDIT2 ;HEX CHAR LDAX D ;GET ASCII CHAR CPI '.' ;PERIOD ENDS INPUT JZ EDIT3 ;BACK FOR MORE EDITING JMP HEXERR ;ERROR NOT HEX CHAR EDIT2: LDA INBUF+1 ;LOAD NO OF CHAR TYPED ORA A JZ EDITX ;NO REPLACEMENT IF JUST CR MOV A,L ;CONVERTED CHAR BACK TO A LHLD IPOINT ;LOAD MEMORY BUFFER POINTER LXI D,080H ;OFFSET DAD D ;CALC MEMORY ADDR MOV M,A ;STORE NEW INPUT TO MEMORY EDITX: PRINT CRLF,$ LDA IPOINT ;LEAST SIGNIFICANT HALF OF ADDR INR A ;INCR BY ONE ANI 7FH ;COUNT MOD 128 STA IPOINT JMP PTX ;INPUT MORE DATA EDIT3: LXI H,0 SHLD LINE ;RESET LINE NO TO ZERO CALL PRTSEC ;PRINT BUFFER WITH HEADING JMP EDIT1 ;BACK FOR ADDITIONAL EDITING ; WRTDSK: LDA TK0FLAG ;ON TRACK 0 ? ORA A ; JNZ WRITE$0 ;YES, NEEDS SPECIAL TREATMENT CALLBIOS DWRITE ;WRITE BUFFER BACK ON DISK JMP ENDFIL ;EXIT ; WRITE$0: JMP ENDFIL ; ; READ TRACK AND SECTOR DIRECT ; RDISK: CALL SETUP RDISK1: LDED BSEC ;GET NEXT SECTOR TO READ LDA HARD$D ORA A ;HARD DISK? JNZ RDISK2 ;TRACK 0 SAME AS OTHERS LDA TK0$FLAG ORA A ;TRACK 0 NEEDS SPECIAL TREATMENT JNZ READ$0 RDISK2: LHLD SPT ;GET SECTORS/TRACK FROM DPB SHLD SPT$ERR CPHL ;SECTOR NO. > SPT? JC GO$ON ;YES, ERROR MOV A,D ORA E ;SECTOR 0? JZ BADSEC ;YES, NOT ALLOWED LHLD BSEC ;NO, GET SECTOR NO. DCR L ;ADJUST FOR SECTRAN PUSH H POP B ;BC <--- SECTOR NUMBER LHLD XLT ;GET SECTOR TABLE ADDRESS RDISK3: XCHG ;PUT INTO DE CALLBIOS DSECTRAN ;GET THE PHYSICAL SECTOR ORA A ;RESET CARRY PUSH H POP B ;BC <--- SECTOR TO READ CALLBIOS DSETSEC GO$ON: JC BADSEC ;WRONG SECTOR NO TRK2: LHLD TRACK ;GET TRACK NO. PUSH H POP B LXI H,TRK$RET PUSH H ;RETURN ADDRESS ONTO STACK LHLD WBOOT+1 MVI L,ST$OFFSET PCHL ;WERE OFF TO SEE THE WIZARD TRK$RET: JC BADTRK ;WRONG TRACK NO CALLBIOS DREAD ;READ TRACK AND SECTOR JMP PRTSEC ; READ$0: LXI H,26 ;SINGLE DENSITY SECTORS PER TRACK SHLD SPT$ERR CPHL ;SECTOR NO. TOO BIG? JC GO$ON ;YES, ERROR MOV A,D ORA E ;SECTOR 0? JZ BADSEC ;YES, NOT ALLOWED LHLD BSEC ;NO, GET SECTOR NUMBER DCR L PUSH H POP B ;BC <--- SECTOR NUMBER LXI H,XLT$SD ;TRANSLATE TABLE JMP RDISK3 ; ; PRINT DRIVE, TRACK AND SECTOR HEADING ; PRTSEC: LDA NEWDRV ;NEW DRIVE NO ADI 41H ;ADD ASCII OFFSET PUSH PSW PRINT POP PSW MOV E,A MVI C,2 CALL BDOS PRINT HEADER,$ PRINT '- Track ' LHLD TRACK DECOUT PRINT ' Logical Sector ' LXI H,0 LHLD BSEC DECOUT PRINT ' Dump Count ' LHLD DCOUNT INX H SHLD DCOUNT DECOUT PRINT CRLF,$ PRINT CRLF,$ CALL PRTBUF ;PRINT IT LDA LINE+1 ;GET HI BYTE OF HEX ADDRESS ORA A ;IF NOT 0 JNZ SECOMP ;DONT ZERO LINE COUNT LXI H,0 SHLD LINE ;RESET HEX ADDRESS COUNT SECOMP: LHLD ESEC ;END SECTOR NUMBER XCHG ;DE <--- END SECTOR LHLD BSEC ;SECTOR JUST READ CPHL ;COMPARE THEM RZ ;EXIT IF THEY ARE EQUAL INX H ;BUMP TO NEXT SECTOR SHLD BSEC JMP RDISK1 ; ; DUMP ENTIRE TRACK IF NO SECTOR INPUT ; WHLTRK: LXI H,1 ;BEGIN SECTOR SHLD BSEC ;SAVE IT FOR THIS DUMP LDA TK0FLAG ORA A ;ON FLOPPY TRACK 0? LXI H,26 ;FLOPPY TRACK 0 ALWAYS HAS 26 SECTORS JNZ ENDSEC ;YES, SAVE IT IMMEDIATELY LHLD SPT ;NO, HIGHEST SECTOR NO. FROM DPB ENDSEC: SHLD ESEC ;SAVE IT FOR THIS DUMP JMP DOREAD ;GO READ IT ; ; FILL IN FCB FOR NAMED FILE ; FILNAM: MVI A,TRUE STA FDFLAG ;SET FILE DUMP FLAG FILFCB FCB,82H ;FILL IN FCB NAME FROM INPUT BUFFER JC NAMERR ;ERROR IN FILE NAME MATCH FCB+9,'COM' ;TEST FOR COM FILE JNZ SELDR LXI H,100H SHLD LINE ;SET LINE NO. TO 100 SELDR: LDA NEWDRV ;SELECT NEW DRIVE MOV E,A DISKIO LOGIN FILSER: DISKIO SEARCH,FCB ;LOOK FOR FILE ORA A ;FOUND IT? PUSH PSW ;SAVE BDOS RETURN INFO LDA EXFLAG ;GET EXTENT COUNT ORA A ;1ST EXTENT? JZ ERR1 ;YES, CHECK FOR FILE NOT FOUND POP PSW ;RESTORE BDOS RETURN INFO JM ENDFIL ;IF NOT FOUND, BACK FOR MORE INPUT JMP RDFILE ; ; ERR1: POP PSW ;RESTORE BDOS RETURN INFO JM OPNERR ;IF NOT FOUND, TELL THE USER RDFILE: RRC RRC RRC ;SAME AS 5 'ADD A' INSTRUCTIONS ANI 60H ;MASK THE BITS OF INTEREST ADI 80H ;ADD BASE ADDRESS OF BUFFER ADI 0CH ;ADD OFFSET TO EXTENT NO. PUSH PSW FILL DIRBUF,DIRBUF+21,00 ;INITIALISE BUFFER POP PSW MOV L,A MVI H,0 ;SET UP SOURCE ADDRESS LXI D,DIRBUF ;SET UP DESTINATION ADDRESS MVI C,20 ;SET UP COUNT MVI B,0 ;DITTO MOVE ;DO THE MOVE LXI H,RCOUNT ;POINT TO RECORD COUNT MOV A,M ;GET RECORD COUNT CPI 128 ;POSSIBLY ANOTHER EXTENT? JNZ NOEXT ;NO, DUMP THE GROUPS LDA EXFLAG ;YES, GET EXTENT COUNT INR A ;ADD 1 TO IT STA EXFLAG ;SAVE IT NOEXT: PUSH H ;TEMP SAVE H LHLD DSM ;GET DSM VALUE LXI D,0FF00H ;SET NO. BYTES / GROUP DAD D ;IF > 255 THEN TWO BYTES POP H JC TWO$BYTE ONE$BYTE: INX H ;BUMP TO NEXT GROUP NO. PUSH H MOV A,M ;GET THE NEXT GROUP NO. CPI 00 ;DONE LAST GROUP? JZ QUIT ;YES, CHECK FOR MORE EXTENTS MVI H,0 MOV L,A ;GROUP NO. IN HL CALL GROUPS ;DISPLAY THE SECTORS POP H JMP ONE$BYTE ; TWO$BYTE: MVI A,8 ;GROUP POSITIONS/DIR ENTRY STA P$COUNT LOOP2: INX H ;POINT TO NEXT GROUP NO. MOV A,M ;GET LOW BYTE INX H PUSH H ;SAVE POINTER MOV H,M ;GET HI BYTE MOV L,A ;FORM GROUP NUMBER DJZ QUIT ;QUIT IF EMPTY GROUP POSITION CALL GROUPS ;DISPLAY THE SECTORS LDA P$COUNT ;CHECK IF LAST GROUP NO. DCR A JZ QUIT ;YES, CHECK FOR NEXT EXTENT STA P$COUNT ;SAVE FOR NEXT LOOP CHECK POP H JMP LOOP2 ; QUIT: POP H ;KEEP STACK CLEAN XRA A STA SCOUNT ;RESET SECTOR COUNT LXI H,FCB+12 ;POINT TO EXTENT NO. IN FCB LDA EXFLAG ;GET NEXT EXTENT NO. CMP M ;ARE THEY EQUAL JZ ENDFIL ;YES, NO MORE EXTENTS SO EXIT MOV M,A ;NO, STUFF NEXT EXTENT NUMBER JMP FILSER ;LOOK FOR NEXT EXTENT ; ENDFIL: XRA A STA TK0FLAG ;RESET TRACK 0 FLAG STA EXFLAG ;RESET EXTENT COUNT STA FDFLAG ;RESET FILE DUMP FLAG STA SCOUNT ;RESET SECTORS DONE COUNT STA DCOUNT ;RESET DUMP COUNT LOW BYTE STA DCOUNT+1 ; " " " HI BYTE LDA INFLAG ;SEE WHERE TO GO ORA A JZ MONITOR JMP NEWIN ; ; ; PRTBUF - PRINT BUFFER IN HEX AND ASCII ; PRTBUF: MVI B,8 ;8 LINES LXI H,080H ;INITIAL BUFFER POINTER SHLD IPOINT ;STORAGE FOR POINTER BPRN: LHLD IPOINT ;LOAD POINTER MVI C,16 ;CHAR PER LINE SAVE B,H ;PROTECT B,H DURING PRINT CALLS LDA LINE+1 ;GET HIGH BYTE OF HEX ADDR ORA A ;IS IT 00? JZ SIMPLE ;YES, PAD 1ST TWO POSITIONS HEXOUT LINE+1 ;PRINT HIGH BYTE OF HEX ADDR JMP LOWBYT SIMPLE: PRINT ' ' ;PRINT SPACES INSTEAD OF, LOWBYT: HEXOUT LINE ;PRINT LOW BYTE OF ADDRESS PRINT ' : ' RESTORE H,B PLOOP: MOV A,M ;GET A BYTE SAVE B,H HEXOUT PRINT SPACE,$ RESTORE H,B INX H ;INCR MEMORY POINTER DCR C ;DECR CHARACTER COUNT JZ SKIP ;DONE 16 YET? MOV A,C ;NO, SO CONTINUE ANI 3 ;TIME FOR SPACE MARKER? JNZ PLOOP ;NO, PRINT SOME MORE SAVE B,H PRINT SPACE,$ ;YES, PRINT SPACE MARKER RESTORE H,B JMP PLOOP ;PRINT SOME MORE SKIP: SAVE B PRINT SPACE,$ RESTORE B LHLD IPOINT ;RESET POINTER FOR ASCII MVI C,10H ;RESET CHAR COUNT PLOOP1: MOV A,M ;GET A BYTE ANI 7FH ;MASK OFF HIGH BIT CPI 7FH ;DELETE CODE JZ PERIOD ;PRINT PERIOD FOR DELETE CPI 20H ;TEST FOR CONTROL CHAR JP SKIPX ;SKIP SUBSTITUTION PERIOD: MVI A,2EH ;ASCII PERIOD SKIPX: SAVE B,H CHAROUT ;PRINT IT SAVE REGS RESTORE H,B INX H ;INCR MEMORY POINTER MOV A,C CPI 9 ;CHECK 8 CHAR JNZ DECC2 SAVE B,H PRINT SPACE,$ RESTORE H,B DECC2: DCR C ;DECR CHAR COUNT JNZ PLOOP1 ;PRINT SOME MORE SAVE B PRINT CRLF,$ ;CARRIAGE RETURN CALL PRNCON ;PRINT CONTROL? POP B INDEX LINE,16 ;INCR LINE NO BY 16 DCR B ;DECR LINE COUNT RZ ;RETURN IF LINE COUNT ZERO INDEX IPOINT,16 ;INCR POINTER BY 16 JMP BPRN ;LOOP BACK ; ; PRINT CONTROL AND ESCAPE ; PRNCON: MVI C,11 CALL 5 ANI 1 RZ ;RETURN CHARIN ;READ CONSOLE CPI 3 ;TEST FOR CONTROL C JZ ENDFIL ;EXIT IF CONTROL C CPI ' ' ;TEST FOR SPACE JZ ENDFIL ;ABORT FUNCTION RET ; ; THIS SECTION DISPLAYS A CPM ALLOCATION GROUP ; GROUP: SCAN ;GET THE GROUP NO DECIN ;CONVERT TO BINARY JC INERR ;INPUT ERROR IF CARRY SET CALL GROUPS ;DO THIS GROUP JMP ENDFIL ;EXIT ; GROUPS: SHLD G ;SAVE GROUP NO XCHG ;DE <--- GROUP NO. LHLD DSM ;GET MAX GROUP NO. CPHL ;GROUP NO. TOO BIG? JC BADGRP ;YES, ERROR MESSAGE LXI H,0 ;NO SHLD S ;SET SECTOR COUNT TO 0 GRP1: CALL GRPTS ;CONVERT TO TRACK AND SECTOR LHLD TRACK ;GET LAST TRACK ACCESSED LDED NEW$TRACK ;GET NEXT TRACK TO ACCESS CPHL ;SAME TRACK ? XCHG SHLD TRACK ;STORE TRACK NO. CNZ SETUP ;NO, SET UP THE DRIVE CALL RDISK1 ;PRINT THE SECTOR LDA FDFLAG ;FILE DUMP IN PROGRESS? ORA A JZ GRP2 ;NO, CONTINUE LDA SCOUNT ;GET SECTORS DONE COUNT INR A STA SCOUNT ;SAVE IT AGAIN LXI H,RCOUNT CMP M ;HAVE WE DONE ALL THE SECTORS RZ ;YES, RETURN GRP2: LXI H,BLM ;POINT TO (SECTORS/BLOCK)-1 MOV L,M ;GET (SECTORS/BLOCK)-1 MVI H,0 XCHG ;DE <--- " " LHLD S ;GET SECTOR COUNT CPHL ;DONE LAST SECTOR IN BLOCK? RZ ;YES INX H ;NO, BUMP SECTOR COUNT SHLD S ;SAVE IT JMP GRP1 ;PRINT ANOTHER SECTOR ; ; GRPTS CONVERT CPM GROUP AND SECTOR NUMBER TO TRK AND SEC ; GRPTS: LHLD SPT XCHG ;DE <--- SECTORS/TRACK LXI H,0 DSUB ;FORM DIVISOR SHLD DIVISOR ;SAVE IT LHLD G ;GET GROUP NO. LDA BSH ;GET BLOCK SHIFT FACTOR SHIFT$LOOP: DAD H ;SHIFT LEFT ONE DCR A ;ENOUGH SHIFTS ? JNZ SHIFT$LOOP ;NO DO IT AGAIN PUSH H ;TEMP SAVE HL LHLD S ;GET SECTOR NO. XCHG ;DE <--- " " POP H DAD D ;HL NOW HAS G*(BLOCK SIZE)+S PUSH H ;TEMP SAVE HL LHLD DIVISOR XCHG ;DE <--- DIVISOR LHLD OFF ;GET NO. OF RESERVED TRACKS PUSH H POP B ;BC <--- NO. OF RESERVED TRACKS POP H ;HL <--- DIVIDEND DCX B ;ADJUST FOR LOOP ENTRY DIVIDE: DAD D ;SUBTRACT DIVISOR INX B ;ADJUST TRACK NO. JC DIVIDE ;LOOP TILL MINUS PUSH H PUSH B POP H SHLD NEW$TRACK ;STORE TRACK NO. LHLD SPT ;INDEX INTO TABLE XCHG ;DE <--- INDEX POP H STORE: DAD D ;FORM LOGICAL SECTOR NUMBER INR L ;ADJUST FOR SECTRAN LATER SHLD BSEC ;SAVE IN BEGINNING SECTOR SHLD ESEC ;SAVE IN END SECTOR TOO RET ; ; THIS ROUTINE DISPLAYS THE DISK SECTOR ALLOCATION MAP ; MAP: LDA NEWDRV MOV E,A DISKIO LOGIN ;LOG IN SELECTED DRIVE DISKIO ?ALLOC ;GET POINTER TO ALLOCATION MAP MOV H,B MOV L,A ;HL <--- POINTER TO MAP SHLD IPOINT ;SAVE IT LXI H,0 SHLD G ;ZERO COUNT OF UNUSED GROUPS PRINT PRINT <'GROUP ALLOCATION MAP - DRIVE '> LDA NEWDRV ;NEW DRIVE NO ADI 41H ;ADD ASCII OFFSET MOV E,A MVI C,2 CALL BDOS PRINT XRA A LHLD DSM ;GET NO. BLOCKS (GROUPS) INX H SHLD MAP$COUNT ;SAVE FOR BLOCKS+1 LXI D,-48 ;48 BITS MAPPED/LINE MAP1: DAD D ;SUBTRACT A LINE INR A ;BUMP LINE COUNT JC MAP1 MOV D,A ;D <--- NO. LINE TO DISPLAY LHLD IPOINT ;POINTER TO DISK ALLOCATION MAP MAP2: MVI C,6 ;WORDS PER LINE MAPX: SAVE PRINT ' ' RESTORE MAP3: MVI B,8 ;BITS PER WORD MOV A,M ;GET A BYTE FROM ALLOC MAP MAP4: RAL ;SHIFT LEFT THRU CARRY SAVE B,D,H,PSW JC MAP5 ;PRINT A ONE PRINT '0' ;PRINT A ZERO LHLD G ;UNUSED GROUPS INX H ;ADD 1 SHLD G ;STORE IT BACK JMP MAP6 MAP5: PRINT '1' ;PRINT A ONE MAP6: RESTORE PSW,H,D,B SAVE PSW,H ;SAVE BIT MAP BYTE LHLD MAP$COUNT ;GET BYTES REMAINING DCX H SHLD MAP$COUNT ;SAVE NEW BYTES LEFT DJZ FINISHED ;QUIT IF DONE MOV A,B ;BIT COUNT CPI 1 ;LAST BIT OF BYTE? JZ BITS ;YES DCR B RESTORE H,PSW JMP MAP4 ; BITS: RESTORE H MOV A,C ;GET WORD COUNT CPI 1 ;LAST WORD OF LINE? JZ NEW$LINE ;YES DCR C ;ADJUST WORD COUNT INX H ;BUMP POINTER TO NEXT BYTE RESTORE PSW JMP MAP3 ; NEW$LINE: INX H ;BUMP BYTE POINTER SAVE PRINT CRLF,$ ;NEXT LINE ON SCREEN RESTORE RESTORE PSW JMP MAP2 ; FINISHED: RESTORE PSW PRINT DECOUT G ;PRINT NO OF UNUSED BLOCKS/GROUPS PRINT <' GROUPS REMAINING ON DISK OUT OF '> DECOUT DSM ;PRINT MAX NUMBER OF BLOCKS/GROUPS PRINT JMP ENDFIL ;EXIT ; ; THIS ROUTINE DUMPS THE DIRECTORY GROUPS ; DIR: LXI D,0FFFFH ;SET UP DE LDA AL0 ;GET FIRST DIR ALLOC MAP DIR$TEST: RAL ;IS BIT SET? JNC DIR$DUMP2 ;NO, DUMP THE DIRECTORY INX D ;YES, BUMP BLOCK COUNT PUSH PSW MVI A,8 ;NO. OF BITS IN A BYTE CMP E ;DONE 8 BITS? JZ NEXT$BYTE ;YES, TTEST AL1 MVI A,16 ;MAX NO. OF BITS CMP E ;DONE 16 BITS? JZ DIR$DUMP1 ;YES, DUMP DIRECTORY POP PSW JMP DIR$TEST ;TEST NEXT BIT ; NEXT$BYTE: POP PSW ;KEEP STACK STRAIGHT LDA AL1 ;GET AL1 JMP DIR$TEST ;GO TEST IT ; DIR$DUMP1: POP PSW ;KEEP STACK STRAIGHT DIR$DUMP2: LXI H,0 ;START WITH GROUP 0 DIR$LOOP: SAVE H,D CALL GROUPS ;DO THE DUMP RESTORE D,H CPHL ;DONE ALL THE DIR GROUPS? INX H ;BUMP GROUP NO. JNZ DIR$LOOP ;YES, NO DO IT AGAIN JMP ENDFIL ;EXIT ; SETUP: LDA NEWDRV MOV E,A DISKIO LOGIN ;SELECT NEW DRIVE (IF REQUESTED) CALLBIOS DHOME ;HOME SELECTED DRIVE RET ; ; FIND THE SECTOR SIZE AND NUMBER OF SIDES OF THE MEDIA ; DISKDATA: CALL SETUP ;LOG DRIVE INTO BDOS LDA NEWDRV ;GET DRIVE NO. IF HARD AND FIRST CPI 3 ;HARD DISK? JNC FLOPPY ;NO MVI A,TRUE ;SET A FLAG STA HARD$D JMP NEXT ENDIF IF HARD AND NOT FIRST CPI 2 ;HARD DISK? JC FLOPPY ;NO MVI A,TRUE ;SET A FLAG STA HARD$D JMP NEXT ENDIF FLOPPY: XRA A STA HARD$D NEXT: LXI B,NEWSTK ;END OF THIS PROGRAM CALLBIOS DSETDMA LDA NEWDRV ;NOW GET THE MOV C,A ; XLT LOCATION CALLBIOS DSELDSK ;SELECT THE DRIVE MOV A,M ;GET XLT ADDR LO BYTE INX H ;POINT TO XLT HI BYTE MOV H,M ;GET XLT ADDR HI BYTE MOV L,A ;FORM ADDRESS SHLD XLT ;SAVE XLT ADDRESS MVI C,1 ;SET TO TRACK OTHER THAN 0 CALLBIOS DSETTRK ;DO IT MVI C,1 CALLBIOS DSETSEC ;SET THE SECTOR CALLBIOS DREAD ;READ THE DISK MVI C,31 ;GET DISK PARAMETER BLOCK CALL BDOS ;HL POINTS TO BIOS DPB ON RETURN SHLD DPB$ADDR ;SAVE DPB ADDRESS LXI D,DPB ;POINT TO PROGRAM DPB STORAGE AREA LXI B,15 ;LENGTH TO MOVE MOVE ;COPY DPB FROM BIOS LDA HARD$D ORA A ;ON HARD DISK? CALL HARDWARE ;NO, HARDWARE SPECIFIC ROUTINE LXI B,0080H ;RESET DMA ADRESS CALLBIOS DSETDMA RET ; ; ;**************************************************************** ;* * ;* HARDWARE * ;* * ;* This is routine has to be provided by the user * ;* to suit their disk controller hardware. It must * ;* set up the display header to suit the types * ;* of drive you are using. This is up to you * ;* but I would suggest something informative * ;* about the disk format, i.e. single/double * ;* sided, single/double density, sector size * ;* etc. as in the DJ2D example below. * ;* * ;**************************************************************** ; HARDWARE: LXI H,HEAD$HARD ;POINTER TO HEADER FOR HARD DISK JNZ MOVER ;DISPLAY ONLY IF HARD FLAG SET LHLD DPB$ADDR ;GET DPB START DCX H ;GODBOUT HAS DISK TYPE BEFORE XLT MOV A,M ;A <---- DISK TYPE LXI H,HEAD$TABLE RAL ;MULTIPLY DISK TYPE BY 2 MVI D,0 MOV E,A ;DE <---- OFFSET INTO TABLE DAD D ;HL <---- POINTS TO HEADER ADDRESS CONTENTS ;HL <---- POINTS TO HEADER MOVER: LXI D,HEADER ;BUFFER FOR DISPLAY HEADER LXI B,14 ;LENGTH OF MESSAGE MOVE ;MOVE IT RET ; HEAD$TABLE: DW HEAD$128S DW HEAD$128D DW HEAD$256S DW HEAD$256D DW HEAD$512S DW HEAD$512D DW HEAD$1024S DW HEAD$1024D ; HEAD$128S: DB ' : 1S/1D/128 ' ; HEAD$256S: DB ' : 1S/2D/256 ' ; HEAD$512S: DB ' : 1S/2D/512 ' ; HEAD$1024S: DB ' : 1S/2D/1024 ' ; HEAD$128D: DB ' : 2S/1D/128 ' ; HEAD$256D: DB ' : 2S/2D/256 ' ; HEAD$512D DB ' : 2S/2D/512 ' ; HEAD$1024D: DB ' : 2S/2D/1024 ' ; HEAD$HARD: DB ' : Hard Disk ' ; ; ERROR AND EXIT ROUTINES ; ; INERR: PRINT JMP ENDFIL ; BADSEC: PRINT DECOUT SPT$ERR JMP ENDFIL ; BADTRK: PRINT JMP ENDFIL ; BADGRP: PRINT DECOUT DSM RET ; OPNERR: PRINT LDA NEWDRV ;NEW DRIVE NO ADI 41H ;ADD ASCII OFFSET MOV E,A MVI C,2 CALL BDOS JMP ENDFIL ; RDERR: PRINT JMP MONITOR ; NAMERR: PRINT JMP ENDFIL ; ADERR: PRINT JMP EDIT1 ;ADDRESS ERROR ON EDIT ; HEXERR: PRINT JMP PTX ; VERSION$ERROR: PRINT <'Sorry, you need CP/M version 2.0 or later',CR,LF> PRINT <'to run this disk dump program'> ; MONITOR: PRINT CRLF,$ LDA DRVNO ;RESTORE LOGGED DRIVE NO MOV E,A DISKIO LOGIN LHLD OLDSTK SPHL ;RESET OLD STACK POINTER RET ; ; ; DATA ALLOCATIONS ; SPACE: DB ' $' ;ASCII SPACE CRLF: DB 0DH,0AH,24H ;ASCII CR LF XLT: DW 00 ;SECTOR TRANSLATE TABLE ADDDR DIVISOR:DW 00 ;USED IN GROUP CALCS SEC$INDEX:DW 00 ;DITTO I: DW 00 ;PSEUDO INDEX REGISTER LINE: DW 00 ;LINE NUMBER FOR LISTING IPOINT: DW 00 ;VARIABLE BUFFER POINTER LASTIN: DB 0 ;LAST CONSOLE INPUT CHAR INFLAG: DB 0 ;FLAG, RET FOR MORE CONSOLE INPUT DRVNO: DB 0 ;STORAGE FOR ORIGINALLY LOGGED DRIVE NEWDRV: DB 0 ;STORAGE FOR NEW DRIVE NO TK0FLAG:DB 0 ;DRIVE ON TRACK 0 HARD$D: DB 0 ;HARD DISK FLAG TRACK: DW 0 ;SELECTED TRACK NEW$TRACK:DW 0 ;NEXT TRACK TO ACCESS BSEC: DW 00 ;SELECTED BEGINNING SECTOR ESEC: DW 00 ;SELECTED ENDING SECTOR DCOUNT: DW 00 ;SECTORS DUMPED COUNT SCOUNT: DB 0 ;SECTORS DUMPED IN CURRENT EXTENT P$COUNT:DB 0 ;GROUPS DONE COUNT G: DW 00 ;CPM GROUP NO S: DW 00 ;SECTOR NO WITHIN GROUP G MAP$COUNT:DW 00 ;GROUPS REMAINING TO MAP OLDSTK: DW 00 ;STORAGE FOR OLD STACK POINTER INB: DW 00 ;STORES POINTER TO INPUT BUFFER AREA OUTB: DW 00 ;STORES POINTER TO DIRECTORY BUFFER AREA FDFLAG: DB 0 ;FILE DUMP IN PROGRESS FLAG EXFLAG: DB 0 ;EXTENT CHECK FLAG AND COUNT SPT$ERR:DW 0 ;MAX SECTOR NO. FOR BADSEC ERROR ; DPB$ADDR: DW 0 ;START OF DPB IN BIOS DPB: ;START OF DISK PARAMETER BLOCK SPT: DW 00 ;TOTAL NUMBER OF SECTORS/TRACK BSH: DB 0 ;DATA ALLOC BLOCK SHIFT FACTOR BLM: DB 0 ;CP/M DOCUMENTATION STRIKES AGAIN EXM: DB 0 ;EXTENT MASK DSM: DW 00 ;MAXIMUM DATA BLLOCK (GROUP) NUMBER DRM: DW 00 ;TOTAL NO. OF DIRECTORY ENTRIES AL0: DB 0 ;BIT MAP OF THE NO. OF BLOCKS (GROUPS) AL1: DB 0 ; RESERVED FOR THE DIRECTORY CKS: DW 00 ;DIRECTORY CHECK VECTOR OFF: DW 00 ;NUMBER OF RESERVED TRACKS ; HEADER: DS 14 ;DISPLAY HEADER MESSAGE BUFFER DB '$' ; INBUF: DS 10 ;USED AS CONSOLE INPUT BUFFER DIRBUF: DS 03 ;BUFFER FOR FILE GROUP ALLOCATION INFO RCOUNT: DS 01 ;NO. OF RECORDS IN CURRENT EXTENT ALLOC: DS 18 ;GROUP ALLOCATION TABLE ; XLT$SD: DB 00,06,12,18,24,04,10,16,22,02,08,14,20 DB 01,07,13,19,25,05,11,17,23,03,09,15,21 ; ENDSTK: DS 64 ;STACK SPACE ALLOCATION NEWSTK: ;SP LOAD POINT END BEGIN