TITLE 'MITS 88DCDD DISK TO CP/M FILE TRANSFER' PAGE 58 ; MITS TO CP/M FILE CONVERSION ROUTINE ; CODED 11/80 THRU 1/81 (MY FIRST CP/M PROGRAM) ; FOLLOWS CONVPATB FAIRLY CLOSELY ( SEE THIS WELL DOCUMENTED PROGRAM ) ; USES DIFFERENT USER INTERFACE ETC... ; ; ; ; TRUE EQU 0FFFFH FALSE EQU NOT TRUE DEBUGGING EQU TRUE ; SAY BUGS NOT OUT YET ***** CHANGE LATER ***** CHECKOUT EQU FALSE ; USED TO INTERFERE WITH CARD BUFFER LOCATION EQU 100H ; LOCATION OF THE START OF THIS STUFF NFILES EQU 255 ; NUMBER OF FILES IN MITS DIRECTORY NSECTS EQU 32 ; 32 SECTORS PER TRACK DBIAS EQU 7 ; BIAS IN MITS DIRECTORY ; WHY ISN'T ANY PROGRAM IN HARMONY WITH ITS DOC? DSIZE EQU 16 ; LENGTH OF MITS DIRECTORY ENTRY BSIZE EQU 137 ; SECTOR LENGTH ON 88-DCDD PERTEC FD-400'S NFPS EQU BSIZE/DSIZE ; NUMBER FILES/SECTOR (TRUNCATED) VERS EQU 10 ; VERSION 1.0 MODL EQU 1 ; MODIFICATION LEVEL 0 DTRACK EQU 70 ; DIRECTORY TRACK ENDSLOT EQU 0377Q ; FLAG FOR LAST FILE CTLC EQU 'C'-64 ; CONTROL C CTLU EQU 'U'-64 ; CONTROL U BACKSP EQU 'H'-64 ; BACKSPACE (CTL H) CTLD EQU 'D'-64 ; CONTROL D CTLP EQU 'P'-64 ; CONTROL P CTLZ EQU 'Z'-64 ; CONTROL Z CTLS EQU 'S'-64 CTLQ EQU 'Q'-64 CR EQU 0DH ; CARRIAGE RETURN LF EQU 0AH ; LINE FEED ; ; MACROS ; CPM MACRO ?F,?P PUSH B PUSH D PUSH H IF NOT NUL ?F MVI C,?F ENDIF IF NOT NUL ?P LXI D,?P ENDIF CALL BDOS POP H POP D POP B ENDM MSG MACRO ?M,?J IF NOT NUL ?M LXI H,?M ENDIF CALL PRMSG IF NOT NUL ?J JMP ?J ENDIF ENDM ; ; ORG LOCATION ; START OF SOMETHING ; ; THISðPROGRAM WILL READ A MITS FILE THRU THE 88-DCDD CONTROLLER AND ; BY MEANS OF RESIDENT CP/M WRITE THE FILE TO A CP/M DISK. ; ......................................................................... ; ; PROGRAMMED BY A. L. BENDER, M.D. ; ; ......................................................................... ; ; MCNVT WILL USE ANY REPRESENTATION OF THE CP/M FILENAME ALLOWED ; JMP MCNVT IF DEBUGGING PATCH DS 50 ENDIF OND DS NFILES*DSIZE OP DS 1 ; CURRENTr. **** Where is further documentation available: MITSCNVT.DOC as well as program listing. ********** Hardware dependRENT MITS DISK ADDR DW 0 ; I/O ADDRESS IN MITS PACKAGE (LIKE DMA ADDR) NWDS DB 0 ; NUMBER OF WORDS TO BE READ BY MITS PACKAGE FCOUNT DS 1 ; NUMBER OF FILES ACTUALLY IN MITS DIRECTORY BUFFER DS BSIZE ; READ MITS BUFFER FCB DS 33 ; FILE CONTROL BLOCK FN DB 0 ; CURRENT FILE NUMBER BEING PROCESSED RWFLAG DB 0 ; READ/WRITE FLAG FOR MAKEFCB RANDFLAG: DB 0 ; 0=SEQUENTIAL 2=RANDOM 1=ISFMS (SPECIAL NSI FILE) WRCOUNT:DB 0 ; BYTES WRITTEN MITSNAME: DS 8 ; MITS FILE NAME CRCEL DW 0 ; I-RECORD ADDR CRCL1 DW 0 ; L RECORD ADDR FRSTCH: DB 0 ; FIRST CHARACTER IN MITS FILE NREC: DW 0 ; NUMBER RECORDS WRITTEN ; ; --- CP/M INTERFACE EQUATES --- ; BDOS EQU 5 ; ENTRY TO CP/M I/O ROUTINE DOSBUF EQU 0080H ; DEFAULT BUFFER CLOSEF EQU 16 ; CLOSE FILE CONS EQU 1 ; READ CONSOLE INPUT BYTE TO A CONSTAT EQU 11 EXIT EQU 0 ; EXIT ADDRESS CREATEF EQU 22 ; CREATE FILE DELETEF EQU 19 ; DELETE FILE COMMAND OPENF EQU 15 ; OPEN FILE READF EQU 20 ; READ FILE WRITEF EQU 21 ; WRITE FILE TBUFF EQU 0080H ; DEFAULT BUFFER TFCB EQU 005CH ; DEFAULT FCB SETDMA: EQU 26 ; SET ADDRESS OF DMA RDBUF: EQU 10 ; READ BUFFERED CONSOLE TYPEF EQU 2 ; CONSOLE OUTPUT SRCHF EQU 17 ; SEARCH FOR FILE IN DIRECTORY ; ;----- CONVASCI - CONVERT BINARY NUMBER IN BC TO ASCII ; IF RADIX=8 CONVERSION WILL BE OCTAL ; IF RADIX=10 CONVERSION WILL BE DECIMAL ; ; ENTER WITH NUMBER IN BC (B=LSB, C=MSB) ; RETURNS WITH NUMBER IN M1-M5 (LSB->MSB) AND ; ADDRESS OF M1 IN BC ; ; REGISTERS DE AND HL PRESERVED ; ; RADIX IS IN A ON ENTRY (A=10 OR A=8) (THIS WORKS FOR ANY BASE <=10) ; ; IF ENTRY IS AT SETRADIX THEN A MUST BE SET IF CONVASCI IS USED THEN ; RADIX IS ASSUMED 10 OR SET. ; SETRADIX STA RADIX RET ; CONVASCI PUSH H PUSH B LXI H,M1 XRA A MVI B,5 CV1: MOV M,A INX H DCR B JNZ CV1 POP B MOV H,B MOV L,C PUSH D MVI D,5 LXI B,M1 CV2 CALL CONVONE STAX B INX B DCR D JNZ CV2 POP D POP H LXI B,M1 RET CONVONE PUSH B MVI C,10 RADIX EQU $-1 CALL DIVIDE POP B ADI '0' RET M1 DB 0,0,0,0,0 ; ; ; DIVIDE 16 BITS BY 8 BITS ; HL=>DIVIDEND ; C=>DIVISOR ; ; RETURNS WITH HL=>QUOTIENT ; C=>DIVISOR ; A=>REMAINDER ; DIVIDE XRA A CMP C STC RZ MVI B,16 ; NUMBER OF TIMES TO LOOP D1 DAD H RAL CMP C JC D2 SUB C INX H D2 DCR B JNZ D1 RET ; DIRECTORY LOOKUP ROUTINE ; USED TO SEARCH MFD BEGINNING AT OND ; LOOKUP: LXI H,OND ; GET BASE OF DIRECTORY LDA FCOUNT ; NUMBER OF FILES IN DIRECTORY MOV B,A ; NUMBR OF FILES IN DIRECTORY LOOK1 MVI C,8 ; NUMBER OF BYTES IN FILENAME PUSH D LOOK2 LDAX D ; INPUT FILE TO LOOKUP ADDR IN DE CMP M JNZ LOOK3 ; NOT THIS ENTRY INX D INX H DCR C JNZ LOOK2 MOV A,M STA TRACK ; SET TRACK ADDRESS INX H MOV A,M STA SECTOR INX H MOV A,M ; FILE TYPE SUI 2 ; ZERO FOR SEQUENTIAL STA RANDFLAG ; RANDOM/SEQUENTIAL FLAG INX H MOV A,M ; FILE NUMBER STA FN ; SAVE FILE NUMBER (PREVENT FILE LINK ERROR LATER) POP D ORA A ; CLEAR CARRY RET ;HL=>ENTRY LOOK3 DCR B ; DECREMENT NUMBER OF FILES JNZ LOOK4 ; JUMP IF MORE TO DO POP D STC ; FAILED, FILE NOT IN DIRECTORY RET LOOK4 MVI A,DSIZE-8 ADD C ; NUMBER OF BYTES TO SKIP PAST CALL ADDAHL ; ADD A TO HL POP D JMP LOOK1 ; PRMPT PUSH H PUSH D CALL CRLF MVI A,'*' CALL OUTEEE POP D POP H RET NAMEMOV: LXI B,8 MVI A,' ' LXI D,MITSNAME PUSH D CALL FILLB POP D MVI C,9 ; MITS FILE NAME SIZE+1 MOVE1: MOV A,M ; PICK UP MITS FILE NAME OR DISK CALL TERMT ; CHECK TERMINATION RZ ; PROPER STAX D ; SAVE IT AWAY INX H INX D DCR C ; COUNT JNZ MOVE1 MSG BMFN ; IMPROPER MITS FILE NAME XRA A STA TBUFF JMP INPUTX ; GET CARD IMAGE BADTERM: MSG BADPUNK,INPUTX ; IMPROPER PUNCTUATION BADDISK: MSG DSKERR,INPUTX ; BAD DISK NUMBER (MITS DISK) ; INPUTCDI: LXI H,TBUFF MOV A,M ; GET CHARACTER COUNT OF TBUFFER CPI 2 ; IF 0 OR 1 CHARACTER, NO INPUT ON TBUFF JC INPUT1 ; NO LINE IMAGE PUSH H INR A ; POSITION BEYOND INPUT CALL ADDAHL ; UPDATE POINTER MVI M,CR ; PUT CR AT END OF LINE BUFFER POP H LXI D,FCB ; SET FCB ADDRESS INX H ; SET H TO FW OF TBUFF CALL SKIPS ; SKIP BLANKS LEADING MSG MOV A,M ; GET F.C OF IMAGE CPI '=' ; IF FC IS = THEN WANT DIRECTORY ONLY JZ PUTDIR ; PUT OUT DIRECTORY THEN RESTORE STACK REINITIALIZE CALL MAKEFCB ; BUILD FCB JNC SCAN2 ; GO TO SCAN MITS FILE NAME LXI H,CPFMSG ; INDICATE CP/M FILE NAME IS IN ERROR INPERR: CALL PRMSG INPUTX: XRA A LXI H,TBUFF MOV M,A INX H LXI B,080H ; C=128 BYTE BUFFER, B=NR WDS READ INPUT1 CALL PRMPT ; PROMPT INPUT FROM CONSOLE MVI A,125 ; SO IT WILL FIT TBUFF... STA BUFFER ; CONSTRUCT READ BUFFER CPM RDBUF,BUFFER LXI D,BUFFER+1 ; TRANSFER IMAGE TO TBUFF LXI H,TBUFF ; [PRETEND IT WAS THERE ALWAYS] LDA BUFFER+1 ; GET COUNT OF BUFFER BYTES INR A ; COUNT BYTE MOV B,A ; STUFF INTO COUNTER INPUT2 LDAX D ; MOVE STRING FROM BUFFER TO TBUFF MOV M,A ; INX H ; INX D ; DCR B ; JNZ INPUT2 ; LOOP MVI A,CR ; TACK ON FINAL C/R CHARACTER MOV M,A ; TO BUFFER (10 FUNCTION DOESN'T PUT IT THERE) CALL CRLF JMP INPUTCDI SCAN2: CPI CR ; SEE IF IMAGE IS NOT COMPLETE JNZ SCAN3 ; SO FAR SO GOOD LXI H,NOMITS JMP INPERR ; ERROR IN INPUT SCAN3: LXI D,MITSNAME CALL NAMEMOV ; MOVE MITS FILE NAME JC BADTERM CPI ',' ; LOOK FOR COMMA TERM JNZ BADTERM INX H ; GET TO THE NUMBER NOT THE COMMA CALL DN ; CONVERT DISK NUMBER TO BINARY STA DISK CPI 16 ; HIGHEST DISK + 1 JNC BADDISK MOV A,M CALL TERMT JNZ BADDISK XRA A STA TBUFF RET ; ; DN / CONVERTS STRING AT HL TO BINARY IN A ; HL ADVANCED TO END OF INTEGER DN: XRA A PUSH D DN1: MOV D,A ; SAVE A MOV A,M SUI '0' ; TAKE BIAS AWAY JC DNX ; DONE, GET OUT CPI 10 ; DONE, IF > JNC DNX MOV E,A MOV A,D RLC ; RLC ; *4 ADD D ; *5 RLC ; *10 ADD E ; ADD DIGIT INX H JMP DN1 DNX: MOV A,D POP D RET ; MAKEFCB.LIB 9/4/78 ; ORIGINAL VERSION IN CP/M LIBRARY VOL 8 ; CORRECTED 9/78 BY P. HOLLIDAY ; ; LOCAL SYMBOLS ; FCBSIZ: EQU 33 ; SIZE OF FCB FNMLEN: EQU 11 ; LENGTH OF FILE NAME MAKEFCB:DS 0 ; ENTRY POINT LABEL MTFCB: PUSH H ; COMMAND STRING POINTER PUSH D ; FCB ADDRESS STA RWFLAG ; SAVE READ/WRITE FLAG LXI B,FCBSIZ ; FILL FCB WITH ZERO CALL CLRB ; CLEAR FCB LXI D,FCB+1 LXI B,FNMLEN ; FILL FILE NAME AREA MVI A,' ' ; WITH BLANKS CALL FILLB POP D POP H ; RESTORE POINTERS CALL SKIPS ; PASS LEADING BLANKS INX H ; CHECK FOR DISK CODE MOV A,M DCX H CPI ':' ; EXPLICIT DISK JNZ MTFCB1 ; NOT EXPLICIT DISK MOV A,M ; VALID DISK CODE? INX H INX H SBI '@' ; SENSE A-Z RC ; IN CASE ZERO TEST FAILS CPI 'Z'-'A'+1 CMC RC ; SET IF IN ERROR STAX D ; SAVE DISK CODE AT FCB+0 ;PROCESS FILE NAME FIELD MTFCB1: INX D MVI C,8 CALL GETNAM MOV A,M ; TEST FOR FILE TYPE SEPARATOR INX H CPI '.' JNZ MTFCB2 MVI C,3 CALL GETNAM MOV A,M INX H ;CHECK TERMINATION OF FIELD MTFCB2: CALL TERMT RET ; RETURN TO USER ; ;PROCESS NAME FIELD ; GETNAM: MOV A,M ; GET CHARACTER FROM COMMAND STRING INX H CPI '?' ; ALLOW AMBIGUITY TO EXIST IN NAME JNZ GETN20 ; NOT AMBIGUOUS CHARACTER LDA RWFLAG ; GET R/W FLAG ORA A ; SET FLAGS MVI A,'?' ; RESET ? CHAR JZ GETNA1 ; STORE AMBIG CHAR JMP GETNA3 ; NG,WRITING FILE ? DISALLOWED GETN20: CPI '*' ; CHECK FOR FULL FIELD OF ??? JZ GETNA2 CALL VALCHR ; TEST FOR VALID CHARACTERS IN NAME JC GETNA3 ; INVALID, SKIP OVER REMAINDER OF FIELD GETNA1: STAX D ; SAVE FILE NAME OR TYPE INX D DCR C ; ACCUMULATE EVERYTHING JNZ GETNAM ; LOOP TO FINISH FIELD RET ; DONE WITH SCAN GETNA2: LDA RWFLAG ORA A ; TEST FOR WRITE OPERATION ON FILE JZ GETNA3 ; NG,WRITE ON AMBIGUOUS FILE NAME MVI A,'?' MVI B,0 ; FILL WITH ? JMP FILLB ; FILLB WILL RETURN TO USER GETNA3: INX D ; SKIP TO END OF FIELD IN FCB DCR C JNZ GETNA3 DCX H ; POINT TO NEXT CHARACTER IN INPUT STRING RET ; TEST FOR VALID CHARACTER IN NAME FIELD ; RETURN IF INVALID WITH CARRY SET ; ADDED TEST FOR = SIGN ALSO 12/19/80 ; VALCHR: CPI CR ; TEST FOR C/R CMC ; COMPL CARRY RZ CPI '*' CMC RZ CPI ',' CMC RZ CPI '=' CMC RZ CPI '.' CMC RZ CPI ' ' RC CPI '^'+1 CMC RC CPI ':' CMC RNC CPI 'A'-1 RET ; ;TEST FOR VALID FILE NAME TERMINATOR ; TERMT: CPI ' ' RZ CPI ',' RZ CPI CR RZ CPI ';' RZ CPI '=' RZ STC RET ; ;SKIP SPACES IN COMMAND STRING ; SKIPS: MVI A,' ' SKIPS1: CMP M RNZ INX H JMP SKIPS1 ; FILL BLOCK WITH VALUE ; ENTER WITH VALUE IN A ; DE=START OF BLOCK ; BC=LENGTH OF BLOCK ; CLRB: XRA A ; ENTRY TO ZERO BLOCK FILLB: INR B ; DOUBLE TALK TO AVOID MESSING WITH A DCR B JNZ FILLB1 INR C DCR C RZ FILLB1: STAX D INX D DCX B JMP FILLB ; ; END OF MAKEFCB.LIB ; ; ; ; ; FNCALC - CALCULATES THE FILE NUMBER RELATIVE TO THE OLD DIRECTORY ; ; ENTER WITH B=SLOT-K ; ; THE TERM NEW DIRECTORY REFERS TO THE MITS DIRECTORY WITH ALL DELETED FILES ; REMOVED. OND=>IS THE "ORIGIN OF THE NEW DIRECTORY" FCOUNT=>THE NUMBER OF ; FILES REALLY PRESENT IN THE NEW DIRECTORY ; FNCALC LDA BUFFER+1 PUSH B RLC ; *2 RLC ; *4 RLC ; *8 (THE BOOK IS WRONG, ITS 8*SSECTOR+) MOV C,A ; SECTOR MVI A,9 SUB B ADD C ; 8*SECTOR+(SLOT+1) POP B RET ; ; ; MESSAGES ; SIGNON DB 0DH,0AH,'MITS FILE COPY VERS ' DB VERS/10+'0','.',VERS MOD 10+'0' DB ' (,',MODL+'0',')' DB 0 FMTERR DB 0DH,0AH,'DIRECTRY FMT ERR' DB 0 NFMSG DB 0DH,0AH,'NMBR OF FILES IN CURRENT ' DB 'DIRECTORY:',0 FLERRM DB 0DH,0AH,'FILE LINK ERROR ON MITS DISK',0 CKSUM DB 0DH,0AH,'CHECKSUM ERROR ON MITS FILE',0 DIRRD DB 0DH,0AH,'ERROR TRYING TO RECOVER MITS DIRECTORY FROM DISK',0 CPFMSG DB 0DH,0AH,'CP/M FILE NAME IN ERROR',0 TRKERR DB 0DH,0AH,'BAD TRACK ADDRESS',0 SECERR DB 0DH,0AH,'BAD SECTOR ADDRESS',0 FMTNG DB 0DH,0AH,'DATA SECTOR FORMAT IMPROPER',0 RDMSG DB 0DH,0AH,'READING MITS FILE',0 ENDMSG DB CR,0AH,'END OF CP/M DISK MEDIUM',0 EXTMSG DB CR,0AH,'ERROR ENCOUNTERED EXTENDING CP/M DISK',0 FULMSG: DB CR,0AH,'CP/M DIRECTORY FULL',0 NOMITS: DB CR,0AH,'NO MITS DISK FILE SPECIFIED',0 NAMERR DB CR,0AH,'ERROR SPECIFYING MITS DISK',0 DSKERR DB CR,0AH,'ERROR IN CONVERTING DISK NUMBER',0 NFMDMS DB ' FILES IN MITS DIRECTORY',CR,LF,0 DB CR,0AH,'TOO MANY OR TOO LONG ARGUMENTS',0 BMFN DB CR,LF,'BAD MITS FILE NAME (TOO LONG)',0 BADPUNK DB CR,LF,'IMPROPER FILE SYNTAX',0 FSRCHF DB CR,LF,'MITS FILE SEARCH FAILED',0 ; ; CHARACTER OUTPUT TO CONSOLE ; OUTEEE: MOV E,A CPM TYPEF ; TYPE A CHARACTER RET CRLF MVI A,0DH CALL OUTEEE MVI A,0AH JMP OUTEEE ; PRMSG: ; ;PRINT MESSAGE TO ZERO BYTE ;FOR DETAILS SEE INTEL ISIS MANUAL OR CP/M SAMPLE BIOS MOV A,M ORA A RZ MOV E,A CPM TYPEF INX H JMP PRMSG ; ; ; ; START OF MAIN PROGRAM ; MCNVT LXI H,0 DAD SP ; SAVE CP/M STATUS AS THIS PROGRAM DOESN'T CLOBBER IT SHLD CPMSTK ; STACK POINTER FOR CP/M MCNVT1 LXI SP,STACK ; GET NEW STACK ADDRESS MSG SIGNON ; PUT OUT SIGNON MESSAGE MCNVT1A: CALL INITIAL ; INITIALIZE CALL SETFILES CALL MDRD ; RECOVER MITS FILE DIRECTRY CALL SORT ; SORT DIRECTORY CALL PRINTDIRECTRY LXI D,MITSNAME CALL LOOKUP ; LOOKUP NAME IN DIRECTORY JNC MCNVT2 ; SEARCH SUCCESSFUL MSG FSRCHF,MCNVT1A ; SEARCH FAILED MCNVT2: CALL COPYFILE CALL CRLF LHLD NREC ; GET WRITE COUNTER MOV B,H MOV C,L CALL CONVASCI ; CONVERT TO ASCII LXI H,M1+4 ; START OF DIGIT STRING MVI B,5 ; NO OF ASCII DIGITS MVI E,0 ; FLAG TO SUPRESS ZERO MCNVT3: MOV A,M ; GET A DIGIT CPI '0' JZ MCNVT6 MOV E,A ; SET FLAG SIGNIFICANT DIGIT MCNVT4: CALL OUTEEE MCNVT5: DCX H DCR B JNZ MCNVT3 CALL MCNVT8 MSG BLOCKMSG,MCNVT7 MCNVT6: MOV D,A MOV A,E ORA A JZ MCNVT5 ; LEADING ZEROS MOV A,D ; IN SIGNIFICANT PART OF INTEGER JMP MCNVT4 BLOCKMSG: DB ' SECTORS COPIED TO CP/M FILE.',CR,LF,0 MCNVT7: CALL CLWRF ; CLOSE WRITE FILE JMP MCNVT1A MCNVT8: LXI H,BINARY LDA FRSTCH INR A JZ MCNVT9 ; JUMP IF BINARY DATA LXI H,ASCII MCNVT9: CALL PRMSG RET BINARY: DB ' BINARY DATA',0 ASCII: DB ' ASCII BYTE DATA',0 ; PRINT DIRECTORY ON MITS DISK - INVOKED BY =N ; PUTDIR: INX H CALL DN STA DISK CALL PMITS ; PRINT SORTED DIRECTORY XRA A STA TBUFF ; ZEROIZE TO PREVENT COMING BACK IN A LOOP LXI SP,STACK JMP MCNVT1A ; PRINT MITS FILE DIRECTORY ; THE DIRECTORY IS STORED AT OND ; IT MAY BE PRESORTED BY SORT OR IT MAY BE PRINTED ; WITHOUT SORTING. ; PRINTDIRECTRY: CALL CRLF LDA FCOUNT CALL DECOUT MSG NFMDMS ; PUT OUT NUMBER OF FILES LDA FCOUNT ; GET PRESET MOV B,A ; NUMBER OF FILES IN DIRECTORY LXI D,OND ; ORIGIN OF THE NEW MITS DIRECTORY PRDIR1: CALL DLIST ; PRINT ONE DIRECTORY ENTRY LXI H,DSIZE ; LENGTH OF A DIRECTORY ENTRY DAD D ; PLUS ADDRESS XCHG ; TO D DCR B JNZ PRDIR1 ; LOOP UNTIL ENTIRE DIRECTORY PRINTED RET DLIST: PUSH H PUSH D PUSH B ; SAVE EVERYTHING XCHG ; HL=ADDRESS OF THIS ENTRY LXI B,0803H ; MVI C,3; MVI B,8 DLIST1 MOV A,M ; FILE NAME TO A CALL OUTEEE INX H DCR B JNZ DLIST1 MVI A,' ' ; BLANK DLIST2: CALL OUTEEE ; (THREE OF THEM) DCR C JNZ DLIST2 ; TO PRINTER MOV A,M ; GET TRACK NUMBER CALL DECOUT ; PRINT IT MVI A,',' ; PRINT BLANK INX H CALL OUTEEE MOV A,M ; GET SECTOR NUMBER CALL DECOUT ; PRINT SECTOR NUMBER MVI A,',' CALL OUTEEE INX H MOV A,M MVI B,'R' CPI 4 ; 4=RANDOM JZ DLIST3 MVI B,'S' DLIST3: MOV A,B CALL OUTEEE ; PRINT FILE TYPE MVI A,',' CALL OUTEEE INX H ; GET TO FILE NUMBER MOV A,M CALL DECOUT ; PRINT FILE NUMBER CALL CRLF POP B POP D POP H RET ; ; DECOUT => DECIMAL OUTPUT ; ; SUPPRESS LEADING ZERO ; OUTPUT A BLANK INSTEAD ; DECOUT: PUSH D PUSH B MVI E,0 ; CLEAR ZERO FLAG MVI C,100 ; DIVIDE BY 100 CALL DECOU1 MVI C,10 ; DIVIDE BY 10 CALL DECOU1 ADI '0' ; DIVIDE BY '1' CALL OUTEEE ; UNITS POP B POP D RET DECOU1: MVI B,'0'-1 INR B SUB C JNC DECOU1+2 ; LOOP UNTIL DIVIDE RESULTS IN REMAINDER ADD C MOV D,A MOV A,B CPI '0' ; SENSE ZERO JNZ DECOU2 ; NOT ZERO, SET FLAG NZ, OUTPUT ASCII MOV A,E ; GET ZERO FLAG ORA A ; SET MOV A,D RZ DECOU2: INR E ; SET FLAG MOV A,B CALL OUTEEE MOV A,D RET ; ; COPYFILE => READS MITS FILE / WRITES CPM FILE ; ; AT THE START OF THE COPY, TRACK=TRACK ADDRESS OF FILE ; SECTOR = SECTOR ADDRESS OF FILE. DISK IS SELECTED FROM READ OF DIRECTORY ; TRACK AND SECTOR WERE SET BY DIRECTORY SEARCH SUBROUTINE. ; ; COPY PROCEEDS ONE SECTOR AT A TIME. ; READ MITS SECTOR, UPDATE TRACK AND SECTOR, WRITE CP/M SECTOR LOOP ETC. ; TERMINATES ON ZERO TRACK/SECTOR OR EOF CHARACTER. ; COPYFILE: LDA RANDFLAG ; IS FILE RANDOM ORA A ; SET JNZ APOLOGY ; DONT DO AT THIS TIME CPYFL1: CALL RDMITS ; READ MITS DISK CALL WRCPM ; WRITE CP/M FILE LHLD BUFFER+5 MOV A,L ORA H JNZ CPYFL1 RET APOLOGY: MSG APMSG,MCNVT APMSG DB CR,LF,'CANT DO RANDOM FILES YET',0 ; ;INITIALIZE ; INITIAL: LXI H,BUFFER ; SET BUFFER ADDRESS SHLD ADDR MVI A,BSIZE STA RWFLAG ; SAY READING STA NWDS XRA A STA OP ; READING=0 STA RWFLAG IF CHECKOUT STA TBUFF ENDIF OUT 8 ; SELECT DRIVE 0 LXI H,0 SHLD NREC ; INITIALIZE WRITE COUNTER CALL INPUTCDI RET ; ; PMITS => RECOVERS AND PRINTS MITS DIRECTORY ; PMITS CALL MDRD CALL SORT CALL PRINTDIRECTRY RET ; ; SETFILES ; THIS ROUTINE SETS UP THE OUTPUT FILE ; IT CALLS ON CP/M TO SEARCH FOR THE FILE AND THEN IT ; DESTROYS IT IF FOUND. ; SETFILES: LXI D,FCB ; SET UP FCB ADDRESS AS INPUT PUSH D CPM SRCHF INR A ; NOT FOUND? JZ SET1 ; YES POP D PUSH D CPM DELETEF SET1 POP D PUSH D CPM CREATEF POP D CALL SETUPO ; OPEN FILE CPM SETDMA,BUFFER+7 ; DMA ADDRESS TO WRITE MITS FILE RET ; RETURN TO USER ; ; END OF PROGRAM ; ; ; SECTOR TRACK ROUTINE FOR 88-DCDD ; SECGET DI ; SECTOR ACQUIRE DON'T ALLOW TRAPPING SG1 IN 9 ; GET CURRENT DATA STUFF RAR JC SG1 ANI 31 ; MASK OFF SECTOR NUMBER CMP E ; E=>DESIRED SECTOR JNZ SG1 ; NXT ONE MAYBE RET ; ; TRACK ROUTINE ; TRACKGET IN 8 ; GET STATUS OF DISK ANI 4 ; IS HEAD LOADED? CNZ LOADHEAD ; NOPE, LOAD IT CALL FINDTRACK ; FIND TRACK IN RAT LDA TRK ; FOR DEBUGGING TRK IS PUT HERE WHEN FOUND IN RAT CMP D ; IS THIS THE DESIRED TRACK ON THIS DISK? RZ ; YES PUSH PSW ; SAVE RESULTS OF COMPARE CALL LOADHEAD POP PSW JM STEPIN ; NEGATIVE MEANS HEAD IS TOO FAR TOWARDS EDGE STEPOUT CALL POUT ; POSITIVE, MEANS TOO FAR TOWARDS CENTER LDA TRK DCR A STA TRK ; COUNT DOWN TRACK AS WE STEP HEAD CMP D ; IS THIS THE DESIRED TRACK? JNZ STEPOUT ; NO, KEEP COUNTING CALL STORETRACK ; PUT TRACK BACK IN RAT JMP MOVE STEPIN CALL PIN LDA TRK INR A STA TRK ; INCREMENT AS WE GO IN TOWARDS THE HUB CMP D JNZ STEPIN CALL STORETRACK JMP MOVE PIN CALL MOVE MVI A,1 OUT 9 RET ; STEPS HEAD INWARDS 1 TRACK LOADHEAD MVI A,4 ; 4 SAYS MOVE HEAD ONTO THE SURFACE OUT 9 LH1 IN 8 ; GET DISK STATUS ANI 4 ; MOVEMENT ALLOWED? RZ JMP LH1 TRACK0 XRA A STA TRK ; SET IT TO ZERO CALL STORETRACK ; FIX RAT TR01 CALL MOVE IN 8 ANI 0100Q ; CHECK IF ON TRACK ZERO RZ ; YES, DONE CALL POUT ; STEP HEAD TOWARDS TRACK 0 JMP TR01 POUT CALL MOVE MVI A,2 ; COMMAND TO STEP OUT OUT 9 RET MOVE IN 8 ANI 2 ; IS HEAD MOVEMENT ALLOWED (VALID SECTOR INDEX PULSE) RZ ; YES JMP MOVE HEADUNLOAD MVI A,8 ; UNLOAD COMMAND OUT 9 RET FINDTRACK PUSH H ; FINDS TRACK IN RAPID ACCESS TABLE LDA DISK LXI H,RAT CALL ADDAHL ; ADD A TO HL (GET WHICH DISK IT IS) MOV A,M ; GET THE ENTRY FOR THAT DISK STA TRK ; SET THAT TOO POP H RET ADDAHL: ADD L MOV L,A RNC INR H RET ; THATS ALL THERE IS TO IT STORETRACK PUSH H LXI H,RAT LDA DISK CALL ADDAHL ; ADD A TO HL GET THE RIGHT SLOT IN RAT LDA TRK MOV M,A POP H RET ; RAPID ACCESS TABLE RAT DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 TRK EQU RAT+16 ; ; READ A SECTOR FROM MITS DISK. SECTOR AND TRACK ARE ASSUMED SET ; PRIOR TO ENTRY. IF SECTOR AND TRACK ARE WRONG FOR FILE ; GROUP INDICATES "FILE LINK ERROR" ; ; IF CHECKSUM IS IN ERROR, "CHECKSUM ERROR" WILL BE INDICATED ; RDMITS LDA TRACK CPI 77 ; SENSE OFF DISK JP BADTRK ADI 0 JM BADTRK LDA SECTOR ADI 0 JM BADSEC CPI 32 JP BADSEC LXI H,BUFFER SHLD ADDR MVI A,BSIZE STA NWDS CALL DISKIN ; INPUT THE SECTOR LDA FN ; GET CURRENT FILE NUMBER LXI H,BUFFER+2 ; FILENUMBER ON DISK CMP M ; SHOULD ALWAYS BE = JNZ BADLNK ; FILE LINK ERROR INX H MOV A,M ; NUMBER DATA BYTES IN SECTOR STA WRCOUNT ; SAVE NUMBER OF BYTES TO WRITE INX H MOV C,M ; GET CHECKSUM LHLD BUFFER+5 MOV A,H ANI 1 MOV A,H JZ RDMIT1 ADI 16 ANI 1FH RDMIT1: STA SECTOR MOV A,L STA TRACK ADD H MOV B,A LDA FN ADD B MOV B,A LDA WRCOUNT ADD B MVI B,128 LXI H,BUFFER+7 CSCALC ADD M INX H DCR B JNZ CSCALC XRA C ; CHECKSUM JNZ BADCKS PUSH H LHLD NREC MOV A,H ORA L JNZ SKIPIT LDA BUFFER+7 STA FRSTCH ; SAVE FIRST CHARACTER OF FILE SKIPIT: POP H IF DEBUGGING MOV A,M ; LOOK FOR CHECK BYTE INR A ; 255+1=0 RZ LXI H,CKBYTE ; CHECK BYTE ERROR JMP CPMERR CKBYTE DB CR,LF,'CHECK BYTE NOT FOUND IN MITS FILE' ENDIF IF NOT DEBUGGING RET ENDIF ; ; WRITE CP/M DISK FILE ; WRCPM: LDA WRCOUNT ; GET WORD COUNT CPI 128 ; CHECK FOR FULL BUFFER JZ WRCPM1 ; YES,WRITE IT MOV B,A ; SAVE COUNT LXI H,BUFFER+7 ; START OF DATA REGION CALL ADDAHL ; ADD WORDS WRITTEN LDA FRSTCH INR A ; =255=>BINARY FILE JZ ZSR ; ZERO OUT REMAINDER OF BUFFER MVI A,1AH ; EOF MARK FOR ASCII FILES ZSR MOV M,A ; STORE ZERO OR 1A IN BUFFER MVI A,128 SUB B INX H DCR A JZ WRCPM1 ; JUMP IF ONLY ONE CHARACTER REMAINING (DONE) MOV B,A XRA A ZRLOOP: MOV M,A ; ZEROIZE THE REST OF THE BUFFER INX H DCR B JNZ ZRLOOP WRCPM1: CPM WRITEF,FCB LHLD NREC ; INCREMENT RECORD COUNT INX H SHLD NREC ORA A RZ ; WRITE OPERATION COMPLETED OK CPI 2 ; < MEANS ERROR EXTENDING > MEANS DIRECTRY ERR JZ ENDDSK JC EXTERR JMP DIRFUL ; ; SET UP CPM FILE ; SETUPO: CPM OPENF ; OPEN CP/M FILE CPI 255 JZ DIRFUL RET ; ; SET UP FCB FOR OUTPUT ; ; DATA IS IN TFCB AND TFCB+16 ; KATHY: PUSH B LDAX D MOV M,A INX D INX H DCX B MOV A,B ORA C JNZ KATHY+1 POP B RET ; ; CLOSE WRITE FILE ; CLWRF: CPM CLOSEF,FCB ; CLOSE WRITE FILE RET ; ; ; ; ERROR CONDITIONS ; BADLNK LXI H,FLERRM CALL PRMSG JMP EXIT ; WE ARE ROGH ON ERRORS - YOU MIGHT WANT TO GO ON BADSEC LXI H,SECERR ; SECTOR NOT 0-31 CALL PRMSG JMP EXIT BADTRK LXI H,TRKERR ; TRACK NOT 0-76 CALL PRMSG JMP EXIT BADCKS LXI H,CKSUM CALL PRMSG JMP EXIT BADFMT LXI H,FMTNG CALL PRMSG JMP EXIT ENDDSK: LXI H,FULMSG ; DISK FULL JMP CPMERR ; ERROR ENCOUNTERED IN CP/M SEGMENT OF PROGRAM EXTERR: LXI H,EXTMSG JMP CPMERR DIRFUL LXI H,FULMSG CPMERR CALL PRMSG JMP EXIT ; ; ;; READ MITS FILE DIRECTORY ; ; DESTROYS EVERYTHING - USES EVERYTHING ; DISK IS LEFT WITH HEAD UNLOADED ON TRACK 70 ; ; DOESN'T SORT DIRECTORY ; ; MDRD LDA DISK ; SELECT DISK CALL DISKSET XRA A STA SECTOR STA FCOUNT ; ZER OFILE COUNTER STA OP ; READ=>0 MVI A,DTRACK ; DIRECTORY TRACK STA TRACK ; DIRECTORY TRACK LXI D,OND ; SET ORIGIN OF THE NEW DIRECTORY MDRD1 LXI H,BUFFER ; SET ORIGIN OF INPUT BUFFER SHLD ADDR ; SET ADDRESS OF INPUT BUFFER TO READ RTN MVI A,BSIZE ; BUFFER SIZE STA NWDS ; SET CALL DISKIN ; READ A SECTOR LXI H,BUFFER+DBIAS ; START OF MEANINGFUL DATA IN DIRECTORY MVI B,NFPS MDRD2 MOV A,M ORA A JZ MDRD5 ; DELETED OR EMPTY FILE CPI ENDSLOT ; LAST ENTRY IN MITS DIRECTORY RZ PUSH H MVI A,11 CALL ADDAHL ; POINT TO FIRST UNUSED LOC IN THIS ENTRY CALL FNCALC MOV M,A ; PUT FILE NUMBER IN OLD DIRECTORY IF DEBUGGING LDA SECTOR INX H MOV M,A INX H MVI A,9 SUB B MOV M,A ENDIF POP H MVI C,DSIZE ; SIZE OF ENTRY MDRD3 MOV A,M STAX D INX D INX H DCR C JNZ MDRD3 ; LOOP TILL DIRECTORY IS OBTAINED LDA FCOUNT ; INCREMENT FILE COUNT INR A STA FCOUNT MDRD4 DCR B ; NUMBER OF DIRECTORY ENTRIES/SECTOR JNZ MDRD2 JMP MDRD6 ; READ NEXT DIRECTORY SECTOR MDRD5 PUSH D LXI D,DSIZE ; PASS VACANT DIRECTORY ENTRY DAD D POP D JMP MDRD4 MDRD6 LDA SECTOR ADI 17 ; LATENCY CALCULATION SCHTICK CPI 32 JC MDRD7 SUI 32 ; REDUCE MODULO 32 MDRD7 STA SECTOR JMP MDRD1 ;SHELL-METZNER SORT ; THIS IS AN 8080 ADAPTATION OF THE SHELL SORT AS MODIFIED BY MARLENE METZNER ; ; IT WILL SORT ANY FIXED LENGTH RECORD OF UP TO 255 BYTES INTO ASCENDING ORDER. ; BY MODIFICATION OF THE PROGRAM AT "COMP" IT CAN SORT INTO DESCENDING ORDER OR ; CAN BE MADE TO EXIT EACH TIME THAT AN EQUAL RECORD IS FOUND. ; ; ; ; REGISTER USE: ; ; B=VAR I , C= VAR J , D= VAR K , E= VAR L , H= VAR M ; FOR MORE DETAILS SEE KNUTH, DONALD E.: THE ART OF COMPUTER PROGRAMMING, ; VOL. 3: SORTING AND SEARCHING. ADDISON-WESLEY, 1973 ; THERE IS NO DIRECT REFERENCE TO METZNER'S MODIFICATION SORT: LDA FCOUNT ; NUMBER OF RECORDS TO SORT MOV H,A ; PUT IT IN H (FIRST TIME ONLY) SORT1: MOV A,H ; START NEW PASS ORA A ; CLEAR CARRY FLAG RAR ;M=M/2 (VARM) ORA A ; CLEAR CARRY MOV H,A ; M=INT(M/2) RZ ; SORT FINISHED LDA FCOUNT ; GET N (NUMBER OF RECORDS) SUB H ; MINUS M MOV D,A ; SAVE IN D (K) MVI C,1 ; SET VAR J=1 SORT2: MOV B,C ; SET I=J INNER LOOP SORT3: MOV A,B ADD H ; L=I+M (VAR L) MOV E,A SORT4: PUSH H PUSH D PUSH B MOV A,B ; GET I CALL SETAD ; CALCULATE ADDRESS (DISPLACEMENTS INTO RECORD) SHLD CRCEL ; SAVE I ADDRESS DISPLACED POP B POP D POP H SORT5: PUSH H PUSH D PUSH B MOV A,E ; GET L CALL SETAD ; CALCULATE ADDRESS (DISPLACEMENT INTO RECORD) SHLD CRCL1 ; SAVE L ADDRESS DISPLACED POP B POP D POP H SORT6: PUSH H PUSH D PUSH B MVI B,8 ; LENGTH OF SORT FIELD LHLD CRCL1 ; L RECORD ADDRESS XCHG ; MOVE L RECORD COMPARE ADDRESS TO DE LHLD CRCEL ; I-RECORD XCHG ; I-RECORD ADDRESS TO DE, L RECORD TO HL CALL COMP ; COMPARE STRINGS POP B POP D POP H TEST: ORA A JZ SORT7 JM SORT7 ; SORT7=>NO SWAP CALL XFER ; SWAP SUBROUTINE MOV A,B SUB H MOV B,A ; I=I-M JC SORT7 JNZ SORT3 ; SET NEW L SORT7: INR C ; INCREMENT J COUNT MOV A,D CMP C ; J>K? JC SORT1 ; YES, START NEW (NEXT) PASS JMP SORT2 ; ELSE CONTINUE THIS PASS ; SUBROUTINES ;SETAD - SET ADDRESS ; SETAD: MVI D,0 MOV E,A MVI A,DSIZE ; LENGTH OF RECORD TO SORT MOV H,D MOV L,D MVI B,8 SETAD1: DAD H RLC JNC SETAD2 DAD D SETAD2: DCR B JNZ SETAD1 XCHG LXI H,OND-DSIZE DAD D RET ; ; XFER - SWAPS STRINGS I AND J ; XFER: PUSH H PUSH D PUSH B MVI B,DSIZE LHLD CRCEL XCHG LHLD CRCL1 XFER1: LDAX D MOV C,A MOV A,M STAX D MOV M,C INX D INX H DCR B JNZ XFER1 POP B POP D POP H RET COMP: DCR B RM LDAX D SUB M INX D INX H JZ COMP RET ; ; HARD SECTOR DISK INPUT ; HSDI CALL SECGET MVI C,BSIZE HSDI1 IN 8 ORA A JM HSDI1 IN 10 MOV M,A INX H DCR C JZ HSDI2 DCR C NOP IN 10 MOV M,A INX H JNZ HSDI1 HSDI2 EI RET ; ;DISK INPUT DRIVER COUPLER ; DISKIN PUSH H PUSH D PUSH B LDA DISK OUT 8 ; SELECT DISK LDA TRACK MOV D,A CALL TRACKGET LDA SECTOR MOV E,A LHLD ADDR CALL HSDI CALL HEADUNLOAD POP B POP D POP H RET DISKSET: PUSH PSW OUT 8 ; SELECT DISK NOP ; IN CASE HARDWARE DOESN'T WORK IN 8 ; SENSE READY ANI 020H ; SENSE INTERRUPTS ENABLED (READY) JNZ WAITUP ; POP PSW CALL TRACK0 RET WAITUP: MVI A,200 WAIT1: DCR A JNZ WAIT1 POP A OUT 8 NOP NOP JMP DISKSET DS 50 ; STACK REGION STACK EQU $ CPMSTK DW 0 ; CP/M STACK POINTER END 0100H ; START OF TPA