home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / cpmug / cpmug082.ark / NSCOPY.ASM < prev    next >
Encoding:
Assembly Source File  |  1984-04-29  |  34.2 KB  |  1,380 lines

  1.     TITLE    'North Star Disk Copy Program V4.2 of 09/17/81'
  2. ;    PAGE    44
  3. ;
  4. ; These routines copyright (c) 1980, 1981, 1982 by Steve Bogolub,
  5. ; 2338 S. Scoville Ave., Berwyn, IL 60402. This software may be
  6. ; used freely for non-commercial purposes only, and may not be sold.
  7. ;
  8. ;************************************************************
  9. ;
  10. ;  The purpose of this program is to allow the operator
  11. ; to copy, format, or validate North Star double density
  12. ; disks. Copying can be done between any two North Star
  13. ; drives, and can include all tracks, or just the system
  14. ; (0 and 1) tracks or data tracks (2 - LTRK) for special
  15. ; system handling, where LTRK is the last data track,
  16. ; which is 34 for Shugart SA400 and 39 for most others.
  17. ; The variable LASTTRK at 103H contains the genned-in
  18. ; value of LTRK, and can be patched to change the default
  19. ; disk size within reasonable bounds. If the number is
  20. ; too big, the generated DPB for the ID block will become
  21. ; incorrect. The patching feature is intended primarily
  22. ; for switching between 35 and 40 track versions, but
  23. ; can be used in a pinch for formatting larger sizes
  24. ; for experimental purposes.
  25. ;
  26. ; The allowed functions are:
  27. ;
  28. ;  1)    Copy all tracks from source disk to destination
  29. ;    disk. The density of sector zero on track zero
  30. ;    of the source determines the density of the
  31. ;    destination.
  32. ;
  33. ;  2)    Copy only the system tracks from source disk
  34. ;    to destination disk. If source disk is double
  35. ;    density, tracks 0 and 1 only are copied. If
  36. ;    source disk is single density, tracks 0, 1,
  37. ;    and 2 only are copied.
  38. ;
  39. ;  3)    Copy only the data tracks from source disk to
  40. ;    destination disk. If source disk is double
  41. ;    density, tracks 2-LTRK inclusive are copied.
  42. ;    If source disk is single density, tracks 3-LTRK
  43. ;    inclusive are copied.
  44. ;
  45. ;  4)    Validate the source disk. This is done by
  46. ;    reading all tracks.
  47. ;
  48. ;  5)    Format the destination disk in double
  49. ;    density. This is done by writing data
  50. ;    blocks with each byte containing the
  51. ;    hex value "E5" to all sectors of all
  52. ;    tracks. To be Lifeboat-compatible, we
  53. ;    write a double-density single-sided
  54. ;    disk ID block into track zero, sector
  55. ;    zero.
  56. ;
  57. ;  6)    Format the destination disk in single
  58. ;    density. Similar to 5) above.
  59. ;
  60. ;  7)    Format the destination disk for double
  61. ;    sided, 80 trks/side, double density.
  62. ;
  63. ;  In addition, the user is given the options of
  64. ; warm booting CP/M, or cold booting by jumping
  65. ; to the standard North Star ROM boot address. For
  66. ; functions 1 - 3, the user is asked for the source
  67. ; and destination drive letters. For function 4,
  68. ; the user is asked for just the destination drive
  69. ; letter, since the source is unused. For function
  70. ; 5, the user is asked for just the source letter,
  71. ; since the destination is unused.
  72. ;
  73. ;  To drive the disks at top speed, this program
  74. ; contains a complete set of North Star disk
  75. ; driver routines. CP/M's BIOS routines are used
  76. ; to write messages to the console and get user
  77. ; replies. All the area up to the BIOS warm
  78. ; boot page is assumed available for buffer
  79. ; space, so take note if a non-contiguous BIOS
  80. ; is in use.
  81. ;
  82. ;  This program may be restarted at 100H.
  83. ;
  84. ;  This program is built on the wreckage of the
  85. ; CP/M User's group COPY program, after most of
  86. ; it was discarded.
  87. ;
  88. ;************************************************************
  89.  
  90.     ORG    100H
  91. ;
  92. ;EQUATES
  93. ;
  94. WBOOT    EQU    0    ;CP/M WARM BOOT ADDRESS
  95. CBOOT    EQU    0E800H    ;NORTH STAR ROM BOOT ADDRESS
  96. NDRIVE    EQU    4    ;NUMBER OF NORTH STAR DRIVES ON SYSTEM
  97. LASTSEC    EQU    9
  98. LTRK    EQU    35-1    ;NORMAL DRIVE IS 35 TRACK
  99. LASTT80    EQU    159    ;80 TRACK DOUBLE SIDE DRIVE
  100. BDOS    EQU    5
  101. IDOFF    EQU    050H    ;Offset into BUF0 where Lifeboat
  102.             ; ID should be placed
  103. CR    EQU    0DH
  104. LF    EQU    0AH
  105. ;
  106. ;************************************************************
  107. ;
  108. ;  Start the program here.
  109. ;
  110. START:    JMP    BEGIN
  111. ;
  112. LASTTRK: DB    LTRK        ;Contains last trk # (34 for
  113.                 ; a 35-track drive)
  114. ;
  115. ;  Do one-time initialization involving LASTTRK, BIOS
  116. ; vectors, and NSTRK.
  117. ;
  118. BEGIN:    LXI    SP,STKTOP    ;Set stack ptr
  119.     LHLD    WBOOT+1        ;GET BIOS VECTORS
  120.     LXI    D,BVECT        ; INTO OUR PROGRAM
  121.     MVI    B,BVECTL
  122. ;
  123. MVECT:    MOV    A,M
  124.     STAX    D
  125.     INX    H
  126.     INX    D
  127.     DCR    B
  128.     JNZ    MVECT
  129.     LXI    H,0FFFFH    ;INIT TRK TABLE
  130.     SHLD    NSTRK
  131.     SHLD    NSTRK+2
  132.     MOV    A,L
  133.     STA    CURDSK        ;NO CURRENT DISK YET
  134.     LDA    IDSSPT        ;Calc single density
  135.     CALL    CALCSZ        ; disk size in groups
  136.     SHLD    IDSSIZ        ;Fix ID table
  137.     LDA    IDDSPT        ;Repeat for double
  138.     CALL    CALCSZ        ; density
  139.     SHLD    IDDSIZ
  140.     LDA    LASTTRK        ;Get ASCII # trks
  141.     INR    A
  142.     MVI    B,'0'-1        ; by repeat subtracts
  143. ATEN:    INR    B
  144.     SUI    10
  145.     JNC    ATEN        ;Get 10's in B
  146.     ADI    10+'0'        ; and 1's in A
  147.     STA    SIGNTK+1    ;Fix SIGNON msg
  148.     MOV    A,B
  149.     STA    SIGNTK
  150.     LXI    H,SIGNON
  151.     CALL    MSGOT    ;Tell who we are
  152. ;
  153. LIST:    LXI    SP,STKTOP    ;Reload stack ptr
  154.             ; in case here after error
  155.     CALL    MOFF    ;Turn off North Star motors
  156.             ; to allow disk switching
  157.     LXI    H,FLIST    ;Print out the menu
  158.     CALL    MSGOT
  159.     CALL    CNSIN    ;GET REPLY
  160.     LXI    H,CRLF    ;RET CARRIAGE AFTER
  161.     CALL    MSGOT
  162.     STA    FUNC    ;Save for later
  163. ;
  164. ;  Dispatch to routine based on choice, unless it was bad.
  165. ;
  166.     CPI    '1'
  167.     JZ    ALLSET    ;COPY ALL
  168.     CPI    '2'
  169.     JZ    SYSSET    ;COPY SYSTEM
  170.     CPI    '3'
  171.     JZ    DATSET    ;COPY DATA
  172.     CPI    '4'
  173.     JZ    VALSET    ;VALIDATE
  174.     CPI    '5'
  175.     JZ    FORSTD    ;FORMAT DOUBLE DENSITY
  176.     CPI    '6'
  177.     JZ    FORSTS    ;FORMAT SINGLE DENSITY
  178.     CPI    '7'
  179.     JZ    FORS80    ;FORMAT 80-TRKS, DOUBLE SIDED
  180.     CPI    '8'
  181.     JZ    EXIT    ;WARM BOOT
  182.     CPI    3    ;ALLOW CTRL-C FOR WARM BOOT TOO
  183.     JZ    EXIT
  184.     CPI    '9'
  185.     JZ    CEXIT    ;COLD BOOT
  186.     LXI    H,SELER
  187.     CALL    MSGOT    ;BAD NUMBER GIVEN
  188.     JMP    LIST    ;GO ASK AGAIN
  189. ;************************************************************
  190. ;
  191. SIGNON:    DB    CR,LF,'North Star Copy V4.2 of 09/17/81 -- '
  192. SIGNTK:    DB    ((LTRK+1)/10)+'0',((LTRK+1) MOD 10)+'0'
  193.     DB    ' track version$'
  194. FLIST:    DB    CR,LF
  195.     DB    CR,LF,'Function List:'
  196.     DB    CR,LF
  197.     DB    CR,LF,'  1. Copy all tracks, using density'
  198.     DB    ' of source disk'
  199.     DB    CR,LF,'  2. Copy system tracks only,'
  200.     DB    ' using density of source disk'
  201.     DB    CR,LF,'  3. Copy data tracks only, using'
  202.     DB    ' density of source disk'
  203.     DB    CR,LF,'  4. Validate'
  204.     DB    CR,LF,'  5. Format DOUBLE density'
  205.     DB    CR,LF,'  6. Format SINGLE density'
  206.     DB    CR,LF,'  7. Format 80 trk ds/dd'
  207.     DB    CR,LF,'  8. Warm boot'
  208.     DB    CR,LF,'  9. Cold boot'
  209.     DB    CR,LF
  210.     DB    CR,LF,'Enter function number: $'
  211. SELER:    DB    CR,LF,'Not a valid number',CR,LF,'$'
  212. ;
  213. SRCMSG:    DB    'Enter source$'
  214. DSTMSG:    DB    'Enter destination$'
  215. SDMSG:    DB    ' drive (A-'
  216.     DB    NDRIVE-1+'A',') or <ctrl-C> to reselect: $'
  217. ;
  218. MESGA:    DB    CR,LF,'Compare error on track $'
  219. MESGB:    DB    ' (hex) sector $'
  220. MESGC:    DB    ' -- permanent $'
  221. MESGD:    DB    CR,LF,'Source read error exit $'
  222. MESGE:    DB    CR,LF,'Destination write error exit $'
  223. MESGF:    DB    CR,LF,'Destination read error exit $'
  224. S1:    DB    CR,LF,'Ready to copy $'
  225. S2:    DB    ' from disk '
  226. SSRC:    DB    0,': to disk '
  227. SDST:    DB    0,':.$'
  228. SSYS:    DB    'system tracks only$'
  229. SDAT:    DB    'data tracks only$'
  230. SALL:    DB    'all tracks$'
  231. DFOR:    DB    CR,LF,'Ready to format and validate disk '
  232. DFORD:    DB    0,': in DOUBLE density,',CR,LF
  233.     DB    'overwriting all previous data there.$'
  234. SFOR:    DB    CR,LF,'Ready to format and validate disk '
  235. SFORD:    DB    0,': in SINGLE density,',CR,LF
  236.     DB    'overwriting all previous data there.$'
  237. FOR80:    DB    CR,LF,'Ready to format and validate '
  238.     DB    '80 trk double sided disk '
  239. FOR80D:    DB    0,': in',CR,LF,'DOUBLE density, '
  240.     DB    'overwriting all previous data there.$'
  241. SVAL:    DB    CR,LF,'Ready to validate disk '
  242. SVALS:    DB    0,':.$'
  243. GOMSG:    DB    CR,LF,CR,LF
  244.     DB    'If that is what you want, switch disks if'
  245.     DB    CR,LF
  246.     DB    'appropriate and type <CR> when ready: $'
  247. INSERT:    DB    CR,LF,'Insert system disk in drive A'
  248.     DB    ' and type <CR> to $'
  249. BOOT:    DB    ' boot: $'
  250. WMSG:    DB    'warm$'
  251. CMSG:    DB    'cold$'
  252. ABMSG:    DB    ' ^C',CR,LF,'** Console abort **$'
  253. DONMSG:    DB    CR,LF,'Function complete.$'
  254. CRLF:    DB    CR,LF,'$'
  255. CTCMSG:    DB    '^C$'
  256. ;
  257. ;  This is the Lifeboat-compatible label we write to a
  258. ; double density disk when we format it. Note that the
  259. ; contents of the second part of the label are actually
  260. ; a CP/M disk parameter block. We assume this must match
  261. ; the disk we are formatting, so this DPB is for a
  262. ; double-density single-sided disk. The name seems to
  263. ; be ignored, so we use NSCOPY (Lifeboat uses FORMAT).
  264. ; The rest of the data between the name and the DPB
  265. ; has no meaning to us, so we are just blindly using
  266. ; the stuff Lifeboat puts there, which doesn't seem
  267. ; to hurt.
  268. ;
  269. IDD:    DB    'NSCOPY  '    ;Format program name
  270.     DB    0,0,0,0,90H,0,0,0,90H    ; ???
  271. IDDSPT:    DW    40    ;DPB - Sectors per track
  272.     DB    3    ;Block shift factor
  273.     DB    07H    ;Block mask
  274.     DB    0    ;Exm mask
  275. IDDSIZ:    DW    (((LTRK-1)*40)/8)-1 ;Disk size in groups - 1
  276.     DW    63    ;Directory max entries
  277.     DB    11000000B ;Alloc 0
  278.     DB    0    ;Alloc 1
  279.     DW    16    ;Check size
  280.     DW    2    ;Track offset to data
  281. ;
  282. IDLEN    EQU    $-IDD    ;# bytes in label
  283. ;
  284. ;  SINGLE DENSITY LIFEBOAT LABEL (SEE IDD ABOVE)
  285. ;
  286. IDS:    DB    'NSCOPY  '    ;Format program name
  287.     DB    0,0,0,0,10H,0,0,0,10H    ; ???
  288. IDSSPT:    DW    20    ;DPB - Sectors per track
  289.     DB    3    ;Block shift factor
  290.     DB    07H    ;Block mask
  291.     DB    0    ;Null mask
  292. IDSSIZ:    DW    (((LTRK-1)*20)/8)-1 ;Disk size in groups - 1
  293.     DW    63    ;Directory max entries
  294.     DB    11000000B ;Alloc 0
  295.     DB    0    ;Alloc 1
  296.     DW    16    ;Check size
  297.     DW    3    ;Track offset to data
  298. ;
  299. ;  DUMMY 80 TRACKS PER SIDE, DOUBLE SIDE, DOUBLE
  300. ; DENSITY LABEL. WE PUT THIS ON OUR DRIVE FOR OUR
  301. ; OWN INFORMATION, SINCE LIFEBOAT DOES NOT SUPPORT
  302. ; ANY SUCH FORMAT.
  303. ;
  304. ID80:    DB    'NSCOPY  '    ;Format program name
  305.     DB    0,0,0,0,0F0H,0,0,0,0F0H    ; ???
  306.     DW    40    ;DPB - Sectors per track
  307.     DB    4    ;Block shift factor
  308.     DB    0FH    ;Block mask
  309.     DB    0    ;Exm mask
  310.     DW    395-1    ;Disk size in groups - 1
  311.     DW    127    ;Directory max entries
  312.     DB    11000000B ;Alloc 0
  313.     DB    0    ;Alloc 1
  314.     DW    32    ;Check size
  315.     DW    2    ;Track offset to data
  316. ;
  317. ;  CALCSZ calculates a group size for a disk whose
  318. ; number of 128-byte sectors is supplied in acc on
  319. ; entry. The two-byte result is returned in HL.
  320. ; Note that only the formula (LASTTRK-1)*SECTORS/8-1
  321. ; is used, so the disk shouldn't be too big if this
  322. ; is to be valid.
  323. ;
  324. CALCSZ:    MOV    E,A    ;Get # sectors/trk
  325.     MVI    D,0    ; into DE
  326.     LDA    LASTTRK    ;Get # trks
  327.     DCR    A    ; - 1 into acc
  328.     LXI    H,0    ;Init total # sectors
  329. ;
  330. CSZ5:    DAD    D    ;Count up sectors
  331.     DCR    A
  332.     JNZ    CSZ5
  333.     MVI    B,3    ;Divide result by 8
  334. ;
  335. CSZ10:    MOV    A,H    ;Shift right
  336.     ORA    A
  337.     RAR
  338.     MOV    H,A
  339.     MOV    A,L
  340.     RAR
  341.     MOV    L,A
  342.     DCR    B    ; 3 times for divide
  343.     JNZ    CSZ10
  344.     DCX    H    ; - 1 to complete
  345.     RET        ;Ret answer in HL
  346. ;
  347. ;  ASKSRC IS USED TO GET THE SOURCE DRIVE NAME FROM
  348. ; THE USER. SRCDSK IS SET ON RETURN WITH A VALUE FROM
  349. ; 0 TO NDRIVE-1, AND ACC CONTAINS THE ASCII DRIVE
  350. ; LETTER. IF USER TYPED CTRL-C, WE EXIT BACK TO LIST.
  351. ;
  352. ASKSRC:    LXI    H,SRCMSG    ;GET SOURCE
  353.     CALL    ASKC
  354.     JC    ASKSRC    ;GO BACK IF BAD LETTER
  355.     CPI    NDRIVE
  356.     JNC    ASKSRC
  357.     STA    SRCDSK    ; ELSE SET DRIVE NUMBER
  358.     ADI    'A'    ;RESTORE LETTER FOR CALLER
  359.     STA    SSRC    ;SET FOR COPY FUNCTIONS
  360.     RET
  361. ;
  362. ;  ASKDST IS USED TO GET THE DESTINATION DRIVE
  363. ; NAME. DSTDSK IS SET ON RETURN WITH A VALUE FROM
  364. ; 0 TO NDRIVE-1, AND ACC CONTAINS THE ASCII DRIVE
  365. ; LETTER. IF USER TYPED CTRL-C, WE EXIT BACK TO LIST.
  366. ;
  367. ASKDST:    LXI    H,DSTMSG    ;GET DESTINATION
  368.     CALL    ASKC
  369.     JC    ASKDST    ;GO BACK IF BAD LETTER
  370.     CPI    NDRIVE
  371.     JNC    ASKDST
  372.     STA    DSTDSK    ; ELSE SET DRIVE NUMBER
  373.     ADI    'A'    ;RESTORE LETTER FOR CALLER
  374.     STA    SDST    ;SET FOR COPY FUNCTIONS
  375.     RET
  376. ;
  377. ASKC:    CALL    MSGOT
  378.     LXI    H,SDMSG
  379.     CALL    MSGASK
  380.     SUI    'A'
  381.     RET
  382. ;
  383. ;  MAIN COPY ROUTINE HERE. PERFORM FUNCTION BETWEEN
  384. ; TRACKS SPECIFIED BY THE TWO BYTES AT TRKSRT.
  385. ;
  386. COPY:    MVI    A,1    ;ASSUME ONE TRK AT A TIME
  387.     STA    NTR    ; FOR FORMAT OR VALIDATE CASES
  388.     LDA    FUNC    ;CHECK FUNCTION
  389.     CPI    '5'    ;FORMAT?
  390.     JNC    FRSTRK    ;DENSITY ALL SET IF SO
  391.     CALL    SETDD    ;ASSUME DOUBLE D IF NOT
  392.     XRA    A    ;SET UP SOURCE READ IF SO
  393.     STA    HSTSEC    ; ON SECTOR ZERO
  394.     STA    HSTTRK    ; OF TRACK ZERO
  395.     LDA    SRCDSK
  396.     STA    HSTDSK
  397.     LXI    H,MESGD    ;IN CASE OF ERROR
  398.     SHLD    IOEMSG
  399.     LXI    H,BUF1    ;PT TO SCRATCH BUFFER
  400.     SHLD    HSTADR
  401.     CALL    SETUP    ;SELECT DISK AND SEEK
  402.     CALL    READ    ;READ THE SECTOR
  403.     LDA    ERFLAG    ;CHECK FOR ERRORS
  404.     ORA    A
  405.     CNZ    FAILR    ;ERROR IF CAN'T READ SECTOR
  406.     LDA    NSDENS    ;CHECK DENSITY
  407.     ORA    A
  408.     JZ    SETNTR    ;ALL SET IF DOUBLE D
  409.     CALL    SETSD    ;SET SINGLE DENS VARIABLES
  410.     LDA    FUNC    ;IF SINGLE, MAY NEED ADJUSTMENTS
  411.     CPI    '1'    ;COPY ALL TRACKS?
  412.     JZ    SETNTR    ;ALL SET IF SO
  413.     CPI    '4'    ;VALIDATE?
  414.     JZ    FRSTRK    ;ALSO ALL SET
  415.     CPI    '2'    ;COPY SYSTEM TRACKS ONLY?
  416.     LXI    H,3*256+0 ;ASSUME SO
  417.     JZ    SDSYS    ;GO STUFF IF SO
  418.     LDA    LASTTRK    ;Data copy if not
  419.     INR    A
  420.     MOV    H,A
  421.     MVI    L,0
  422. SDSYS:    SHLD    TRKSRT    ;NEW START OR END
  423. ;
  424. SETNTR:    LDA    FUNC    ;CHECK FOR VALIDATE
  425.     CPI    '4'    ; IN CASE DOUBLE DENSITY
  426.     JZ    FRSTRK    ;ONE TRACK AT A TIME IF SO
  427.     LHLD    TRKSIZ    ;GET TRACK SIZE
  428.     LDA    WBOOT+2    ;GET BIOS BASE PAGE
  429.     DCR    A    ;ADJUST FOR COMPARE
  430.     XCHG        ;TRK SIZE TO DE
  431.     LXI    H,BUF0    ;BUF STARTS HERE
  432.     MVI    B,0    ;INIT TRACK CTR
  433. ;
  434. SNTRL:    DAD    D    ;ADD ANOTHER BUFFER
  435.     JC    SNTRD    ;OUT IF NO MORE MEM
  436.     INR    B    ;ASSUME ROOM
  437.     CMP    H    ;UP TO BIOS YET?
  438.     JNC    SNTRL    ;GO BACK IF NOT
  439.     DCR    B    ;ONE LESS TRACK IF SO
  440. SNTRD:    MOV    A,B
  441.     STA    NTR    ;CAN READ THIS MANY
  442. ;
  443. FRSTRK:    LDA    TRKSRT    ;SET 1ST TRK TO DO
  444.     STA    HSTTRK
  445.     ADI    '0'    ;GET ASCII EQUIV
  446.     STA    CTRK    ; FOR STATUS REPORTING
  447. ;
  448. RDLOOP:    LDA    HSTTRK    ;REMEMBER START TRACK FOR
  449.     STA    STRK    ; THIS BUFFER, FOR WRITING
  450.     LXI    H,BUF0    ;INIT INPUT BUFFER ADDRESS
  451.     SHLD    BUF0A
  452.     LDA    NTR    ;CAN FIT THIS MANY TRACKS
  453. ;
  454. RDNT:    STA    NTRC    ;UPDATE # TRKS ROOM LEFT
  455.     CALL    BCNSCK    ;CHECK FOR CONSOLE ABORT
  456.     ORA    A
  457.     CNZ    ABORT    ;IF CTRL-C, NO RETURN
  458.     LDA    CTRK    ;SHOW NEXT TRACK TO DO
  459.     PUSH    PSW    ;SAVE FOR BOP
  460.     CALL    CNSOT    ;OUTPUT DIGIT
  461.     POP    PSW    ;GET BACK AGAIN
  462.     INR    A    ;NOW BOP BY ONE
  463.     CPI    '9'+1    ;GOING OVER NOW?
  464.     JC    CTRKNZ    ;PASS IF NOT
  465.     MVI    A,' '    ;SPACE OVER EACH TEN
  466.     CALL    CNSOT
  467.     MVI    A,'0'    ;REWIND DIGIT
  468. CTRKNZ:    STA    CTRK    ;SAVE NEXT TRK #
  469.     LDA    FUNC    ;SEE IF FORMATTING ONLY
  470.     CPI    '5'
  471.     JNC    WONLY    ;WRITE ONLY IF SO
  472.     LDA    SRCDSK    ;IF NOT,
  473.     STA    HSTDSK    ; SELECT SOURCE DRIVE
  474.     CALL    READT    ;READ ENTIRE TRACK
  475.     LDA    FUNC    ;CHECK FUNCTION
  476.     CPI    '4'    ;VALIDATE?
  477.     JZ    SKPW    ;SKIP WRITE IF SO
  478.     LDA    HSTTRK    ;BOP TRK #
  479.     INR    A
  480.     STA    HSTTRK
  481.     LXI    H,TRKSRT+1
  482.     CMP    M    ;READ LAST TRACK?
  483.     JZ    WRLOOP    ;GO WRITE IF SO
  484.     LHLD    BUF0A    ;ADVANCE BUF PTR IF NOT
  485.     XCHG
  486.     LHLD    TRKSIZ    ; BY ONE TRACK
  487.     DAD    D
  488.     SHLD    BUF0A
  489.     LDA    NTRC    ;COUNT OFF LAST TRACK
  490.     DCR    A
  491.     JNZ    RDNT    ;IF MORE ROOM, GO READ
  492. ;
  493. WRLOOP:    LDA    STRK    ;REWIND CURR TRK #
  494.     STA    HSTTRK    ; FOR WRITE
  495.     LXI    H,BUF0    ;DITTO BUF PTR
  496.     SHLD    BUF0A
  497. ;
  498. ;  HERE IF FORMATTING ONLY
  499. ;
  500. WONLY:    LDA    DSTDSK    ;SELECT DESTINATION DRIVE
  501.     STA    HSTDSK
  502.     LDA    NTR    ;WRITE THIS MANY TRKS
  503. ;
  504. WRNT:    STA    NTRC    ;THIS MANY LEFT TO WRITE
  505.     XRA    A    ;REWIND COMPARE ERR CNT
  506.     STA    CMPERR
  507. RETRYW:
  508.     CALL    BCNSCK    ;CHECK FOR CONSOLE ABORT
  509.     ORA    A
  510.     CNZ    ABORT    ;IF CTRL-C, NO RETURN
  511.     CALL    WRITET    ;WRITE TRACK
  512.     CALL    COMPT    ;REREAD AND COMPARE
  513.     JNZ    RETRYW    ;RETRY IF ERR
  514. ;
  515. ;  Check to see if we just wrote track zero. If so,
  516. ; make sure the Lifeboat label area is set to 0E5H's,
  517. ; just in case we are formatting. If we are in fact
  518. ; copying, it doesn't matter, since we're done with
  519. ; this track anyway.
  520. ;
  521.     LDA    HSTTRK    ;See if just wrote track zero
  522.     ORA    A
  523.     JNZ    SKPW    ;Pass if not
  524.     LXI    H,BUF0+IDOFF    ;If so, pt to label area
  525.     MVI    B,IDLEN    ;This many bytes to fill
  526. ;
  527. FFIX:    MVI    M,0E5H    ;Stuff an E5
  528.     INX    H
  529.     DCR    B    ;Count it off
  530.     JNZ    FFIX    ;Do the whole label
  531. ;
  532. ;  HERE TO SKIP TRACK WRITE ON VALIDATE ONLY
  533. ;
  534. SKPW:    LDA    HSTTRK
  535.     INR    A
  536.     STA    HSTTRK
  537.     LXI    H,TRKSRT+1 ;POINT TO LAST TRACK+1 STORAGE
  538.     CMP    M    ;ARE WE DONE?
  539.     RZ        ;RETURN TO CALLER IF SO
  540.     LHLD    BUF0A    ;ADVANCE BUF PTR IF NOT
  541.     XCHG
  542.     LHLD    TRKSIZ    ; BY ONE TRACK
  543.     DAD    D
  544.     SHLD    BUF0A
  545.     LDA    NTRC    ;COUNT OFF LAST TRK
  546.     DCR    A
  547.     JNZ    WRNT    ;GO BACK IF MORE TO WRITE
  548.     JMP    RDLOOP    ;IF NOT, GO READ NEXT BUFFER
  549. ;
  550. ;
  551. COMPT:    LXI    H,MESGF    ;Load address of msg for
  552.     SHLD    IOEMSG    ; destination read error
  553.     LXI    H,BUF1
  554.     CALL    RT2    ;REREAD INTO BUF1
  555.     LHLD    TRKSIZ    ;GET TRACK SIZE IN BYTES
  556.     MOV    B,H    ; INTO BC
  557.     MOV    C,L
  558.     LHLD    BUF0A
  559.     LXI    D,BUF1
  560. CMPLP:    LDAX    D
  561.     CMP    M
  562.     JNZ    CERR
  563.     INX    H
  564.     INX    D
  565.     DCX    B
  566.     MOV    A,C    ;End of buffer yet?
  567.     ORA    B
  568.     JNZ    CMPLP    ;Keep checking if not
  569.     RET
  570. CERR:    PUSH    H
  571.     LXI    H,MESGA
  572.     CALL    MSGOT    ;REPORT COMPARE ERROR
  573.     LDA    HSTTRK
  574.     CALL    HXBOT
  575.     LXI    H,MESGB
  576.     CALL    MSGOT
  577.     POP    H
  578.     LDA    BUF0A    ;CALC OFFSET INTO BUFFER
  579.     SUB    L
  580.     LDA    BUF0A+1    ;ONLY NEED KEEP HIGH
  581.     SBB    H
  582.     MOV    H,A    ;SAVE FOR NOW
  583.     LDA    NSCNT    ;GET DENSITY FLAG
  584.     ORA    A    ;SET ZERO COND CODE IF DOUBLE DENS
  585.     MOV    A,H
  586.     JNZ    CERRSD    ;NUMBER RIGHT IF SINGLE DENS
  587.     RAR        ;A DOUBLE DENS SECTOR IS TWO PAGES
  588. CERRSD:    CALL    HXBOT    ;PRINT SECTOR
  589.     LDA    CMPERR
  590.     INR    A
  591.     STA    CMPERR    ;INCREMENT ERROR COUNT
  592.     CPI    10
  593.     RNZ
  594.     LXI    H,MESGC    ;REPORT GIVING UP
  595.     CALL    MSGOT
  596.     XRA    A
  597.     RET
  598. ;
  599. ;
  600. READT:    LXI    H,MESGD    ;Load address of msg for
  601.     SHLD    IOEMSG    ; source read error
  602.     LHLD    BUF0A
  603. ;
  604. ;  ENTER HERE WITH IOEMSG AND HL PRELOADED FOR
  605. ; COMPARE TRACK READ
  606. ;
  607. RT2:    SHLD    HSTADR
  608.     CALL    SETUP        ;SELECT DRIVE AND
  609.                 ; SEEK TO TRACK
  610.     LDA    ERFLAG        ;CHECK FOR ERRORS
  611.     ORA    A
  612.     CNZ    FAILR    ;Index pulse not found is fatal
  613.     MVI    C,0
  614. RT3:    PUSH    B
  615.     MOV    A,C
  616.     STA    HSTSEC
  617.     CALL    READ
  618.     LDA    NSDENS    ;CHECK FOR DENSITY MISMATCH
  619.     MOV    C,A
  620.     LDA    NSCNT
  621.     CMP    C
  622.     JZ    RT4    ;GO ON IF OK
  623.     MVI    A,5    ;SET ERROR IF NOT
  624.     STA    ERFLAG
  625.     LXI    H,SDEMSG
  626.     CALL    DSKERR    ;RAT ON BAD SECTOR
  627. RT4:    LDA    ERFLAG
  628.     ORA    A    ;Any errors?
  629.     CNZ    FAILR
  630.     LHLD    HSTADR    ;Advance read address
  631.     XCHG
  632.     LHLD    BLKSIZ
  633.     DAD    D
  634.     SHLD    HSTADR
  635.     POP    B
  636.     MVI    A,LASTSEC
  637.     CMP    C
  638.     RZ
  639.     INR    C
  640.     JMP    RT3
  641. ;
  642. ;
  643. WRITET:    LHLD    BUF0A
  644.     SHLD    HSTADR
  645.     CALL    SETUP        ;SELECT DRIVE AND
  646.                 ; SEEK TO TRACK
  647.     LDA    ERFLAG        ;CHECK FOR ERRORS
  648.     ORA    A
  649.     CNZ    FAILW    ;Index pulse not found is fatal
  650.     MVI    C,0
  651. WT3:    PUSH    B
  652.     MOV    A,C
  653.     STA    HSTSEC
  654.     CALL    WRITE
  655.     LDA    ERFLAG
  656.     ORA    A    ;Any errors?
  657.     CNZ    FAILW
  658.     LHLD    HSTADR    ;Advance write address
  659.     XCHG
  660.     LHLD    BLKSIZ
  661.     DAD    D
  662.     SHLD    HSTADR
  663.     POP    B
  664.     MVI    A,LASTSEC
  665.     CMP    C
  666.     RZ
  667.     INR    C
  668.     JMP    WT3
  669. ;************************************************************
  670. SYSSET:
  671.     CALL    ASKSRC
  672.     CALL    ASKDST
  673.     CALL    PRNTS1
  674.     LXI    H,SSYS
  675.     CALL    MSGOT
  676.     CALL    PRNTS2
  677.     MVI    L,0        ;FIRST TRACK TO TRANSFER
  678.     MVI    H,2        ;LAST TRACK PLUS ONE
  679.     JMP    PUTPAR
  680. ;************************************************************
  681. DATSET:
  682.     CALL    ASKSRC
  683.     CALL    ASKDST
  684.     CALL    PRNTS1
  685.     LXI    H,SDAT
  686.     CALL    MSGOT
  687.     CALL    PRNTS2
  688.     MVI    L,2        ;FIRST TRACK TO TRANSFER
  689.     LDA    LASTTRK        ;Last track plus one
  690.     INR    A
  691.     MOV    H,A
  692.     JMP    PUTPAR
  693. ;************************************************************
  694. ALLSET:
  695.     CALL    ASKSRC
  696.     CALL    ASKDST
  697.     CALL    PRNTS1
  698.     LXI    H,SALL
  699.     CALL    MSGOT
  700.     CALL    PRNTS2
  701.     JMP    DOALL        ;DO ALL TRACKS
  702. ;************************************************************
  703. ;
  704. ;  Format disk. Fill BUF0 with 0E5H's, except for a Lifeboat-
  705. ; compatible label, so that Lifeboat CP/M can read and write
  706. ; our disks. After track zero is formatted, COPY will make
  707. ; the entire buffer 0E5H again by overwriting the label.
  708. ;
  709. FORSTD:    CALL    ASKDST
  710.     STA    DFORD
  711.     LXI    H,DFOR
  712.     CALL    MSGOT
  713.     LDA    LASTTRK        ;Set for all tracks
  714.     INR    A
  715.     MOV    H,A
  716.     MVI    L,0
  717.     SHLD    TRKSRT
  718.     CALL    SETDD        ;SET UP DOUBLE DENS VARS
  719.     LXI    D,IDD        ;PT TO DOUBLE DENS ID
  720. ;
  721. FLBOTH:                ;MERGE HERE FROM FORSTS
  722.     MOV    B,H        ;MOVE # BYTES/TRK TO BC
  723.     MOV    C,L
  724.     LXI    H,BUF0        ;Fill track buffer with E5's
  725. FL:    MVI    M,0E5H        ;Set a byte to E5
  726.     DCX    B        ; and count it off
  727.     INX    H        ;Bop buffer ptr
  728.     MOV    A,B
  729.     ORA    C
  730.     JNZ    FL        ;Go back if more to set
  731.     LXI    H,BUF0+IDOFF    ;Now time to put in label
  732.     MVI    B,IDLEN        ;Move in this many bytes
  733. ;
  734. FL5:    LDAX    D        ;Get label byte
  735.     MOV    M,A        ; and store it
  736.     INX    H        ; then bop ptrs
  737.     INX    D
  738.     DCR    B        ;Count off a byte
  739.     JNZ    FL5        ;Go back if more
  740.     JMP    AGIN        ;DO ALL TRACKS
  741. ;
  742. ;  SINGLE DENSITY FORMAT DISK
  743. ;
  744. FORSTS:    CALL    ASKDST
  745.     STA    SFORD
  746.     LXI    H,SFOR
  747.     CALL    MSGOT
  748.     LDA    LASTTRK        ;Set for all tracks
  749.     INR    A
  750.     MOV    H,A
  751.     MVI    L,0
  752.     SHLD    TRKSRT
  753.     CALL    SETSD        ;SET UP SINGLE DENS VARS
  754.     LXI    D,IDS        ;PT TO SINGLE DENS ID
  755.     JMP    FLBOTH        ;GO MERGE WITH FORSTD
  756. ;
  757. ;  80 TRK DRIVE FORMAT
  758. ;
  759. FORS80:    CALL    ASKDST
  760.     STA    FOR80D
  761.     LXI    H,FOR80
  762.     CALL    MSGOT
  763.     LXI    H,(LASTT80+1) SHL 8 ;SET FOR ALL TRACKS
  764.     SHLD    TRKSRT
  765.     CALL    SETDD        ;SET UP DOUBLE DENS VARS
  766.     LXI    D,ID80        ;80 TRK ID
  767.     JMP    FLBOTH        ;GO MERGE WITH FORSTD
  768. ;
  769. ;  DOUBLE DENSITY VARIABLES SETUP, HL = BYTES/TRK ON RETURN
  770. ;
  771. SETDD:    LXI    H,512
  772.     SHLD    BLKSIZ        ;# BYTES/SECTOR
  773.     MVI    A,00H
  774.     STA    NSCNT        ;DENSITY FLAG = DOUBLE
  775.     LXI    H,512*(LASTSEC+1) ;# BYTES/TRACK
  776.     SHLD    TRKSIZ        ;SET TRACK SIZE
  777.     RET
  778. ;
  779. ;  SINGLE DENSITY VARIABLES SETUP, HL = BYTES/TRK ON RETURN
  780. ;
  781. SETSD:    LXI    H,256
  782.     SHLD    BLKSIZ
  783.     MVI    A,80H
  784.     STA    NSCNT
  785.     LXI    H,256*(LASTSEC+1)
  786.     SHLD    TRKSIZ
  787.     RET
  788. ;************************************************************
  789. VALSET:
  790.     CALL    ASKSRC
  791.     STA    SVALS
  792.     LXI    H,SVAL
  793.     CALL    MSGOT
  794. ;
  795. DOALL:    MVI    L,0        ;1st trk to write
  796.     LDA    LASTTRK        ;Last trk + 1
  797.     INR    A
  798.     MOV    H,A
  799. ;
  800. PUTPAR:    SHLD    TRKSRT        ;PUT PARAMETERS IN
  801.                 ; TRKSRT AND TRKSRT+1
  802. ;
  803. AGIN:    LXI    H,GOMSG        ;Wait until user ready
  804.     CALL    MSGASK        ;Print message and get reply
  805.     CPI    CR
  806.     JNZ    AGIN
  807. ;************************************************************
  808.     CALL    COPY        ;MAIN ROUTINE
  809.     LXI    H,DONMSG    ;SAY WE'RE DONE
  810.     CALL    MSGOT
  811.     JMP    LIST        ;DONE. GO ASK FOR MORE TO DO.
  812. ;
  813. ;
  814. PRNTS1:    LXI    H,S1
  815.     JMP    MSGOT
  816. ;
  817. PRNTS2:    LXI    H,S2
  818.     JMP    MSGOT
  819. ;************************************************************
  820. FAILR:    LHLD    IOEMSG    ;Get addr of appro error msg
  821.     JMP    DIE
  822. FAILW:    LXI    H,MESGE
  823. DIE:    CALL    MSGOT
  824.     JMP    LIST        ;GO TRY SOMETHING ELSE
  825. ;
  826. ;  HERE ON CONSOLE ABORT
  827. ;
  828. ABORT:    CALL    BCNSIN    ;GET CONSOLE CHAR
  829.     CPI    3    ;CTRL-C?
  830.     RNZ        ;IGNORE IF NOT
  831.     LXI    H,ABMSG
  832.     CALL    MSGOT    ;REPORT STOPPING
  833.     JMP    LIST    ;GO TRY SOMETHING ELSE
  834. ;************************************************************
  835. EXIT:    LXI    H,INSERT
  836.     CALL    MSGOT
  837.     LXI    H,WMSG
  838.     CALL    MSGOT
  839.     LXI    H,BOOT
  840.     CALL    MSGASK        ;WAIT BEFORE REBOOTING
  841.     CPI    CR
  842.     JNZ    EXIT
  843.     JMP    WBOOT        ;GO WARM BOOT CP/M
  844. ;
  845. CEXIT:    LXI    H,INSERT
  846.     CALL    MSGOT
  847.     LXI    H,CMSG
  848.     CALL    MSGOT
  849.     LXI    H,BOOT
  850.     CALL    MSGASK
  851.     CPI    CR
  852.     JNZ    CEXIT
  853.     JMP    CBOOT        ;GO COLD BOOT NORTH STAR
  854. ;
  855. ;
  856. ;
  857. ;
  858. ;  NORTH STAR MEMORY MAPPED I/O ADDRESSES
  859. ;
  860. WDATA    EQU    0E900H        ;WRITE DATA. DATA IS
  861.                 ; LOW 8 ADRESS BITS.
  862. CORDER    EQU    0EA00H        ;CONTROLLER ORDER
  863. CCMND    EQU    0EB00H        ;CONTROLLER COMMAND
  864. ;
  865. ;  MOFF SHUTS OFF THE NORTH STAR DRIVE MOTORS
  866. ; AND RESETS THE CONTROLLER.
  867. ;
  868. MOFF:    LDA    CCMND+17H    ;RESET CONTROLLER
  869.     RET
  870. ;
  871. ;  WRITEHST PERFORMS THE PHYSICAL WRITE TO THE
  872. ; NORTH STAR DISK. ON ENTRY, SECTOR IS IN HSTSEC. ON
  873. ; EXIT, ERROR FLAG IS IN ERFLAG (ZERO IF NONE).
  874. ;
  875. ;  ***  INTERRUPTS MUST BE DISABLED HERE  **
  876. ;
  877. WRITE:    DI            ;WRITE NORTH STAR
  878.     XRA    A
  879.     STA    ERFLAG        ;NO ERROR YET
  880.     LDA    CCMND+20H    ;GET B-STATUS
  881.     ANI    02H        ;IS DISK WRITE-PROTECTED?
  882.     MVI    A,6        ;ASSUME SO, ERROR CODE 6
  883.     STA    ERFLAG
  884.     JNZ    WPERR        ;WRITE ALWAYS FAILS IF SO
  885.     CALL    SEKSEC        ;WAIT FOR OUR SECTOR
  886.     LHLD    HSTADR        ;GET ADDRESS TO WRITE FROM
  887.     MVI    B,31        ;ASSUME DOUBLE DENSITY WRITE
  888.     MVI    E,2
  889.     LDA    NSCNT        ; THEN CHECK
  890.     MOV    C,A        ;PUT DATA COUNT IN C
  891.     ORA    A
  892.     JZ    WRIT5        ;GO ON IF DOUBLE D
  893.     MVI    B,15        ; ELSE CORRECT
  894.     DCR    E
  895. WRIT5:    LDA    CCMND+16H    ;INITIATE SECTOR WRITE
  896. ;
  897. WRIT10:    LDA    CCMND+15H    ;KEEP MOTORS RUNNING, GET A-STAT
  898.     ANI    08H        ;MUST LOOP UNTIL 96 USEC WINDOW
  899.     JNZ    WRIT10        ; PAST, SO LOOP WHILE WI TRUE
  900. ;
  901. ;  NOW WRITE THE 15 OR 31 BYTES OF LEADING ZEROES ON THE SECTOR
  902. ;
  903. WRIT15:    LDA    WDATA+00H    ;WRITE A BYTE OF ZEROES
  904.     NOP            ;KILL TIME
  905.     MVI    D,WDATA SHR 8    ;KILL TIME AND LOAD D FOR LATER
  906.     DCR    B        ;COUNT OFF A ZERO BYTE
  907.     JNZ    WRIT15        ;DO THEM ALL
  908. ;
  909. ;  FOLLOW WITH ONE OR TWO SYNCH BYTES
  910. ;
  911. WRIT17:    LDA    WDATA+0FBH    ;WRITE A SYNCH BYTE
  912.     DCR    E
  913.     JNZ    WRIT17        ;GO BACK IF DOUBLE D
  914. ;
  915. ;  NOW WRITE OUT 256 OR 512 BYTES. DO THIS TWO AT A TIME SO
  916. ; WE CAN USE SINGLE PRECISION COUNTER. B IS ZERO FROM ABOVE
  917. ; TO INIT THE CRC BYTE.
  918. ;
  919. WRIT20:    MOV    A,M        ;GET NEXT BYTE TO OUTPUT
  920.     MOV    E,A        ; IN OUTPUT REG
  921.     XRA    B        ;ADD INTO CHECKSUM
  922.     RLC
  923.     MOV    B,A        ;LEAVE CHECKSUM IN B
  924.     LDAX    D        ;WRITE DATA BYTE TO DISK
  925.     INX    H        ;BOP BUF PTR
  926.     MOV    A,M        ;REPEAT FOR NEXT BYTE
  927.     MOV    E,A
  928.     XRA    B
  929.     RLC
  930.     MOV    B,A
  931.     LDAX    D
  932.     INX    H
  933.     DCR    C        ;COUNT OFF LAST PAIR OF BYTES
  934.     JNZ    WRIT20        ;GO BACK IF MORE TO WRITE
  935.     MOV    E,B        ;IF NOT, TIME TO WRITE CHECKSUM
  936.     INX    B        ;KILL TIME
  937.     LDAX    D        ; THEN WRITE THE BYTE
  938.     XRA    A        ;DONE, INDICATE NO ERROR
  939.     STA    ERFLAG
  940. ;
  941. WHSTRT:    RET            ; AND RETURN TO CALLER
  942. ;
  943. WPERR:    LXI    H,WPEMSG    ;WRITE PROTECT ERROR
  944.     CALL    DSKERR        ;TELL OPERATOR
  945.     JMP    WHSTRT        ; THEN LEAVE
  946. ;
  947. ;  READHST PERFORMS THE PHYSICAL READ FROM THE
  948. ; NORTH STAR DISK. ON ENTRY, SECTOR IS IN HSTSEC. ON
  949. ; EXIT, ERROR FLAG IS IN ERFLAG (ZERO IF NONE).
  950. ;
  951. ;  ***  INTERRUPTS MUST BE DISABLED HERE  ***
  952. ;
  953. READ:    DI            ;READ NORTH STAR
  954.     MVI    A,10        ;RETRY COUNT ON ERROR
  955.     STA    RTCNT
  956. ;
  957. READRT:    CALL    SEKSEC        ;WAIT FOR OUR SECTOR
  958.     MVI    B,08CH        ;COUNT FOR SYNCH CHAR LOOP
  959.     LXI    D,CCMND+40H    ;SET UP READ DATA REGS
  960. ;
  961. ;  WAIT FOR RE SO WE CAN DO SECTOR READ, AND TEST
  962. ; THE DOUBLE DENSITY BIT.
  963. ;
  964. WAITRE:    LDA    CCMND+10H    ;GET A-STATUS
  965.     ANI    04H        ;CHECK RE
  966.     JZ    WAITRE        ;LOOP UNTIL RE TRUE
  967.     XTHL            ;KILL TIME TO GET INTO ZEROES
  968.     XTHL
  969.     XTHL
  970.     XTHL
  971.     XTHL
  972.     XTHL
  973.     XTHL
  974.     XTHL
  975.     LDA    CCMND+10H    ;GET A-STATUS AGAIN
  976.     ANI    20H        ;ARE WE READING DOUBLE DENS?
  977.     RAL            ;GET ZERO IN NSDENS IF SO
  978.     RAL            ; ELSE GET 80H
  979.     XRI    80H
  980.     STA    NSDENS
  981. ;
  982. ;  NOW WAIT FOR SYNCH CHAR DETECTED. ERROR IF WE HAVE TO
  983. ; WAIT TOO LONG.
  984. ;
  985. READ5:    LDA    CCMND+10H    ;WAIT FOR SYNCH CHAR DETECTED
  986.     RRC            ;CHECK BIT
  987.     JC    READ15        ;OUT IF GOT IT
  988.     DCR    B        ;COUNT DOWN IF NOT
  989.     JNZ    READ5        ;GO BACK IF STILL OK
  990.     MVI    A,1        ;IF WAITED TOO LONG, SYNCH ERROR
  991.     LXI    H,SYEMSG    ;SYNCH ERROR MESSAGE
  992. ;
  993. RERR:    STA    ERFLAG        ;STORE ERROR CODE
  994.     LDA    RTCNT        ;COUNT OFF A RETRY
  995.     DCR    A
  996.     STA    RTCNT
  997.     JNZ    READRT        ;IF COUNT LEFT, GO RETRY
  998. ;
  999. ;  READ ERROR RETRIES FAILED. FLAG ERROR.
  1000. ;
  1001. FRERR:    CALL    DSKERR        ;TELL OPERATOR OF ERROR THEN OUT
  1002. ;
  1003. RHSTRT:    RET
  1004. ;
  1005. ;  READ THE DATA INTO HSTBUF
  1006. ;
  1007. READ15:    LHLD    HSTADR        ;READ INTO HERE
  1008.     MVI    B,0        ;INIT CHECKSUM BYTE
  1009.     LDA    NSDENS        ;LOAD COUNT
  1010.     MOV    C,A        ; INTO C-REG
  1011. ;
  1012. READ20:    LDAX    D        ;READ NEXT DATA BYTE
  1013.     MOV    M,A        ; AND PUT IT IN BUFFER
  1014.     XRA    B        ;ADD TO CHECKSUM
  1015.     RLC
  1016.     MOV    B,A
  1017.     INX    H        ;BOP BUFFER PTR
  1018.     NOP            ;KILL TIME
  1019.     LDAX    D        ;GET NEXT BYTE
  1020.     MOV    M,A
  1021.     XRA    B
  1022.     RLC
  1023.     MOV    B,A
  1024.     INX    H
  1025.     DCR    C        ;COUNT OFF LAST PAIR
  1026.     JNZ    READ20        ;GO BACK IF MORE TO DO
  1027.     LDAX    D        ; ELSE READ CRC BYTE
  1028.     XRA    B        ; AND CHECK IT AGAINST OURS
  1029.     STA    ERFLAG        ;IF OK, ZERO EFLAG
  1030.     JZ    RHSTRT        ; AND RETURN TO CALLER
  1031.     MVI    A,2        ; ELSE FLAG CHECKSUM ERROR
  1032.     LXI    H,RERMSG    ;MESSAGE IF NEEDED
  1033.     JMP    RERR        ;GO MAYBE RETRY
  1034. ;
  1035. ;  SETUP SELECTS THE UNIT CORRESPONDING TO HSTDSK,
  1036. ; SEEKS TO THE TRACK IN HSTTRK. WRITE PRECOMPENSATION
  1037. ; IS SET IF REQUIRED AS WELL. ON ERROR, ERFLAG CONTAINS
  1038. ; A NON-ZERO VALUE ON RETURN.
  1039. ;
  1040. SETUP:    MVI    B,00H        ;ASSUME TOP SIDE
  1041.     LDA    HSTTRK        ;CHECK TARGET TRK
  1042.     STA    TRUTRK        ;ASSUME GOING HERE
  1043.     SUI    80        ;GOING TO SIDE TWO?
  1044.     JC    SIDE1        ;PASS IF NOT
  1045.     MOV    B,A        ;CALC # ON OPPOSITE SIDE
  1046.     MVI    A,80-1        ; TO MOVE BACK TOWARD
  1047.     SUB    B        ; TRK ZERO
  1048.     MVI    B,40H        ;SIDE TWO SELECT
  1049.     STA    TRUTRK        ;GOING HERE
  1050. SIDE1:
  1051.     LDA    NSCNT        ;GET DOUBLE D BIT
  1052.     XRI    80H
  1053.     MOV    C,A        ; INTO C-REG
  1054.     LDA    HSTDSK        ;WANT THIS DISK
  1055.     INR    A        ;REMAP TO CONTROLLER MASK
  1056.     CPI    03H        ;IF UNIT 1 OR 2,
  1057.     JC    SET0        ; GOT CORRECT MASK
  1058.     RAL            ;IF 3 OR 4, MUST MAP
  1059.     ANI    0CH        ; TO 4 OR 8 RESPECTIVELY
  1060. SET0:    ORA    C        ;OR IN DENSITY BIT
  1061.     ORA    B        ;OR IN SIDE MASK
  1062.     MOV    C,A        ;SAVE IN REG C
  1063.     CALL    WAIT1S        ;WAIT A SECTOR TIME, GET B-STAT
  1064.     ANI    10H        ;ARE MOTORS ALREADY ON?
  1065.     LDA    CCMND+15H    ;GIVE THEM EXTRA KICK ANYWAY
  1066.     JNZ    SET5        ;BRANCH IF SO
  1067.     MVI    D,17H        ;WAIT FOR MOTORS TO
  1068.     CALL    SCWAIT        ; COME UP TO SPEED IF NOT
  1069.     JMP    SET10        ; THEN GO SELECT DRIVE
  1070. ;
  1071. SET5:    LDA    CURDSK        ;IS THIS THE CURRENT DISK?
  1072.     CMP    C        ;COMPARE DISK AND SIDE
  1073.     JZ    SET20        ;GO SEEK TO TRACK IF SO
  1074. ;
  1075. ;  MUST SELECT NEW DISK OR SIDE
  1076. ;
  1077. SET10:    MOV    A,C
  1078.     STA    CURDSK        ;NEW CURRENT DISK
  1079.     MVI    B,CORDER SHR 8    ;SET UP FOR SELECT
  1080.     LDAX    B        ; AND DO IT
  1081.     MVI    D,2        ;WAIT TWO SECTOR TIMES
  1082.     CALL    SCWAIT        ; BEFORE LOOKING FOR INDEX
  1083.     MVI    B,12        ;DON'T LOOK TOO LONG
  1084. ;
  1085. SET15:    CALL    WAIT1S        ;WAIT ONE SECTOR TIME
  1086.     LDA    CCMND+10H    ;GET A-STATUS
  1087.     ANI    40H        ;INDEX HOLE SEEN?
  1088.     JNZ    SET20        ;CAN GO SEEK NOW IF SO
  1089.     DCR    B        ;COUNT DOWN IF NOT
  1090.     JNZ    SET15        ; AND MAYBE GO LOOK AGAIN
  1091. ;
  1092. ;  INDEX HOLE NOT FOUND. THAT'S A FATAL ERROR.
  1093. ;
  1094.     MVI    A,4        ;NO INDEX PULSE
  1095.     STA    ERFLAG
  1096.     LXI    H,NIPMSG
  1097.     JMP    DSKERR        ;GO TELL OPERATOR ON WAY OUT
  1098. ;
  1099. ;  SEEK TO TRACK SPECIFIED BY TRUTRK NOW, AND SET
  1100. ; WRITE PRECOMPENSATION IF APPROPRIATE.
  1101. ;
  1102. SET20:    CALL    SEEK        ;SEEK TO TRUTRK
  1103.     LDA    TRUTRK        ;WHERE ARE WE?
  1104.     CPI    14H+1        ;ARE WE BEYOND TRACK 14H?
  1105.     JC    SET25        ;GO ON IF NOT
  1106.     LDA    NSCNT        ;WRITING DOUBLE DENSITY?
  1107.     ORA    A
  1108.     JNZ    SET25        ;NO PRECOMP IF NOT
  1109.     LDA    CURDSK        ;IF SO, GET CURRENT MASK
  1110.     ORI    20H        ; AND SET PRECOMP BIT
  1111.     MVI    H,CORDER SHR 8
  1112.     MOV    L,A
  1113.     MOV    A,M        ;SET BIT IN CONTROLLER
  1114. SET25:    XRA    A        ;NO ERRORS
  1115.     STA    ERFLAG
  1116.     RET            ;SETUP IS DONE
  1117. ;
  1118. ;  HERE TO POSITION TO HSTSEC WITHIN THE CURRENT TRACK.
  1119. ;
  1120. SEKSEC:    LDA    HSTSEC        ;GET TARGET SECTOR
  1121.     MOV    C,A        ;IN C
  1122.     STA    ERSEC        ;SET UP FOR POSSIBLE ERROR
  1123. ;
  1124. SET30:    CALL    WAIT1S        ;WAIT FOR NEXT SECTOR
  1125.     LDA    CCMND+35H    ;KICK MOTORS AND GET SECNUM
  1126.     ANI    0FH        ;STRIP NON-SECTOR BITS
  1127.     CMP    C        ;IS THIS THE TARGET SECTOR?
  1128.     JNZ    SET30        ;WAIT UNTIL IT IS
  1129.     RET            ;POSITIONED TO SECTOR
  1130. ;
  1131. ;  SEEK TO TRACK SPECIFIED BY TRUTRK. CURRENT OFFSET INTO
  1132. ; NSTRK TABLE IS GIVEN BY HSTDSK.
  1133. ;
  1134. SEEK:    LDA    TRUTRK        ;GET TARGET TRACK
  1135.     MOV    D,A        ; INTO D
  1136.     LDA    HSTDSK        ;GET NSTRK INDEX
  1137.     MOV    C,A
  1138.     MVI    B,0
  1139.     LXI    H,NSTRK        ;PT AT TABLE
  1140.     DAD    B        ; THEN AT CORRECT ENTRY
  1141.     MOV    A,M        ;GET CURRENT TRACK
  1142.     INR    A        ;IS THIS DISK NEW?
  1143.     JNZ    SEEK5        ;PASS IF NOT
  1144.     PUSH    D        ;MUST HOME HEAD IF SO
  1145.     STA    TRUTRK        ; TO KNOW WHERE WE ARE
  1146.     MVI    A,90        ;MAKE SURE STEP TO ZERO
  1147.     MOV    M,A
  1148.     PUSH    H
  1149.     CALL    SEEK        ;GO TO TRACK ZERO
  1150.     POP    H
  1151.     POP    D
  1152.     MOV    A,D
  1153.     STA    TRUTRK        ;RESTORE TRUTRK
  1154. ;
  1155. SEEK5:    MOV    A,D
  1156.     SUB    M        ;SEE HOW FAR AWAY WE ARE
  1157.                 ; FROM TARGET TRACK
  1158.     MOV    M,D        ; BUT ALWAYS SET NEW TRACK
  1159.     RZ            ;IF THERE, DONE
  1160.     LXI    H,CORDER+30H    ;ASSUME STEPPING IN
  1161.     MOV    C,A        ;SAVE STEP COUNT
  1162.     JP    STEPIN        ;BRANCH IF RIGHT
  1163.     CMA            ;IF WRONG, NEGATE COUNT
  1164.     INR    A
  1165.     MOV    C,A        ; THEN SAVE THAT
  1166.     LDA    CCMND+20H    ;GET B-STATUS
  1167.     ANI    01H        ;ARE WE ON TRACK ZERO?
  1168.     RNZ            ;MUST BE DONE IF SO
  1169.     MVI    L,10H        ;IF NOT, STEPPING OUT
  1170. ;
  1171. STEPIN:    LDA    CURDSK        ;GET CURRENT UNIT MASK
  1172.     ORA    L        ;FORM FINAL CORDER VALUE
  1173.     MOV    L,A
  1174.     MOV    D,M        ;SET THE STEP FLIP-FLOP
  1175.     ORI    10H
  1176.     MOV    L,A
  1177.     MOV    D,M        ;SET IT AGAIN FOR SOME REASON
  1178.     XRI    10H
  1179.     MOV    L,A
  1180.     MOV    D,M        ;NOW RESET THE STEP FLIP-FLOP
  1181. ;
  1182. ;  WAIT WHILE HEAD STARTS MOVING
  1183. ;
  1184.     MVI    A,14H
  1185. STEPW1:    MVI    D,38H
  1186. STEPW2:    DCR    D        ;KILL TIME
  1187.     JNZ    STEPW2
  1188.     DCR    A
  1189.     JNZ    STEPW1
  1190. ;
  1191. ;  THE STEP RATE DETERMINES HOW LONG TO WAIT. ONE SECTOR
  1192. ; TIME IS 20 MSEC. A SLOW SHUGART SA400 MAY REQUIRE 40
  1193. ; MSEC, OR TWO SECTOR TIMES. MOST TYPICAL SA400'S WILL
  1194. ; WORK WITH 20 MSEC, SO THAT'S WHAT WE'LL USE HERE. WE
  1195. ; WILL CALL SCWAIT INSTEAD OF WAIT1S IN CASE WE NEED TO
  1196. ; PATCH THIS VALUE.
  1197. ;
  1198.     MVI    D,1        ;NOW WAIT 20 MSEC
  1199. ;    MVI    D,2        ;NOW WAIT 40 MSEC
  1200.     CALL    SCWAIT
  1201.     LDA    CCMND+25H    ;GET B-STATUS AND KICK MOTORS
  1202.     ANI    01H        ;ARE WE AT TRACK ZERO?
  1203.     JNZ    WAIT1S        ;DONE STEPPING IF SO
  1204.     DCR    C        ; ELSE COUNT OFF LAST TRACK
  1205.     JNZ    STEPIN        ;GO BACK IF MORE TO DO
  1206.                 ; ELSE WAIT ONE MORE SECTOR TIME
  1207.                 ; TO MAKE SURE SAFE FOR I/O
  1208. ;
  1209. ;  SECTOR WAIT. ON ENTRY, # SECTORS TO WAIT IS IN D.
  1210. ; ON EXIT, D=0 AND ACC=A-STATUS. CALL WAIT1S TO WAIT
  1211. ; ONE SECTOR TIME.
  1212. ;
  1213. WAIT1S:    MVI    D,1        ;WAIT ONE SECTOR TIME
  1214. ;
  1215. SCWAIT:    LDA    CCMND+11H    ;RESET SECTOR FLAG
  1216. SCW5:    LDA    CCMND+10H    ;GET A-STATUS
  1217.     ORA    A        ;CHECK SECTOR FLAG
  1218.     JP    SCW5        ;WAIT FOR IT IF NOT UP
  1219.     LDA    CCMND+11H    ; ELSE RESET SECTOR FLAG
  1220.     DCR    D        ;COUNT DOWN WAIT COUNTER
  1221.     JNZ    SCW5        ;GO BACK IF MORE TO DO
  1222.     RET            ; ELSE RETURN A-STATUS IN ACC
  1223. ;
  1224. ;  DISK ERRORS REPORTED HERE
  1225. ;
  1226. DSKERR:    PUSH    H        ;SAVE BODY ADDRESS
  1227.     MVI    A,CR        ;EJECT LINE
  1228.     CALL    CNSOT
  1229.     MVI    A,LF
  1230.     CALL    CNSOT
  1231.     POP    H
  1232.     CALL    MSGOT        ;REPORT BODY
  1233.     LDA    HSTDSK        ;THIS DISK
  1234.     ADI    'A'
  1235.     STA    ASCDSK
  1236.     LXI    H,ERRMSG
  1237.     CALL    MSGOT
  1238.     LDA    HSTTRK        ;THIS TRACK
  1239.     CALL    HXBOT
  1240.     LXI    H,SECMSG
  1241.     CALL    MSGOT
  1242.     LDA    ERSEC        ;THIS SECTOR
  1243.                 ;FALL INTO HXBOT TO FINISH
  1244. ;
  1245. ;  DISPLAY HEXIDECIMAL EQUIVALENT OF ACC CONTENTS
  1246. ;
  1247. HXBOT:    PUSH    PSW        ;SAVE CHAR
  1248.     RRC            ;SWAP NIBBLES
  1249.     RRC
  1250.     RRC
  1251.     RRC
  1252.     CALL    HXNOT        ;OUTPUT HIGH NIBBLE
  1253.     POP    PSW        ; THEN LOW NIBBLE
  1254. HXNOT:    ANI    0FH        ;STRIP HIGH NIBBLE
  1255.     CPI    10        ;LESS THAN 10
  1256.     JC    HXNNM        ;PASS IF SO
  1257.     ADI    'A'-'9'-1    ;ADD LETTER OFFSET
  1258. HXNNM:    ADI    '0'        ;MAKE ASCII
  1259. ;
  1260. CNSOT:    PUSH    H        ;Save all regs
  1261.     PUSH    D
  1262.     PUSH    B        ; but PSW
  1263.     MOV    C,A
  1264.     CALL    BCNSOT        ;OUTPUT CHAR TO CONSOLE
  1265.     POP    B        ;Restore regs
  1266.     POP    D
  1267.     POP    H
  1268.     RET            ;Return to caller
  1269. ;
  1270. CNSIN:    PUSH    H        ;SAVE ALL REGS
  1271.     PUSH    D
  1272.     PUSH    B
  1273.     CALL    BCNSIN        ;READ CONSOLE CHAR
  1274.     MOV    C,A        ;CHAR TO C FOR ECHO
  1275.     PUSH    PSW        ;SAVE CHAR READ
  1276.     CPI    20H        ;IS CHAR DISPLAYABLE?
  1277.     CNC    BCNSOT        ;ECHO TO OUTPUT IF SO
  1278.     POP    PSW        ;RESTORE CHAR READ
  1279.     POP    B        ;RESTORE BC AND DE
  1280.     POP    D
  1281.     CPI    3        ;CHECK FOR CTRL-C
  1282.     LXI    H,CTCMSG    ;IN CASE GOT
  1283.     CZ    MSGOT        ;ECHO IF GOT
  1284.     POP    H        ;RESTORE HL NOW
  1285.     CPI    'A'+20H        ;FOLD LOWER CASE TO UPPER
  1286.     RC
  1287.     CPI    'Z'+20H+1
  1288.     RNC
  1289.     SUI    20H
  1290.     RET
  1291. ;
  1292. MSGASK:    CALL    MSGOT    ;OUTPUT MSG @HL
  1293.     CALL    CNSIN    ;GET OPERATOR REPLY
  1294.     CPI    3    ;CTRL-C?
  1295.     JZ    LIST    ;BACK TO MENU IF SO
  1296.     LXI    H,CRLF    ;EJECT LINE IF NOT, THEN
  1297.             ; RET CHAR IN ACC
  1298. ;
  1299. MSGOT:    PUSH    PSW        ;SAVE CALLER FLAGS
  1300. MSGL:    MOV    A,M        ;LOAD CHAR
  1301.     CPI    '$'        ;END OF STRING?
  1302.     JZ    MSGR        ;OUT IF SO
  1303.     CALL    CNSOT        ;IF NOT, OUTPUT CHAR
  1304.     INX    H        ;ADVANCE PTR
  1305.     JMP    MSGL        ;GO BACK FOR NEXT CHAR
  1306. ;
  1307. MSGR:    POP    PSW        ;RESTORE CALLER PSW
  1308.     RET
  1309. ;
  1310. ;  BIOS JUMP VECTORS STUFFED HERE AT PROG STARTUP
  1311. ;
  1312. BVECT:    JMP    $-$    ;WARM BOOT
  1313. BCNSCK:    JMP    $-$    ;CONSOLE STATUS TO ACC
  1314. BCNSIN:    JMP    $-$    ;CONSOLE INPUT TO ACC
  1315. BCNSOT:    JMP    $-$    ;CONSOLE OUTPUT FROM C
  1316. ;
  1317. BVECTL:    EQU    $-BVECT    ;# BYTES OF VECTORS
  1318. ;
  1319. ;  DISK ERROR MESSAGES
  1320. ;
  1321. WPEMSG:    DB    'Protect$'
  1322. SDEMSG:    DB    'Density mismatch$'
  1323. RERMSG:    DB    'CRC$'
  1324. SYEMSG:    DB    'No synch$'
  1325. NIPMSG:    DB    'No index$'
  1326. ;
  1327. ERRMSG:    DB    ' err on '
  1328. ASCDSK:    DB    ' :, trk $'
  1329. SECMSG:    DB    ', sec $'
  1330. ;
  1331. ;  NORTH STAR DRIVER CURRENT TRACK TABLE
  1332. ;
  1333. NSTRK:    DS    4    ;EACH ENTRY CONTAINS THE
  1334.             ; LAST TRACK POSITION FOR
  1335.             ; UNIT 1-4
  1336.             ; 0FFH=NEVER ACCESSED
  1337. ;
  1338. ;  NORTH STAR DRIVER VARIABLES
  1339. ;
  1340. HSTDSK:    DS    1    ;HOST DISK NUMBER
  1341. ERFLAG:    DS    1    ;ERROR REPORTING
  1342. CURDSK:    DS    1    ;CURRENT ACTIVE DISK,
  1343.             ; 0FFH=NONE YET
  1344. NSDENS:    DS    1    ;DENSITY FLAG FOR LAST
  1345.             ; BLOCK READ. DD=00H, SD=80H
  1346. NSCNT:    DS    1    ;DENSITY FLAG AND COUNT FOR
  1347.             ; NEXT BLOCK TO WRITE. DD=00H,
  1348.             ; SD=80H
  1349. TRKSIZ:    DS    2    ;# BYTES/TRACK
  1350. BLKSIZ:    DS    2    ;# BYTES/SECTOR
  1351. HSTADR:    DS    2    ;XFER MEM ADDRESS
  1352. HSTTRK:    DS    1    ;HOST TRACK NUMBER
  1353. TRUTRK:    DS    1    ;TRACK # AFTER SIDE ADJUST
  1354. HSTSEC:    DS    1    ;HOST SECTOR NUMBER
  1355. RTCNT:    DS    1    ;ERROR RETRY COUNTER
  1356. ERSEC:    DS    1    ;SECTOR IN ERROR
  1357. ;
  1358. ;  MAIN COPY PROGRAM DATA AREA
  1359. ;
  1360. TRKSRT:    DS    2    ;STORAGE FOR FIRST AND
  1361.             ; LAST+1 TRACK NUMBERS
  1362. BUF0A:    DS    2    ;CURR READ TRK ADDR
  1363. NTR:    DS    1    ;# TRKS THAT FIT IN BUF0
  1364. NTRC:    DS    1    ;NTR COUNTER
  1365. STRK:    DS    1    ;START TRK # IN BUF0
  1366. CTRK:    DS    1    ;CURR TRK # FOR STATUS IN
  1367.             ; ASCII, LOW DIGIT ONLY
  1368. CMPERR:    DS    1    ;NUMBER OF COMPARE ERRORS
  1369. FUNC:    DS    1    ;SELECTED FUNCTION NUMBER
  1370. SRCDSK:    DS    1    ;SOURCE DRIVE NUMBER
  1371. DSTDSK:    DS    1    ;DESTINATION DRIVE NUMBER
  1372. IOEMSG:    DS    2    ;FAILR (read error) msg addr
  1373. STK:    DS    128
  1374. STKTOP:    DS    1
  1375. ;
  1376. BUF1:    DS    512*(LASTSEC+1)    ;COMPARE BUFFER
  1377. BUF0:            ;BIG READ BUFFER (UP TO BIOS)
  1378. ;
  1379.     END
  1380.