;************************************************************************ ; * ; ISIS II TO CPM * ; FILE COPY UTILITY * ; * ; VERSION 2.2 * ; Modified by Rod Whitworth to allow nomination of the * ; drive & file of origin and destination. An input file * ; cannot reside on drive A: and a name must be given. * ; The output file defaults to A:nnnnnnnn.typ (named as * ; in the input). The output drive name is also optional * ; The original program also transferred only whole sectors * ; causing garbage to be placed on end of files: fixed now. * ;************************************************************************ cdisk equ 4 ;logged disk stored here FALSE EQU 0 TRUE EQU NOT FALSE LOGICAL EQU TRUE ;SET TRUE IF SECTORS INCREMENTED IN BIOS ORG 100H ICOPY: LXI SP,STACK ;SET STACK LDA CDISK ;WHERE LOGGED STA ODISK ;SAVED FOR LATER LDA TFCB ORA A JZ EXIT ; NO FILE SPECIFIED SUI 1 STA DRNUM ;INPUT DRIVE MOV C,A ;SELECT DISK LXI D,0 ;IN CASE NOT LOGGED IN CALL SDSK CALL VALID ;SEE IF IT'S OK FOR INPUT CALL HOME ;HOME INPUT DISK LDA OFCB+1 ;IS THERE A NAME CPI 20H ;IF NOT IT'S A SPACE & WE CAN LXI D,TFCB ;USE THE OLD NAME JZ OTRAN ;BY JUMPING AROUND LXI D,OFCB ;POINT TO OUTPUT DISK & NAME OTRAN: LXI H,VFCB ;POINT TO OUR FCB MVI B,16 CALL MOVE ;PUT IT SAFELY AWAY LDA OFCB ;FIND THE REAL DESTINATION DISK STA VFCB ;MAYBE REDUNDANT BUT SO WHAT ?? ORA A ;IS IT DEFAULT ? JZ STDSK SUI 1 ;OR DOES IT NEED ADJUSTMENT ? STDSK: STA DESTN ;READY FOR SET-UP XRA A STA VFCB+32 ;SET CURRENT RECORD TO ZERO LXI D,DIRLNK ;POINT TO DIR LINK BLOCK LINK LXI H,DBCA ;DIR BCA CALL GLB ;GET LINK BLOCK ICL0: LXI H,DBCA ;DIR BCA CALL GDB ;GET DIR BLOCK JC NOTF ;NO MORE DIR BLOCKS, ERR LXI H,DBUF ;DIR BUFFER SHLD DENT ;SAVE IN POINTER MVI A,8 ;NUMBER OF ENTRIES/BLOCK STA DCNT ;SAVE ICL1: LHLD DENT ;GET DIR ENTRY PTR MOV A,M ;GET STATUS BYTE CPI 00 ;ACTIVE? JNZ ILN1 ;NO, GET NEXT ENTRY INX H ;POINT TO FN LXI D,TFCB+1 ;POINT TO ENTERED FN MVI B,6 ;FN SIZE CALL FCHK ;TEST FN JNZ ILN1 ;NO, GET NEXT ENTRY LHLD DENT ;GET DIR ENTRY ADDR LXI D,7 ;OFFSET TO EXT. DAD D ;ADDR OF EXT. LXI D,TFCB+1+8 ;EXT MVI B,3 ;SIZE OF EXT. CALL FCHK ;TEST EXT JZ ICL2 ;OK, FOUND FILE ILN1: LHLD DENT ;POINTER TO ENTRY LXI D,16 ;SIZE OF ENTRY DAD D ;POINT TO NEXT ENTRY SHLD DENT LDA DCNT ;ENTRY COUNTER DCR A ;DECREMENT STA DCNT JNZ ICL1 ;LOOP JMP ICL0 NOTF: LXI D,MSG1 MVI C,09 CALL CPM JMP EXIT IOERR: LXI D,MSG2 MVI C,09 CALL CPM JMP EXIT ICL2: LHLD DENT ;GET DIR ENTRY ADDRESS LXI D,11 ;OFFSET TO BYTE COUNT OF LAST BLOCK DAD D MOV A,M STA LASTX ;# OF BYTES IN LAST TRANSFER INX H ;POINT TO BLOCK COUNT MOV E,M INX H MOV D,M ;BLOCK COUNT IN DE XCHG SHLD BCNT ;SAVE BLOCK COUNT INX D ;POINT TO LINK BLOCK LINK LXI H,FBCA ;FILE BCA CALL GLB ;GET LINK BLOCK LDA DESTN MOV C,A ;OUTPUT DISK # CALL SDSK ;SET DISK LXI D,VFCB ;POINT TO FCB MVI C,DELETE ;BYE TO ANY OLD ONE CALL CPM LXI D,VFCB MVI C,CREATE CALL CPM ;CREATE FILE CPI 0FFH ;ERROR? JZ IOERR ICL3: LXI H,FBCA ;POINT TO BCA CALL GDB ;GET DATA BLOCK JC DONE ;FINS LXI D,FBUF ;COPY FBUF TO TBUF LXI H,TBUF LDA XFERC ;TRANSFER SIZE MOV B,A CPI 128 CNZ FLAST ;FILL BUFF WITH EOF IF SHORT CALL MOVE LDA DESTN MOV C,A CALL SDSK ;SET DISK FOR OUTPUT LXI D,VFCB MVI C,WRITE CALL CPM ;WRITE THE BLOCK ON CPM ORA A JNZ IOERR LHLD BCNT ;GET BLOCK COUNT DCX H ;DECREMENT SHLD BCNT MOV A,H CPI 0 ;TEST FOR DONE JNZ ICL3 ;NO, LOOP MOV A,L CPI 1 JZ CSWAP CPI 0 JNZ ICL3 DONE: LDA DESTN MOV C,A CALL SDSK ;SET DISK FOR OUTPUT LXI D,VFCB ;FCB MVI C,CLOSE CALL CPM EXIT: LDA ODISK MOV C,A CALL SDSK ;FORCE LOGIN TO ORIGINAL DISK JMP BOOT ;FINISHED ;***************************************; ; ; GLB - GET LINK BLOCK ; ; DE= A(LINK TO LINK BLOCK) ; HL= A(BLOCK CONTROL AREA) ; ;***************************************; GLB: SHLD BCAP ;SAVE BCA ADDR CALL SEEKR ;READ LINK BLOCK LHLD BCAP ;GET BCA ADDR LXI D,BCBL ;OFFSET TO LINK BUFFER DAD D LXI D,TBUF MVI B,128 CALL MOVE ;COPY TO LINK BUFFER LHLD BCAP ;GET BCA ADDR LXI D,BCBL+4 ;OFFSET TO FIRST DATA LINK XCHG DAD D ;DE=A(FIRST DATA LINK) XCHG LXI B,BCAL ;OFFSET TO LINK PTR DAD B MOV M,E INX H MOV M,D ;SET LINK PTR LHLD BCAP ;BCA ADDR LXI D,BCALC ;LINK COUNT DAD D MVI M,62 ;NO OF LINKS RET ;****************************************: ; ; GDB: GET DATA BLOCK ; ; HL= A(BLOCK CONTROL AREA) ; ;****************************************; GDB: SHLD BCAP ;SAVE BCA ADDR LXI D,BCAL ;OFFSET TO LINK BUF DAD D MOV E,M INX H MOV D,M ;GET LINK ADDR PUSH D ;SAVE LINK ADDR LDAX D ;GET LINK BYTE INX D MOV C,A LDAX D ;GET ANOTHER LINK BYTE ORA C ;TEST FOR ZERO LINK POP D JZ GDBE ;END, EXIT PUSH D ;SAVE D AGAIN PUSH H CALL SEEKR ;GET DATA BLOCK POP H POP D INX D INX D MOV M,D DCX H MOV M,E ;UPDATE LINK PRT LHLD BCAP ;GET BCA ADDR LXI D,BCBD ;OFFSET TO DATA BUF DAD D LXI D,TBUF MVI B,128 CALL MOVE ;COPY DATA TO BUF LHLD BCAP ;GET BCA ADDR LXI D,BCALC ;LINK COUNT DAD D DCR M ;DECREMENT RNZ ;OK, CONTINUE LHLD BCAP ;GET BCA ADDR LXI D,BCBL+2 ;POINT TO LINK BUF DAD D MOV E,M ;GET LINK INX H MOV D,M DCX H MOV E,A ORA D ;TEST FOR ZERO LINK JZ GDBE ;END, EXIT XCHG ;DE = A(NEXT LINK) LHLD BCAP ;BCA ADDR CALL GLB ;GET LINK BLOCK RET GDBE: STC ;INDICATE EOF RET ;************************************; ; ; FCHK: FILE ID CHECK ; ; DE = A(ISIS FILE ID) ; HL = A(CPM FILE ID) ; B = SIZE OF FIELD ; ;*************************************; FCHK: XCHG FCK1: LDAX D ;GET BYTE CPI 00 ;SEE IF END OF ID JNZ FCK2 ;YES, SEE IF END OK MOV A,M ;GET BYTE CPI ' ' ;END BOTH RZ ;DONE ORA 1 RET ;DONE FCK2: CMP M ;COMPARE RNZ ;N,G. INX D INX H DCR B ;DECREMENT COUNT JNZ FCK1 RET ;***************************************; ; ; SEEKR: SEEK DISK BLOCK ; ; DE = A(LINK) ; ;***************************************; SEEKR: PUSH D ;SAVE DE LDA DRNUM MOV C,A LXI D,1 ;WE'VE BEEN HERE BEFORE CALL SDSK POP D PUSH D LDAX D ;GET SECTOR MOV C,A CALL SSEC ;SET SECTOR POP D PUSH D INX D LDAX D ;GET TRACK MOV C,A CALL STRK CALL READ ;READ BLOCK POP D RET ;************************************************ ; * ; FLAST: SET UP BUFFER FOR LAST BLOCK * ; INITIALISE TO 1AH (CP/M EOF) * ; PRIOR TO TRANSFER OF REAL DATA * ; * ;************************************************ FLAST: PUSH H LXI H,TBUF MVI A,128 EOFL: MVI M,01AH INX H DCR A JNZ EOFL POP H RET CSWAP: ;DOES THE COUNT CORRECTION FOR ;THE LAST BLOCK LDA LASTX STA XFERC JMP ICL3 ;*****************************************; ; ; MOVE: MOVE DATA ; ; DE = A (SOURCE) ; HL = A(DEST) ; B = COUNT ; ;******************************************; MOVE: LDAX D ;GET BYTE MOV M,A ;STORE BYTE INX H INX D ;BUMP PTRS DCR B ;DECREMENT COUNT JNZ MOVE RET ;*******************************************; ; ; CPM INTERFACE ROUTINES ; ;*******************************************; VALID: ;CHECKS DPB TO SEE IF SS/SD FLOPPY AND EXIT IF NOT ;HL = 0 IF NOT SELECTABLE ELSE -> DPH ADDR MOV A,H ORA L JZ DONE ;GO TO CPM LXI D,10 DAD D MOV A,M INX H MOV H,M MOV L,A ;HL -> DPB MOV A,M CPI 26 JNZ DONE ;IF NOT 26 SPT INX H MOV A,M ORA A JNZ DONE ;HIGH BYTE OF SPT LXI D,4 DAD D MOV A,M CPI 242 ;SINGLE DENSITY DSM JNZ DONE RET ;PRETTY GOOD CHANCE IT'S OK NOW SDSK: LHLD 0001H ;GET BIOS ADDR MVI L,1BH PCHL SSEC: LHLD 0001H MVI L,21H IF LOGICAL ;USED TO REDUCE THE SECTOR # DCR C ;IF THE BIOS INCREMENTS IT ENDIF ;TO 'CORRECT' LOGICAL TO PHYSICAL PCHL STRK: LHLD 0001H MVI L,1EH PCHL READ: LHLD 0001H MVI L,27H PCHL HOME: LHLD 0001H MVI L,18H PCHL ;******************************************; ; ; BLOCK CONTROL AREA DEFINITIONS ; ;******************************************; BCA EQU 0 BCAL EQU 0 BCALC EQU BCAL+2 BCBL EQU BCALC+1 BCBD EQU BCBL+128 ;******************************************; ; ; DATA ; ;******************************************; MSG1: DB 'FILE NOT FOUND',0DH,0AH,'$' MSG2: DB 'I/O ERROR',0DH,0AH,'$' XFERC: DB 128 ;INITIAL BLOCK SIZE MODIFIED FOR LAST LASTX: DS 1 ;BYTE COUNT OF LAST RECORD DRNUM DS 1 ;INPUT DRIVE DESTN DS 1 ;OUTPUT DRIVE ODISK DB 0 ;PROBLY A: DIRLNK: DB 01,01 DENT: DS 2 DCNT: DS 1 BCNT: DS 2 BCAP: DS 2 DS 64 STACK EQU $ DBCA: DS 2 DS 1 DS 128 DBUF: DS 128 FBCA: DS 2 DS 1 DS 128 FBUF: DS 128 VFCB DS 36 TBUF EQU 0080H TFCB EQU 005CH OFCB EQU 006CH ;OUTPUT FILE DRIVE AND [NAME] CPM EQU 0005H BOOT EQU 0000H CREATE EQU 22 WRITE EQU 21 CLOSE EQU 16 DELETE EQU 19 END