TITLE 'North Star Disk Copy Program V4.2 of 09/17/81' ; PAGE 44 ; ; These routines copyright (c) 1980, 1981, 1982 by Steve Bogolub, ; 2338 S. Scoville Ave., Berwyn, IL 60402. This software may be ; used freely for non-commercial purposes only, and may not be sold. ; ;************************************************************ ; ; The purpose of this program is to allow the operator ; to copy, format, or validate North Star double density ; disks. Copying can be done between any two North Star ; drives, and can include all tracks, or just the system ; (0 and 1) tracks or data tracks (2 - LTRK) for special ; system handling, where LTRK is the last data track, ; which is 34 for Shugart SA400 and 39 for most others. ; The variable LASTTRK at 103H contains the genned-in ; value of LTRK, and can be patched to change the default ; disk size within reasonable bounds. If the number is ; too big, the generated DPB for the ID block will become ; incorrect. The patching feature is intended primarily ; for switching between 35 and 40 track versions, but ; can be used in a pinch for formatting larger sizes ; for experimental purposes. ; ; The allowed functions are: ; ; 1) Copy all tracks from source disk to destination ; disk. The density of sector zero on track zero ; of the source determines the density of the ; destination. ; ; 2) Copy only the system tracks from source disk ; to destination disk. If source disk is double ; density, tracks 0 and 1 only are copied. If ; source disk is single density, tracks 0, 1, ; and 2 only are copied. ; ; 3) Copy only the data tracks from source disk to ; destination disk. If source disk is double ; density, tracks 2-LTRK inclusive are copied. ; If source disk is single density, tracks 3-LTRK ; inclusive are copied. ; ; 4) Validate the source disk. This is done by ; reading all tracks. ; ; 5) Format the destination disk in double ; density. This is done by writing data ; blocks with each byte containing the ; hex value "E5" to all sectors of all ; tracks. To be Lifeboat-compatible, we ; write a double-density single-sided ; disk ID block into track zero, sector ; zero. ; ; 6) Format the destination disk in single ; density. Similar to 5) above. ; ; 7) Format the destination disk for double ; sided, 80 trks/side, double density. ; ; In addition, the user is given the options of ; warm booting CP/M, or cold booting by jumping ; to the standard North Star ROM boot address. For ; functions 1 - 3, the user is asked for the source ; and destination drive letters. For function 4, ; the user is asked for just the destination drive ; letter, since the source is unused. For function ; 5, the user is asked for just the source letter, ; since the destination is unused. ; ; To drive the disks at top speed, this program ; contains a complete set of North Star disk ; driver routines. CP/M's BIOS routines are used ; to write messages to the console and get user ; replies. All the area up to the BIOS warm ; boot page is assumed available for buffer ; space, so take note if a non-contiguous BIOS ; is in use. ; ; This program may be restarted at 100H. ; ; This program is built on the wreckage of the ; CP/M User's group COPY program, after most of ; it was discarded. ; ;************************************************************ ORG 100H ; ;EQUATES ; WBOOT EQU 0 ;CP/M WARM BOOT ADDRESS CBOOT EQU 0E800H ;NORTH STAR ROM BOOT ADDRESS NDRIVE EQU 4 ;NUMBER OF NORTH STAR DRIVES ON SYSTEM LASTSEC EQU 9 LTRK EQU 35-1 ;NORMAL DRIVE IS 35 TRACK LASTT80 EQU 159 ;80 TRACK DOUBLE SIDE DRIVE BDOS EQU 5 IDOFF EQU 050H ;Offset into BUF0 where Lifeboat ; ID should be placed CR EQU 0DH LF EQU 0AH ; ;************************************************************ ; ; Start the program here. ; START: JMP BEGIN ; LASTTRK: DB LTRK ;Contains last trk # (34 for ; a 35-track drive) ; ; Do one-time initialization involving LASTTRK, BIOS ; vectors, and NSTRK. ; BEGIN: LXI SP,STKTOP ;Set stack ptr LHLD WBOOT+1 ;GET BIOS VECTORS LXI D,BVECT ; INTO OUR PROGRAM MVI B,BVECTL ; MVECT: MOV A,M STAX D INX H INX D DCR B JNZ MVECT LXI H,0FFFFH ;INIT TRK TABLE SHLD NSTRK SHLD NSTRK+2 MOV A,L STA CURDSK ;NO CURRENT DISK YET LDA IDSSPT ;Calc single density CALL CALCSZ ; disk size in groups SHLD IDSSIZ ;Fix ID table LDA IDDSPT ;Repeat for double CALL CALCSZ ; density SHLD IDDSIZ LDA LASTTRK ;Get ASCII # trks INR A MVI B,'0'-1 ; by repeat subtracts ATEN: INR B SUI 10 JNC ATEN ;Get 10's in B ADI 10+'0' ; and 1's in A STA SIGNTK+1 ;Fix SIGNON msg MOV A,B STA SIGNTK LXI H,SIGNON CALL MSGOT ;Tell who we are ; LIST: LXI SP,STKTOP ;Reload stack ptr ; in case here after error CALL MOFF ;Turn off North Star motors ; to allow disk switching LXI H,FLIST ;Print out the menu CALL MSGOT CALL CNSIN ;GET REPLY LXI H,CRLF ;RET CARRIAGE AFTER CALL MSGOT STA FUNC ;Save for later ; ; Dispatch to routine based on choice, unless it was bad. ; CPI '1' JZ ALLSET ;COPY ALL CPI '2' JZ SYSSET ;COPY SYSTEM CPI '3' JZ DATSET ;COPY DATA CPI '4' JZ VALSET ;VALIDATE CPI '5' JZ FORSTD ;FORMAT DOUBLE DENSITY CPI '6' JZ FORSTS ;FORMAT SINGLE DENSITY CPI '7' JZ FORS80 ;FORMAT 80-TRKS, DOUBLE SIDED CPI '8' JZ EXIT ;WARM BOOT CPI 3 ;ALLOW CTRL-C FOR WARM BOOT TOO JZ EXIT CPI '9' JZ CEXIT ;COLD BOOT LXI H,SELER CALL MSGOT ;BAD NUMBER GIVEN JMP LIST ;GO ASK AGAIN ;************************************************************ ; SIGNON: DB CR,LF,'North Star Copy V4.2 of 09/17/81 -- ' SIGNTK: DB ((LTRK+1)/10)+'0',((LTRK+1) MOD 10)+'0' DB ' track version$' FLIST: DB CR,LF DB CR,LF,'Function List:' DB CR,LF DB CR,LF,' 1. Copy all tracks, using density' DB ' of source disk' DB CR,LF,' 2. Copy system tracks only,' DB ' using density of source disk' DB CR,LF,' 3. Copy data tracks only, using' DB ' density of source disk' DB CR,LF,' 4. Validate' DB CR,LF,' 5. Format DOUBLE density' DB CR,LF,' 6. Format SINGLE density' DB CR,LF,' 7. Format 80 trk ds/dd' DB CR,LF,' 8. Warm boot' DB CR,LF,' 9. Cold boot' DB CR,LF DB CR,LF,'Enter function number: $' SELER: DB CR,LF,'Not a valid number',CR,LF,'$' ; SRCMSG: DB 'Enter source$' DSTMSG: DB 'Enter destination$' SDMSG: DB ' drive (A-' DB NDRIVE-1+'A',') or to reselect: $' ; MESGA: DB CR,LF,'Compare error on track $' MESGB: DB ' (hex) sector $' MESGC: DB ' -- permanent $' MESGD: DB CR,LF,'Source read error exit $' MESGE: DB CR,LF,'Destination write error exit $' MESGF: DB CR,LF,'Destination read error exit $' S1: DB CR,LF,'Ready to copy $' S2: DB ' from disk ' SSRC: DB 0,': to disk ' SDST: DB 0,':.$' SSYS: DB 'system tracks only$' SDAT: DB 'data tracks only$' SALL: DB 'all tracks$' DFOR: DB CR,LF,'Ready to format and validate disk ' DFORD: DB 0,': in DOUBLE density,',CR,LF DB 'overwriting all previous data there.$' SFOR: DB CR,LF,'Ready to format and validate disk ' SFORD: DB 0,': in SINGLE density,',CR,LF DB 'overwriting all previous data there.$' FOR80: DB CR,LF,'Ready to format and validate ' DB '80 trk double sided disk ' FOR80D: DB 0,': in',CR,LF,'DOUBLE density, ' DB 'overwriting all previous data there.$' SVAL: DB CR,LF,'Ready to validate disk ' SVALS: DB 0,':.$' GOMSG: DB CR,LF,CR,LF DB 'If that is what you want, switch disks if' DB CR,LF DB 'appropriate and type when ready: $' INSERT: DB CR,LF,'Insert system disk in drive A' DB ' and type to $' BOOT: DB ' boot: $' WMSG: DB 'warm$' CMSG: DB 'cold$' ABMSG: DB ' ^C',CR,LF,'** Console abort **$' DONMSG: DB CR,LF,'Function complete.$' CRLF: DB CR,LF,'$' CTCMSG: DB '^C$' ; ; This is the Lifeboat-compatible label we write to a ; double density disk when we format it. Note that the ; contents of the second part of the label are actually ; a CP/M disk parameter block. We assume this must match ; the disk we are formatting, so this DPB is for a ; double-density single-sided disk. The name seems to ; be ignored, so we use NSCOPY (Lifeboat uses FORMAT). ; The rest of the data between the name and the DPB ; has no meaning to us, so we are just blindly using ; the stuff Lifeboat puts there, which doesn't seem ; to hurt. ; IDD: DB 'NSCOPY ' ;Format program name DB 0,0,0,0,90H,0,0,0,90H ; ??? IDDSPT: DW 40 ;DPB - Sectors per track DB 3 ;Block shift factor DB 07H ;Block mask DB 0 ;Exm mask IDDSIZ: DW (((LTRK-1)*40)/8)-1 ;Disk size in groups - 1 DW 63 ;Directory max entries DB 11000000B ;Alloc 0 DB 0 ;Alloc 1 DW 16 ;Check size DW 2 ;Track offset to data ; IDLEN EQU $-IDD ;# bytes in label ; ; SINGLE DENSITY LIFEBOAT LABEL (SEE IDD ABOVE) ; IDS: DB 'NSCOPY ' ;Format program name DB 0,0,0,0,10H,0,0,0,10H ; ??? IDSSPT: DW 20 ;DPB - Sectors per track DB 3 ;Block shift factor DB 07H ;Block mask DB 0 ;Null mask IDSSIZ: DW (((LTRK-1)*20)/8)-1 ;Disk size in groups - 1 DW 63 ;Directory max entries DB 11000000B ;Alloc 0 DB 0 ;Alloc 1 DW 16 ;Check size DW 3 ;Track offset to data ; ; DUMMY 80 TRACKS PER SIDE, DOUBLE SIDE, DOUBLE ; DENSITY LABEL. WE PUT THIS ON OUR DRIVE FOR OUR ; OWN INFORMATION, SINCE LIFEBOAT DOES NOT SUPPORT ; ANY SUCH FORMAT. ; ID80: DB 'NSCOPY ' ;Format program name DB 0,0,0,0,0F0H,0,0,0,0F0H ; ??? DW 40 ;DPB - Sectors per track DB 4 ;Block shift factor DB 0FH ;Block mask DB 0 ;Exm mask DW 395-1 ;Disk size in groups - 1 DW 127 ;Directory max entries DB 11000000B ;Alloc 0 DB 0 ;Alloc 1 DW 32 ;Check size DW 2 ;Track offset to data ; ; CALCSZ calculates a group size for a disk whose ; number of 128-byte sectors is supplied in acc on ; entry. The two-byte result is returned in HL. ; Note that only the formula (LASTTRK-1)*SECTORS/8-1 ; is used, so the disk shouldn't be too big if this ; is to be valid. ; CALCSZ: MOV E,A ;Get # sectors/trk MVI D,0 ; into DE LDA LASTTRK ;Get # trks DCR A ; - 1 into acc LXI H,0 ;Init total # sectors ; CSZ5: DAD D ;Count up sectors DCR A JNZ CSZ5 MVI B,3 ;Divide result by 8 ; CSZ10: MOV A,H ;Shift right ORA A RAR MOV H,A MOV A,L RAR MOV L,A DCR B ; 3 times for divide JNZ CSZ10 DCX H ; - 1 to complete RET ;Ret answer in HL ; ; ASKSRC IS USED TO GET THE SOURCE DRIVE NAME FROM ; THE USER. SRCDSK IS SET ON RETURN WITH A VALUE FROM ; 0 TO NDRIVE-1, AND ACC CONTAINS THE ASCII DRIVE ; LETTER. IF USER TYPED CTRL-C, WE EXIT BACK TO LIST. ; ASKSRC: LXI H,SRCMSG ;GET SOURCE CALL ASKC JC ASKSRC ;GO BACK IF BAD LETTER CPI NDRIVE JNC ASKSRC STA SRCDSK ; ELSE SET DRIVE NUMBER ADI 'A' ;RESTORE LETTER FOR CALLER STA SSRC ;SET FOR COPY FUNCTIONS RET ; ; ASKDST IS USED TO GET THE DESTINATION DRIVE ; NAME. DSTDSK IS SET ON RETURN WITH A VALUE FROM ; 0 TO NDRIVE-1, AND ACC CONTAINS THE ASCII DRIVE ; LETTER. IF USER TYPED CTRL-C, WE EXIT BACK TO LIST. ; ASKDST: LXI H,DSTMSG ;GET DESTINATION CALL ASKC JC ASKDST ;GO BACK IF BAD LETTER CPI NDRIVE JNC ASKDST STA DSTDSK ; ELSE SET DRIVE NUMBER ADI 'A' ;RESTORE LETTER FOR CALLER STA SDST ;SET FOR COPY FUNCTIONS RET ; ASKC: CALL MSGOT LXI H,SDMSG CALL MSGASK SUI 'A' RET ; ; MAIN COPY ROUTINE HERE. PERFORM FUNCTION BETWEEN ; TRACKS SPECIFIED BY THE TWO BYTES AT TRKSRT. ; COPY: MVI A,1 ;ASSUME ONE TRK AT A TIME STA NTR ; FOR FORMAT OR VALIDATE CASES LDA FUNC ;CHECK FUNCTION CPI '5' ;FORMAT? JNC FRSTRK ;DENSITY ALL SET IF SO CALL SETDD ;ASSUME DOUBLE D IF NOT XRA A ;SET UP SOURCE READ IF SO STA HSTSEC ; ON SECTOR ZERO STA HSTTRK ; OF TRACK ZERO LDA SRCDSK STA HSTDSK LXI H,MESGD ;IN CASE OF ERROR SHLD IOEMSG LXI H,BUF1 ;PT TO SCRATCH BUFFER SHLD HSTADR CALL SETUP ;SELECT DISK AND SEEK CALL READ ;READ THE SECTOR LDA ERFLAG ;CHECK FOR ERRORS ORA A CNZ FAILR ;ERROR IF CAN'T READ SECTOR LDA NSDENS ;CHECK DENSITY ORA A JZ SETNTR ;ALL SET IF DOUBLE D CALL SETSD ;SET SINGLE DENS VARIABLES LDA FUNC ;IF SINGLE, MAY NEED ADJUSTMENTS CPI '1' ;COPY ALL TRACKS? JZ SETNTR ;ALL SET IF SO CPI '4' ;VALIDATE? JZ FRSTRK ;ALSO ALL SET CPI '2' ;COPY SYSTEM TRACKS ONLY? LXI H,3*256+0 ;ASSUME SO JZ SDSYS ;GO STUFF IF SO LDA LASTTRK ;Data copy if not INR A MOV H,A MVI L,0 SDSYS: SHLD TRKSRT ;NEW START OR END ; SETNTR: LDA FUNC ;CHECK FOR VALIDATE CPI '4' ; IN CASE DOUBLE DENSITY JZ FRSTRK ;ONE TRACK AT A TIME IF SO LHLD TRKSIZ ;GET TRACK SIZE LDA WBOOT+2 ;GET BIOS BASE PAGE DCR A ;ADJUST FOR COMPARE XCHG ;TRK SIZE TO DE LXI H,BUF0 ;BUF STARTS HERE MVI B,0 ;INIT TRACK CTR ; SNTRL: DAD D ;ADD ANOTHER BUFFER JC SNTRD ;OUT IF NO MORE MEM INR B ;ASSUME ROOM CMP H ;UP TO BIOS YET? JNC SNTRL ;GO BACK IF NOT DCR B ;ONE LESS TRACK IF SO SNTRD: MOV A,B STA NTR ;CAN READ THIS MANY ; FRSTRK: LDA TRKSRT ;SET 1ST TRK TO DO STA HSTTRK ADI '0' ;GET ASCII EQUIV STA CTRK ; FOR STATUS REPORTING ; RDLOOP: LDA HSTTRK ;REMEMBER START TRACK FOR STA STRK ; THIS BUFFER, FOR WRITING LXI H,BUF0 ;INIT INPUT BUFFER ADDRESS SHLD BUF0A LDA NTR ;CAN FIT THIS MANY TRACKS ; RDNT: STA NTRC ;UPDATE # TRKS ROOM LEFT CALL BCNSCK ;CHECK FOR CONSOLE ABORT ORA A CNZ ABORT ;IF CTRL-C, NO RETURN LDA CTRK ;SHOW NEXT TRACK TO DO PUSH PSW ;SAVE FOR BOP CALL CNSOT ;OUTPUT DIGIT POP PSW ;GET BACK AGAIN INR A ;NOW BOP BY ONE CPI '9'+1 ;GOING OVER NOW? JC CTRKNZ ;PASS IF NOT MVI A,' ' ;SPACE OVER EACH TEN CALL CNSOT MVI A,'0' ;REWIND DIGIT CTRKNZ: STA CTRK ;SAVE NEXT TRK # LDA FUNC ;SEE IF FORMATTING ONLY CPI '5' JNC WONLY ;WRITE ONLY IF SO LDA SRCDSK ;IF NOT, STA HSTDSK ; SELECT SOURCE DRIVE CALL READT ;READ ENTIRE TRACK LDA FUNC ;CHECK FUNCTION CPI '4' ;VALIDATE? JZ SKPW ;SKIP WRITE IF SO LDA HSTTRK ;BOP TRK # INR A STA HSTTRK LXI H,TRKSRT+1 CMP M ;READ LAST TRACK? JZ WRLOOP ;GO WRITE IF SO LHLD BUF0A ;ADVANCE BUF PTR IF NOT XCHG LHLD TRKSIZ ; BY ONE TRACK DAD D SHLD BUF0A LDA NTRC ;COUNT OFF LAST TRACK DCR A JNZ RDNT ;IF MORE ROOM, GO READ ; WRLOOP: LDA STRK ;REWIND CURR TRK # STA HSTTRK ; FOR WRITE LXI H,BUF0 ;DITTO BUF PTR SHLD BUF0A ; ; HERE IF FORMATTING ONLY ; WONLY: LDA DSTDSK ;SELECT DESTINATION DRIVE STA HSTDSK LDA NTR ;WRITE THIS MANY TRKS ; WRNT: STA NTRC ;THIS MANY LEFT TO WRITE XRA A ;REWIND COMPARE ERR CNT STA CMPERR RETRYW: CALL BCNSCK ;CHECK FOR CONSOLE ABORT ORA A CNZ ABORT ;IF CTRL-C, NO RETURN CALL WRITET ;WRITE TRACK CALL COMPT ;REREAD AND COMPARE JNZ RETRYW ;RETRY IF ERR ; ; Check to see if we just wrote track zero. If so, ; make sure the Lifeboat label area is set to 0E5H's, ; just in case we are formatting. If we are in fact ; copying, it doesn't matter, since we're done with ; this track anyway. ; LDA HSTTRK ;See if just wrote track zero ORA A JNZ SKPW ;Pass if not LXI H,BUF0+IDOFF ;If so, pt to label area MVI B,IDLEN ;This many bytes to fill ; FFIX: MVI M,0E5H ;Stuff an E5 INX H DCR B ;Count it off JNZ FFIX ;Do the whole label ; ; HERE TO SKIP TRACK WRITE ON VALIDATE ONLY ; SKPW: LDA HSTTRK INR A STA HSTTRK LXI H,TRKSRT+1 ;POINT TO LAST TRACK+1 STORAGE CMP M ;ARE WE DONE? RZ ;RETURN TO CALLER IF SO LHLD BUF0A ;ADVANCE BUF PTR IF NOT XCHG LHLD TRKSIZ ; BY ONE TRACK DAD D SHLD BUF0A LDA NTRC ;COUNT OFF LAST TRK DCR A JNZ WRNT ;GO BACK IF MORE TO WRITE JMP RDLOOP ;IF NOT, GO READ NEXT BUFFER ; ; COMPT: LXI H,MESGF ;Load address of msg for SHLD IOEMSG ; destination read error LXI H,BUF1 CALL RT2 ;REREAD INTO BUF1 LHLD TRKSIZ ;GET TRACK SIZE IN BYTES MOV B,H ; INTO BC MOV C,L LHLD BUF0A LXI D,BUF1 CMPLP: LDAX D CMP M JNZ CERR INX H INX D DCX B MOV A,C ;End of buffer yet? ORA B JNZ CMPLP ;Keep checking if not RET CERR: PUSH H LXI H,MESGA CALL MSGOT ;REPORT COMPARE ERROR LDA HSTTRK CALL HXBOT LXI H,MESGB CALL MSGOT POP H LDA BUF0A ;CALC OFFSET INTO BUFFER SUB L LDA BUF0A+1 ;ONLY NEED KEEP HIGH SBB H MOV H,A ;SAVE FOR NOW LDA NSCNT ;GET DENSITY FLAG ORA A ;SET ZERO COND CODE IF DOUBLE DENS MOV A,H JNZ CERRSD ;NUMBER RIGHT IF SINGLE DENS RAR ;A DOUBLE DENS SECTOR IS TWO PAGES CERRSD: CALL HXBOT ;PRINT SECTOR LDA CMPERR INR A STA CMPERR ;INCREMENT ERROR COUNT CPI 10 RNZ LXI H,MESGC ;REPORT GIVING UP CALL MSGOT XRA A RET ; ; READT: LXI H,MESGD ;Load address of msg for SHLD IOEMSG ; source read error LHLD BUF0A ; ; ENTER HERE WITH IOEMSG AND HL PRELOADED FOR ; COMPARE TRACK READ ; RT2: SHLD HSTADR CALL SETUP ;SELECT DRIVE AND ; SEEK TO TRACK LDA ERFLAG ;CHECK FOR ERRORS ORA A CNZ FAILR ;Index pulse not found is fatal MVI C,0 RT3: PUSH B MOV A,C STA HSTSEC CALL READ LDA NSDENS ;CHECK FOR DENSITY MISMATCH MOV C,A LDA NSCNT CMP C JZ RT4 ;GO ON IF OK MVI A,5 ;SET ERROR IF NOT STA ERFLAG LXI H,SDEMSG CALL DSKERR ;RAT ON BAD SECTOR RT4: LDA ERFLAG ORA A ;Any errors? CNZ FAILR LHLD HSTADR ;Advance read address XCHG LHLD BLKSIZ DAD D SHLD HSTADR POP B MVI A,LASTSEC CMP C RZ INR C JMP RT3 ; ; WRITET: LHLD BUF0A SHLD HSTADR CALL SETUP ;SELECT DRIVE AND ; SEEK TO TRACK LDA ERFLAG ;CHECK FOR ERRORS ORA A CNZ FAILW ;Index pulse not found is fatal MVI C,0 WT3: PUSH B MOV A,C STA HSTSEC CALL WRITE LDA ERFLAG ORA A ;Any errors? CNZ FAILW LHLD HSTADR ;Advance write address XCHG LHLD BLKSIZ DAD D SHLD HSTADR POP B MVI A,LASTSEC CMP C RZ INR C JMP WT3 ;************************************************************ SYSSET: CALL ASKSRC CALL ASKDST CALL PRNTS1 LXI H,SSYS CALL MSGOT CALL PRNTS2 MVI L,0 ;FIRST TRACK TO TRANSFER MVI H,2 ;LAST TRACK PLUS ONE JMP PUTPAR ;************************************************************ DATSET: CALL ASKSRC CALL ASKDST CALL PRNTS1 LXI H,SDAT CALL MSGOT CALL PRNTS2 MVI L,2 ;FIRST TRACK TO TRANSFER LDA LASTTRK ;Last track plus one INR A MOV H,A JMP PUTPAR ;************************************************************ ALLSET: CALL ASKSRC CALL ASKDST CALL PRNTS1 LXI H,SALL CALL MSGOT CALL PRNTS2 JMP DOALL ;DO ALL TRACKS ;************************************************************ ; ; Format disk. Fill BUF0 with 0E5H's, except for a Lifeboat- ; compatible label, so that Lifeboat CP/M can read and write ; our disks. After track zero is formatted, COPY will make ; the entire buffer 0E5H again by overwriting the label. ; FORSTD: CALL ASKDST STA DFORD LXI H,DFOR CALL MSGOT LDA LASTTRK ;Set for all tracks INR A MOV H,A MVI L,0 SHLD TRKSRT CALL SETDD ;SET UP DOUBLE DENS VARS LXI D,IDD ;PT TO DOUBLE DENS ID ; FLBOTH: ;MERGE HERE FROM FORSTS MOV B,H ;MOVE # BYTES/TRK TO BC MOV C,L LXI H,BUF0 ;Fill track buffer with E5's FL: MVI M,0E5H ;Set a byte to E5 DCX B ; and count it off INX H ;Bop buffer ptr MOV A,B ORA C JNZ FL ;Go back if more to set LXI H,BUF0+IDOFF ;Now time to put in label MVI B,IDLEN ;Move in this many bytes ; FL5: LDAX D ;Get label byte MOV M,A ; and store it INX H ; then bop ptrs INX D DCR B ;Count off a byte JNZ FL5 ;Go back if more JMP AGIN ;DO ALL TRACKS ; ; SINGLE DENSITY FORMAT DISK ; FORSTS: CALL ASKDST STA SFORD LXI H,SFOR CALL MSGOT LDA LASTTRK ;Set for all tracks INR A MOV H,A MVI L,0 SHLD TRKSRT CALL SETSD ;SET UP SINGLE DENS VARS LXI D,IDS ;PT TO SINGLE DENS ID JMP FLBOTH ;GO MERGE WITH FORSTD ; ; 80 TRK DRIVE FORMAT ; FORS80: CALL ASKDST STA FOR80D LXI H,FOR80 CALL MSGOT LXI H,(LASTT80+1) SHL 8 ;SET FOR ALL TRACKS SHLD TRKSRT CALL SETDD ;SET UP DOUBLE DENS VARS LXI D,ID80 ;80 TRK ID JMP FLBOTH ;GO MERGE WITH FORSTD ; ; DOUBLE DENSITY VARIABLES SETUP, HL = BYTES/TRK ON RETURN ; SETDD: LXI H,512 SHLD BLKSIZ ;# BYTES/SECTOR MVI A,00H STA NSCNT ;DENSITY FLAG = DOUBLE LXI H,512*(LASTSEC+1) ;# BYTES/TRACK SHLD TRKSIZ ;SET TRACK SIZE RET ; ; SINGLE DENSITY VARIABLES SETUP, HL = BYTES/TRK ON RETURN ; SETSD: LXI H,256 SHLD BLKSIZ MVI A,80H STA NSCNT LXI H,256*(LASTSEC+1) SHLD TRKSIZ RET ;************************************************************ VALSET: CALL ASKSRC STA SVALS LXI H,SVAL CALL MSGOT ; DOALL: MVI L,0 ;1st trk to write LDA LASTTRK ;Last trk + 1 INR A MOV H,A ; PUTPAR: SHLD TRKSRT ;PUT PARAMETERS IN ; TRKSRT AND TRKSRT+1 ; AGIN: LXI H,GOMSG ;Wait until user ready CALL MSGASK ;Print message and get reply CPI CR JNZ AGIN ;************************************************************ CALL COPY ;MAIN ROUTINE LXI H,DONMSG ;SAY WE'RE DONE CALL MSGOT JMP LIST ;DONE. GO ASK FOR MORE TO DO. ; ; PRNTS1: LXI H,S1 JMP MSGOT ; PRNTS2: LXI H,S2 JMP MSGOT ;************************************************************ FAILR: LHLD IOEMSG ;Get addr of appro error msg JMP DIE FAILW: LXI H,MESGE DIE: CALL MSGOT JMP LIST ;GO TRY SOMETHING ELSE ; ; HERE ON CONSOLE ABORT ; ABORT: CALL BCNSIN ;GET CONSOLE CHAR CPI 3 ;CTRL-C? RNZ ;IGNORE IF NOT LXI H,ABMSG CALL MSGOT ;REPORT STOPPING JMP LIST ;GO TRY SOMETHING ELSE ;************************************************************ EXIT: LXI H,INSERT CALL MSGOT LXI H,WMSG CALL MSGOT LXI H,BOOT CALL MSGASK ;WAIT BEFORE REBOOTING CPI CR JNZ EXIT JMP WBOOT ;GO WARM BOOT CP/M ; CEXIT: LXI H,INSERT CALL MSGOT LXI H,CMSG CALL MSGOT LXI H,BOOT CALL MSGASK CPI CR JNZ CEXIT JMP CBOOT ;GO COLD BOOT NORTH STAR ; ; ; ; ; NORTH STAR MEMORY MAPPED I/O ADDRESSES ; WDATA EQU 0E900H ;WRITE DATA. DATA IS ; LOW 8 ADRESS BITS. CORDER EQU 0EA00H ;CONTROLLER ORDER CCMND EQU 0EB00H ;CONTROLLER COMMAND ; ; MOFF SHUTS OFF THE NORTH STAR DRIVE MOTORS ; AND RESETS THE CONTROLLER. ; MOFF: LDA CCMND+17H ;RESET CONTROLLER RET ; ; WRITEHST PERFORMS THE PHYSICAL WRITE TO THE ; NORTH STAR DISK. ON ENTRY, SECTOR IS IN HSTSEC. ON ; EXIT, ERROR FLAG IS IN ERFLAG (ZERO IF NONE). ; ; *** INTERRUPTS MUST BE DISABLED HERE ** ; WRITE: DI ;WRITE NORTH STAR XRA A STA ERFLAG ;NO ERROR YET LDA CCMND+20H ;GET B-STATUS ANI 02H ;IS DISK WRITE-PROTECTED? MVI A,6 ;ASSUME SO, ERROR CODE 6 STA ERFLAG JNZ WPERR ;WRITE ALWAYS FAILS IF SO CALL SEKSEC ;WAIT FOR OUR SECTOR LHLD HSTADR ;GET ADDRESS TO WRITE FROM MVI B,31 ;ASSUME DOUBLE DENSITY WRITE MVI E,2 LDA NSCNT ; THEN CHECK MOV C,A ;PUT DATA COUNT IN C ORA A JZ WRIT5 ;GO ON IF DOUBLE D MVI B,15 ; ELSE CORRECT DCR E WRIT5: LDA CCMND+16H ;INITIATE SECTOR WRITE ; WRIT10: LDA CCMND+15H ;KEEP MOTORS RUNNING, GET A-STAT ANI 08H ;MUST LOOP UNTIL 96 USEC WINDOW JNZ WRIT10 ; PAST, SO LOOP WHILE WI TRUE ; ; NOW WRITE THE 15 OR 31 BYTES OF LEADING ZEROES ON THE SECTOR ; WRIT15: LDA WDATA+00H ;WRITE A BYTE OF ZEROES NOP ;KILL TIME MVI D,WDATA SHR 8 ;KILL TIME AND LOAD D FOR LATER DCR B ;COUNT OFF A ZERO BYTE JNZ WRIT15 ;DO THEM ALL ; ; FOLLOW WITH ONE OR TWO SYNCH BYTES ; WRIT17: LDA WDATA+0FBH ;WRITE A SYNCH BYTE DCR E JNZ WRIT17 ;GO BACK IF DOUBLE D ; ; NOW WRITE OUT 256 OR 512 BYTES. DO THIS TWO AT A TIME SO ; WE CAN USE SINGLE PRECISION COUNTER. B IS ZERO FROM ABOVE ; TO INIT THE CRC BYTE. ; WRIT20: MOV A,M ;GET NEXT BYTE TO OUTPUT MOV E,A ; IN OUTPUT REG XRA B ;ADD INTO CHECKSUM RLC MOV B,A ;LEAVE CHECKSUM IN B LDAX D ;WRITE DATA BYTE TO DISK INX H ;BOP BUF PTR MOV A,M ;REPEAT FOR NEXT BYTE MOV E,A XRA B RLC MOV B,A LDAX D INX H DCR C ;COUNT OFF LAST PAIR OF BYTES JNZ WRIT20 ;GO BACK IF MORE TO WRITE MOV E,B ;IF NOT, TIME TO WRITE CHECKSUM INX B ;KILL TIME LDAX D ; THEN WRITE THE BYTE XRA A ;DONE, INDICATE NO ERROR STA ERFLAG ; WHSTRT: RET ; AND RETURN TO CALLER ; WPERR: LXI H,WPEMSG ;WRITE PROTECT ERROR CALL DSKERR ;TELL OPERATOR JMP WHSTRT ; THEN LEAVE ; ; READHST PERFORMS THE PHYSICAL READ FROM THE ; NORTH STAR DISK. ON ENTRY, SECTOR IS IN HSTSEC. ON ; EXIT, ERROR FLAG IS IN ERFLAG (ZERO IF NONE). ; ; *** INTERRUPTS MUST BE DISABLED HERE *** ; READ: DI ;READ NORTH STAR MVI A,10 ;RETRY COUNT ON ERROR STA RTCNT ; READRT: CALL SEKSEC ;WAIT FOR OUR SECTOR MVI B,08CH ;COUNT FOR SYNCH CHAR LOOP LXI D,CCMND+40H ;SET UP READ DATA REGS ; ; WAIT FOR RE SO WE CAN DO SECTOR READ, AND TEST ; THE DOUBLE DENSITY BIT. ; WAITRE: LDA CCMND+10H ;GET A-STATUS ANI 04H ;CHECK RE JZ WAITRE ;LOOP UNTIL RE TRUE XTHL ;KILL TIME TO GET INTO ZEROES XTHL XTHL XTHL XTHL XTHL XTHL XTHL LDA CCMND+10H ;GET A-STATUS AGAIN ANI 20H ;ARE WE READING DOUBLE DENS? RAL ;GET ZERO IN NSDENS IF SO RAL ; ELSE GET 80H XRI 80H STA NSDENS ; ; NOW WAIT FOR SYNCH CHAR DETECTED. ERROR IF WE HAVE TO ; WAIT TOO LONG. ; READ5: LDA CCMND+10H ;WAIT FOR SYNCH CHAR DETECTED RRC ;CHECK BIT JC READ15 ;OUT IF GOT IT DCR B ;COUNT DOWN IF NOT JNZ READ5 ;GO BACK IF STILL OK MVI A,1 ;IF WAITED TOO LONG, SYNCH ERROR LXI H,SYEMSG ;SYNCH ERROR MESSAGE ; RERR: STA ERFLAG ;STORE ERROR CODE LDA RTCNT ;COUNT OFF A RETRY DCR A STA RTCNT JNZ READRT ;IF COUNT LEFT, GO RETRY ; ; READ ERROR RETRIES FAILED. FLAG ERROR. ; FRERR: CALL DSKERR ;TELL OPERATOR OF ERROR THEN OUT ; RHSTRT: RET ; ; READ THE DATA INTO HSTBUF ; READ15: LHLD HSTADR ;READ INTO HERE MVI B,0 ;INIT CHECKSUM BYTE LDA NSDENS ;LOAD COUNT MOV C,A ; INTO C-REG ; READ20: LDAX D ;READ NEXT DATA BYTE MOV M,A ; AND PUT IT IN BUFFER XRA B ;ADD TO CHECKSUM RLC MOV B,A INX H ;BOP BUFFER PTR NOP ;KILL TIME LDAX D ;GET NEXT BYTE MOV M,A XRA B RLC MOV B,A INX H DCR C ;COUNT OFF LAST PAIR JNZ READ20 ;GO BACK IF MORE TO DO LDAX D ; ELSE READ CRC BYTE XRA B ; AND CHECK IT AGAINST OURS STA ERFLAG ;IF OK, ZERO EFLAG JZ RHSTRT ; AND RETURN TO CALLER MVI A,2 ; ELSE FLAG CHECKSUM ERROR LXI H,RERMSG ;MESSAGE IF NEEDED JMP RERR ;GO MAYBE RETRY ; ; SETUP SELECTS THE UNIT CORRESPONDING TO HSTDSK, ; SEEKS TO THE TRACK IN HSTTRK. WRITE PRECOMPENSATION ; IS SET IF REQUIRED AS WELL. ON ERROR, ERFLAG CONTAINS ; A NON-ZERO VALUE ON RETURN. ; SETUP: MVI B,00H ;ASSUME TOP SIDE LDA HSTTRK ;CHECK TARGET TRK STA TRUTRK ;ASSUME GOING HERE SUI 80 ;GOING TO SIDE TWO? JC SIDE1 ;PASS IF NOT MOV B,A ;CALC # ON OPPOSITE SIDE MVI A,80-1 ; TO MOVE BACK TOWARD SUB B ; TRK ZERO MVI B,40H ;SIDE TWO SELECT STA TRUTRK ;GOING HERE SIDE1: LDA NSCNT ;GET DOUBLE D BIT XRI 80H MOV C,A ; INTO C-REG LDA HSTDSK ;WANT THIS DISK INR A ;REMAP TO CONTROLLER MASK CPI 03H ;IF UNIT 1 OR 2, JC SET0 ; GOT CORRECT MASK RAL ;IF 3 OR 4, MUST MAP ANI 0CH ; TO 4 OR 8 RESPECTIVELY SET0: ORA C ;OR IN DENSITY BIT ORA B ;OR IN SIDE MASK MOV C,A ;SAVE IN REG C CALL WAIT1S ;WAIT A SECTOR TIME, GET B-STAT ANI 10H ;ARE MOTORS ALREADY ON? LDA CCMND+15H ;GIVE THEM EXTRA KICK ANYWAY JNZ SET5 ;BRANCH IF SO MVI D,17H ;WAIT FOR MOTORS TO CALL SCWAIT ; COME UP TO SPEED IF NOT JMP SET10 ; THEN GO SELECT DRIVE ; SET5: LDA CURDSK ;IS THIS THE CURRENT DISK? CMP C ;COMPARE DISK AND SIDE JZ SET20 ;GO SEEK TO TRACK IF SO ; ; MUST SELECT NEW DISK OR SIDE ; SET10: MOV A,C STA CURDSK ;NEW CURRENT DISK MVI B,CORDER SHR 8 ;SET UP FOR SELECT LDAX B ; AND DO IT MVI D,2 ;WAIT TWO SECTOR TIMES CALL SCWAIT ; BEFORE LOOKING FOR INDEX MVI B,12 ;DON'T LOOK TOO LONG ; SET15: CALL WAIT1S ;WAIT ONE SECTOR TIME LDA CCMND+10H ;GET A-STATUS ANI 40H ;INDEX HOLE SEEN? JNZ SET20 ;CAN GO SEEK NOW IF SO DCR B ;COUNT DOWN IF NOT JNZ SET15 ; AND MAYBE GO LOOK AGAIN ; ; INDEX HOLE NOT FOUND. THAT'S A FATAL ERROR. ; MVI A,4 ;NO INDEX PULSE STA ERFLAG LXI H,NIPMSG JMP DSKERR ;GO TELL OPERATOR ON WAY OUT ; ; SEEK TO TRACK SPECIFIED BY TRUTRK NOW, AND SET ; WRITE PRECOMPENSATION IF APPROPRIATE. ; SET20: CALL SEEK ;SEEK TO TRUTRK LDA TRUTRK ;WHERE ARE WE? CPI 14H+1 ;ARE WE BEYOND TRACK 14H? JC SET25 ;GO ON IF NOT LDA NSCNT ;WRITING DOUBLE DENSITY? ORA A JNZ SET25 ;NO PRECOMP IF NOT LDA CURDSK ;IF SO, GET CURRENT MASK ORI 20H ; AND SET PRECOMP BIT MVI H,CORDER SHR 8 MOV L,A MOV A,M ;SET BIT IN CONTROLLER SET25: XRA A ;NO ERRORS STA ERFLAG RET ;SETUP IS DONE ; ; HERE TO POSITION TO HSTSEC WITHIN THE CURRENT TRACK. ; SEKSEC: LDA HSTSEC ;GET TARGET SECTOR MOV C,A ;IN C STA ERSEC ;SET UP FOR POSSIBLE ERROR ; SET30: CALL WAIT1S ;WAIT FOR NEXT SECTOR LDA CCMND+35H ;KICK MOTORS AND GET SECNUM ANI 0FH ;STRIP NON-SECTOR BITS CMP C ;IS THIS THE TARGET SECTOR? JNZ SET30 ;WAIT UNTIL IT IS RET ;POSITIONED TO SECTOR ; ; SEEK TO TRACK SPECIFIED BY TRUTRK. CURRENT OFFSET INTO ; NSTRK TABLE IS GIVEN BY HSTDSK. ; SEEK: LDA TRUTRK ;GET TARGET TRACK MOV D,A ; INTO D LDA HSTDSK ;GET NSTRK INDEX MOV C,A MVI B,0 LXI H,NSTRK ;PT AT TABLE DAD B ; THEN AT CORRECT ENTRY MOV A,M ;GET CURRENT TRACK INR A ;IS THIS DISK NEW? JNZ SEEK5 ;PASS IF NOT PUSH D ;MUST HOME HEAD IF SO STA TRUTRK ; TO KNOW WHERE WE ARE MVI A,90 ;MAKE SURE STEP TO ZERO MOV M,A PUSH H CALL SEEK ;GO TO TRACK ZERO POP H POP D MOV A,D STA TRUTRK ;RESTORE TRUTRK ; SEEK5: MOV A,D SUB M ;SEE HOW FAR AWAY WE ARE ; FROM TARGET TRACK MOV M,D ; BUT ALWAYS SET NEW TRACK RZ ;IF THERE, DONE LXI H,CORDER+30H ;ASSUME STEPPING IN MOV C,A ;SAVE STEP COUNT JP STEPIN ;BRANCH IF RIGHT CMA ;IF WRONG, NEGATE COUNT INR A MOV C,A ; THEN SAVE THAT LDA CCMND+20H ;GET B-STATUS ANI 01H ;ARE WE ON TRACK ZERO? RNZ ;MUST BE DONE IF SO MVI L,10H ;IF NOT, STEPPING OUT ; STEPIN: LDA CURDSK ;GET CURRENT UNIT MASK ORA L ;FORM FINAL CORDER VALUE MOV L,A MOV D,M ;SET THE STEP FLIP-FLOP ORI 10H MOV L,A MOV D,M ;SET IT AGAIN FOR SOME REASON XRI 10H MOV L,A MOV D,M ;NOW RESET THE STEP FLIP-FLOP ; ; WAIT WHILE HEAD STARTS MOVING ; MVI A,14H STEPW1: MVI D,38H STEPW2: DCR D ;KILL TIME JNZ STEPW2 DCR A JNZ STEPW1 ; ; THE STEP RATE DETERMINES HOW LONG TO WAIT. ONE SECTOR ; TIME IS 20 MSEC. A SLOW SHUGART SA400 MAY REQUIRE 40 ; MSEC, OR TWO SECTOR TIMES. MOST TYPICAL SA400'S WILL ; WORK WITH 20 MSEC, SO THAT'S WHAT WE'LL USE HERE. WE ; WILL CALL SCWAIT INSTEAD OF WAIT1S IN CASE WE NEED TO ; PATCH THIS VALUE. ; MVI D,1 ;NOW WAIT 20 MSEC ; MVI D,2 ;NOW WAIT 40 MSEC CALL SCWAIT LDA CCMND+25H ;GET B-STATUS AND KICK MOTORS ANI 01H ;ARE WE AT TRACK ZERO? JNZ WAIT1S ;DONE STEPPING IF SO DCR C ; ELSE COUNT OFF LAST TRACK JNZ STEPIN ;GO BACK IF MORE TO DO ; ELSE WAIT ONE MORE SECTOR TIME ; TO MAKE SURE SAFE FOR I/O ; ; SECTOR WAIT. ON ENTRY, # SECTORS TO WAIT IS IN D. ; ON EXIT, D=0 AND ACC=A-STATUS. CALL WAIT1S TO WAIT ; ONE SECTOR TIME. ; WAIT1S: MVI D,1 ;WAIT ONE SECTOR TIME ; SCWAIT: LDA CCMND+11H ;RESET SECTOR FLAG SCW5: LDA CCMND+10H ;GET A-STATUS ORA A ;CHECK SECTOR FLAG JP SCW5 ;WAIT FOR IT IF NOT UP LDA CCMND+11H ; ELSE RESET SECTOR FLAG DCR D ;COUNT DOWN WAIT COUNTER JNZ SCW5 ;GO BACK IF MORE TO DO RET ; ELSE RETURN A-STATUS IN ACC ; ; DISK ERRORS REPORTED HERE ; DSKERR: PUSH H ;SAVE BODY ADDRESS MVI A,CR ;EJECT LINE CALL CNSOT MVI A,LF CALL CNSOT POP H CALL MSGOT ;REPORT BODY LDA HSTDSK ;THIS DISK ADI 'A' STA ASCDSK LXI H,ERRMSG CALL MSGOT LDA HSTTRK ;THIS TRACK CALL HXBOT LXI H,SECMSG CALL MSGOT LDA ERSEC ;THIS SECTOR ;FALL INTO HXBOT TO FINISH ; ; DISPLAY HEXIDECIMAL EQUIVALENT OF ACC CONTENTS ; HXBOT: PUSH PSW ;SAVE CHAR RRC ;SWAP NIBBLES RRC RRC RRC CALL HXNOT ;OUTPUT HIGH NIBBLE POP PSW ; THEN LOW NIBBLE HXNOT: ANI 0FH ;STRIP HIGH NIBBLE CPI 10 ;LESS THAN 10 JC HXNNM ;PASS IF SO ADI 'A'-'9'-1 ;ADD LETTER OFFSET HXNNM: ADI '0' ;MAKE ASCII ; CNSOT: PUSH H ;Save all regs PUSH D PUSH B ; but PSW MOV C,A CALL BCNSOT ;OUTPUT CHAR TO CONSOLE POP B ;Restore regs POP D POP H RET ;Return to caller ; CNSIN: PUSH H ;SAVE ALL REGS PUSH D PUSH B CALL BCNSIN ;READ CONSOLE CHAR MOV C,A ;CHAR TO C FOR ECHO PUSH PSW ;SAVE CHAR READ CPI 20H ;IS CHAR DISPLAYABLE? CNC BCNSOT ;ECHO TO OUTPUT IF SO POP PSW ;RESTORE CHAR READ POP B ;RESTORE BC AND DE POP D CPI 3 ;CHECK FOR CTRL-C LXI H,CTCMSG ;IN CASE GOT CZ MSGOT ;ECHO IF GOT POP H ;RESTORE HL NOW CPI 'A'+20H ;FOLD LOWER CASE TO UPPER RC CPI 'Z'+20H+1 RNC SUI 20H RET ; MSGASK: CALL MSGOT ;OUTPUT MSG @HL CALL CNSIN ;GET OPERATOR REPLY CPI 3 ;CTRL-C? JZ LIST ;BACK TO MENU IF SO LXI H,CRLF ;EJECT LINE IF NOT, THEN ; RET CHAR IN ACC ; MSGOT: PUSH PSW ;SAVE CALLER FLAGS MSGL: MOV A,M ;LOAD CHAR CPI '$' ;END OF STRING? JZ MSGR ;OUT IF SO CALL CNSOT ;IF NOT, OUTPUT CHAR INX H ;ADVANCE PTR JMP MSGL ;GO BACK FOR NEXT CHAR ; MSGR: POP PSW ;RESTORE CALLER PSW RET ; ; BIOS JUMP VECTORS STUFFED HERE AT PROG STARTUP ; BVECT: JMP $-$ ;WARM BOOT BCNSCK: JMP $-$ ;CONSOLE STATUS TO ACC BCNSIN: JMP $-$ ;CONSOLE INPUT TO ACC BCNSOT: JMP $-$ ;CONSOLE OUTPUT FROM C ; BVECTL: EQU $-BVECT ;# BYTES OF VECTORS ; ; DISK ERROR MESSAGES ; WPEMSG: DB 'Protect$' SDEMSG: DB 'Density mismatch$' RERMSG: DB 'CRC$' SYEMSG: DB 'No synch$' NIPMSG: DB 'No index$' ; ERRMSG: DB ' err on ' ASCDSK: DB ' :, trk $' SECMSG: DB ', sec $' ; ; NORTH STAR DRIVER CURRENT TRACK TABLE ; NSTRK: DS 4 ;EACH ENTRY CONTAINS THE ; LAST TRACK POSITION FOR ; UNIT 1-4 ; 0FFH=NEVER ACCESSED ; ; NORTH STAR DRIVER VARIABLES ; HSTDSK: DS 1 ;HOST DISK NUMBER ERFLAG: DS 1 ;ERROR REPORTING CURDSK: DS 1 ;CURRENT ACTIVE DISK, ; 0FFH=NONE YET NSDENS: DS 1 ;DENSITY FLAG FOR LAST ; BLOCK READ. DD=00H, SD=80H NSCNT: DS 1 ;DENSITY FLAG AND COUNT FOR ; NEXT BLOCK TO WRITE. DD=00H, ; SD=80H TRKSIZ: DS 2 ;# BYTES/TRACK BLKSIZ: DS 2 ;# BYTES/SECTOR HSTADR: DS 2 ;XFER MEM ADDRESS HSTTRK: DS 1 ;HOST TRACK NUMBER TRUTRK: DS 1 ;TRACK # AFTER SIDE ADJUST HSTSEC: DS 1 ;HOST SECTOR NUMBER RTCNT: DS 1 ;ERROR RETRY COUNTER ERSEC: DS 1 ;SECTOR IN ERROR ; ; MAIN COPY PROGRAM DATA AREA ; TRKSRT: DS 2 ;STORAGE FOR FIRST AND ; LAST+1 TRACK NUMBERS BUF0A: DS 2 ;CURR READ TRK ADDR NTR: DS 1 ;# TRKS THAT FIT IN BUF0 NTRC: DS 1 ;NTR COUNTER STRK: DS 1 ;START TRK # IN BUF0 CTRK: DS 1 ;CURR TRK # FOR STATUS IN ; ASCII, LOW DIGIT ONLY CMPERR: DS 1 ;NUMBER OF COMPARE ERRORS FUNC: DS 1 ;SELECTED FUNCTION NUMBER SRCDSK: DS 1 ;SOURCE DRIVE NUMBER DSTDSK: DS 1 ;DESTINATION DRIVE NUMBER IOEMSG: DS 2 ;FAILR (read error) msg addr STK: DS 128 STKTOP: DS 1 ; BUF1: DS 512*(LASTSEC+1) ;COMPARE BUFFER BUF0: ;BIG READ BUFFER (UP TO BIOS) ; END