; -- DFOCO -- ; ; BY S. J. SINGER ; 10 NOV 1979 ; TRUE: EQU 0FFH FALSE: EQU 00H ; PERSCI: EQU FALSE ;CONDITIONAL ASSEMBLY SWITCH FOR FAST SEEK ; ;PERSCI DRIVES (SET TRUE 0FFH FOR PERSCI) DELTA: EQU FALSE ;CONDITIONAL SWITCH FOR DELTA CONTROLLER TARBELL:EQU FALSE ;CONDITIONAL SWITCH FOR NEW TARBELL DOUBLE ; ;DENSITY CONTROLLER ; ; (SET BOTH DELTA AND TARBELL FALSE FOR OLD TARBELL CONTROLLER) ; DUAL: EQU FALSE ;CONDITIONAL SWITCH FOR DUAL DRIVES STEP: EQU 1 ;STEPPING RATE 1=6 MSEC, 2=10 MSEC, 3=20 MSEC ; (0=3 MSEC, 1=6 MSEC, 2=10 MSEC, 3=15 MSEC 1791) ; (USE STEP = 6 FOR PERSCI DRIVES) ; MACLIB MACRO ;INCLUDE SYSTEM MACROS ORG 100H LXI H,0 DAD SP ;GET STACK POINTER SHLD OLDSTK LXI SP,NEWSTK ;SET UP NEW STACK LXI H,TRKTBL ;POINT TO TRACK TABLE MVI B,4 ST2: MOV M,A ;STORE IN TABLE INX H DCR B JNZ ST2 ;SET 4 TRACK LOCATIONS DISKIO ?DRIVE ;GET CURRENTLY LOGGED DRIVE NO STA DRIVE ;SAVE IT STA DRVNO ;SELECTED DRIVE STA NEWDRV ;ALSO SAVE IN NEW DRIVE NO IF NOT DUAL LXI H,TRKTBL ;POINT TO TRACK TABLE MVI D,0 MOV E,A ;DRIVE NO DAD D IN TRACK ;GET TRACK FROM 1771 MOV M,A ;STORE IT IN TABLE ENDIF 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 XRA A 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 <'CP/M FAST FORMAT-COPY UTILITY',CR,LF> PRINT <'COPYRIGHT NOV 1979 BY S J SINGER',CR,LF> NEWIN: PRINT MVI A,0FFH ;SET SWITCH TO RETURN HERE AGAIN STA INFLAG LXI SP,NEWSTK ;RESET STACK POINTER FILL 80H,0FFH ;ZERO INPUT BUFFER INPUT 80H ;READ FILE NAME ; ; SEARCH INPUT BUFFER FOR INITIAL COMMAND STRING ; START: MVI A,10 STA RETRYS ;SET DEFAULT READ OR WRITE RETRYS TO 10 XRA A STA VALFLG ;SET OTHER DEFAULTS STA VERFLG STA NOFILL STA DDFLG ;SINGLE DENSITY STA FORMSW ;RESET PROGRAM SWITCHES TO FALSE STA OFFSET ;SET OFFSET TO ZERO STA SECSIZ ;DEFAULT TO IBM STANDARD FORMAT STA CODE ;SPECIAL PASCAL FLAG CODE T 0 S 1 B 128 MVI A,26 STA NUMSEC ;NUMBER OF SECTORS INR A STA GAP ;FORMAT ADDR LEADER GAP MVI A,13 STA DGAP ;GAP FOR MFM MVI A,51 STA DNUMSEC ;NUMBER OF SECTORS (MFM) LXI H,183 SHLD FILOFF ;FILL OFFSET (FM) LXI H,195 SHLD DFILOFF ;FILL OFFSET (MFM) LXI H,128 SHLD BYTES ;128 BYTES PER SECTOR LDA 'S' CALL DENSEL ;DEFAULT IS SINGLE DENSITY MVI A,0DDH STA DENCODE ;DEFAULT DOUBLE DENSITY CODE (SINGLE SIDE) LXI H,SECMAP0 ;STANDARD MAP TRACK 0 CALL STDMAP FILL SECMAP,SECMAP+104 INSTR 82H,40H,'NOVAL' ;CHECK FOR VALIDATION OFF JNC START0 MVI A,0FFH STA VALFLG ;SET SWITCH START0: INSTR 82H,40H,'RETRY' ;CHANGE DEFAULT? JNC START2 CALL GETNUM ;GET RETRYS ORA A JNZ START1 INR A ;NO ZERO RETRYS START1: STA RETRYS ;SAVE IT START2: INSTR 82H,40H,'SIZE' CC SIZE INSTR 82H,40H,'4D' ;"QUAD" DISK ? JNC START2A MVI A,4DH ;QUAD CODE STA DENCODE JMP START2B START2A:INSTR 82H,40H,'DD' JNC STARTX START2B:MVI A,0FFH STA DDFLG ;SET DOUBLE DENSITY FLAG STARTX: INSTR 82H,40H,'MAP' JC MAP INSTR 82H,40H,'DCOPY' ;COPY DOUBLE DENSITY? JC DCOPY INSTR 82H,40H,'COPY' ;COPY A DISK? JC COPY INSTR 82H,40H,'DFORM' JC DFORMAT ;DOUBLE DENSITY FORMAT INSTR 82H,40H,'FORM' JC FORMAT ;SEARCH FOR FORMAT INSTR 82H,40H,'DVALID' ;VALIDATE DOUBLE DENSITY JC DVALID INSTR 82H,40H,'VALID' ;VALIDATE DISK? JC VALID JMP NEWIN ; ; COPY WILL COPY A DISK FROM ONE DRIVE TO ANOTHER AS QUICKLY AS POSSIBLE ; THE PROGRAM WILL READ THE FORMAT FROM TRACK 2 OF BOTH DISKS TO OPTIMIZE ; THE COPY OPERATION. ALL OF THE AVAILABLE MEMORY BETWEEN THE END OF FOCO ; AND THE BEGINNING OF CP/M WILL BE USED BY COPY. ; DCOPY: MVI A,0FFH STA DDFLG ;SET DOUBLE DENSITY FLAG ; COPY: LHLD 6 ;POINTS TO TOP OF MEMORY LXI D,TRKBUF ;END OF PROGRAM CALL DBLSUB ;SUBTRACT DE FROM HL MVI C,0 ;ZERO TRACK COUNT XCHG IF DELTA OR TARBELL MVI A,6+STEP ;SECTOR OFFSET ELSE MVI A,5+STEP ENDIF STA CPYOFF ;SAVE FOR LATER LXI H,128*26 ;MAX BYTES PER TRACK LDA SECSIZ ;SECTOR SIZE CODE ORA A ;IF 128 THEN SECSIZ=0 JZ C1 LXI H,512*8 ;MAX BYTES PER TRACK C1: LDA DDFLG ;DENSITY FLAG ORA A JZ C1A DAD H ;DOUBLE IT (512*16) LDA SECSIZ ;SECTOR SIZE CODE CPI 2 JZ C1A LXI H,51*128 ;128 BYTE SECTORS? ORA A JZ C1A LXI H,26*256 ;MUST BE 256 BYTE SECTORS THEN C1A: SHLD TRKSIZE ;SAVE IT XCHG C2: CALL DBLSUB ;SUBTRACT JC C4 ;EXIT ON CARRY INR C ;INCR TRACK COUNT JMP C2 ;LOOP TILL HL GOES MINUS C4: MOV A,C ;TRACK LIMIT STA TRKLIM ;TRACKS THAT CAN BE READ ON ONE PASS LDA DDFLG ;DENSITY SWITCH ORA A JZ C4A MVI A,'D' CALL DENSEL ;SELECT DOUBLE DENSITY LDA CPYOFF ;SECTOR OFFSET FOR COPY ADD A ;DOUBLE IT FOR DOUBLE DENSITY STA CPYOFF C4A: XRA A STA SOURCE ;DEFAULT SOURCE DISK 'A:' STA VERFLG ;DEFAULT VERIFICATION ON INR A STA DEST ;DEFAULT DEST DISK 'B:' LXI H,SECMAP MVI A,'W' ;READ WRITE MAPPING FOR 51 SECTORS CALL STDMAP ;DEFAULT STD SECTOR MAP FOR A: LXI H,SECMAP1 MVI A,'W' ;READ WRITE MAPPING FOR 51 SECTORS CALL STDMAP ;DEFAULT STD SECTOR MAP FOR B: INSTR 82H,40H,'NOFILL';NO FILL WITH E5 REQUEST JNC C5 MVI A,0FFH STA NOFILL ;SET SWITCH C5: INSTR 82H,40H,'NOVER' ;NO VERIFICATION REQUEST JNC C6 MVI A,0FFH STA VERFLG ;SET FLAG FOR NO VERIFICATION C6: INSTR 82H,40H,'FORM' JNC C7 MVI A,0FFH STA FORMSW ;SET FORMAT SWITCH C7: CALL GETRK ;GET TRACK SPECIFICATIONS IF ANY INSTR 82H,40H,'COPY' ;POSITION BUFFER POINTER AFTER 'COPY' SCAN ,40H ;LOOK FOR START OF SOURCE IF ANY JZ C10 LXI D,DSKNAME ;DE POINTS TO TABLE OF NAMES MVI C,0 ;COUNT OF DRIVE NO CLX: SAV MVI C,2 ;LENGTH OF NAME MATCH ;DOES IT MATCH RES JZ C8 INR C ;INCR DRIVE NO MOV A,C ;DRIVE NO TO A CPI 4 JP SCANERR INX D INX D ;POINT TO NEXT NAME IN TABLE JMP CLX C8: MOV A,C ;DRIVE NO TO A STA SOURCE ;SAVE SOURCE C9: INSTR 82H,40H,'TO' ;DESTINATION MARKER JNC C10 ;NO TO USE DEFAULTS CALL GETDRV ;LOOK FOR DESTINATION DRIVE JNC SCANERR ;MISSING DEST IF NO CARRY STA DEST ;SAVE DESTINATION LXI H,SOURCE ;POINT TO SOURCE CMP M ;CHECK IF SAME JNZ C10 PRINT PRINT <'IS THIS WHAT YOU WANT? (Y/N) '> CALL CHECKY C10: CALL CPYFORM PRINT <'DISK '> LDA SOURCE CALL PRNDRV PRINT <' TO DISK '> LDA DEST CALL PRNDRV UTX: LDA FORMSW ;CHECK FORMAT SWITCH ORA A JNZ CFX ;TO COPY FORMAT INSTR 82H,40H,'USING' ;GET FORMAT FROM DISK? JNC C10A CALL GETNUM ;GET TRACK NUMBER CALL TRKTEST ;MAKE SURE ITS OK STA TNUM ;SAVE IT LDA DEST ;DEST DRIVE CALL SELECT CALL HOME LXI H,SECMAP ;POINT TO SECTOR MAP LDA TNUM ;TRACK NUMBER CALL RDFORM ;READ FORMAT MOVE SECMAP,SECMAP1,52 ;SAME MAP FOR BOTH C10A: LDA STRK ORA A JNZ C10B LDA ETRK CPI 76 JZ C10E LXI H,STRK LDA ETRK CMP M ;IS THERE JUST ONE TRACK JZ C10B PRINT <' TRACKS '> JMP C10C C10B: PRINT <' TRACK '> C10C: LHLD STRK DECOUT ;PRINT STARTING TRACK LDA ETRK LXI H,STRK CMP M JZ C10E PRINT <' THRU '> LHLD ETRK DECOUT ;PRINT ENDING TRACK C10E: PRINT CHARIN CPI 3 JZ ENDFIL ;EXIT ON CONTROL C LDA SOURCE ;HOME BOTH DRIVES CALL SELECT CALL HOME ;HOME IT LDA DEST CALL SELECT CALL HOME ;HOME IT LDA STRK ;STARTING TRACK NO STA STRKR ;SET STARTING TRACK FOR READ STA STRKW ;SET STARTING TRACK FRO WRITE ; ; START OF ACTUAL COPY LOOP ; C11: LDA SOURCE ;SOURCE DRIVE LXI H,DEST CMP M ;COMPARE JNZ C11A PRINT CHARIN LDA SOURCE CALL HOME C11A: CALL SELECT LDA DDFLG ;DENSITY FLAG STA DENTEMP ;TO TEMPORARY (FOR TRACK ZERO COPY) LDA STRKR ;GET READ START MOV B,A ;STARTING TRACK TO B LDA TRKLIM ;TRACK LIMIT MOV C,A LXI D,TRKBUF ;POINTS TO MEMORY BUFFER C12: MOV A,B ;TRACK NO TO A STA TNUM ;TRACK NUMBER FOR ERROR MESS LXI H,SECMAP ;READ SECTOR MAP ORA A ;TRACK ZERO JNZ C14 MVI A,'S' CALL DENSEL ;SELECT SINGLE DENSITY LXI H,SECMAP0 ;SECTOR MAP FOR TRACK 0 MOV A,B ;TRACK NO BACK TO A C14: CALL SEEK ;GET PROPER TRACK CALL RDTRK ;READ A TRACK INTO MEMORY MOV A,B ;TRACK NO TO A ORA A ;IS IT TRACK ZERO JNZ C15 LDA DENTEMP ;DENSITY TEMPORARY ORA A ;GO ON IF SINGLE JZ C15 MVI A,'D' CALL DENSEL ;SELECT DOUBLE DENSITY C15: LDA ETRK ;ENDING TRACK LXI H,SECMAP CMP B ;COMPARE WITH START TRACK JZ C20 ;FINISHED READ INR B ;INCREMENT TRACK DCR C ;DECR TRACK LIMIT JZ C20 ;FINISHED READ PUSH H LHLD TRKSIZE DAD D ;ADD OFFSET XCHG POP H LDA CPYOFF ;SECTOR OFFSET C16: CALL MAPSLEW ;OFFSET SECTOR MAP FOR SPEED JMP C12 ;KEEP READING TRACKS C20: MOV A,B ;LAST TRACK READ STA STRKR ;SAVE FOR NEXT READ LDA DEST ;DESTINATION DRIVE LXI H,SOURCE CMP M JNZ C21 PRINT CHARIN LDA DEST CALL HOME C21: CALL SELECT LDA STRKW ;STARTING TRACK FOR WRITE MOV B,A LDA TRKLIM ;MAX TRACKS THAT FIT IM MEMORY MOV C,A LXI D,TRKBUF ;MEMORY BUFFER C22: MOV A,B ;TRACK NO STA TNUM ;SAVE FOR ERROR MESS LXI H,SECMAP1 ;WRITE SECTOR MAP ORA A JNZ C23 ;GO ON IF NOT TRACK ZERO MVI A,'S' CALL DENSEL ;SELECT SINGLE DENSITY MOV A,B ;TRACK NO BACK TO A LXI H,SECMAP0 ;TRACK ZERO SECTOR MAP C23: CALL SEEK CALL WRTRK ;WRITE A TRACK LXI H,SECMAP1 MOV A,B ;TRACK NUMBER ORA A JNZ C23A ;GO ON IF NOT TRACK ZERO LDA DENTEMP ;DENSITY TEMPORARY ORA A JZ C23A MVI A,'D' CALL DENSEL ;SELECT MFM C23A: LDA ETRK ;ENDING TRACK NO CMP B JZ C40 ;ALL DONE WITH COPY INR B DCR C ;DECR TRACK LIMIT JZ C30 ;FINISHED WRITE PUSH H LHLD TRKSIZE ;FULL TRACK OFFSET C24: DAD D ;ADD IT XCHG POP H LDA CPYOFF ;SECTOR OFFSET C26: CALL MAPSLEW JMP C22 ;KEEP WRITING TRACKS C30: MOV A,B ;LAST TRACK WRITTEN STA STRKW ;SAVE IT FOR NEXT TIME JMP C11 ;GO READ SOME MORE C40: PRINT JMP ENDFIL ; ; THIS COPY FORMAT LOGIC JUMPS TO THE FORMAT ROUTINE ; CFX: XRA A ;ZERO STA TNUM INSTR 82H,40H,'USING' JNC CFX1 CALL GETNUM ;TRACK NUMBER CALL TRKTEST ;CHECK IT STA TNUM CFX1: LDA SOURCE CALL SELECT ;SOURCE DRIVE HAS FORMAT CALL HOME LXI H,SECMAP LDA TNUM CALL RDFORM ;READ FORMAT INTO SECMAP LDA DEST STA NEWDRV ;NEW DRIVE NUMBER LXI H,SECMAP ;CHECK SECTORS READ FROM DISK MVI C,26 ;SECTOR COUNT CFX3: MOV A,M ;GET A SECTOR ORA A JM CFX4 ;ERROR IF MINUS JZ CFX4 ;ERROR IF ZERO CPI 27 JP CFX4 ;ERROR IF > 26 INX H DCR C ;DECR SECTOR COUNT JNZ CFX3 ;LOOP FOR 26 SECTORS PRINT CALL RDISP ;DISPLAY IT PRINT JMP FMNS ;TO FORMAT ROUTINE CFX4: PRINT <'INCORRECT SECTOR NUMBER READ FROM SOURCE DISK',CR,LF> CALL RDISP JMP ENDFIL ;BACK TO INPUT ROUTINES ; ; ; CPYFORM LOGIC FOR COPYING FORMAT RATHER THAN DATA ; CPYFORM:PRINT LDA FORMSW ;SWITCH ON IF FORMAT ORA A JZ CP3 PRINT <'FORMAT FROM '> CP3: RET ; ; DISPLAY DISK SECTOR MAPPING ; MAP: XRA A STA TNUM ;SELECT TRACK ZERO LXI H,82H ;POINT TO START OF INPUT BUFFER CALL GETDRV ;CHECK IF NEW DRIVE REQUESTED JNC MAP3 STA NEWDRV MAP3: CALL GETRK ;READ TRACK SPECS IF ANY STA TNUM ;SAVE TRACK NUMBER MAP4: LDA NEWDRV ;SELECTED DRIVE CALL SELECT LDA TNUM ;GET BACK TRACK NO LXI H,SECMAP ;POINT TO SECTOR TABLE CALL RDFORM ;READ TRACK FORMAT CALL CLEAR ;CLEAR SCREEN PRINT LDA NEWDRV ;GET DRIVE NO CALL PRNDRV ;PRINT DRIVE NAME MAP5: PRINT <' TRACK '> MAP6: LHLD TNUM DECOUT ;CONVERT TO DECIMAL AND PRINT PRINT CALL RDISP ;DISPLAY SECTOR MAP JMP ENDFIL ;BYE ; ; DISK VALIDATION ROUTINES ; DVALID: MVI A,0FFH STA DDFLG ;SET DOUBLE DENSITY ; VALID: LXI H,82H ;POINT TO START OF INPUT BUFFER CALL GETDRV ;CHECK NEW DRIVE NUMBER JNC VDD0 STA NEWDRV ;SAVE NEW DRIVE NO VDD0: MVI A,0FFH ;SET SWITCH FOR STD FORMAT STA TNUM ;SELECT TRACK 0 LDA DDFLG ;DENSITY SWITCH ORA A JZ VDX MVI A,'D' CALL DENSEL ;SELECT DOUBLE DENSITY VDX: INSTR 82H,40H,'USING' JNC VALID0 CALL GETNUM CALL TRKTEST ;CHECK FOR GOOD TRACK NUMBER STA TNUM ;SET TRACK NUMBER VALID0: LDA NEWDRV REVAL: CALL SELECT CALL HOME LDA DDFLG ;DENSITY FLAG STA DENTEMP ;TO TEMPORARY FOR TRACK ZERO READ LXI H,SECMAP ;POINT TO SECTOR TABLE LDA TNUM ;CHECK TRACK NUMBER ORA A ;0FFH IF DEFAULT TO STD FORMAT JP VD1 ;READ SECTOR FORMAT FROM DISK XRA A ;READ ONLY MAPPING 51 SECTORS CALL STDMAP ;OTHERWISE USE STANDARD FORMAT JMP VD2 VD1: CALL RDFORM ;GET SECTOR MAPPING FROM TRACK TNUM VD2: XRA A STA HARDERR ;ZERO ERROR COUNTERS STA SOFTERR STA TNUM ;START WITH TRACK ZERO LXI H,SECMAP0 ;SECTOR MAP FOR TRACK 0 MVI A,'S' CALL DENSEL ;SELECT SINGLE DENSITY VALID1: LDA TNUM ;GET A TRACK NUMBER LXI D,TRKBUF ;TRACK BUFFER CALL RDTRK ;VALIDATE THE TRACK LXI H,SECMAP ;STANDARD SECTOR MAP LDA TNUM ;TRACK NUMBER ORA A ;TRACK 0 JNZ VALIDP ;SKIP IF NOT TRACK ZERO LDA DENTEMP ;DENSITY TEMPORARY ORA A JZ VALIDO MVI A,'D' CALL DENSEL ;SELECT DOUBLE DENSITY VALIDO: LDA TNUM ;LOAD TRACK NO VALIDP: CPI 76 ;FINISHED 76 TRACKS? JZ VALID2 INR A ;INCREMENT TRACK COUNT STA TNUM ;STORE IT BACK CALL SEEK ;STEP TO NEXT TRACK LDA SECSIZ ;SECTOR SIZE CODE CPI 2 ;CHECK 512 JNZ VALIDR MVI A,3 JMP VALIDD IF DELTA OR TARBELL VALIDR: MVI A,6+STEP ELSE VALIDR: MVI A,5+STEP ENDIF VALIDD: MOV B,A ;OFFSET TO B LDA DDFLG ORA A MOV A,B ;MOVE OFFSET BACK JZ VALIDS ADD A ;DOUBLE OFFSET DCR A ;SUBTRACT 1 MOV B,A LDA SECSIZ ;SECTOR SIZE CODE ORA A MOV A,B ;MOVE OFFSET BACK JZ VALIDS DCR A ;SUBTRACT 1 VALIDS: LXI H,SECMAP ;POINT TO SECTOR MAP CALL MAPSLEW ;PRECESS IT 5 + STEP SECTORS LXI H,SECMAP CALL CHECKC ;ABORT ON CONTROL C JMP VALID1 ;LOOP FOR 76 TRACKS VALID2: LDA HARDERR ;CHECK ERRORS ORA A JNZ VALID8 ;HARD ERRORS HERE PRINT VALID3: LDA NEWDRV ;GET DRIVE NUMBER CALL PRNDRV ;PRINT DRIVE NAME VALID6: LDA SOFTERR ;SOFT ERRORS ORA A JZ ENDFIL DCR A ;CHECK FOR SINGLE SOFT ERROR JZ VALID12 PRINT LHLD SOFTERR ;PRINT SOFT ERRORS DECOUT ;PRINT ERRORS IN DECIMAL PRINT <' RETRYS'> VALIDX: LDA HARDERR ORA A ;CHECK NO OF HARD ERRORS JZ ENDFIL ;RET FOR MORE INPUT IF NONE PRINT <' AND '> LHLD HARDERR DECOUT ;PRINT HARD ERRORS IN DECIMAL LDA HARDERR DCR A JZ VALID9 VALID7: PRINT <' HARD ERRORS'> JMP ENDFIL ;BACK FOR MORE INPUT VALID8: PRINT JMP VALID3 VALID9: PRINT <' HARD ERROR'> JMP ENDFIL VALID12:PRINT JMP VALIDX ; ; ; ; DISK FORMATTING ROUTINES ; DFORMAT:MVI A,0FFH ;SET FLAG STA DDFLG JMP FM00 ; ; FORMAT: LDA DDFLG ;DOUBLE DENSITY? ORA A JZ FM1 ;DEFAULT SINGLE DENSITY IF ZERO FM00: MVI A,'D' CALL DENSEL ;SELECT DOUBLE DENSITY FM1: CALL GETRK ;GET TRACK SPECS LXI H,82H ;POINT TO START OF INPUT BUFFER CALL GETDRV ;GET DRIVE NUMBER JNC FM3 STA NEWDRV FM3: INSTR 82H,40H,'SKEW' ;FIXED SKEW FACTOR? JC SKEW ;GO DO IT INSTR 82H,40H,'SPEC' ;SPECIAL FORMAT? JC SPF LDA DDFLG ;DENSITY SWITCH ORA A JNZ FM3A LDA SECSIZ ;CHECK IF STANDARD FORMAT ORA A JZ FM4 ;STD IF ZERO FM3A: PRINT DECOUT BYTES ;NUMBER OF BYTES PER SECTOR PRINT <' BYTES PER SECTOR',CR,LF> LDA DDFLG ORA A JZ FM3C PRINT <'DOUBLE DENSITY '> DECOUT DNUMSEC JMP FM3E FM3C: PRINT <'SINGLE DENSITY '> LDA NUMSEC MOV L,A MVI H,0 DECOUT FM3E: PRINT <' SECTORS PER TRACK',CR,LF,LF> JMP FM5 FM4: PRINT PRINT <'STANDARD IBM 3740 FORMAT',CR,LF,LF> FM5: LXI H,SECMAP ;POINT TO SECTOR MAP CALL STDMAP ;SET UP STANDARD MAPPING FMNS: INSTR 82H,40H,'OFFSET';TRACK OFFSET? JNC FM0 CALL GETNUM ;GET OFFSET STA OFFSET ;SAVE IT FM0: PRINT <'INSERT DISK TO BE FORMATTED IN DRIVE '> LDA NEWDRV CALL PRNDRV ;PRINT DRIVE LETTER PRINT FM6: CHARIN ;WAIT FOR CHARACTER INPUT (ANY WILL DO) CPI 3 JZ ENDFIL ;TRAP OUT ON CONTROL C FM7: LDA NEWDRV CALL SELECT CALL DOFORM MVI A,0FFH ;SET SWITCH TO SUPRESS READ FORMAT STA TNUM ;MOVE STARTING TRACK NUMBER LDA VALFLG ;CHECK VALIDATION SWITCH ORA A JNZ ENDFIL ;IF NOT ZERO NO VALIDATION JMP VALID0 ;NOW VALIDATE DISK JUST TO MAKE SURE ; SPF: PRINT PRINT <'PHYSICAL LOGICAL',CR,LF,' SECTOR SECTOR',CR,LF> FILL SECMAP,SECMAP+27 LXI H,SECMAP ;POINTS TO SECTOR TABLE MVI C,1 ;SECTOR COUNT MVI B,26 ;SECTOR LIMIT SPF2: MOV A,C ;PSEC TO A STA PSEC ;READY FOR CONVERSION SAV ;PUSH REGS PRINT LDA PSEC CPI 10 JP SPF3 ;LINE UP COLUMNS PRINT SPACE,$ SPF3: DECOUT PSEC ;CONVERT AND PRINT NUMBER PRINT <' '> ;SOME SPACES FILL 80H,90H ;ZERO BUFFER INPUT 80H ;INPUT THE LOGICAL SECTOR LXI H,82H ;START OF BUFFER CALL GETNUM ;GET SECTOR CALL SECERR ;CHECK FOR ERRORS RES JC SPF2 ;DO THAT ONE OVER MOV M,A ;CONVERTED LSEC TO TABLE INX H INR C ;INCR COUNTERS DCR B JNZ SPF2 ;LOOP FOR 26 SECTORS CALL CLEAR ;CLEAR SCREEN CALL RDISP ;REDISPLAY SECTOR MAP RD6: PRINT FILL 80H,90H ;ZERO BUFFER INPUT 80H LDA 81H ;NO OF CHAR TYPED IN ORA A JNZ RD8 ;CORRECT INPUT PRINT JMP FMNS ;TO FORMAT ROUTINE RD8: LXI H,82H ;POINT TO START OF BUFFER CALL GETNUM ;GET SECTOR STA PSEC ;SAVE PHYSICAL SECTOR PRINT PRINT <'PHYSICAL LOGICAL',CR,LF,' SECTOR SECTOR',CR,LF,' '> DECOUT PSEC PRINT <' '> FILL 80H,90H INPUT 80H LXI H,82H CALL GETNUM ;LSEC ORA A JZ RD9 ;ALLOW ZERO SECTOR HERE FOR ERROR CORRECTION CALL SECERR ;CHECK FOR ERRORS JC RD6 ;BACK FOR MORE INPUT RD9: LXI H,SECMAP MOV B,A ;SAVE LSEC IN B LDA PSEC ;GET BACK PSEC MOV E,A ;OFFSET TO E MVI D,0 ;ZERO D DAD D ;ADD IN OFFSET DCX H ;BACK UP ONE (TABLE STARTS AT ZERO) MOV M,B ;LOGICAL SECTOR NO TO TABLE CALL CLEAR ;CLEAR SCREEN CALL RDISP ;REDISPLAY JMP RD6 ;CONTINUE ; ; STDMAP SET UP SECTOR MAP POINTED TO BY HL WITH STANDARD FORMAT ; STDMAP: SAVE MOV C,A ;READ WRITE CODE TO C (W=WRITE) LDA NUMSEC ;NUMBER OF SECTORS MOV B,A ;TO B LDA DDFLG ;DENSITY FLAG ORA A JZ STDMAP1 LDA DNUMSEC ;NUMBER SECTORS DD MOV B,A CPI 51 JZ STDMAP2 ;INTERLEAVE FOR 128 BYTE SECTORS STDMAP1:MVI C,1 ;SECTOR COUNT STD1: MOV M,C ;MOVE SECTOR NO TO TABLE INX H INR C ;INCR SEC NO AND TABLE POINTER DCR B ;SECTOR COUNT JNZ STD1 ;LOOP FOR NUMSEC SECTORS JMP STD6 STDMAP2:LXI D,DDMAP ;POINT TO DOUBLE DENSITY MAP MOV A,C ;GET BACK READ WRITE CODE CPI 'W' ;IS IT WRITE JNZ STD4 LXI D,DDMAP1 STD4: LDAX D MOV M,A ;MOVE SECTOR NO INX D INX H ;INCR POINTERS DCR B ;DECR COUNT JNZ STD4 STD6: RES RET ; ; SKEW ROUTINE ASSIGNS A SPECIFIED CONSTANT (MORE OR LESS) INTERVAL ; BETWEEN SECTORS ; SKEW CALL GETNUM ;SKEW FACTOR STA SKF ;SAVE IT FILL SECMAP,SECMAP+27 ;INITIALIZE MAP TO ZERO MVI B,1 ;CURRENT SECTOR NUMBER LXI H,SECMAP ;POINTS TO SECTOR MAP MVI C,26 ;MAX SECTOR COUNT LDA SKF ;GET BACK SKEW FACTOR MOV D,A ;SAVE IT IN D SKEW1: MOV A,B ;GET THE SECTOR NUMBER CALL SRTAB ;IS IT ALREADY IN THE TABLE JNC SKEW4 ;OK TO USE IT IF NO CARRY INR A ;INCR BY ONE CALL MOD26 ;MAKE SURE ITS NOT > 26 SKEW4: MOV M,A ;SAVE IT IN TABLE INX H ;INCR TABLE POINTER MOV A,D ;SKEW FACTOR ADD B ;ADD PRESENT SECTOR NO CALL MOD26 ;COMPUTE VALUE MOD 26 MOV B,A ;PUT IT BACK IN B DCR C ;DECR SECTOR COUNT JNZ SKEW1 ;LOOP FOR 26 SECTORS CALL RDISP ;REDISPLAY MAP WHEN FINISHED JMP RD6 ;CONTINUE ; ; MOD26 ROUTINE COMPUTES A SECTOR NUMBER MOD 26 ; MOD26: CPI 27 ;IS SECTOR NO > 26 RM ;RETURN IF NOT SBI 26 ;SUBTRACT 26 RET ; ; REDISPLAY SECTOR MAPPING ; RDISP: PRINT PRINT <'PHYSICAL LOGICAL PHYSICAL LOGICAL',CR,LF> PRINT <' SECTOR SECTOR SECTOR SECTOR',CR,LF> LXI H,SECMAP MVI B,13 MVI C,1 RD1: SAV ;SAVE REGISTERS MOV A,C ;PHYSICAL SECTOR STA PSEC ;READY FOR CONVERSION ADI 13 ;INCR BY 13 STA PSEC1 ;PHYSICAL SECTOR SECOND COL MOV A,M ;GET LOGICAL SECTOR STA LSEC LXI D,13 DAD D ; MOV A,M ;GET LOGICAL SECTOR FOR SECOND COL STA LSEC1 ;STORE FOR CONVERSION PRINT LDA PSEC CPI 10 JP RD2 PRINT SPACE,$ ;ADJUST COL SPACING RD2: DECOUT PSEC ;PRINT PSEC PRINT <' '> LDA LSEC CPI 10 JP RD3 PRINT SPACE,$ RD3: LDA LSEC ORA A JNZ RD13 PRINT <'-'> JMP RD14 RD13: DECOUT LSEC ;PRINT LSEC RD14: PRINT <' '> LDA PSEC1 CPI 10 JP RD4 PRINT SPACE,$ RD4: DECOUT PSEC1 ;SECOND PHYSICAL SECTOR PRINT <' '> LDA LSEC1 CPI 10 JP RD5 PRINT SPACE,$ RD5: LDA LSEC1 ORA A JNZ RD15 PRINT <'-'> JMP RD16 RD15: DECOUT LSEC1 ;SECOND LOGICAL SECTOR RD16: RES INX H ;TABLE POINTER INR C ;PSEC NUMBER DCR B ;LINE COUNT JNZ RD1 ;LOOP FOR 13 LINES RET ; ; DISK FORMATTING ROUTINES. THREE SECTOR SIZES ARE AVAILABLE BOTH ; SINGLE AND DOUBLE DENSITY, 128, 256, AND 512 BYTES. THE NUMBER ; OF SECTORS IS AS FOLLOWS: ; ; SINGLE DENSITY (FM) DOUBLE DENSITY (MFM) ; 128 26 51 ; 256 16 26 ; 512 8 16 ; DOFORM: LDA DDFLG ;DOUBLE DENSITY FLAG ORA A JZ DOFORM2 ; ; START OF DOUBLE DENSITY FORMAT ROUTINE ; DOFORM1:CALL HOME LDA SECSIZ CPI 2 JNZ DD1 LDA OFFSET ;SECTOR OFFSET ORA A JNZ DD1 MVI A,15 ;SET DEFAULT OFFSET TO 15 STA OFFSET DD1: LDA STRK ;STARTING TRACK STA TRK ;TO TEMPORARY ORA A CZ TRKZERO ;FORMAT TRACK ZERO SINGLE DENSITY CALL SEEK ;SEEK TRACK IN A REGISTER NEXTT: LXI H,TRKBUF ;POINT TO TRACK BUFFER CALL DINDX LDA DNUMSEC STA FSECT ;NUMBER OF SECTORS DOF1D: CALL DADDR CALL DDAT LDA FSECT DCR A STA FSECT JNZ DOF1D CALL FILBUF DOF3D: LHLD DFILOFF ;SECTOR OFFSET SHLD FOFF ;TO TEMPORARY DOF4D: LXI H,TRKBUF ;POINT TO FORMAT BUFFER CALL DFILADR ;PLACE TRACK AND SECTOR NUMBERS IN BUFFER DOF5D: LXI D,TRKBUF ;POINT TO TRACK BUFFER LXI H,WLOOP ;LOOP JUMP ADDR MVI A,0F4H ;TRACK WRITE COMMAND OUT DCOM ;ISSUE IT CALL WLOOP ;WRITE FORMAT DONEITD:XTHL XTHL IN STATP ;READ STATUS ANI 0FFH ;TEST IT JNZ ERRMSG ;ERROR HERE LDA TRK ;TRACK NO INR A ;INCREMENT IT STA TRK MOV C,A ;STORE TEMPORARILY IN C LDA ETRK ;END TRK CMP C ;COMPARE RM ;RETURN IF MINUS INCTRKD:MVI A,59H ;STEP COMMAND OUT DCOM ;ISSUE IT IN WAIT IF PERSCI LXI H,0FFFH ;DELAY CONST MVI A,1 ;PERSCI STEP COMMAND OUT WAIT LLLD: DCX H ;DECR COUNT MOV A,H ORA L JNZ LLLD ;LOOP ENDIF CALL CHECKC ;ABORT ON CONTROL C LDA OFFSET ;OFFSET NEXT TRACK ORA A JZ DOF4D LXI H,SECMAP ;SECTOR MAP CALL MAPSLEW JMP NEXTT ; ; WLOOP - FAST OUTPUT LOOP FOR DOUBLE DENSITY FORMATTING ; ASSUMES HL COTAINS JMP TO START OF LOOP AND TOP OF STACK ; RETURN ADDR. LOOP RUNS IN 58 T-STATES OR 14.5 USEC AT 4 MHZ ; WLOOP: IN WAIT ;WAIT FOR INTRQ OR DRQ ORA A ;SET FLAGS RP ;RETURN ON INTRQ (FAST TEST IF NO RET) LDAX D ;GET A BYTE OUT DDATA ;OUTPUT IT INX D ;INCR POINTER PCHL ;FAST JUMP IF HL CONTAINS JUMP ADDR ; TRKZERO:LDA ETRK ;END TRACK PUSH PSW ;SAVE IT ON STACK XRA A ;ZERO STA ETRK ;JUST DO ONE TRACK LDA DDFLG ;DENSITY FLAG STA DENTEMP ;TO TEMPORARY LDA SECSIZ ;SECTOR SIZE CODE STA SIZTEMP ;TO TEMPORARY LDA NUMSEC ;NUMBER OF SECTORS PER TRACK STA SECTEMP MVI A,26 STA NUMSEC ;SET NUMBER OF SECTORS TO 26 LHLD BYTES ;NUMBER OF BYTES PER SECTOR SHLD BYTETEMP ;SAVE IT LXI H,128 SHLD BYTES ;SET BYTES TO 128 LDA GAP ;INTER SECTOR GAP STA GAPTEMP MVI A,27 STA GAP LHLD FILOFF ;OFFSET SHLD OFFTEMP LXI H,183 SHLD FILOFF XRA A STA SECSIZ ;SECTOR SIZE 0 MVI A,'S' CALL DENSEL ;SELECT SINGLE DENSITY LXI H,SECMAP CALL STDMAP ;SINGLE DENSITY STD MAP LDA DENTEMP ;DENSITY FLAG ORA A MVI A,10H ;DOUBLE DENSITY JNZ TZ2 MVI A,20H TZ2: MOV B,A ;SAVE IT IN B LDA SIZTEMP ORA B ;OR WITH B STA CODE ;SAVE IN CODE CPI 10H ;128 BYTE DOUBLE DENSITY JNZ TZ4 LDA DENCODE STA CODE TZ4: CALL NEXTONE ;SINGLE DENSITY FORMAT LDA SIZTEMP STA SECSIZ ;RESTORE SECTOR SIZE LDA SECTEMP STA NUMSEC ;RESTORE NUMBER OF SECTORS LHLD BYTETEMP SHLD BYTES ;RESTORE NUMBER OF BYTES LDA GAPTEMP STA GAP ;RESTORE GAP LHLD OFFTEMP SHLD FILOFF ;RESTORE OFFSET LDA DENTEMP ORA A JZ TRKZ1 MVI A,'D' CALL DENSEL ;SELECT DOUBLE DENSITY TRKZ1: LXI H,SECMAP CALL STDMAP ;DOUBLE DENSITY STD MAP MVI A,59H ;STEP COMMAND OUT DCOM IN WAIT POP PSW ;GET BACK OLD END TRACK STA ETRK ;RESTORE IT MVI A,1 ;START DOUBLE DENSITY ON TRACK 1 STA TRK ;SET TRACK TO ONE RET ; ; ; ; START OF SINGLE DENSITY FORMAT ROUTINE ; ; DOFORM2:CALL HOME ;HOME SELECTED DRIVE LDA STRK ;STARTING TRACK STA TRK ;TO TEMPORARY ORA A CZ TRKZERO ;FORMAT TRACK ZERO STANDARD 3740 FORMAT CALL SEEK ;SEEK TRACK IN A NEXTONE:LXI H,TRKBUF ;POINT TO TRACK BUFFER CALL INDX LDA NUMSEC STA FSECT ;STORE IT DOF1: CALL ADDR CALL DATA LDA FSECT DCR A ;DECR SECTOR COUNT STA FSECT JNZ DOF1 CALL FILBUF ;FILL END OF BUFFER WITH FF'S DOF3: LHLD FILOFF ;SECTOR OFFSET SHLD FOFF ;TO TEMPORARY DOF4: LXI H,TRKBUF ;POINT TO FORMAT BUFFER CALL FILADR ;PLACE TRACK AND SECTOR NUMBERS IN BUFFER LDA TRK ;CHECK FOR TRACK ZERO ORA A JNZ DOF5 LDA CODE ;DENSITY AND SECTOR SIZE CODE STA TRKBUF+229 ;FOR BOTH DELTA AND TARBELL STA TRKBUF+230 ;TRACK ZERO SECTOR ONE ONLY DOF5: LXI H,TRKBUF ;POINT TO TRACK BUFFER MVI A,0F4H ;TRACK WRITE COMMAND OUT DCOM ;ISSUE IT DOF7: IN WAIT ;WAIT FOR INTERRUPT ORA A ;SET FLAGS JP DONEIT ;INTERRUPT MOV A,M ;GET A BYTE OUT DDATA ;SEND IT INX H ;INCR BUFFER POINTER JMP DOF7 ;LOOP TILL INTRQ DONEIT: XTHL XTHL IN STATP ;READ STATUS ANI 0FFH ;TEST IT JNZ ERRMSG ;ERROR HERE LDA TRK ;TRACK NO INR A ;INCREMENT IT STA TRK MOV C,A ;STORE TEMPORARILY IN C LDA ETRK ;END TRK CMP C ;COMPARE RM ;RETURN IF MINUS INCTRK: MVI A,58H+STEP ;STEP COMMAND OUT DCOM ;ISSUE IT IN WAIT IF PERSCI LXI H,0FFFH ;DELAY CONST MVI A,1 ;PERSCI STEP COMMAND OUT WAIT LLL: DCX H ;DECR COUNT MOV A,H ORA L JNZ LLL ;LOOP ENDIF CALL CHECKC ;ABORT ON CONTROL C LDA OFFSET ;OFFSET NEXT TRACK ORA A JZ DOF4 LXI H,SECMAP ;SECTOR MAP CALL MAPSLEW JMP NEXTONE ; ; ; INDX - INDEX BLOCK FOR IBM FORMATS (NOT REQUIRED FOR 1771 OR 1791) ; INDX: LXI D,40 ;COUNT MVI B,0FFH ;BYTE CALL MOVEIT ;STORE THE BLOCK LXI D,6 ;COUNT MVI B,0 ;ZERO CALL MOVEIT ;STORE THE BLOCK MVI M,0FCH ;INDEX MARK INX H ;INCR POINTER LXI D,26 ;NOW 26 MORE FF'S MVI B,0FFH CALL MOVEIT ;STORE THE BLOCK RET ; ; DINDX - INDEX BLOCK DOUBLE DENSITY (MFM) ; DINDX: LDA SECSIZ ;SECTOR SIZE CODE CPI 1 ;256 BYTES? JZ DINDX1 ;YES, STD IBM (MFM) FORMAT MVI B,4EH ;FILL CHAR LXI D,30 ;30 CALL MOVEIT RET DINDX1: MVI B,4EH ;FILL BYTE LXI D,80 ;COUNT CALL MOVEIT MVI B,0 ;12 ZEROS LXI D,12 CALL MOVEIT MVI B,0F6H ;3 F6'S LXI D,3 CALL MOVEIT MVI M,0FCH ;INDEX MARK INX H MVI B,4EH ;50 4E'S LXI D,50 CALL MOVEIT RET ; ; ADDR - ADDRESS BLOCK ; ADDR: LXI D,6 ;WRITE 6 ZEROS MVI B,0 CALL MOVEIT MVI M,0FEH ;ID ADDRESS MARK INX H LXI D,4 ;TRACK AND SECTOR ZERO INITIALLY XRA A CALL MOVEIT MVI M,0F7H ;WRITE 2 CRC'S INX H RET ; ; DADDR - ADDRESS BLOCK (MFM) ; DADDR: LDA SECSIZ ;SECTOR SIZE CODE ORA A JNZ DADDR1 MVI B,0 ;9 00'S LXI D,9 CALL MOVEIT MVI B,0F5H ;3 F5'S LXI D,3 CALL MOVEIT MVI M,0FEH INX H ;ID ADDR MARK MVI B,0 LXI D,4 ;4 ZEROS FOR TRACK AND SECTOR NO CALL MOVEIT MVI M,0F7H ;WRITE CRC'S INX H RET DADDR1: LXI D,12 ;12 ZEROS MVI B,0 CALL MOVEIT LXI D,3 ;3 F5'S MVI B,0F5H CALL MOVEIT MVI M,0FEH ;ID ADDR MARK INX H LXI D,4 ;4 ZEROS MVI B,0 CALL MOVEIT MVI M,0F7H ;WRITE CRC'S INX H RET ; ; DATA - WRITE DATA BLOCK FILLED WITH E5'S ; DATA: MVI B,0FFH ;WRITE 11 FF'S LXI D,11 CALL MOVEIT MVI B,0 ;NOW 6 ZEROS LXI D,6 CALL MOVEIT MVI M,0FBH ;DATA ADDRESS MARK INX H XCHG ;SWAP DE, HL LHLD BYTES ;NUMBER OF BYTES IN SECTOR XCHG ;SWAP THEM BACK MVI B,0E5H ;DATA FILL CHARACTER CALL MOVEIT MVI M,0F7H ;WRITE 2 CRC'S INX H LDA GAP ;INTERRECORD GAP MOV E,A ;TO E MVI D,0 ;SET D TO ZERO MVI B,0FFH ;GAP BYTE CALL MOVEIT RET ; ; DDAT - FILL DATA BLOCK WITH E5'S (MFM) ; DDAT: MVI B,04EH ;WRITE 22 4E'S LXI D,22 CALL MOVEIT MVI B,0 ;NOW 12 ZEROS LXI D,12 CALL MOVEIT LXI D,3 ;3 F5'S MVI B,0F5H ; CALL MOVEIT MVI M,0FBH ;DATA ADDRESS MARK INX H XCHG ;SWAP DE, HL LHLD BYTES ;NUMBER OF BYTES IN SECTOR XCHG ;SWAP THEM BACK MVI B,0E5H ;DATA FILL CHARACTER CALL MOVEIT MVI M,0F7H ;WRITE 2 CRC'S INX H LDA DGAP ;INTERRECORD GAP MOV E,A ;TO E MVI D,0 ;SET D TO ZERO MVI B,4EH ;GAP BYTE CALL MOVEIT RET ; ; ; MOVEIT ROUTINE HL POINTS TO MEMORY, DE = BYTE COUNT, B CONTAINS BYTE ; MOVEIT: MOV M,B ;STORE BYTE INX H DCX D MOV A,E ORA D JNZ MOVEIT RET ; ; FILADR - FILL IN TRACK AND SECTOR NUMBERS ; FILADR: LXI B,SECMAP ;POINTER TO SECTOR MAP LDA NUMSEC ;NUMBER OF SECTORS STA SEC ;SECTOR COUNTER LHLD FOFF ;FILL ADDR OFFSET XCHG LXI H,TRKBUF+80 ;LOCATION OF FIRST TRACK NUMBER FIL01: LDA TRK ;TRACK NO MOV M,A ;TO BUFFER INX H INX H ;POINT TO SECTOR LDAX B ;SECTOR NUMBER MOV M,A ;TO BUFFER INX H LDA SECSIZ ;SECTOR SIZE CODE MOV M,A ;TO MEMORY DAD D ;INCR BUFFER POINTER INX B ;INCR SECTOR MAP POINTER LDA SEC DCR A STA SEC ;DECR SECTOR COUNT JNZ FIL01 ;LOOP FOR NUMSEC SECTORS RET ; ; DFILADR - FILL IN TRACK AND SECTOR NUMBERS ; DFILADR: LXI B,SECMAP ;POINTER TO SECTOR MAP LDA DNUMSEC ;NUMBER OF SECTORS STA SEC ;SECTOR COUNTER LHLD FOFF ;FILL ADDR OFFSET XCHG LXI H,TRKBUF+43 ;LOCATION OF FIRST TRACK NUMBER LDA SECSIZ ;SECTOR SIZE CODE ORA A JZ DFIL00 LXI H,TRKBUF+46 DFIL00: DCR A JNZ DFIL01 LXI H,TRKBUF+162 ;LOCATION FIRST TRACK NO 256 BYTE SECTORS DFIL01: LDA TRK ;TRACK NO MOV M,A ;TO BUFFER INX H INX H ;POINT TO SECTOR LDAX B ;SECTOR NUMBER MOV M,A ;TO BUFFER INX H LDA SECSIZ ;SECTOR SIZE CODE MOV M,A ;TO MEMORY DAD D ;INCR BUFFER POINTER INX B ;INCR SECTOR MAP POINTER LDA SEC DCR A STA SEC ;DECR SECTOR COUNT JNZ FIL01 ;LOOP FOR NUMSEC SECTORS RET ; ; ; FILBUF - FILL END OF TRACK WITH FF'S OR 4E'S ; FILBUF: LXI D,1024 ;END OF TRACK FILL MVI B,0FFH ;FILL CHAR LDA DDFLG ;CHECK DENSITY FLAG ORA A JZ ET1 MVI B,4EH ;DD FILL BYTE ET1: MOV M,B INX H DCX D ;DECR COUNT MOV A,D ORA E JNZ ET1 RET ; ; IDREAD - READ ID FIELD ON CURRENT TRACK AND PUT DATA IN IDTAB ; IDREAD: LDA RETRYS IDRD01: STA IDECNT ;ERROR COUNT MVI A,0D0H ;INTERRUPT OUT DCOM LXI H,IDTAB ;POINT TO TABLE XTHL XTHL ;SHORT DELAY MVI A,0C4H ;READ ADDR COMMAND OUT DCOM ;SEND IT IDRD02: IN WAIT ;WAIT FOR DRQ OR INTRQ ORA A JP IDRD03 IN DDATA ;READ DATA BYTE MOV M,A ;STORE IT INX H ;INCR POINTER JMP IDRD02 ;LOOP TILL INTRQ IDRD03: IN STATP ;READ STATUS ANI 08H RZ LDA IDECNT ;ERROR COUNT DCR A ;DECR IT JNZ IDRD01 ;TRY AGAIN PRINT JMP ENDFIL ; ; ; ; WAIT ROUTINE CAUSES TIME DELAY OF ABOUT 1/3 SEC AT 4 MHZ ; DELAY: SAV LXI H,09000H ;LOAD DELAY CONSTANT LXI D,1 ;ONE TO DE DL1: XTHL XTHL INX B ;DELAY DAD D JNC DL1 ;LOOP TILL CARRY SET RES RET ; ; ; EXIT ROUTINES ; ENDFIL: PRINT CRLF,$ LDA DRIVE CALL SELECT LDA INFLAG ;SEE WHERE TO GO ORA A JNZ NEWIN ;BACK FOR MORE INPUT MONITOR:LHLD OLDSTK SPHL ;RESET ORIGINAL STACK RET ;BACK TO CP/M ; ; ERROR ROUTINES ; ERRMSG: PRINT LDA NEWDRV ORA A ;TEST DRIVE NUMBER JZ ERM2 PRINT <'B',CR,LF> JMP ENDFIL ERM2: PRINT <'A',CR,LF> JMP ENDFIL ; ; CHECK FOR LEGITIMATE SECTOR NUMBERS (1-26). AND CHECK IF SECTOR NUMBER ; ALREADY ASSIGNED ; SECERR: CPI 1 JP SE0 PRINT JMP SE1 SE0: CPI 27 JM SE2 PRINT SE1: STC RET SE2: LXI H,SECMAP MVI B,26 SE3: CMP M ;CHECK IF SECTOR ALREADY USED JNZ SE4 PRINT JMP SE1 SE4: INX H DCR B JNZ SE3 SE5: ORA A ;CLEAR CARRY RET ; ; SCANERR - NUMBER MISSING WHERE EXPECTED ; SCANERR:PRINT JMP ENDFIL ;EXIT ; ; DECERR - NON NUMERIC CHARACTER IN NUMBER ; DECERR: PRINT JMP ENDFIL ;EXIT ; ; TRKTEST - TEST FOR TRACK BETWEEN 0 AND 76 ; TRKTEST:CPI 77 ;CHECK SECTOR > 76 RM PRINT JMP ENDFIL ; ; ; SEARCH SECTOR TABLE FOR PREVIOUS SECTOR NUMBER ; SET CARRY ON MATCH ; SRTAB: SAV LXI H,SECMAP ;POINT TO TABLE MVI B,26 ;TABLE LENGTH SR1: CMP M ;COMPARE TABLE ENTRY WITH A JNZ SR5 ;GO ON IF NO MATCH STC ;SET CARRY SR3: RES RET SR5: INX H ;INCR POINTER DCR B ;DECR SECTOR COUNT JNZ SR1 ;LOOP FOR 26 SECTORS ORA A ;RESET CARRY JMP SR3 ;EXIT ; ; ; CLEAR ROUTINE CLEARS SCREEN (NULLS FOR SOME TERMINALS) ; CLEAR: SAVE PRINT <1AH,0,0,0,0,0,0,0,0,0,0> RESTORE RET ; ; SEEK ROUTINE MOVES TO TRACK IN A REG (ASSUMES PREVIOUS HOME) ; SEEK: SAV ;SAVE REGS MOV E,A ;SAVE TRACK NO IN E IN TRACK ;READ 1771 TRACK REG MOV B,A ;SAVE IN B CMP E ;COMPARE WITH REQUESTED TRACK JZ SEEK3 IF PERSCI MVI A,40H ;STEP IN JC PSK1 MVI A,60H ;STEP OUT PSK1: OUT DCOM ;OUTPUT STEP DIRECTION MVI A,30 ;DELAY CONST PSK3: DCR A JNZ PSK3 ;WAIT SHORT TIME MOV A,B ;PRESENT TRACK SUB E ;SUBTRACT REQUESTED TRACK JP PSK5 ;OK IF + CMA INR A ;COMPLIMENT IF - PSK5: MOV B,A ;NO OF STEPS IN B MVI A,1 ;PERSCI STEP COMMAND PSK7: OUT WAIT ;STEP PERSCI DCR B JNZ PSK7 IN WAIT ;CLEAR 1771 IN STATP MOV A,E ;DESTINATION TRACK OUT TRACK LDA LATCH ;LATCH CODE FOR SELECTED DRIVE ANI 72H OUT WAIT ;COMMAND WAITS FOR SEEK COMPLETE IN WAIT ;WAIT FOR SEEK COMPLETE LDA LATCH OUT WAIT ;RESET LATCH ELSE MVI D,0 MVI C,5 ;RETRYS SEEK1: MOV A,E ;TRACK NO OUT DDATA ;TRACK NO TO DATA REG SEEKW: IN STATP ;CHECK BUSY RRC JC SEEKW ;WAIT TILL NOT BUSY DOOR CLOSED ETC. MVI A,1CH+STEP ;SEEK COMMAND (6 MSEC) WITH VERIFY OUT DCOM ;DO IT IN WAIT IN STATP ;READ DISK STATUS ANI 91H JZ SEEK3 ;EXIT IF ZERO DCR C ;DECR ERROR COUNT JZ SEEK2 ;SEEK ERROR AFTER 5 RETRYS CALL HOME ;HOME THE DRIVE JMP SEEK1 ;TRY AGAIN SEEK2: PUSH D ;SAVE TRACK NO PRINT POP H ;TRACK NO TO L DECOUT ;PRINT TRACK NO PRINT <' DRIVE '> LDA DRVNO ;GET SELECTED DRIVE CALL PRNDRV ;PRINT A THRU C JMP ENDFIL ;EXIT ENDIF SEEK3: RES ;RESTORE REGS RET ; ; ; HOME SELECTED DRIVE ; HOME: SAV PUSH PSW IF PERSCI XRA A ;TRACK ZERO CALL SEEK ;SEEK IT CALL DELAY MVI A,8 OUT DCOM IN WAIT IN STATP ;CHECK STATUS ANI 4 ;TRACK ZERO BIT JZ HOMERR ;ERROR IF NOT ZERO ELSE HOME1: IN STATP ;CHECK IF BUSY RRC JC HOME1 MVI A,STEP ;HOME COMMAND OUT DCOM ;ISSUE COMMAND CALL DELAY ;WAIT TILL DRIVE HOME HOME3: IN STATP ;READ DISK STATUS ANI 4 ;CHECK TRACK ZERO FLAG JZ HOMERR ;ERROR IF NOT T 0 ENDIF HOME5: LXI H,TRKTBL ;POINT TO TRACK TABLE MVI D,0 LDA DRVNO ;SELECTED DRIVE MOV E,A DAD D ;ADDR OF TABLE ENTRY XRA A ;ZERO MOV M,A ;TRACK ZERO IF NOT PERSCI CALL DELAY ;WAIT ENDIF POP PSW RES RET HOMERR: PRINT LDA DRVNO ;SELECTED DRIVE CALL PRNDRV ;PRINT IT JMP ENDFIL ;EXIT ; ; READ ROUTINE READ SECTOR FROM SELECTED TRACK AND KEEP TRACK OF ; ERRORS. DE POINTS TO THE MEMORY BUFFER. THE SECTOR TO BE READ ; IS IN SNUM. ; READ0: MVI B,88H ;READ WITHOUT HEAD LOAD COMMAND LDA RETRYS ;RETRY COUNT STA ERRORS ;ERROR COUNT JMP READ2 ;TO READ ROUTINE READ1: MVI B,8CH ;READ WITH HEAD LOAD COMMAND LDA RETRYS ;RETRY COUNT STA ERRORS ;ERROR COUNT READ2: LDA SNUM ;GET SECTOR NUMBER OUT SECTP ;SET SECTOR NUMBER INTO 1771 LDA DDFLG ;DENSITY FLAG ORA A JZ READ3 MVI A,1 OUT WAIT+1 ;SET DOUBLE DENSITY READ3: XCHG SHLD BBLOCK ;POINTER TO START OF CURRENT BLOCK MOV A,B ;GET READ COMMAND OUT DCOM ;SENT IT READ5: IN WAIT ;WAIT TILL COMMAND EXECUTED ORA A ;CHECK ERROR STATUS JP READ6 ;DONE IF BIT 7 HI (INTRQ) IN DDATA ;READ DATA MOV M,A ;STORE IT IN BUFFER INX H JMP READ5 ;BACK FOR ANOTHER BYTE READ6: XCHG IN STATP ;DISK STATUS ANI 9DH ;CHECK ERROR BITS RZ ;RETURN IF NONE LDA SOFTERR ;SOFT ERRORS INR A STA SOFTERR ;STORE IT BACK LDA ERRORS ;ERROR COUNT DCR A STA ERRORS ;STORE IT BACK JZ RFILL ;RETRY TRYS IF ZERO XCHG LHLD BBLOCK ;RESET BUFFER POINTER XCHG JMP READ2 ;TRY AGAIN FOR RETRY TIMES RFILL: LDA NOFILL ;ERROR FILL FLAG ORA A ;IF ZERO DON'T FILL WITH E5'S JNZ READ8 SAVE LHLD BBLOCK ;POINTS TO BEGINNING OF READ BLOCK MVI C,128 ;COUNTER MVI A,0E5H ;FILL BYTE READ7: MOV M,A ;STORE E5 INX H ;INCR POINTER DCR C JNZ READ7 ;LOOP FOR 128 BYTES JMP READ9 READ8: SAV ;SAVE REGISTERS READ9: PRINT READ10: LHLD TNUM ;TRACK NUMBER DECOUT ;PRINT DECIMAL PRINT <' SECTOR '> LHLD SNUM ;SECTOR NUMBER DECOUT PRINT <' DRIVE '> LDA DRVNO ;GET SELECTED DRIVE NO CALL PRNDRV ;PRINT DRIVE NO A THRU C READ12: LXI H,HARDERR ;POINT TO HARD ERRORS INR M ;INCREMENT IT MVI A,0FFH ;SET ERROR FLAG RES ;RESTORE REGISTERS CALL CHECKC ;ABORT ON CONTROL C RET ; ; VERIFY ROUTINE READ SECTOR FROM SELECTED TRACK AND KEEP TRACK OF ; ERRORS. DE POINTS TO MEMORY BUFFER. (SWAPPED INTERNALLY WITH HL ; FOR SPEED IN THIS ROUTINE) ; THE SECTOR NUMBER TO BE READ IS IN SNUM ; VER0: MVI B,88H ;READ WITHOUT HEAD LOAD LDA RETRYS ;RETRY COUNT STA ERRORS ;ERROR COUNT JMP VER2 ;TO READ ROUTINE VER1: MVI B,8CH ;READ WITH HEAD LOAD LDA RETRYS ;RETRY COUNT STA ERRORS ;ERROR COUNT VER2: LDA SNUM ;SECTOR NUMBER OUT SECTP ;SET SECTOR NUMBER INTO 1771 XCHG ;SWAP REGISTERS SHLD BBLOCK ;START CURRENT BLOCK MOV A,B ;GET READ COMMAND OUT DCOM ;SENT IT VER5: IN WAIT ;WAIT TILL COMMAND EXECUTED ORA A ;CHECK ERROR STATUS JP VER8 ;DONE IF BIT 7 HI (INTRQ) IN DDATA ;READ DATA CMP M ;COMPARE WITH MEMORY INX H JZ VER5 ;BACK FOR ANOTHER BYTE VER6: XCHG LDA SOFTERR ;SOFT ERRORS INR A ;INCREMENT IT STA SOFTERR ;STORE IT BACK LDA ERRORS ;ERROR COUNT DCR A ;DECREMENT IT STA ERRORS ;STORE IT BACK XCHG LHLD BBLOCK ;RESET MEMORY POINTER XCHG JNZ VER2 ;TRY AGAIN FOR RETRY TIMES PUSH H LXI H,128 ;SECTOR INCR DAD D ;ADD TO MEMORY POINTER XCHG POP H SAVE ;SAVE REGISTERS PRINT JMP READ10 ;PRINT REST OF ERROR MESSAGE AND RET VER8: XCHG ;SWITCH REGISTERS BACK IN STATP ;GET DISK STATUS ANI 9DH ;CHECK ERROR BITS RZ ;RETURN IF NONE XCHG JMP VER6 ; ; ; ; WRITE ROUTINE WRITES A SECTOR ON SELECTED TRACK ; DE POINTS TO THE MEMORY BUFFER. THE SECTOR NUMBER TO BE WRITTEN ; IS IN SNUM. ; WRITE0: LDA RETRYS ;RETRY COUNT WRITE1: STA ERRORS ;ERROR COUNT IN STATP ;READ STATUS ANI 20H ;CHECK HEAD LOAD BIT WRITE2: LDA SNUM ;SECTOR NUMBER OUT SECTP ;SET SECTOR NUMBER INTO 1771 MVI A,0ACH ;WRITE WITH HEAD LOAD JNZ WRITE3 MVI A,0A8H ;WRITE WITH HEAD LOAD WRITE3: OUT DCOM ;ISSUE WRITE COMMND WRITE5: IN WAIT ;WAIT TILL COMMAND EXECUTED ORA A ;CHECK ERROR STATUS JP WRITE7 ;DONE IF BIT 7 HI (INTRQ) LDAX D ;GET A BYTE FROM MEMORY OUT DDATA ;WRITE TO DISK INX D ;INCR POINTER JMP WRITE5 ;BACK FOR ANOTHER BYTE WRITE7: XTHL XTHL ;SHORT DELAY IN STATP ;READ DISK STATUS ANI 0FDH ;CHECK ERROR BITS RZ ;RETURN IF NONE LDA SOFTERR ;SOFT ERRORS INR A ;INCREMENT IT STA SOFTERR ;STORE IT BACK LDA ERRORS ;ERROR COUNT DCR A JNZ WRITE1 ;TRY AGAIN FOR RETRY TIMES SAV PRINT JMP READ10 ;PRINT REST OF ERROR MESS ; ; RDTRK READS A TRACK FOR VALIDATION OR COPY ; HL POINTS TO SECTOR MAP, DE POINTS TO MEMORY BUFFER ; RDTRK: SAV ;SAVE REGISTERS LDA NUMSEC ;COUNT OF SECTORS PER TRACK MOV C,A ;TO C LDA DDFLG ;DENSITY FLAG ORA A JZ RDT0 LDA DNUMSEC ;SECTORS DOUBLE DENSITY MOV C,A RDT0: MOV A,M ;GET A SECTOR NUMBER STA SNUM ;SAVE SECTOR NUMBER IN MEMORY CALL READ1 ;READ WITH HEAD LOAD RDT1: INX H ;INCR SECTOR MAP POINTER DCR C ;DECR SECTOR COUNT JZ RDT4 ;EXIT ORA A ;CHECK SECTOR READ RETURN CODE JNZ RDT0 ;IF ERROR READ WITH HEAD LOAD MOV A,M ;GET A SECTOR NUMBER FROM MAP STA SNUM ;SAVE SECTOR NUMBER IN MEMORY CALL READ0 ;READ DISK WITHOUT HEAD LOAD JMP RDT1 ;LOOP FOR 26 SECTORS RDT4: RES ;RESTORE REGISTERS CALL CHECKC ;ABORT ON CONTROL C RET ; ; ; WRTRK WRITES AND VERIFIES A TRACK ; HL POINTS TO SECTOR MAP, DE POINTS TO MEMORY BUFFER ; WRTRK: SAV ;SAVE REGISTERS LDA NUMSEC ;COUNT OF SECTORS PER TRACK MOV C,A ;TO C LDA DDFLG ;DENSITY SWITCH ORA A JZ WRT LDA DNUMSEC ;NUMBER OF SECTORS (MFM) MOV C,A ;TO C WRT: PUSH H PUSH D ;SAVE POINTERS FOR VERIFICATION WRT0: MOV A,M ;GET A SECTOR NUMBER STA SNUM ;SAVE SECTOR NUMBER IN MEMORY CALL WRITE0 ;CALL WRITE ROUTINE WRT1: INX H ;INCR SECTOR MAP POINTER DCR C ;DECR SECTOR COUNT JZ WRT3 ;EXIT JMP WRT0 ;LOOP TILL SECTOR COUNT IS ZERO WRT3: POP D POP H CALL CHECKC ;ABORT ON CONTROL C LDA VERFLG ;VERIFY FLAG ORA A JNZ WRT20 ;NO VERIFY IF NOT ZERO LDA NUMSEC ;SECTOR COUNT MOV C,A ;TO C LDA DDFLG ;DENSITY FLAG ORA A JZ WRT10 LDA DNUMSEC ;NUMBER OF SECTORS (MFM) MOV C,A ;TO C WRT10: MOV A,M ;GET SECTOR NUMBER STA SNUM ;SAVE IT CALL VER0 ;VERIFY WITHOUT HEAD LOAD WRT11: INX H ;INCR SECTOR MAP POINTER DCR C ;DECR SECTOR COUNT JZ WRT20 ;EXIT ORA A ;CHECK READ ERROR RETURN CODE JZ WRT10 ;BACK TO READ IF NO ERROR PRINT LDA DEST ;DEST DISK NO JMP REVAL WRT20: RES ;RESTORE REGISTERS RET ; ; RDFORM ROUTINE READS A TRACK IN A AND STORES THE SECTOR FORMAT IN A ; TABLE POINTED TO BY HL. A MUST CONTAIN THE DESIRED TRACK NUMBER ; RDFORM: SAV ;PUSH REGISTERS XCHG ;DE POINTS TO SECTOR TABLE STA TNUM ;SAVE TRACK NUMBER LDA DDFLG ;DENSITY FLAD ORA A JNZ RDT7 ;EXIT IF DOUBLE DENSITY CALL TRKRD ;READ TRACK IN A LXI H,TRKBUF+4AH LXI B,183 MVI A,-1 ;SET FLAG FOR FIRST ITERATION STA CNT ;SET SECTOR COUNT TO NUMSEC RDF4: MOV A,M ;GET A BYTE FROM THE TRACK FORMAT CPI 0FEH ;IS IT AN ADDRESS MARK/ JZ RDF5 INX H ;BUMP POINTER JMP RDF4 ;LOOP TILL ADDR MARK FOUND RDF5: INX H ;HL NOW POINTS TO TRACK NO LDA TNUM ;TRACK NUMBER CMP M ;COMPARE AGAINST MEMORY JNZ RDF4 ;LOOK SOME MORE IF NOT SAME LDA CNT ;TEST FOR FIRST ITERATION ORA A JP RDFX MOV A,M ;PICK UP TRACK NO STA TNUM ;SAVE IT RDFX: INX H INX H ;HL NOW POINTS TO FIRST SECTOR NUMBER RDF6: MOV A,M ;GET SECTOR NUMBER STAX D ;STORE IT IN TABLE LDA CNT ;COUNT ORA A ;IS IT THE FIRST SECTOR JP RDFY LDA NUMSEC STA CNT ;SET COUNT FOR 128 BYTE SECTORS INX H ;POINT TO SECTOR SIZE BYTE MOV A,M STA SECSIZ ;SAVE IT PUSH H CPI 1 ;256 BYTE SECTORS JNZ RDFS MVI A,16 STA NUMSEC STA CNT ;SET COUNT LXI H,256 SHLD BYTES RDFS: CPI 2 ;512 BYTE SECTORS JNZ RDFU MVI A,8 ;8 SECTORS PER TRACK STA NUMSEC STA CNT ;SET COUNT LXI H,512 ;512 BYTES PER SECTOR SHLD BYTES RDFU: POP H DCX H ;BACK UP POINTER LDA CNT ;RELOAD COUNT RDFY: DCR A ;DECREMENT IT JZ RDT7 ;FINISHED STA CNT ;STORE BACK COUNT INX D ;INCR TABLE POINTER DAD B ;INCR TRACK DATA POINTER BY 182 JMP RDF4 ;LOOP FOR 26 SECTORS RDT7: RESTORE RET ; ; TRACK READ ROUTINE. TRACK NO IS IN A, HL POINTS TO BUFFER ; TRKRD: SAVE LXI H,TRKBUF ;SET POINTER TO TRACK INPUT BUFFER CALL SEEK ;FIND THE TRACK MVI A,0E4H ;READ TRACK COMMAND OUT DCOM ;ISSUE IT RTF1: IN WAIT ;WAIT AND READ DISK STATUS ORA A JP RTF3 ;EXIT IN DDATA ;READ DATA MOV M,A ;SAVE BYTE IN MEMORY INX H ;INCR POINTER JMP RTF1 ;LOOP TILL INTRQ RTF3: RESTORE RET ; ; THIS ROUTINE OFFSETS THE SECTOR MAP BY A CONSTANT (OFFSET) PER TRACK ; CALLED WITH OFFSET IN A AND HL POINTING TO SECTOR MAP. ; MAPSLEW:SAVE ;SAVE REGS PUSH H ;SAVE POINTER TO SECTOR MAP ON STACK MOV B,A ;SAVE OFFSET IN B XCHG ;SECTOR MAP POINTER TO DE LXI H,NUMSEC ;POINT TO NUMBER OF SECTORS (FM) LDA DDFLG ;DENSITY FLAG ORA A JZ MS0 LXI H,DNUMSEC ;NUMBER OF SECTORS (MFM) MS0: MOV C,M ;SECTOR COUNT TO C MOV L,C ;SECTOR COUNT TO L MVI H,0 MOV A,B ;OFFSET BACK TO A ADD L ;ADD SECTOR COUNT TO OFFSET MOV B,A ;OFFSET+SECTOR COUNT TO B DAD D ;16 BIT ADD DE TO HL MS1: LDAX D ;GET A SECTOR NO (DE POINTS TO SOURCE) MOV M,A ;STORE IT (HL POINTS TO DESTINATION) DCR B ;DECR COUNT OF BYTES TO BE MOVED JZ MS5 ;EXIT MOV A,C ;GET NUMBER OF SECTORS CMP B ;DOES B=26 JNZ MS3 ;JUMP IF NOT POP H ;RESET DESTINATION DCX H ;PRE DECREMENT IT MS3: INX H INX D ;INDEX POINTERS JMP MS1 ;LOOP FOR OFFSET+26 ITERATIONS MS5: RESTORE ;RESTORE REGS RET ; ; SELECT THE DRIVE IN A ; SELECT: SAV MOV C,A LXI H,DRVNO ;POINT TO DRIVE NO CMP M ;COMPARE WITH A JZ SEL5 MOV A,M ;OLD DRIVE NUMBER MOV E,A ;OLD DRIVE NO TO E MVI D,0 LXI H,TRKTBL ;POINT TO TRACK TABLE IN TRACK ;READ 1771 TRACK REG IF DUAL MVI B,4 ;SET ALL TRACKS THE SAME SEL1: MOV M,A ;STORE TRACK INX H ;INCR TRACK TABLE POINTER DCR B JNZ SEL1 ;LOOP FOR 4 DRIVES ELSE DAD D ;COMPUTE ADDR MOV M,A ;TRACK NO TO TABLE ENDIF MOV A,C ;GET NEW DRIVE NO MOV E,A ;NEW DRIVE TO E LXI H,TRKTBL ;POINT TO TRACK TABLE DAD D ;COMPUTE ADDR MOV A,M ;NEW TRACK NO ORA A ;SET FLAGS JP SEL3 ;PREV SELECTED IF NOT MINUS MOV A,C ;NEW DRIVE NO IF DELTA CALL SELDELT ELSE CALL DOSEL ENDIF CALL HOME XRA A ;TRACK ZERO SEL3: OUT TRACK ;SET 1771 TRACK REG SEL5: MOV A,C STA DRVNO ;RESET DRIVE NO MOV A,C ;RESTORE DRIVE NO TO A IF DELTA CALL SELDELT ENDIF IF TARBELL CALL SELTARB ENDIF IF NOT DELTA OR TARBELL CALL DOSEL ENDIF RES RET ; ; ; DOSEL ACTUAL DRIVE SELECT (OLD TARBELL SINGLE DENSITY) ; DOSEL: CMA ;COMPLIMENT A ADD A ADD A ADD A ADD A ;SHIFT LEFT 4 BITS ORI 2 ;LATCH COMMAND STA LATCH ;SAVE IT OUT WAIT ;SELECT DRIVE RET ; ; ; SELTARB SELECT DRIVE (NEW TARBELL CONTROLLER) ; SELTARB:ADD A ADD A ADD A ADD A ;SHIFT LEFT 4 BITS ORI 2 STA LATCH OUT WAIT RET ; ; ; SELDELT SELECT DRIVE (DELTA CONTROLLER) ; SELDELT:CMA ;COMPLIMENT STA LATCH ;SAVE IT OUT WAIT ;SELECT DRIVE RET ; ; ; GETNUM GET A NUMBER FROM INPUT BUFFER AND TEST ; GETNUM: SAV SCAN ,40H JZ SCANERR ;ERROR IF NO NUMBER DECIN ;CONVERT TO DECIMAL JC DECERR ;INPUT ERROR IF CARRY SHLD DECFULL ;SAVE FULL 16 BIT VALUE RES RET ; ; ; ; GETRK GETS AND TESTS STARTING AND ENDING TRACK NUMBERS FROM THE INPUT ; BUFFER. TRACKS STORED IN STRK AND ETRK. ROUTINE RETURNS WITH STRK IN A ; GETRK: SAV XRA A ;ZERO STA STRK ;DEFAULT TO 0 MVI A,76 STA ETRK ;DEFAULT TO 76 INSTR 82H,40H,'TRACK' ;TRACK SPECIFICATIONS? JNC GT5 CALL GETNUM ;GET TRACK NUMBER CALL TRKTEST ;CHECK IT STA STRK ;STARTING TRACK STA ETRK ;SET ENDING TRACK TOO IF NO OTHER SPECIFIED INSTR 82H,40H,'-' ;TRACK SEPARATOR JNC GT5 CALL GETNUM ;GET ENDING TRACK CALL TRKTEST ;CHECK IT STA ETRK ;ENDING TRACK GT5: LDA STRK ;STARTING TRACK TO A RES RET ; ; DBLSUB 16 BIT SUBTRACT DE FROM HL TO HL ; DBLSUB: XRA A ;CLEAR CARRY MOV A,L SBB E ;SUBTRACT LOW BYTES MOV L,A ;BACK TO L MOV A,H SBB D ;SUBTRACT HIGH BYTES MOV H,A ;DIFFERENCE IN HL RET ; ; POLL CONSOLE INPUT FOR CONTROL C ; CHECKC: SAV ;SAVE REGS PUSH PSW MVI C,11 ;CP/M STATUS POLL CODE CALL 5 ;CALL CP/M ANI 1 ;1 IF CHARACTER WAITING JZ CKC3 ;EXIT CHARIN ;READ THE CONSOLE CPI 3 ;WAS IT A CONTROL C JZ ENDFIL ;BACK TO INPUT LOOP CKC3: POP PSW RES ;RESTORE REGS RET ; ; READ CONSOLE FOR YES ; CHECKY: SAV CHARIN ;READ CONSOLE RES CPI 'Y' ;YES RZ JMP ENDFIL ;BACK TO INPUT IF NOT YES ; ; ; SIZE ROUTINE SETS SECTOR SIZES 128, 256, OR 512 BYTES ; SIZE: CALL GETNUM ;GET SECTOR SIZE CPI 128 ;128 BYTE SECTOR RZ ;STANDARD FORMAT RETURN ZERO SET LHLD DECFULL ;CONVERTED DECIMAL NUMBER LXI D,-256 ;COMPARE HL WITH 256 DAD D MOV A,H ORA L ;TEST ZERO JNZ SIZE1 MVI A,1 STA SECSIZ ;256 BYTE SECTORS MVI A,16 STA NUMSEC ;NUMBER OF SECTORS MVI A,26 STA DNUMSEC LXI H,256 SHLD BYTES ;BYTES PER SECTOR MVI A,32 ;ADDR LEADER GAP STA GAP MVI A,46 STA DGAP ;ADDR LEADER GAP (MFM) LXI H,316 ;SECTOR OFFSET (FM) SHLD FILOFF LXI H,359 ;SECTOR OFFSET (MFM) SHLD DFILOFF RET SIZE1: LHLD DECFULL ;CONVERTED DECIMAL NUMBER LXI D,-512 ;COMPARE HL WITH 512 DAD D ;ADD TO HL MOV A,H ORA L JNZ SIZE3 ;ERROR NOT 512 OR 128 MVI A,2 ;SET SIZE TO 512 STA SECSIZ LXI H,512 ;BYTES PER SECTOR SHLD BYTES MVI A,8 ;SECTORS PER TRACK STA NUMSEC MVI A,16 STA DNUMSEC ;SECTORS PER TRACK (MFM) MVI A,50 ;ADDR LEADER GAP STA GAP MVI A,64 STA DGAP LXI H,590 ;OFFSET FOR 512 BYTES (FM) SHLD FILOFF LXI H,633 SHLD DFILOFF ;OFFSET FOR 512 BYTES (MFM) RET SIZE3: PRINT JMP ENDFIL ; ; DENSEL - SELECT DENSITY ; FOR DELTA DOUBLE DENSITY CONTROLLER ; IF DELTA DENSEL: CPI 'D' ;DOUBLE DENSITY ? JZ DENSEL1 MVI A,2 OUT WAIT+1 ;SELECT SINGLE DENSITY XRA A STA DDFLG RET DENSEL1:MVI A,1 ;SELECT DOUBLE DENSITY OUT WAIT+1 MVI A,0FFH STA DDFLG RET ENDIF ; ; FOR NEW TARBELL DOUBLE DENSITY CONTROLLER ; IF TARBELL DENSEL: CPI 'D' ;DOUBLE DENSITY JZ DENSEL1 XRA A STA DDFLG ;SET DENSITY FLAG LDA LATCH ANI 0F7H STA LATCH OUT WAIT ;SELECT SINGLE DENSITY RET DENSEL1:MVI A,0FFH STA DDFLG LDA LATCH ORI 08H STA LATCH OUT WAIT ;SELECT DOUBLE DENSITY RET ENDIF ; ; ; FOR OLD TARBELL 1771 BASED CONTROLLER ; IF NOT TARBELL AND NOT DELTA DENSEL: CPI 'D' RNZ ;JUST RETURN IF NOT DD PRINT JMP ENDFIL ENDIF ; ; GETDRV SEARCH COMMAND STRING FOR DRIVE NAME AND RETURN CODE ; A:=0 B:=1 C:=2 D:=3 CARRY SET IF DRIVE PRESENT ; GETDRV IS CALLED WITH HL POINTING TO STARTING POSITION FOR SEARCH ; GETDRV: SAV ;SAVE REGS LXI D,DSKNAME ;POINT TO NAME TABLE MVI C,0 ;DRIVE NUMBER GD1: SAV MVI B,40H ;STRING LENGTH MVI C,2 ;SUBSTRING LENGTH INSTR RES JC GD3 ;FOUND NAME ON CARRY MOV A,C ;DRIVE NO TO A CPI 3 ;CHECK LIMIT JZ GD3 INR C ;INCR DRIVE NO INX D INX D ;POINT TO NEXT NAME JMP GD1 ;LOOP FOR 4 DRIVES GD3: MOV A,C ;DRIVE NO TO A RES RET ; DSKNAME:DB 'A:' ;TABLE OF DISK NAMES DB 'B:' DB 'C:' DB 'D:' ; ; PRNDRV PRINT DRIVE NAME CORRESPONDING TO CODE IN A REG ; 0=A 1=B 2=C 3=D >3 ERROR ; PRNDRV: SAV CPI 4 ;CHECK RANGE JP PRDR3 ;ERROR IF > 3 ADI 'A' ;CALC LETTER TO PRINT CHAROUT ;PRINT IT PRDR1: RES RET PRDR3: PRINT JMP PRDR1 ; ; ; ; ; EQUATES AND DATA ALLOCATIONS ; DISK EQU 0F8H ;DISK BASE ADDR DCOM EQU DISK ;DISK COMMAND PORT STATP EQU DISK ;DISK STATUS PORT TRACK EQU DISK+1 ;DISK TRACK COMMAND SECTP EQU DISK+2 ;DISK SECTOR PORT DDATA EQU DISK+3 ;DISK DATA PORT WAIT EQU DISK+4 ;DISK WAIT CONTROL PORT SPACE: DB ' $' ;ASCII SPACE CRLF: DB 0DH,0AH,24H ;ASCII CR LF CNT: DB 0 ;TEMP COUNTER TNUM: DW 0 ;TRACK NUMBER SNUM: DW 0 ;SECTOR NUMBER HARDERR:DW 0 ;HARD DISK ERRORS SOFTERR:DW 0 ;SOFT DISK ERRORS ERRORS: DB 0 ;RETRY COUNTER DURING READ OR VERIFY VERERR: DB 0 ;VERIFY ERROR FLAG, SET TO FF ON COPY ERROR VERFLG: DB 0 ;FLAG WHEN FF NO VERIFICATION DURING COPY NOFILL DB 0 ;FLAG, WHEN TRUE (FF) NO FILL WITH E5 ON ERROR FORMSW: DB 0 ;COPY FORMAT SWITCH FORMAT IF TRUE (FF) RETRYS: DB 0 ;MAXIMUM NUMBER OF RETRYS INFLAG: DB 0 ;FLAG, IF TRUE RETURN FOR MORE CONSOLE INPUT VALFLG: DB 0 ;VALIDATION FLAG, VALIDATE AFTER FORMAT IF 0 DDFLG: DB 0 ;DOUBLE DENSITY FLAG SKF: DB 0 ;SKEW FACTOR TRKLIM: DB 0 ;THE NUMBER OF TRACKS THAT FIT IN MEMORY OFFSET: DB 0 ;TRACK SECTOR OFFSET DRIVE: DB 0 ;STORAGE FOR ORIGINALLY LOGGED DRIVE NO DRVNO DB 0 ;SELECTED DRIVE NEWDRV: DB 0 ;NEW DRIVE NO LATCH DB 0 ;LATCH COMMAND TRKTBL: DB 0 ;TRACK POS A: DB 0 ;TRACK POS B: DB 0 ;TRACK POS C: DB 0 ;TRACK POS D: SOURCE: DB 0 ;SOURCE DRIVE FOR COPY OPERATION DEST: DB 0 ;DESTINATION DRIVE FOR COPY OLDSTK: DW 0 ;OLD STACK POINTER ENDSTK: DS 48 ;NEW STACK NEWSTK: DW 0 ;TOP OF NEW STACK SECSIZ: DB 0 ;SECTOR SIZE CODE FOR FORMAT (0,1 OR 2) NUMSEC: DB 0 ;NUMBER OF SECTORS PER TRACK DNUMSEC:DB 0 ;NUMBER OF BYTES PER SECTOR (MFM) FSECT: DB 0 ;SECTOR COUNT USED IN FORMATTING BYTES: DW 0 ;NUMBER OF BYTES PER SECTOR GAP: DB 0 ;FORMAT ADDR LEADER GAP DGAP: DB 0 ;FORMAT ADDR LEADER GAP (MFM) FILOFF: DW 0 ;SECTOR OFFSET IN TRACK BUFFER (FM) DFILOFF:DW 0 ;SECTOR OFFSET IN TRACK BUFFER (MFM) FOFF: DW 0 ;TEMP STORAGE FOR SECTOR OFFSET CPYOFF: DB 0 ;OFFSET USED FOR COPY ROUTINES TRK: DB 0 ;TRACK NUMBER USED IN FORMATTING DISK SEC: DB 0 ;SECTOR COUNT USED IN FORMATTING STRK: DW 0 ;STARTING TRACK FOR FORMAT OR COPY ETRK: DW 0 ;ENDING TRACK FOR FORMAT OR COPY STRKR: DB 0 ;STARTING TRACK FOR READ STRKW: DB 0 ;STARTING TRACK FOR WRITE PSEC: DW 0 ;PHYSICAL SECTOR PSEC1: DW 0 ;ANOTHER LSEC: DW 0 ;LOGICAL SECTOR LSEC1: DW 0 ;ANOTHER BBLOCK: DW 0 ;POINTER TO START OF CURRENT READ BLOCK SECMAP: DS 104 ;PHYSICAL TO LOGICAL SECTOR MAP FOR READ SECMAP1:DS 104 ;SECTOR MAP FOR WRITE SECMAP0:DS 53 ;SECTOR MAP TRACK ZERO - ALWAYS SINGLE DENSITY TRKSIZE:DW 0 ;NO OF BYTES PER TRACK FOR COPY ROUTINES DENCODE:DB 0 ;DOUBLE DENSITY CODE (LAST BYTE SECTOR 1 T 0) CODE: DB 0 ;SPECIAL CODE FOR DISK ID FOR PASCAL DENTEMP:DB 0 ;TEMP STORAGE FOR DDFLG SIZTEMP:DB 0 ;TEMP STORAGE FOR SECSIZ SECTEMP:DB 0 ;TEMP STORAGE FOR NUMSEC BYTETEMP:DW 0 ;TEMP STORAGE FOR BYTES GAPTEMP:DB 0 ;TEMP STORAGE FOR GAP OFFTEMP:DW 0 ;TEMP STORAGE FOR OFFSET DDMAP: DB 1,18,35,10,27,44,2,19,36,11,28,45,3 DB 20,37,12,29,46,4,21,38,13,30,47,5 DB 22,39,14,31,48,6,23,40,15,32,49,7 DB 24,41,16,33,50,8,25,42,17,34,51,9,26,43 ; DDMAP1: DB 1,35,27,2,36,28,3,37,29,4,38,30,5,39,31 DB 6,40,32,7,41,33,8,42,34,9,43,18,10,44,19,11,45 DB 20,12,46,21,13,47,22,14,48,23,15,49,24,16,50 DB 25,17,51,26 DECFULL:DW 0 ;FULL 16 BIT VALUE OF DECIMAL INPUT IDECNT: DB 0 ;ERROR COUNT FOR ID READ IDTAB: DB 0 ;ADDR FIELD FOR ID READ IDTAB1: DB 0 ;ZERO IDTAB2: DB 0 ;SECTOR ADDR IDTAB3: DB 0 ;ZERO IDTAB4: DB 0 ;CRC IDTAB5: DB 0 ;CRC TRKBUF: DB 0 ;BUFFER STORAGE END ; ;