; DATE 02/16/84 16:16 last update ; 02/16/84 the program has been converted to support both CP/M-86 ver 3.1 ; and CCP/M-86 ver 3.1. ; MP/M is not supported but only because I don't have a way to test this ; version on the MPM operating system. TITLE 'UNERA FOR CP/M-86 VER3.1' ; UNERA31.A86 ; by: H.H. Van Tassell, 120 Hill Hollow Rd, Watchung NJ 07060 (201)755-5272 ; ; This is a program to recover erased files in CP/M-86 and is modelled on the ; UNERA program for CP/M-80 on SIG/M volume 76. See volumes 76 and 44 for ; author credits and more information. ; ; The program reads the directory, sector by sector, listing filenames that ; have been erase by placing an 0E5H as byte 0. The extent number is also ; listed. NO check is made to determine if the disk space has been re-allocated ; to another file after the file was erased. After listing the file names, the ; user is asked if recovery is desired. A page of help is displayed if the ; program is invoked with // as the file name. ; The direct BIOS disk call data structure was choosen for conversion to ; CP/M-86 versions 3.0 and higher (CONCURRENT and PLUS). ; ; TO GENERATE PROGRAM: ; RASM86 UNERA $SZPZ ; LINK86 UNERA [data[add [100]]] ; ; SLINES EQU 22 ;LINES ON CONSOLE LESS 2 FALSE EQU 0 TRUE EQU NOT FALSE CR EQU 13 LF EQU 10 TAB EQU 9 CONIN EQU 1 ;READ CONSOLE DCONIN EQU 6 ;DIRECT CONSOLE READ RESET EQU 13 ;SYSTEM RESET SELDSK EQU 14 ;SELECT DISK GETDR EQU 25 ;GET DRIVE DIRBIOS EQU 50 ;DIRECT BIOS CALLS ; DIRECT BIOS CALL PARAMETER BLOCK DATA STRUCTURE ; BPB_FUNC EQU BYTE PTR 0[BX] BPB_CX EQU WORD PTR 1[BX] BPB_DX EQU WORD PTR 3[BX] ; DISK BIOS CALLS DATA STRUCTURE ; SELECT_DISK EQU WORD PTR 0[BX] SET_TRACK EQU WORD PTR 2[BX] SET_DMASEG EQU WORD PTR 4[BX] SET_DMAOFF EQU WORD PTR 6[BX] SET_SECTOR EQU WORD PTR 8[BX] READ_SECTOR EQU WORD PTR 10[BX] WRITE_SECTOR EQU WORD PTR 12[BX] SECTOR_XLAT EQU WORD PTR 14[BX] TBUF EQU 80H ;TRANSIT DEFAULT BUFFER FCB EQU 5CH ;DEFAULT FILE CONTROL BLOCK DRV_DPB equ 31 ;BDOS call 31 BIO_SELDSK equ 9 ;BIOS function number BIO_READ equ 10 ;BIOS function number BIO_WRITE equ 11 ;BIOS function number ; PARTIAL DATA STRUCTURE OF DPH ; LOG_SEQN equ byte ptr 6 ;to force reset of permanent media DPB_PTR31 equ word ptr 8 ;offset of DPB pointer in DPH (v3.1) DPB_PTR11 equ word ptr 10 ;offset in version 1.1 DPB_SIZE equ 17 ;size of Disk Parameter Block ; DPB DATA STRUCTURE ; SPT equ word ptr 0[bx] BSH equ byte ptr 2[bx] BLM equ byte ptr 3[bx] EXM equ byte ptr 4[bx] DSM equ word ptr 5[bx] DRM equ word ptr 7[bx] AL0 equ byte ptr 9[bx] AL1 equ byte ptr 10[bx] CKS equ word ptr 11[bx] OFF equ word ptr 13[bx] PHYSHF equ byte ptr 15[bx] PHYMSK equ byte ptr 16[bx] BIOS_PTR equ dword ptr .28h ;loc of BIOS entry in SYSDAT UDA_SEG equ word ptr .4eh ;loc of UDA seg in system data area ;------- for CCP/M -3.1 ---------------- S_SYSDAT equ 154 ;get system data area P_PDADR equ 156 ;get PDA address CCPM_31 equ 1431h ;CCP/M-86 version number P_UDA equ word ptr 10h ;User Data Area ;----------------------------------------- CSEG MOV CX,DS ;USING DATA SEGMENT MOV SS,CX ;SET UP LOCAL STACK LEA SP,STACK CALL HELLO CALL PCHECK CALL TRYFIX CMP FIXCNT,0 ;WERE ANY FIXABLE FILES FOUND? JZ NO_RECOVER CALL RECOVER ;YES, GO RECOVER EM NO_RECOVER: CALL BYE EXIT: MOV CL,SELDSK ;RETURN TO CURRENT DISK MOV DL,BYTE PTR CURDR INT 224 MOV CL,RESET ;RESET SYSTEM INT 224 QUIT: MOV CL,0 MOV DL,0 INT 224 ; SAY WHO WE ARE HELLO: MOV DX,OFFSET HMSG ;POINT TO HELLO MESSAGE CALL PRINT RET ; CHECK FOR VALID PARAMETERS PCHECK: CALL FCBCHK ;MAKE SURE FILE IS SPECIFIED CALL CPMCHK ;CHECK CP/M VERSION RET ; ASK IF THEY WANT TO RECOVER THE REVIEWED FILES RECOVER: MOV DX,OFFSET RVMSG ;ASK IF RECOVERY WANTED CALL PRINT MOV CL,CONIN ;GET ANSWER INT 224 AND AL,5FH ;MAKE UPPER CASE CMP AL,'Y' JNE EXIT ;EXIT UNLESS YES MOV VIEW_EM,0 ;RESET THE VIEW FLAG MOV FIX_EM,0FFH ;SET THE FIX EM FLAG MOV AL,BYTE PTR MAXSEC ;RESTORE MAXDIR MOV BYTE PTR MAXDIR,AL MOV SECTOR,0 ;SECTOR MOV FIXCNT,0 ;AND FIXCOUNT CALL TRYFIX ;AND FIXEM RET ; LOOK THROUGH THE DIRECTORY TRYING TO MATCH FCB FILENAME TRYFIX: CALL NXTSECT ;GET A DIRECTORY SECTOR JNZ TRY_MORE ;RETURNS ZERO SET IF NO MORE RET TRY_MORE: CALL CHKENT ;CHECK IT OUT AND MAYBE FIX JMPS TRYFIX ;KEEP IT UP TILL DONE ; SIGN OFF BYE: CMP FIXCNT,0 ;CHECK FOR ACTIVITY JE NOFIND MOV DX,OFFSET BMSG ;WARN EM CALL PRINT RET NOFIND: MOV DX,OFFSET NFMSG ;SAY NOTHING FOUND CALL PRINT RET ; MAKE SURE A LEGAL FILENAME WAS FOUND FCBCHK: ; scans tbuffer at 80h for a / as indication of help wanted ; returns with ZF set if '/' is found in buffer ; push es ! push ds ! pop es ;save ES, ES=DS xor cx,cx mov di,80h ;point to tbuffer @ 80h mov cl,byte ptr[di] ;CX=length of tbuf string inc cx mov al,'/' repnz scasb ;scan for / pop es ;ZF set if help signal jz help CMP BYTE PTR .FCB+1,' ' ;IS 1ST BYTE A NON BLANK JBE NO_NAME MOV CL,GETDR ;GET CURRENT DRIVE INT 224 MOV BYTE PTR CURDR,AL ;SAVE IT MOV AL,BYTE PTR .FCB ;SEE IF DEFAULT DRIVE SPEC CMP AL,0 JZ DEFAULT ;YES, NO DEC DEC AL ;ELSE DEC IT PUSH AX MOV CL,SELDSK ;SELECT DISK MOV DL,AL INT 224 POP AX JMPS NOT_DEFAULT DEFAULT: MOV AL,CURDR NOT_DEFAULT: MOV BYTE PTR .FCB,AL ;PUT IT BACK AND MOV DRIVE,AL ADD AL,'A' ;MAKE IT ASCII MOV BYTE PTR FILNAM0,AL ;AND PUT IT IN FILNAM DATA RET NO_NAME: MOV DX,OFFSET NOFMSG ;CANT FIND A FILE NAME CALL PRINT JMP QUIT ; GIVE EM SOME HELP AND QUIT HELP: MOV DX,OFFSET HLPMSG CALL PRINT JMP QUIT IS_MPM: MOV DX,OFFSET MPMSG CALL PRINT JMP EXIT UNK_VER: MOV DX,OFFSET WVMSG CALL PRINT JMP EXIT ; CHECKS CPM VERSION AND INITIALIZES THINGS CPMCHK: MOV CL,12 ;GET VERSION NUMBER INT 224 MOV CPM_VERSION,AX ;SAVE IT TEST AH,01H ;IS IT MP/M ? JNZ IS_MPM CMP AL,22H ;IS IT VERSION 11 JE VER_11 CMP AL,31H ;IS IT VERSION 31 JE VER_31 JMP UNK_VER ;UNKNOWN VERSION VER_11: MOV CALL_TBL,OFFSET TABLE11 JMPS VER_OK VER_31: MOV CALL_TBL,OFFSET TABLE31 VER_OK: MOV CL,BYTE PTR .FCB ;GET DRIVE XOR CH,CH XOR DX,DX ;FIRST SELECTION MOV BX,CALL_TBL CALL SELECT_DISK ;SELECT DISK CMP BX,0 ;IS DISK OK JNZ DISKOK ;TELL IF NOT OK CALL ILDISK DISKOK: ;A CALL TO DISK SELECT COPYS CMP BYTE PTR CPM_VERSION,31H ! JE SETUP31 SETUP11: MOV AX,ES:WORD PTR [BX] ;XLAT TABLE ADDRESS IN BX MOV XLAT_ADR,AX MOV CL,31 ;GET DISK PARAMETERS INT 224 MOV AX,ES:WORD PTR 13[BX] ;GET DIRECTORY TRACK MOV DX,ES:WORD PTR 7[BX] ;DX=DRM MOV CL,2 ;SHIFT RIGHT TWICE JMPS COM_SETUP SETUP31: MOV BX,OFFSET DPB ;THE DPB TO LOCAL STORAGE MOV AX,SPT MOV SEC_PER_TRK,AX MOV AL,4 MOV CL,PHYSHF ;GET PHYSICAL SHIFT CMP CL,0 ! JZ SSSD ;PHYSHF IS ZERO FOR SSSD SHL AL,CL ;SHIFT LEFT ? TIMES GIVES SSSD: MOV DIR_PER_SEC,AL ;NUMBER DIR ENTRYS/SECTOR MOV AX,OFF ;GET DIRECTORY TRACK MOV DX,DRM ;GET NUMBER OF DIR ENTRYS-1 MOV CL,PHYSHF ADD CL,2 COM_SETUP: INC DX ;ACCOUNT FOR -1 SHR DX,CL ;SHIFT RIGHT ? TIMES = SECTORS MOV MAXDIR,DX ;SAVE NUMBER OF DIR SECTORS MOV MAXSEC,DX MOV TRACK,AX ;SAVE DIRECTORY TRACK MOV SECTOR,0 ;ZERO SECTOR COUNT MOV FIXCNT,0 MOV CX,DS MOV DMASEG,CX MOV BX,CALL_TBL CALL SET_DMASEG ;SET DMA SEGMENT TO DATA SEG MOV CX,DMAOFF MOV BX,CALL_TBL CALL SET_DMAOFF ;SET DMA TO DIR_BUF RET ; READS NEXT SECTOR (GROUP OF DIRECTORY ENTRIES) ; RETURN WITH ZERO SET IF NO MORE NXTSECT: CMP MAXDIR,0 JNZ DO_SECT RET ;RET WITH ZERO SET DO_SECT: MOV CX,TRACK ;SET TRACK MOV BX,CALL_TBL CALL SET_TRACK MOV CX,SECTOR MOV BX,CALL_TBL CALL SECTOR_XLAT ;RETURNS XLATED SECT IN BX MOV CX,BX MOV BX,CALL_TBL CALL SET_SECTOR MOV BX,CALL_TBL CALL READ_SECTOR AND AL,1 ;REVERSE SENSE OF ERROR FLAG XOR AL,1 ;RETURN WITH ZERO SET IF BAD READ RET ; CHECK THE CURRENT GROUP DIRECTORY ENTRIES AGAINST ARGUMENT ; IF MATCH, REWRITE SECTOR WITH REACTIVATED FIRST BYTE CHKENT: MOV REWRT,0 ;ASSUME NO REWRITE MOV CL,DIR_PER_SEC ;# ENTRIES TO CHECK MOV BX,OFFSET DIR_BUF ;THIS IS WHERE THEY ARE AT... CKLOOP: CMP BYTE PTR [BX],0E5H ;IS IT UNUSED? JNE CKINC ;NO, GO DO ANOTHER CMP BYTE PTR 1[BX],0E5H ;IF THIS IS AN E5 THEN ITS JE CKINC ;...NOT A DIR NAME CMP BYTE PTR 1[BX],00H ;IF THIS IS AN 00 THEN ITS JE CKINC ;...NOT A DIR NAME PUSH BX CALL COMPAR ;COMPARE WITH ARGUMENT POP BX JNZ CKINC ;JMP IF ZERO NOT SET, NO MATCH CMP FIX_EM,0FFH ;SHOULD WE FIX EM? JNE NO_FIX MOV BYTE PTR [BX],0 ;ELSE, REACTIVATE IT MOV REWRT,0FFH ;SET REWRITE FLAG NO_FIX: INC FIXCNT ;BUMP FIX COUNTER CMP VIEW_EM,0FFH ;IS THE VIEW FLAG SET? JNE CKINC ;NO,JMP OVER THE SHOW-OFF PUSH BX CALL SHOWIT ;ELSE, TELL EM HOW GOOD YOU ARE POP BX CKINC: ;DO ANOTHER ENTRY ADD BX,32 DEC CL ;ONE LESS TO DO JNZ CKLOOP ;GO DO IT CMP REWRT,0 ;NEED REWRITE JZ CKDONE ;NO, THEN DONE WITH CHECK ; WRITE DIRECTORY ENTRY BACK TO THE DISK MOV CX,TRACK ;SET TRACK MOV BX,CALL_TBL CALL SET_TRACK MOV CX,SECTOR MOV BX,CALL_TBL CALL SECTOR_XLAT ;RETURNS XLATED SECT IN BX MOV CX,BX MOV BX,CALL_TBL CALL SET_SECTOR MOV BX,CALL_TBL CALL WRITE_SECTOR CMP AL,0 JZ CKDONE JMP ERRWRT ;WOOPS CKDONE: DEC MAXDIR ;REDUCE SECTORS LEFT INC SECTOR ;BUMP TO NEXT SECTOR RET ; COMPARE 11 BYTES OF DIRECTORY ENTRY AGAINST ARGUMENT ; RETURN WITH ZERO FLAG SET IF MATCH IS MADE COMPAR: MOV CL,11 ;COMP 11 CHARS. INC BX ;BX POINTS TO DIR ENTRY MOV SI,FCB+1 ;SI POINT TO FCB ARGUMENT CPLOOP: MOV AL,[BX] ;GET DIR CHAR AND AL,7FH ;STRIP PARITY CMP [SI],AL ;ARE FCB & DIR ENTRY THE SAME? JE DO_MORE CMP BYTE PTR[SI],'?' ;IF FCB IS A ?, ANY THING GOES JE DO_MORE RET ;RETURN ZERO NOT SET IF NOT SAME DO_MORE: INC BX INC SI DEC CL JNZ CPLOOP ;LOOP FOR 11 CHARS. RET ;RET WITH ZERO SET IF SAME ; MOVE FILE NAME TO DATA AREA AND SHOW IT ON CONSOLE ; ENTRY BX POINTS TO NAME-1 IN DIR_BUF SHOWIT: PUSH DS ;MAKE SURE ES IS CORRECT POP ES MOV SI,BX ;POINT TO FILE NAME INC SI ;NOW ITS CORRECT MOV DI,OFFSET FILNAM1 ;PUT IT THERE MOV CX,8 ;FIRST MOVE NAME CALL MOVEIT ;USE ROUTINE TO STRIP HI BIT INC DI ;JUMP OVER DOT MOV CX,3 ;MOVE TYPE CALL MOVEIT MOV AL,[SI] ;GET EXTENT ADD AL,'0' ;MAKE IT ASCII MOV BYTE PTR FILNAM2,AL ;PUT IN AWAY MOV DX,OFFSET FILNAM ;GET READY TO PRINT CMP FIXCNT,1 ;IS IT THE FIRST RECOVERY? JNE NOT_FIRST MOV DX,OFFSET RCMSG ;GIVE PRAMBLE NOT_FIRST: CALL PRINT INC LINES ;BUMP LINE COUNT CMP LINES,SLINES JB NO_WAIT CALL WAIT NO_WAIT: RET ; MOVE CX BYTES FROM DS:SI TO ES:DI AND STRIP HI BIT MOVEIT: MOV AL,[SI] AND AL,7FH MOV ES:[DI],AL INC DI ! INC SI LOOP MOVEIT RET ; PRINT MESSAGE POINTED TO BY DX, terminated with either a 0 PRINT: MOV BX,DX PRN_LP: MOV DL,[BX] CMP DL,0 ! JE PRN_RET INC BX MOV CL,2 PUSH BX INT 224 POP BX JMPS PRN_LP PRN_RET: RET ; SPECIFIED ILLEGAL DISK ILDISK: MOV DX,OFFSET ILMSG CALL PRINT JMP EXIT ; ERROR ON DISK WRITE ERRWRT: MOV DX,OFFSET WMSG CALL PRINT JMP EXIT ; DISPLAY WAIT MESSAGE AND WAIT FOR KEY PRESS WAIT: MOV DX,OFFSET WTMSG0 CALL PRINT CALL KEYPRESS MOV DX,OFFSET WTMSG1 CALL PRINT MOV LINES,0 RET ; WAIT FOR A KEY PRESS AND RETURN IT IN AL KEYPRESS: MOV CL,DCONIN ;DIRECT CONSOLE IO MOV DL,0FFH ;REQUEST AN INPUT CHECK INT 224 CMP AL,0 JE KEYPRESS RET ; DIRECT BIOS CALL FOR CP/M-86 VERSION 1.1 ; SELECT_DISK11: MOV AL,9 ;BIOS FUCN 9 JMPS BIOS ;RETURNS DPH ADDR IN ES:BX SET_TRACK11: MOV AL,10 JMPS BIOS SET_DMASEG11: MOV AL,17 JMPS BIOS SET_DMAOFF11: MOV AL,12 JMPS BIOS SET_SECTOR11: MOV AL,11 JMPS BIOS READ_SECTOR11: MOV AL,13 JMPS BIOS WRITE_SECTOR11: MOV AL,14 JMPS BIOS SECTOR_XLAT11: MOV AL,16 MOV DX,XLAT_ADR ;RETURN XLATED SECTOR IN BX JMPS BIOS BIOS: MOV BX,OFFSET BPB ;FILL IN BIOS PARAMETER BLOCK MOV BPB_FUNC,AL MOV BPB_CX,CX MOV BPB_DX,DX MOV CL,DIRBIOS ;BDOS FUNC 50 MOV DX,BX INT 224 ;CALL IT RET ; DIRECT BIOS CALLS FOR CP/M-86 VERSION 3.1 ; SET_SECTOR31: mov sector,cx ret SET_TRACK31: mov track,cx ret SECTOR_XLAT31: mov bx,cx ret SET_DMASEG31: ;DMA IS SET IN CPMCHK ROUTINE SET_DMAOFF31: ret ;++++++++++++++++++++++++++++++++++++++ SELECT_DISK31: ;selects a drive ;------ ; resets login sequence number of drive to 0, to force ; permanent media to be logged in again on disk reset ; Entry: CL = drive to select ; DL = 0 if initial select, else 1 push es ! push ds ;save context push cx ;save drive call getsu ;set up DS and ES pop cx ;restore drive mov ax,BIO_SELDSK ;do the BIOS SELDSK call callf BIOS_ptr ;call indirect BIOS mov LOG_SEQN[bx],0 ;force disk reset: 0 login sequence no. pop es ! push es ;get DS into ES mov di,offset dpb ;setup dest of dpb mov si,DPB_PTR31[bx] ;get the info from DPH mov cx,DPB_SIZE rep movsb ;copy DPB into local storage pop ds ! pop es ;restore context ret READ_SECTOR31: ;reads a physical sector ;---- mov bx,BIO_READ jmp biosiopb WRITE_SECTOR31: ;writes a physical sector ;----- mov bx,BIO_WRITE biosiopb: ;put the IOPB on the stack, call BIOS push ds ;ds will contain SYSDAT seg push es ;es will contain UDA seg ;push iopb onto stack mov ah,mcnt mov al,drive push ax ;drive and multi-sector count push track ;track # push sector ;sector # = 0 push dmaseg ;track buffer DMA segment push dmaoff ;track buffer DMA offset = 0 call getsu ;set up DS-SYSDAT and ES-UDA mov ax,bx ;set I/O function into AX callf BIOS_ptr ;call indirect the BIOS ;AL,BL = return status add sp,10 ;restore stack pop es ;restore original ES pop ds ;ditto for DS ret ;====== GETSU: ;====== CMP CPM_VERSION,CCPM_31 ;IS IT CCP/M? JNE GETSU10 getsu14: ;get sysdat and uda addrs for CCP/M ver 1431 ;----- ; entry: DS = local data seg ; exit: DS = SYSDAT seg, ES=UDA seg (for call to XIOS) mov ax,udaaddr ;get the saved value or ax,ax ;set flags jz getsu14a ;uninitialized, go do the OS call mov es,ax ;we've been here before, just load regs mov ds,sysaddr ret getsu14a: mov cl,S_SYSDAT ;will return system data seg in ES int 224 mov sysaddr,es ;save system data segment mov cl,P_PDADR ;will return PDA address in BX int 224 ; mov pdaddr,bx ;and save it mov ax,es:P_UDA[bx] ;grab UDA_seg mov udaaddr,ax ;save for future calls push ax ;save uda_seg mov ds,sysaddr pop es ;restore uda_seg ret ;---------------- getsu10: ;get sysdat and uda addrs ;----- ; entry: DS = local data seg ; exit: DS = SYSDAT seg, ES=UDA seg (for call to BIOS) mov ax,udaaddr ;get the saved value or ax,ax ;set flags jz getsu10a ;uninitialized, go do the OS call mov es,ax ;we've been here before, just load regs mov ds,sysaddr ret getsu10a: mov cl,DRV_DPB ;will return segment of SYSDAT in ES int 224 mov ax,es:UDA_seg ;grab UDA_seg mov udaaddr,ax ;save for future calls push ax ;save uda_seg mov ax,es mov sysaddr,ax ;save for future calls mov ds,ax pop es ;restore uda_seg ret ; ***** DATA STORAGE AREA***************** DSEG HLPMSG DB CR,LF,LF DB 'USAGE: A>UNERA Dr:FILENAME.TYP',CR,LF,LF DB TAB,'Filename and/or type may be wildcards.',CR,LF DB TAB,'Wildcards may be either ? or *',CR,LF,LF DB TAB,'CAUTION! use the * wildcard with care.',CR,LF DB TAB,'Using *.* will recover ALL erased filenames.',CR,LF,LF DB TAB,'The recoverable file(s) matching the FILNAME.TYP',CR,LF DB TAB,'will be listed, you then have an option to quit.',CR,LF,LF DB TAB,'Be SURE to check recovered files before using to',CR,LF DB TAB,'confirm that they are OK and function properly.',CR,LF DB TAB,'If possible, make a CRC check on recovered files.',CR,LF,LF DB TAB,'HINT: for best results use UNERA immediately after',CR,LF DB TAB,'making an unwanted erasure, else the space may be',CR,LF DB TAB,'re-allocated to another file and recovery is impossible.' DB CR,LF,0 HMSG DB CR,LF,'UNERA ver 3.1 (2-16-84) for CP/M-86, CP/M-86+ & CCP/M-86 // for HELP',0 WMSG DB CR,LF,'ERROR OCCURED DURING DISK WRITE - ABORTED',0 ILMSG DB CR,LF,'SPECIFIED AN ILLEGAL DISK DRIVE - ABORTED',0 BMSG DB CR,LF,'PLEASE! check recovered files before using them',0 NOFMSG DB CR,LF,'NO FILE NAME SPECIFIED - ABORTED',0 NFMSG DB CR,LF,'FILE NOT FOUND',0 WVMSG DB CR,LF,'Only CP/M-86 ver 1.1 & 3.1 Plus and CCP/M ver 3.1 are Supported',0 MPMSG DB CR,LF,'THE MP/M OPERATING SYSTEM IS NOT SUPPORTED',0 RVMSG DB CR,LF,'Do you wish to recover the File(s) (Y/N)? ',0 WTMSG0 DB CR,LF,' Press any key to continue ',0 WTMSG1 DB CR,' ',CR,0 RCMSG DB CR,LF,LF,'Recovered File(s) will be on ' FILNAM0 DB 'X: User 0' FILNAM DB CR,LF FILNAM1 DB 'FILENAME.TYP - Extent # ' FILNAM2 DB 'X',0 TABLE11 DW OFFSET SELECT_DISK11 ;DIRECT BIOS CALLS FOR CP/M-11 DW OFFSET SET_TRACK11 DW OFFSET SET_DMASEG11 DW OFFSET SET_DMAOFF11 DW OFFSET SET_SECTOR11 DW OFFSET READ_SECTOR11 DW OFFSET WRITE_SECTOR11 DW OFFSET SECTOR_XLAT11 TABLE31 DW OFFSET SELECT_DISK31 ;DIRECT BIOS CALLS FOR CP/M-31 DW OFFSET SET_TRACK31 DW OFFSET SET_DMASEG31 DW OFFSET SET_DMAOFF31 DW OFFSET SET_SECTOR31 DW OFFSET READ_SECTOR31 DW OFFSET WRITE_SECTOR31 DW OFFSET SECTOR_XLAT31 CURDR DB 0 ;CURRENT DRIVE HERE LINES DB 2 ;LINES PRINTED ON SCREEN COUNTER FIX_EM DB 0 ;FIX FLAG VIEW_EM DB 0FFH ;VIEW FLAG BPB RS 5 ;SPACE FOR BIOS PARAMETER BLOCK CALL_TBL RW 1 ;ADDRESS OF BIOS CALL TABLE GOES HERE XLAT_ADR RW 1 ;ADDRESS OF TRANSLATION TABLE FIXCNT RB 1 ;NUMBER OF FIXES REWRT RB 1 ;WRITE BACK TO DISK FLAG MAXDIR RW 1 MAXSEC RW 1 DIR_PER_SEC DB 4 ;number directory entrys per sector SEC_PER_TRK DW 26 CPM_VERSION DW 0 ;cpm version sysaddr dw 0 ;save location for sysdat addr udaaddr dw 0 ;save location for process uda addr mcnt db 1 ;multi-sector count drive rb 1 ;drive number (A:=1) track rw 1 ;track number sector rw 1 ;sector number dmaseg rw 1 ;DMA segment for data dmaoff dw offset dir_buf ;DMA offset for data dpb rb DPB_SIZE RW 32 ;32 WORD LOCAL STACK STACK RW 1 dir_buf rs 0000 ;4K data buffer [add[100]] at link END