home *** CD-ROM | disk | FTP | other *** search
- 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 <ctrl-C> 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 <CR> when ready: $'
- INSERT: DB CR,LF,'Insert system disk in drive A'
- DB ' and type <CR> 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
-