home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
SIMTEL
/
CPMUG
/
CPMUG038.ARK
/
DFOCO.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
57KB
|
2,333 lines
; -- 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 <CR,LF,' - DFOCO -',CR,LF>
PRINT <'CP/M FAST FORMAT-COPY UTILITY',CR,LF>
PRINT <'COPYRIGHT NOV 1979 BY S J SINGER',CR,LF>
NEWIN: PRINT <CR,LF,'*'>
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 <CR,LF,'SOURCE AND DESTINATION DRIVE ARE THE SAME',CR,LF>
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 <CR,LF,'TYPE RETURN TO BEGIN COPY '>
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 <CR,LF,'LOAD SOURCE DISK, TYPE RETURN '>
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 <CR,LF,'LOAD DESTINATION DISK, TYPE RETURN '>
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 <CR,LF,LF,'COPY COMPLETE'>
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 <CR,LF,LF,' FORMAT READ FROM SOURCE DISK'>
CALL RDISP ;DISPLAY IT
PRINT <CR,LF,LF>
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<CR,LF,LF,'COPYING '>
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 <CR,LF,' SECTOR FORMAT DRIVE '>
LDA NEWDRV ;GET DRIVE NO
CALL PRNDRV ;PRINT DRIVE NAME
MAP5: PRINT <' TRACK '>
MAP6: LHLD TNUM
DECOUT ;CONVERT TO DECIMAL AND PRINT
PRINT <CR,LF>
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 <CR,LF,'SUCCESSFUL VALIDATION DRIVE '>
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 <CR,LF,LF,'THERE WERE '>
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 <CR,LF,'VALIDATION ERROR DRIVE '>
JMP VALID3
VALID9: PRINT <' HARD ERROR'>
JMP ENDFIL
VALID12:PRINT <CR,LF,'THERE WAS 1 RETRY'>
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 <CR,LF,LF,'FORMAT WITH '>
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 <CR,LF,LF>
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 <CR,LF,'TYPE CARRIAGE RETURN '>
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 <CR,LF,LF,'INPUT SPECIAL SECTOR FORMAT',CR,LF,LF>
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 <CR,LF,' '>
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 <CR,LF,LF,LF,'TYPE RETURN TO FORMAT, SECTOR NO TO CORRECT '>
FILL 80H,90H ;ZERO BUFFER
INPUT 80H
LDA 81H ;NO OF CHAR TYPED IN
ORA A
JNZ RD8 ;CORRECT INPUT
PRINT <CR,LF,LF,'WRITING NON STANDARD FORMAT ON DISK',CR,LF,LF>
JMP FMNS ;TO FORMAT ROUTINE
RD8: LXI H,82H ;POINT TO START OF BUFFER
CALL GETNUM ;GET SECTOR
STA PSEC ;SAVE PHYSICAL SECTOR
PRINT <CR,LF,LF>
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 <CR,LF,' SECTOR MAPPING',CR,LF,LF>
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 <CR,LF,' '>
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 <CR,LF,'ERROR IN READING ID FIELD'>
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 <CR,LF,'FORMATTING ERROR DRIVE '>
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 <CR,LF,' ERROR - SECTOR NUMBERS MUST BE GREATER THAN ZERO'>
JMP SE1
SE0: CPI 27
JM SE2
PRINT <CR,LF,' ERROR - SECTOR GREATER THAN 26'>
SE1: STC
RET
SE2: LXI H,SECMAP
MVI B,26
SE3: CMP M ;CHECK IF SECTOR ALREADY USED
JNZ SE4
PRINT <CR,LF,' SORRY YOU ALREADY USED THAT ONE'>
JMP SE1
SE4: INX H
DCR B
JNZ SE3
SE5: ORA A ;CLEAR CARRY
RET
;
; SCANERR - NUMBER MISSING WHERE EXPECTED
;
SCANERR:PRINT <CR,LF,LF,'MISSING OPERAND, PLEASE START OVER',CR,LF>
JMP ENDFIL ;EXIT
;
; DECERR - NON NUMERIC CHARACTER IN NUMBER
;
DECERR: PRINT <CR,LF,LF,'ERROR IN ENTERING DECIMAL NUMBER, PLEASE START OVER'>
JMP ENDFIL ;EXIT
;
; TRKTEST - TEST FOR TRACK BETWEEN 0 AND 76
;
TRKTEST:CPI 77 ;CHECK SECTOR > 76
RM
PRINT <CR,LF,LF,'TRACK NUMBER MUST BE BETWEEN 0-76',CR,LF>
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 <CR,LF,'SEEK ERROR TRACK '>
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 <CR,LF,'ERROR IN HOMING DRIVE '>
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 <CR,LF,'PERMANENT READ ERROR TRACK '>
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 <CR,LF,'PERMANENT VERIFY 0R READ CRC ERROR TRACK '>
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 <CR,LF,'PERMANENT WRITE ERROR TRACK '>
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 <CR,LF,LF,'VALIDATING DESTINATION DISK',CR,LF>
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 <CR,LF,LF,'ERROR IN FORMAT SECTOR SIZE',CR,LF,BEL>
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 <CR,LF,'DOUBLE DENSITY NOT AVAILABLE FOR 1771',CR,LF>
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 <CR,LF,'ERROR - DRIVE NUMBER GREATER THAN 3',CR,LF>
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
;
;