home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / lambda / soundpot / a / disktest.lbr / DISKTEST.MZC / DISKTEST.MAC
Encoding:
Text File  |  1993-10-26  |  23.5 KB  |  1,082 lines

  1. ;    'Z-80 Floppy Disk Test'
  2. ; Floppy Disk Test for Z-80 CP/M Systems
  3. ;
  4. ; version 1.0  16 December 1980
  5. ; version 1.1   2 January  1984 DmC
  6. ;
  7. ; Resale of this program is PROHIBITED
  8. ;
  9. ; Copyright (c) 1980 by
  10. ; Ray Duncan
  11. ; Laboratory Microsystems
  12. ; 4147 Beethoven Street
  13. ; Los Angeles, CA 90066
  14. ;
  15. ; Modified for the Kaypro Computer Line
  16. ; By Micro Cornucopia Magazine
  17. ;
  18.  
  19.     aseg
  20.     .z80
  21.     org    100h
  22. ;
  23. cpm    equ    5    ;references to
  24. wboot    equ    0     ;operating system
  25. ;
  26. ;            references to ASCII char
  27. cr    equ    0dh
  28. lf    equ    0ah
  29. ff    equ    0ch
  30. tab    equ    09h
  31. ;
  32. ;            parameters for disk
  33. ;
  34. ;
  35. $drvf    equ    0    ;first drive to allow
  36.             ;testing (0=A,1=B,etc)
  37. $drvl    equ    1    ;last drive to allow
  38.             ;testing
  39. $trkf    equ    0    ;first track
  40. $trkl    equ    39    ;last track
  41. $secf    equ    0    ;first sector
  42. $secl    equ    39    ;last sector
  43. $bps    equ    128    ;bytes per sector
  44. $bpt    equ    5120    ;bytes per track
  45. ;
  46.             ;number of digits to
  47.             ;accept in track and
  48.             ;sector assignments
  49. $dig    equ    3    ;(should be set larger
  50.             ; for devices having 
  51.             ; track or sector
  52.             ; numbers >99 )
  53. ;
  54. ;            program identification
  55. $ver    equ    1    ;version
  56. $rev    equ    1    ;revision (kaypro is rev 1 DmC)
  57. ;
  58.  
  59.     jp    dtst    ;enter from CP/M
  60.  
  61.  
  62. ; global variables for use by all routines
  63. ;
  64. pass:    dw    0    ;current pass number
  65. errors:    dw    0    ;error count for pass
  66. ;
  67.             ;the following variables
  68.             ;are used by RDBUF and
  69.             ;WTBUF to address the
  70.             ;disk, and by PERR to
  71.             ;display failing disk
  72.             ;addresses ---
  73. drv:    db    0    ;drive to test
  74. trk:    dw    0    ;current track
  75. sec:    dw    0    ;current sector
  76. buffer:    dw    0    ;current memory address
  77. iolen:    dw    0    ;bytes last transferred
  78.             ;
  79.             ;the following variables
  80.             ;define the area to be
  81.             ;tested on the selected
  82.             ;disk drive ---
  83. trkf:    dw    0    ;first track to test
  84. trkl:    dw    0    ;last track to test
  85. secf:    dw    0    ;first sector to test
  86. secl:    dw    0    ;last sector to test
  87.             ;
  88.             ;the following variables
  89.             ;define the test mode ---
  90.             ;
  91. bypass:    db    0    ;0=do not bypass error
  92.             ;itemization, 1=bypass
  93.             ;error itemization,print
  94.             ;total errors per pass
  95.             ;only.
  96.             ;
  97. skew:    db    0    ;0=no sector skew
  98.             ;1=use sector skew for
  99.             ;  increased test speed
  100.             ;
  101. list:    db    0    ;0=print errors on
  102.             ;terminal, 1=print errors
  103.             ;on list device.
  104.             ;
  105. lockio:    db    0    ;0=no lock
  106.             ;1=lock on read
  107.             ;2=lock on write
  108.             ;
  109. restor:    db    0    ;0=do not restore original
  110.             ;data, 1=restore original
  111.             ;data on diskette
  112.             ;
  113. lockpt:    db    0    ;0=use variable test
  114.             ;data pattern, 1=lock on
  115.             ;user supplied data pattern
  116.             ;
  117. pattrn:    db    0    ;contains user supplied
  118.             ;8 bit data pattern
  119.             ;
  120. passl:    dw    0    ;last pass to do on this
  121.             ;test run
  122.             ;
  123. digits:    db    $dig    ;maximum number of digits
  124.             ;to be accepted during
  125.             ;decimal or hexadecimal
  126.             ;numeric input.
  127.             ;
  128. xtran:    dw    sectrb    ;address of sector
  129.             ;translation table
  130. ;
  131. ; disk test --- main control
  132. ;
  133. dtst:                ;entry from CP/M
  134.     ld    de,dtsta    ;print program title
  135.     ld    c,9
  136.     call    cpm
  137.     ld    hl,(cpm+1)
  138.     ld    de,buffend
  139.     or    a        ;make sure enough user
  140.     sbc    hl,de        ;memory to execute test
  141.     jr    nc,dtst01
  142.     ld    de,dtsts    ;not enough memory,
  143.     ld    c,9        ;print warning and exit.
  144.     call    cpm
  145.     jp    wboot
  146. dtst01: ld    c,12        ;check CP/M version
  147.     call    cpm
  148.     ld    a,l        ;make sure 2.x
  149.     and    0f0h
  150.     cp    20h
  151.     jr    z,dtst02
  152.     ld    de,dtstz    ;not CP/M 2.x, print
  153.     ld    c,9        ;error message and exit
  154.     call    cpm
  155.     jp    wboot
  156. dtst02:    xor    a        ;initialize variables
  157.     ld    (bypass),a
  158.     ld    (skew),a
  159.     ld    (list),a
  160.     ld    (lockio),a
  161.     ld    (restor),a
  162.     ld    (lockpt),a
  163.     ld    (pass),a
  164.     ld    (pass+1),a
  165.     ld    (errors),a
  166.     ld    (errors+1),a
  167.                 ;now set up test
  168.                 ;configuration
  169.     ld    de,dtstb
  170.     call    getyn        ;itemize errors?
  171.     cp    'y'
  172.     jr    z,dtst03    ;yes
  173.     ld    a,1        ;no
  174.     ld    (bypass),a
  175.     jr    dtst04        ;skip query for output
  176.                 ;device, since errors
  177.                 ;will not be listed
  178. dtst03:    ld    de,dtstc    ;audit errors on console
  179.     call    getl        ;or line printer?
  180.     cp    'c'
  181.     jr    z,dtst04    ;c=use console 
  182.     cp    'p'
  183.     call    nz,query
  184.     jr    nz,dtst03    ;no match,try again
  185.     ld    a,1        ;p=use line printer
  186.     ld    (list),a
  187. dtst04:    ld    de,dtstd    ;lock on read or write?
  188.     call    getl
  189.     cp    'n'        ;n=no locks
  190.     jr    z,dtst06
  191.     cp    'r'        ;r=lock on read
  192.     jr    nz,dtst05
  193.     ld    a,1
  194.     ld    (lockio),a
  195.     jr    dtst12        ;bypass querys about
  196.                 ;restore mode and
  197.                 ;data pattern: since
  198.                 ;we are locked in read
  199.                 ;mode, they are
  200.                 ;irrelevant.
  201.                 ;
  202. dtst05:    cp    'w'        ;w=lock on write
  203.     call    nz,query
  204.     jr    nz,dtst04     ;no match,try again
  205.     ld    a,2
  206.     ld    (lockio),a
  207.     jr    dtst08        ;bypass restore question,
  208.                 ;since we are locked in
  209.                 ;write mode.
  210.                 ;
  211. dtst06:    ld    de,dtste    ;restore user data?
  212.     call    getyn
  213.     cp    'y'        ;y=restore
  214.     jr    nz,dtst08 
  215.     ld    a,1        ;n=do not restore
  216.     ld    (restor),a
  217. dtst08:    ld    de,dtstf    ;lock on data pattern?
  218.     call    getyn
  219.     cp    'n'
  220.     jr    z,dtst12    ;n=use variable pattern
  221.     ld    a,1        ;y=lock on pattern
  222.     ld    (lockpt),a     ;supplied by operator
  223.     ld    de,dtstg    ;accept data pattern
  224.     call    geth        ;from keyboard
  225.     ld    (pattrn),a
  226. dtst12:    ld    de,dtsth    ;select drive to be
  227.     call    getl        ;used for test
  228.     sub    'a'        ;convert to logical #
  229.     cp    $drvf        ;make sure its legal
  230.     call    c,query
  231.     jr    c,dtst12     ;too small,try again
  232.     cp    $drvl+1
  233.     call    nc,query
  234.     jr    nc,dtst12    ;too large,try again
  235.     ld    (drv),a        ;save drive assignment
  236.     add    a,'A'        ;also format for output
  237.     ld    (dtsti1),a
  238.     ld    de,dtsti    ;confirm selected drive?
  239.     call    getyn
  240.     cp    'n'
  241.     jr    z,dtst12    ;not confirmed,try again
  242.                 ;
  243.                 ;initialize track
  244.                 ;limits
  245.     ld    hl,$trkf
  246.     ld    (trkf),hl
  247.     ld    hl,$trkl
  248.     ld    (trkl),hl
  249. dtst15:    ld    de,dtstj    ;test all tracks?
  250.     call    getyn
  251.     cp    'y'        ;y=use all of them
  252.     jr    z,dtst20    ;n=user wants to specify
  253.                 ;  range of tracks
  254. dtst17:    ld    de,dtstk    ;enter first track
  255.     call    getn        ;to test
  256.     ld    (trkf),hl     ;save it
  257.     ld    de,dtstl    ;enter last track
  258.     call    getn        ;to test
  259.     ld    (trkl),hl     ;save it
  260.     ld    de,(trkf)    ;make sure first
  261.     or    a        ;track<=last track
  262.     sbc    hl,de
  263.     call    c,query        ;wrong,start over
  264.     jr    c,dtst17
  265. dtst20:                ;initialize sector
  266.                 ;limits
  267.     ld    hl,$secf
  268.     ld    (secf),hl
  269.     ld    hl,$secl
  270.     ld    (secl),hl
  271. dtst22:    ld    de,dtstm    ;use all sectors
  272.     call    getyn        ;of each track?
  273.     cp    'y'
  274.     jr    z,dtst26    ;y=use all sectors
  275.                 ;n=user wants to specify
  276.                 ;range of sectors
  277. dtst24:    ld    de,dtstn    ;enter first sector
  278.     call    getn        ;to test.
  279.     ld    (secf),hl     ;save it.
  280.     ld    de,dtsto    ;enter last sector
  281.     call    getn        ;to test.
  282.     ld    (secl),hl     ;save it.
  283.     ld    de,(secf)    ;make sure first
  284.     or    a        ;sector<=last sector
  285.     sbc    hl,de
  286.     call    c,query
  287.     jr    c,dtst24    ;error,start over
  288.                 ;
  289.                 ;all variables set up
  290.                 ;now --- how many
  291. dtst26:    ld    de,dtstp    ;test passes should be
  292.     call    getn        ;made?
  293.     ld    (passl),hl     ;save # of passes
  294.                 ;
  295.                 ;print advisory message
  296.     ld    de,dtstt    ;as test begins
  297.     ld    c,9
  298.     call    cpm
  299.     ld    de,dtstu    ;remind user whether he
  300.     ld    a,(restor)     ;is using restore
  301.     or    a        ;mode
  302.     jr    z,dtst32
  303.     ld    de,dtstv
  304. dtst32:    ld    c,9
  305.     call    cpm
  306.                 ;
  307. dtst40:                ;begin a pass
  308.     ld    hl,(trkf)
  309.     ld    (trk),hl    ;initialize current track
  310.                 ;
  311. dtst42:                ;process next track
  312.     ld    c,6        ;check for interruption
  313.     ld    e,0ffh
  314.     call    cpm        ;from console
  315.     or    a
  316.     jp    nz,dtst94     ;break detected,quit
  317.     ld    a,(restor)
  318.     or    a        ;is this restore mode?
  319.     jr    z,dtst45    ;no,jump
  320.     ld    hl,buff3    ;yes, save current
  321.     ld    de,merr1    ;disk contents
  322.     call    rdbuf
  323. dtst45:    ld    a,(lockio)
  324.     cp    1        ;is this lock on read?
  325.     jr    z,dtst47    ;yes,jump
  326.     ld    hl,buff1    ;set up test pattern
  327.     ld    de,$bpt    
  328.     call    bufpat
  329.     ld    hl,buff1    ;write test pattern
  330.     ld    de,merr2
  331.     call    wtbuf
  332. dtst47:    ld    a,(lockio)
  333.     cp    2        ;is this lock on write?
  334.     jr    z,dtst70    ;yes,jump
  335.     ld    hl,buff2    ;read back test pattern
  336.                 ;(or just read existing
  337.                 ; data if locked on read)
  338.     ld    de,merr3
  339.     call    rdbuf
  340. dtst50:    ld    a,(lockio)
  341.     or    a        ;is this lock on
  342.                 ;read or write?
  343.     jr    nz,dtst70     ;yes,jump
  344.                 ;no, compare test data
  345.     ld    hl,buff1    ;written to data read
  346.     ld    de,buff2    ;back from disk. If
  347.     ld    bc,merr4    ;difference found,
  348.     call    bufcmp        ;print error message
  349. dtst70:    ld    a,(restor)
  350.     or    a        ;using restore mode?
  351.     jr    z,dtst80    ;no,jump
  352.                 ;yes,write back user's
  353.                 ;data
  354.     ld    hl,buff3
  355.     ld    de,merr6
  356.     call    wtbuf
  357.     ld    hl,buff1    ;verify that
  358.     ld    de,merr7    ;it was rewritten ok
  359.     call    rdbuf
  360.     ld    hl,buff1
  361.     ld    de,buff3
  362.     ld    bc,merr5    ;check restored data
  363.     call    bufcmp
  364.                 ;if difference found,
  365.                 ;print 'data cannot
  366.                 ;be restored'
  367.                 ;
  368. dtst80:                ;advance current track
  369.     ld    de,(trk)
  370.     inc    de
  371.     ld    (trk),de
  372.     ld    hl,(trkl)
  373.     or    a        ;done with all tracks?
  374.     sbc    hl,de
  375.     jp    nc,dtst42     ;no,process another
  376.                 ;
  377. dtst90:                ;end of pass
  378.     ld    bc,(pass)
  379.     inc    bc        ;count passes
  380.     ld    (pass),bc
  381.     ld    hl,dtstr1
  382.     call    conv        ;convert pass #
  383.     ld    bc,(errors)
  384.     ld    hl,dtstr2
  385.     call    conv        ;convert error count
  386.     ld    de,dtstr    ;print pass and errors
  387.     ld    c,9        ;on console
  388.     call    cpm
  389.     ld    a,(list)    ;also using printer?
  390.     or    a
  391.     jr    z,dtst92    ;no,jump
  392.                 ;yes,also send pass
  393.                 ;and error count to
  394.                 ;list device
  395.     ld    hl,dtstr
  396.     call    perr9
  397. dtst92:                ;reset error count
  398.     xor    a
  399.     ld    (errors),a
  400.     ld    (errors+1),a
  401.     ld    hl,(pass)
  402.     ld    de,(passl)
  403.     or    a        ;are enough passes done?
  404.     sbc    hl,de
  405.     jp    c,dtst40    ;not yet,loop
  406. dtst94:                ;done with all passes
  407.     ld    de,dtstw    ;ask whether to exit
  408.     call    getl        ;or to continue test
  409.     cp    'c'        ;c=continue
  410.     jp    z,dtst
  411.     cp    'e'        ;e=exit
  412.     jr    nz,dtst94    ;if no match,try again
  413.     ld    de,dtstx    ;print goodbye
  414.     ld    c,9
  415.     call    cpm        ;and return control
  416.     jp    wboot        ;to CP/M
  417.                 ;
  418. ;
  419. ; routines to read and write up to one track
  420. ;
  421. rdbuf:                ;read current track from
  422.                 ;secf to secl
  423.                 ;
  424.                 ;call hl=buffer base addr
  425.                 ;     de=error msg addr
  426.     ld    (rdbufa),de    ;save message address
  427.     ld    (buffer),hl     ;save buffer address
  428.     ld    hl,0        ;initialize transfer byte
  429.     ld    (iolen),hl     ;count
  430.     call    seldsk        ;select disk
  431.     ld    hl,(secf)
  432.     ld    (sec),hl    ;initialize current sector
  433. rdbuf1:    call    setio        ;set up track,sector,memory
  434.     call    read        ;now request transfer
  435.     or    a        ;was i/o successful?
  436.     jr    z,rdbuf2    ;no error,jump
  437.     ld    de,(rdbufa)
  438.     call    perr        ;i/o error, audit it
  439. rdbuf2:    call    rwadv          ;advance sector address
  440.     jr    nc,rdbuf1    ;not done,read another
  441.     ret            ;back to caller
  442. rdbufa:    dw    0        ;address of error message
  443. ;
  444. wtbuf:                ;write current track
  445.                 ;from secf to secl
  446.                 ;
  447.                 ;call de=error msg addr
  448.                 ;     hl=buffer base addr
  449.                 ;
  450.     ld    (wtbufa),de     ;save message addr
  451.     ld    (buffer),hl     ;save memory addr
  452.     ld    hl,0        ;initialize transfer
  453.     ld    (iolen),hl     ;byte count
  454.     call    seldsk        ;select disk drive
  455.     ld    hl,(secf)
  456.     ld    (sec),hl    ;initialize current sector
  457. wtbuf1:    call    setio        ;set track,sector,memory
  458.     call    write        ;request disk write
  459.     or    a        ;any i/o errors?
  460.     jr    z,wtbuf2    ;no,jump
  461.     ld    de,(wtbufa)
  462.     call    perr        ;error, audit it
  463. wtbuf2:    call    rwadv          ;advance sector address
  464.     jr    nc,wtbuf1    ;not done,write another
  465.     ret            ;back to caller
  466.  
  467. wtbufa    equ    rdbufa        ;save address of error
  468.                 ;message
  469.                 ;
  470. rwadv:                ;advance sector and 
  471.                 ;memory addresses
  472.                 ;
  473.     ld    de,$bps        ; de <- bytes per sector
  474.     ld    hl,(buffer)
  475.     add    hl,de        ;update buffer address
  476.     ld    (buffer),hl
  477.     ld    hl,(iolen)
  478.     add    hl,de        ;count bytes transferred
  479.     ld    (iolen),hl
  480.     ld    de,(sec)
  481.     inc    de        ;advance current sector
  482.     ld    (sec),de
  483.     ld    hl,(secl)
  484.     or    a        ;done with all sectors?
  485.     sbc    hl,de        ;exit with carry set if
  486.                 ;done
  487.     ret
  488. ;
  489. ; set up buffer with test pattern
  490. ;
  491. bufpat:                ;call hl=address of base
  492.                 ;        of buffer
  493.                 ;     de=byte length of
  494.                 ;        area to set up
  495.     ld    a,(lockpt)
  496.     or    a        ;are we locked on user
  497.                 ;specified data pattern?
  498.     jr    nz,bufpa2    ;yes,jump
  499. bufpa1:    ld    a,r        ;read refresh register
  500.     xor    h
  501.     add    a,l
  502.                 ;make data a function of
  503.                 ;memory address
  504.     ld    (hl),a        ;and store it
  505.     inc    hl        ;advance buffer address
  506.     dec    de        ;count bytes stored
  507.     ld    a,d        ;done yet?
  508.     or    e
  509.     jr    nz,bufpa1    ;no,loop
  510.     ret
  511.  
  512. ;                user specified pattern 
  513.  
  514. bufpa2:    ld    a,(pattrn)
  515.     ld    (hl),a        ;store one byte
  516.     inc    hl        ;advance buffer address
  517.     dec    de        ;count bytes stored
  518.     ld    a,d        ;done yet?
  519.     or    e
  520.     jr    nz,bufpa2     ;not done,loop
  521.     ret            ;exit
  522. ;
  523. ;
  524. ;
  525. ; compare specified buffer and print error
  526. ; message if difference found
  527. ;
  528. ;
  529. bufcmp:                ;compare buffers
  530.                 ;
  531.                 ;call bc=address of
  532.                 ;        error message
  533.                 ;     de=address 1st buffer
  534.                 ;     hl=address 2nd buffer
  535.                 ;
  536.     ld    (bufcma),bc     ;save msg address
  537.     ld    (bufcmb),hl     ;save base of buffer
  538.     ld    bc,(iolen)     ;length to compare
  539. bufcm1:    ld    a,(de)        ;fetch byte from 1st buffer
  540.     cp    (hl)        ;compare it to 2nd buffer
  541.     jr    nz,bufcm3    ;difference found,jump
  542. bufcm2:    inc    hl        ;advance buffer addresses
  543.     inc    de
  544.     dec    bc        ;count bytes
  545.     ld    a,b        ;done yet?
  546.     or    c
  547.     jr    nz,bufcm1    ;no,loop
  548.     ret            ;back to caller
  549.                 ;
  550. bufcm3:                ;difference found, print
  551.                 ;error audit trail
  552.     push    bc        ;first save registers
  553.     push    de
  554.     push    hl
  555.     ld    de,(bufcmb)
  556.     or    a
  557.     sbc    hl,de        ;find a buffer offset
  558.     push    hl        ;now divide by bytes per
  559.     pop    bc        ;sector to find relative
  560.     ld    de,$bps        ;sector number
  561.     call    div
  562.     ld    hl,(secf)
  563.     add    hl,bc        ;add relative sector to
  564.                 ;first sector to find
  565.                 ;actual address for use
  566.                 ;by PERR
  567.     ld    (sec),hl
  568.     ld    de,(bufcma)
  569.     call    perr        ;now audit error
  570.     pop    hl        ;restore registers
  571.     pop    de
  572.     pop    bc
  573. bufcm4:                ;advance memory address
  574.                 ;out of this sector where
  575.                 ;an error was found.
  576.     inc    hl        ;bump buffer addresses
  577.     inc    de
  578.     dec    bc        ;done with all data area?
  579.     ld    a,b
  580.     or    c
  581.     ret    z        ;yes,exit compare routine
  582.     ld    a,l        ;check if on new sector  
  583.     and    $bps-1        ;boundary
  584.     jr    z,bufcm1    ;found it, go compare
  585.                 ;more data
  586.     jr    bufcm4        ;keep advancing until
  587.                 ;sector boundary.
  588.                 ;
  589. bufcma:    dw    0        ;address of error message
  590. bufcmb:    dw    0        ;base buffer address
  591. ;
  592. perr:                ;error printing routine,
  593.                 ;prints pass,drive,track,
  594.                 ;sector, and message
  595.                 ;specified by caller on
  596.                 ;console or list device.
  597.                 ;
  598.                 ; call with de=address
  599.                 ;   of message giving
  600.                 ;   type of error
  601.                 ;
  602.     ld    a,(bypass)
  603.     or    a        ;is error itemization
  604.                 ;bypass flag set?
  605.     jr    nz,perr2    ;yes,skip printing
  606.                 ;and go count errors
  607.     ld    (perra),de     ;save message addr.
  608.     ld    bc,(pass)
  609.     inc    bc
  610.     ld    hl,perrc    ;convert current pass
  611.     call    conv
  612.     ld    a,(drv)     ;form drive name
  613.     add    a,'A'
  614.     ld    (perrd),a
  615.     ld    bc,(trk)    ;convert current track
  616.     ld    hl,perre
  617.     call    conv
  618.     ld    bc,(sec)    ;convert current sector
  619.     ld    a,(skew)    ;is skew in effect?
  620.     or    a
  621.     jr    z,perr0        ;no
  622.     call    sectran        ;yes, translate sector
  623. perr0:    ld    hl,perrf
  624.     call    conv
  625.     ld    a,(list)    ;should output be on
  626.     or    a        ;console or printer?
  627.     jr    nz,perr3    ;jump,use printer
  628.                 ;fall thru,use console
  629.     ld    hl,(errors)
  630.     ld    a,h        ;is this first error?
  631.     or    l
  632.     jr    nz,perr1    ;no,jump
  633.     ld    de,dtstq    ;print title for errors
  634.     ld    c,9
  635.     call    cpm
  636. perr1:    ld    de,perrb    ;print disk address
  637.     ld    c,9
  638.     call    cpm
  639.     ld    de,(perra)
  640.     ld    c,9        ;print error type
  641.     call    cpm
  642.                 ;
  643. perr2:                ;count errors
  644.     ld    hl,(errors)
  645.     inc    hl
  646.     ld    (errors),hl
  647.     ret            ;back to caller
  648.                 ;
  649. perr3:                ;errors to printer
  650.     ld    hl,(errors)
  651.     ld    a,h        ;is this 1st error to
  652.     or    l        ;be printed this pass?
  653.     jr    nz,perr4    ;no,jump
  654.     ld    hl,dtstq    ;yes,print title
  655.     call    perr9
  656. perr4:    ld    hl,perrb    ;print disk address
  657.     call    perr9
  658.     ld    hl,(perra)
  659.     call    perr9        ;print error type
  660.     jr    perr2        ;go count errors
  661.                 ;
  662. perr9:                ;send a string 
  663.                 ;terminated by '$'
  664.                 ;to list device
  665.     ld    a,(hl)        ;fetch next char
  666.     cp    '$'        ;is it terminator?
  667.     ret    z        ;yes,exit
  668.     push    hl        ;save string addr.
  669.     ld    e,a        ;send this character
  670.     ld    c,5
  671.     call    cpm
  672.     pop    hl        ;restore string addr
  673.     inc    hl        ;and increment it
  674.     jr    perr9        ;check next char.
  675.                 ;
  676. perra:    dw    0        ;addr of message
  677.                 ;describing error type
  678. perrb:    db    cr,lf
  679. perrc:    db    'nnnn    '     ;pass #
  680. perrd:    db    'n     '       ;drive
  681. perre:    db    'nnnn   '      ;track
  682. perrf:    db    'nnnn   $'     ;sector
  683. ;
  684. ;
  685. ;
  686. ; disk interface to CP/M BIOS
  687. ;
  688. seldsk:    ld    a,(drv)    ;select disk drive
  689.     ld    c,a
  690.     ld    de,24
  691.             ;this routine links
  692.             ;to the desired routine
  693.             ;through the standard
  694.             ;CP/M BIOS jump table
  695. jpbios:    ld    hl,(wboot+1)
  696.     add    hl,de
  697.     jp    (hl)
  698. ;
  699. settrk:    ld    bc,(trk);select track
  700.     ld    de,27
  701.     jr    jpbios
  702. ;
  703. setsec:    ld    bc,(sec);select sector
  704.     ld    de,30
  705.     ld    a,(skew);use sector skew?
  706.     or    a
  707.     jr    z,jpbios;no
  708.     call    sectran ;translate sector addr.
  709.     jr    jpbios
  710. ;
  711. setdma:    ld    bc,(buffer) ;set memory addr.
  712.     ld    de,33
  713.     jr    jpbios
  714. ;
  715. setio:    call    settrk    ;set up track,sector,
  716.     call    setsec    ;and memory address
  717.     call    setdma    ;for subsequent read
  718.     ret        ;or write
  719. ;
  720. read:            ;read one disk sector
  721.     ld    de,36
  722.     jr    jpbios
  723. ;
  724. write:            ;write one disk sector
  725.     ld    de,39
  726.     jr    jpbios
  727. ;
  728. sectran:        ;translate logical to
  729.             ;physical sector number
  730.             ;
  731.             ;call bc=logical sector
  732.             ;return bc=physical sector
  733.     push    hl
  734.     ld    hl,sectrb-1
  735.     add    hl,bc
  736.     ld    c,(hl)
  737.     pop    hl
  738.     ret
  739. sectrb:
  740.     db    1,2,3,4,5,6,7,8,9
  741. ;
  742. ; messages for test initialization and
  743. ; error printing
  744. ;
  745. dtsta:    db    cr,lf,lf
  746.     db    'Z80 Disk Diagnostic '
  747.     db    'Test version '
  748.     db    $ver+'0','.'
  749.     db    $rev+'0',cr,lf
  750.     db    '   Modified for the Kaypro 2 ',cr,lf
  751.     db    ' By Micro Cornucopia Magazine',cr,lf,lf
  752.     db    'Original Version '
  753.     db    '(c) 1980 Laboratory '
  754.     db    'Microsystems',cr,lf,'$'
  755. dtstb:    db    cr,lf,'Itemize '
  756.     db    'errors?    $'
  757. dtstc:    db    cr,lf,'Use '
  758.     db    'console or printer'
  759.     db    '? (C/P) $'
  760. dtstd:    db    cr,lf,'Lock on read '
  761.     db    'or write? (N/R/W) $'
  762. dtste:    db    cr,lf,'Restore '
  763.     db    'original data? $'
  764. dtstf:    db    cr,lf,'Lock on '
  765.     db    'data pattern? $'
  766. dtstg:    db    cr,lf,'Enter data '
  767.     db    'pattern, hex 00-FF$'
  768. dtsth:    db    cr,lf,'Drive '
  769.     db    'to be tested '
  770.     db    '(',$drvf+'A','-'
  771.     db    $drvl+'A',') $'
  772. dtsti:    db    cr,lf,'Confirm: test drive '
  773. dtsti1:    db    'X ? $'
  774. dtstj:    db    cr,lf,'Test all '
  775.     db    'tracks?    $'
  776. dtstk:    db    cr,lf,'First '
  777.     db    'track to test      $'
  778. dtstl:    db    cr,lf,'Last '
  779.     db    'track to test      $'
  780. dtstm:    db    cr,lf,'Test all '
  781.     db    'sectors?    $'
  782. dtstn:    db    cr,lf,'First '
  783.     db    'sector to test    $'
  784. dtsto:    db    cr,lf,'Last '
  785.     db    'sector to test     $'
  786. dtstp:    db    cr,lf,'How many '
  787.     db    'test passes?    $'
  788. dtstq:    db    cr,lf,lf,'Pass  '
  789.     db    'Drive  Track  '
  790.     db    'Sector  Error-type'
  791.     db    cr,lf,'$'
  792. dtstr:    db    cr,lf,lf,'Pass '
  793. dtstr1:    db    'nnnn complete, '
  794. dtstr2:    db    'nnnn errors.'
  795.     db    cr,lf,'$'
  796. dtsts:    db    cr,lf,'Not enough '
  797.     db    'memory to execute.'
  798.     db    cr,lf,'$'
  799. dtstt:    db    cr,lf,lf,'Beginning '
  800.     db    'disk test - push '
  801.     db    'any key to abort '
  802.     db    'program.',cr,lf,'$'
  803. dtstu:    db    'Warning: user '
  804.     db    'data will not be '
  805.     db    'restored.',cr,lf,'$'
  806. dtstv:    db    'User data will be '
  807.     db    'restored.',cr,lf,'$'
  808. dtstw:    db    cr,lf,'Continue or '
  809.     db    'exit test? (C/E)$'
  810. dtstx:    db    cr,lf,lf
  811.     db    'Goodbye.',cr,lf,'$'
  812. dtsty:    db    cr,lf,'Use sector '
  813.     db    'skew?  $'
  814. dtstz:    db    cr,lf,'Need CP/M 2.x '
  815.     db    'to execute.',cr,lf,'$'
  816.  
  817.  
  818. merr1:    db    'read error - original data$'
  819. merr2:    db    'write error - test pattern$'
  820. merr3:    db    'read error - test pattern$'
  821. merr4:    db    'compare error - test pattern$'
  822. merr5:    db    'original data cannot '
  823.     db    'be restored$'
  824. merr6:    db    'write error - restore phase$'
  825. merr7:    db    'read error - restore phase$'
  826. ;
  827. ;
  828. ;
  829. ; utility and console input routines
  830. ;
  831. getyn:                ;get y or n response
  832.                 ;from operator.
  833.                 ;
  834.                 ;call de=address of cue
  835.                 ;return acc=y or n
  836.     push    de        ;save cue address
  837.     ld    c,9        ;print cue message
  838.     call    cpm
  839.     ld    de,getyna
  840.     ld    c,9        ;print possible answers
  841.     call    cpm
  842.     call    getchar        ;get a character
  843.                 ;from console
  844.     or    20h        ;fold to lower case
  845.     pop    de        ;restore cue address
  846.                 ;in case needed again
  847.     cp    'y'        ;make sure response
  848.                 ;is ok
  849.     ret    z        ;exit if y
  850.     cp    'n'
  851.     ret    z        ;exit if n
  852.     push    de
  853.     call    query        ;print question mark if
  854.     pop    de        ;not y or n, try again
  855.     jr    getyn        ;
  856. getyna:    db    '(Y/N) ',tab,'> $'
  857. ;
  858. ;
  859. getl:                ;get any letter response
  860.                 ;from operator.
  861.                 ;
  862.                 ;call de=address of cue
  863.                 ;return acc=ASCII char.
  864.     ld    c,9        ;print cue message
  865.     call    cpm
  866.     ld    de,getla    ;tab and print 
  867.     ld    c,9        ;cue mark
  868.     call    cpm
  869.     call    getchar        ;read console
  870.     or    20h        ;fold to lower case
  871.     ret
  872. getla:    db    tab,'> $'
  873. ;
  874. ;
  875. getn:                ;get a decimal number 
  876.                 ;from the console.
  877.                 ;
  878.                 ;call de=address of cue
  879.                 ;return hl=number
  880.     push    de        ;save cue message address
  881.                 ;in case needed later
  882.     ld    c,9
  883.     call    cpm        ;print cue message
  884.     ld    de,getna    ;print tab and cue mark
  885.     ld    c,9
  886.     call    cpm
  887.     ld    hl,0        ;initialize forming
  888.                 ;answer
  889.     ld    a,(digits)
  890.     ld    b,a        ;total characters allowed
  891.                 ;to be input
  892. getn1:    push    hl        ;save answer
  893.     push    bc        ;save char. count
  894.     call    getchar        ;read console
  895.     pop    bc        ;restore char. count
  896.     pop    hl        ;restore forming answer
  897.     cp    cr        ;is this return?
  898.     jr    z,getn9        ;yes,exit with answer
  899.     cp    '0'        ;is this legal char.?
  900.     jr    c,getn3        ;no, jump
  901.     cp    '9'+1        ;is this legal char.?
  902.     jr    nc,getn3    ;no,jump
  903.     and    0fh        ;isolate bottom 4 bits
  904.                 ;previous data * 10
  905.     push    hl
  906.     pop    de
  907.     add    hl,hl        ;(*2)
  908.     add    hl,hl        ;(*4)
  909.     add    hl,de        ;(*5)
  910.     add    hl,hl        ;(*10)
  911.     ld    e,a        ;now add in this digit
  912.     ld    d,0
  913.     add    hl,de
  914.     djnz    getn1        ;count characters accepted
  915.     jr    getn9        ;enough accepted,exit
  916. getn3:                ;illegal character detected.
  917.     call    query        ;print question mark and
  918.     pop    de        ;restart input
  919.     jr    getn
  920. getn9:                ;input complete,clean
  921.                 ;stack and exit with
  922.                 ;answer in (hl)
  923.     pop    de
  924.     ret
  925. getna:    db    tab,'> $'
  926. getnb:    db    '?$'
  927. ;
  928. ;
  929. geth:                ;get $dig hex digits
  930.                 ;from keyboard
  931.                 ;
  932.                 ;call de=addr of cue
  933.                 ;return acc=lower 8 bits
  934.                 ;     of entered number,
  935.                 ;     hl=entire 16 bit no.
  936.                 ;
  937.     push    de        ;save cue address
  938.                 ;in case needed again
  939.     ld    c,9    
  940.     call    cpm        ;print cue message
  941.     ld    de,getha    ;print tab and cue mark
  942.     ld    c,9
  943.     call    cpm
  944.     ld    hl,0        ;initialize forming
  945.                 ;answer
  946.     ld    a,(digits)
  947.     ld    b,a        ;max digits to accept
  948. geth1:    push    bc        ;save registers
  949.     push    hl
  950.     call    getchar        ;read console
  951.     pop    hl    
  952.     pop    bc        ;restore registers
  953.     cp    cr        ;if carriage return exit
  954.     jr    z,geth25
  955.     cp    '0'        ;make sure its legal
  956.     jr    c,geth3     ;no,jump
  957.     cp    '9'+1        ;if alpha fold to
  958.     jr    c,geth15    ;lower case
  959.     or    20h
  960. geth15:    cp    'f'+1        ;make sure its legal
  961.     jr    nc,geth3    ;no,jump
  962.     cp    'a'        ;check if alpha
  963.     jr    c,geth2     ;jump if 0-9
  964.     add    a,9        ;add correction
  965. geth2:    and    0fh
  966.     add    hl,hl        ;previous data *16
  967.     add    hl,hl        ;(left shift 4 bits)
  968.     add    hl,hl
  969.     add    hl,hl
  970.     add    a,l        ;add this char. to
  971.     ld    l,a        ;forming result
  972.     djnz    geth1        ;keep reading console
  973. geth25:    pop    de        ;clean up stack
  974.     ld    a,l        ;put lower 8 bits
  975.                 ;of answer in acc.
  976.                 ;(in case exit by
  977.                 ; carriage return)
  978.     ret
  979. geth3:    call    query       ;print question mark
  980.     pop    de        ;then restart input
  981.     jr    geth
  982. getha:    db    tab,'> $'
  983. ;
  984. ;
  985. query:    push    af        ;save flags
  986.     ld    c,9        ;print question mark
  987.     ld    de,querya
  988.     call    cpm
  989.     pop    af        ;restore flags
  990.     ret
  991. querya:    db    ' ?$'
  992. ;
  993. ;
  994. getchar:            ;get 1 character from
  995.                 ;console via raw input
  996.                 ;mode.  do not echo a
  997.                 ;carriage return.
  998.     ld    e,0ffh
  999.     ld    c,6
  1000.     call    cpm        ;read console
  1001.     or    a        ;anything there?
  1002.     jr    z,getchar    ;no,try again
  1003.     cp    cr        ;is it a carriage return?
  1004.     ret    z        ;yes
  1005.     push    af        ;no,echo it
  1006.     ld    e,a
  1007.     ld    c,6
  1008.     call    cpm
  1009.     pop    af        ;restore acc. and exit
  1010.     ret
  1011. ;
  1012. ;
  1013. conv:                ;convert binary to
  1014.                 ;decimal ascii
  1015.                 ;
  1016.                 ;call bc=binary data, in
  1017.                 ;        range 0000-9999.
  1018.                 ;     hl=first byte addr
  1019.                 ;     to store output
  1020.                 ;
  1021.     ld    de,1000
  1022.     call    div
  1023.     call    conv9        ;thousands digit
  1024.     ld    de,100
  1025.     call    div
  1026.     call    conv9        ;hundreds digit
  1027.     ld    de,10
  1028.     call    div
  1029.     call    conv9        ;tens digit
  1030.     call    conv9        ;units
  1031.     ret            ;back to caller
  1032. conv9:    ld    a,c        ;turn quotient into
  1033.     add    a,'0'        ;ASCII character
  1034.     ld    (hl),a        ;and store it 
  1035.     inc    hl        ;bump output pointer
  1036.     push    de        ;bc <- remainder
  1037.     pop    bc
  1038.     ret
  1039. ;
  1040. ;
  1041. div:                ;single precision divide
  1042.                 ;call bc=numerator
  1043.                 ;     de=divisor
  1044.                 ;return bc=quotient
  1045.                 ;     de=remainder
  1046.     push    hl
  1047.     ld    hl,0
  1048.     or    a
  1049.     sbc    hl,de
  1050.     ex    de,hl
  1051.     ld    hl,0
  1052.     ld    a,17
  1053. div0:    push    hl
  1054.     add    hl,de
  1055.     jr    nc,div1
  1056.     ex    (sp),hl
  1057. div1:    pop    hl
  1058.     push    af
  1059.     rl    c
  1060.     rl    b
  1061.     rl    l
  1062.     rl    h
  1063.     pop    af
  1064.     dec    a
  1065.     jr    nz,div0
  1066.     or    a
  1067.     rr    h
  1068.     rr    l
  1069.     ex    de,hl
  1070.     pop    hl
  1071.     ret
  1072. ;
  1073. ;
  1074. buff1    equ    1000h    ;disk buffers
  1075. buff2    equ    $bpt*2+buff1
  1076. buff3    equ    $bpt*2+buff2
  1077. buffend    equ    $bpt*2+buff3
  1078. ;
  1079. ;
  1080.     end
  1081.