home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol140 / z80disk.mac < prev    next >
Encoding:
Text File  |  1984-04-29  |  22.0 KB  |  977 lines

  1. .COMMENT ;
  2.  Floppy Disc Test for Z-80 CP/M Systems
  3.  Dr. Dobb's:  April 1981
  4.  
  5. Version 1.0
  6.  
  7. The purchaser may freely create any number of copies of this
  8. program on magnetic media as necessary to support his computer
  9. system(s). Further resale of this program is prohibited.
  10.  
  11. COPYRIGHT (c) 1980 by
  12. Ray Duncan
  13. Laboratory Microsystems
  14. 4147 Beethoven Street
  15. Los Angeles. CA 90066
  16. ;
  17.  
  18. CPM        EQU    5H    ; References to..
  19. WBOOT        EQU    0H    ; ..operating system
  20. ;                  References to..
  21. CR        EQU    0DH    ; ..ASCII characters
  22. LF        EQU    0AH
  23. FF        EQU    0CH
  24. TAB        EQU    09H
  25. ;
  26. ; Parameters for disk (supplied as single density, soft sect.)
  27. $DRVF        EQU    1H    ; First drive to allow
  28. ;                  ..testing (0=A, 1=B etc.)
  29. $DRVL        EQU    3H    ; Last drive to allow test
  30. $TRKF        EQU    0H    ; First track
  31. $TRKL        EQU    76    ; Last track
  32. $SECF        EQU    1    ; First sector
  33. $SECL        EQU    26    ; Last sector
  34. $BPS        EQU    128    ; Bytes per sector
  35. $BPT        EQU    $BPS*$SECL ; Bytes per sector
  36. $DIG        EQU    2    ; Number of digits to accept
  37.                 ; ..in track and sector assign.
  38.                 ; ..(Should be set larger for
  39.                 ; .. devices having track/
  40.                 ; .. sector numbers >99 )
  41. ;
  42. $VER        EQU    1    ; Program version
  43. $REV        EQU    0    ; .. revision
  44. ;
  45.         .Z80
  46.         ASEG
  47. ;
  48.         ORG    100H
  49. START:
  50.         JP    DTST    ; Enter from CPM
  51. ;
  52. ; Global varables for use by all routines
  53. ;
  54. PASS:        DW    0    ; Current pass
  55. ERRORS:        DW    0    ; Error count for pass
  56. ;
  57. ; The following variables are used by RDBUF and WRTBUF to
  58. ;  address the disk, and display failing disk addresses.
  59. ;
  60. DRV:        DB    0    ; Drive to test
  61. TRK:        DW    0    ; Current track
  62. SEC:        DW    0    ; Current sector
  63. BUFFER:        DW    0    ; Current memory address
  64. IOLEN:        DW    0    ; Bytes last transferred
  65. ;
  66. ; The following variables define the area to be tested on
  67. ;  the selected drive.
  68. ;
  69. TRKF:        DW    0    ; First track to test
  70. TRKL:        DW    0    ; Last track to test
  71. SECF:        DW    0    ; First sector to test
  72. SECL:        DW    0    ; Last sector to test
  73. ;
  74. ; The following variables define the test mode
  75. ;
  76. BYPASS:        DB    0    ; 0=do not bypass error item.
  77.                 ; 1=bypass error itemization,
  78.                 ; ..print total errors per pass.
  79. SKEW:        DB    0    ; 0=no sector skew
  80.                 ; 1=use sector skew for speed
  81. LIST:        DB    0    ; 0=print errors on terminal
  82.                 ; 1=print errors on list dev.
  83. LOCKIO:        DB    0    ; 0=no lock
  84.                 ; 1=lock on read
  85.                 ; 2=lock on write
  86. RESTOR:        DB    0    ; 0=do not restore original
  87.                 ; ..data, 1=restore original
  88.                 ; ..data on disk.
  89. LOCKPT:        DB    0    ; 0=use variable test data
  90.                 ; ..pattern, 1=lock on user
  91.                 ; ..supplied data pattern.
  92. PATTRN:        DB    0    ; Contains user supplied
  93.                 ; ..8 bit data pattern.
  94. PASSL:        DW    0    ; Last pass to do on this test
  95. DIGITS:        DB    $DIG    ; Max. number of digits to be
  96.                 ; ..accepted during hex. or dec.
  97.                 ; ..numeric input.
  98. XTRAN:        DW    SECTRB    ; Address of sector XLATE table
  99. ;
  100. ; Disk test --- main control
  101. ;
  102. DTST:                ; Entry from CPM
  103.     LD    DE,DTSTA     ; Print program title
  104.     LD    C,9
  105.     CALL    CPM
  106.     LD    HL,(CPM+1)
  107.     LD    DE,BUFFEND
  108.     OR    A        ; Make sure enough user
  109.     SBC    HL,DE        ; ..memory to execute test
  110.     JR    NC,DTST01
  111.     LD    DE,DTSTS     ; Not enough memory
  112.     LD    C,9        ; Print warning and exit
  113.     CALL    CPM
  114.     JP    WBOOT
  115. DTST01:                ; Ckeck CPM version
  116.     LD    C,12
  117.     CALL    CPM
  118.     LD    A,L        ; Make sure 2.x
  119.     AND    0F0H
  120.     CP    20H
  121.     JR    Z,DTST02
  122.     LD    DE,DTSTZ    ; Not CPM 2.x, print
  123.     LD    C,9        ; ..error message and quit
  124.     CALL    CPM
  125.     JP    WBOOT
  126. DTST02:                ; Initialize variables
  127.     XOR    A
  128.     LD    (BYPASS),A
  129.     LD    (SKEW),A
  130.     LD    (LIST),A
  131.     LD    (LOCKIO),A
  132.     LD    (RESTOR),A
  133.     LD    (LOCKPT),A
  134.     LD    (PASS),A
  135.     LD    (PASS+1),A
  136.     LD    (ERRORS),A
  137.     LD    (ERRORS+1),A
  138.                 ; Now set up test configuration
  139.     LD    DE,DTSTB
  140.     CALL    GETYN        ; Itemize errors?
  141.     CP    'y'
  142.     JR    Z,DTST03     ; Yes
  143.     LD    A,1        ; No
  144.     LD    (BYPASS),A
  145.     JR    DTST04        ; Skip query for output device
  146.                 ; ..since errors will not be listed
  147. DTST03:                ; Audit errors on console
  148.     LD    DE,DTSTC     ; ..or line printer?
  149.     CALL    GETL
  150.     CP    'c'
  151.     JR    Z,DTST04     ; c=use console
  152.     CP    'p'
  153.     CALL    NZ,QUERY
  154.     JR    NZ,DTST03     ; No match, try again
  155.     LD    A,1        ; p=use line printer
  156.     LD    (LIST),A
  157. DTST04:                ; Lock on read or write?
  158.     LD    DE,DTSTD
  159.     CALL    GETL
  160.     CP    'n'        ; n=no locks
  161.     JR    Z,DTST06
  162.     CP    'r'        ; r=lock on read
  163.     JR    NZ,DTST05
  164.     LD    A,1
  165.     LD    (LOCKIO),A
  166.     JR    DTST12        ; Bypass queries about restore
  167.                 ; ..mode and data pattern, since
  168.                 ; ..we are locked in read mode
  169. DTST05:
  170.     CP    'w'        ; w=lock on write
  171.     CALL    NZ,QUERY
  172.     JR    NZ,DTST04     ; No match, try again
  173.     LD    A,2
  174.     LD    (LOCKIO),A
  175.     JR    DTST08        ; Bypass restore question
  176.                 ; ..since we are locked in
  177.                 ; ..write mode
  178. DTST06:
  179.     LD    DE,DTSTE     ; Restore user data?
  180.     CALL    GETYN
  181.     CP    'y'        ; y=restore
  182.     JR    NZ,DTST08
  183.     LD    A,1        ; n=do not restore
  184.     LD    (RESTOR),A
  185. DTST08:
  186.     LD    DE,DTSTF     ; Lock on data pattern?
  187.     CALL    GETYN
  188.     CP    'n'
  189.     JR    Z,DTST12    ; n=use variable pattern
  190.     LD    A,1        ; y=lock on pattern
  191.     LD    (LOCKPT),A    ; ..supplied by operator
  192.     LD    DE,DTSTG    ; Accept data pattern
  193.     CALL    GETH        ; ..from keyboard
  194.     LD    (PATTRN),A
  195. DTST12:
  196.     LD    DE,DTSTH    ; Select drive to be tested
  197.     CALL    GETL
  198.     SUB    'a'        ; Convert to logical number
  199.     CP    $DRVF        ; Make sure its legal
  200.     CALL    C,QUERY
  201.     JR    C,DTST12    ; Too small, try again
  202.     CP    $DRVL+1
  203.     CALL    NC,QUERY
  204.     JR    NC,DTST12    ; Too large, try again
  205.     LD    (DRV),A        ; Save drive assignment
  206.     ADD    A,'A'        ; Also format for output
  207.     LD    (DTSTI1),A
  208.     LD    DE,DTSTI    ; Confirm selected drive?
  209.     CALL    GETYN
  210.     CP    'n'
  211.     JR    Z,DTST12    ; Not confirmed, try again
  212.     LD    HL,$TRKF    ; Initialize track limits
  213.     LD    (TRKF),HL
  214.     LD    HL,$TRKL
  215.     LD    (TRKL),HL
  216. DTST15:
  217.     LD    DE,DTSTJ    ; Test all tracks?
  218.     CALL    GETYN
  219.     CP    'y'        ; y=use all of them
  220.     JR    Z,DTST20    ; n=user wants to specify
  221. DTST17:
  222.     LD    DE,DTSTK    ; Enter first track to test
  223.     CALL    GETN
  224.     LD    (TRKF),HL    ; Save it
  225.     LD    DE,DTSTL    ; Enter last track to test
  226.     CALL    GETN
  227.     LD    (TRKL),HL    ; Save it
  228.     LD    DE,(TRKF)    ; Make sure first
  229.     OR    A        ; ..track<=last track
  230.     SBC    HL,DE
  231.     CALL    C,QUERY        ; Wrong, start again
  232.     JR    C,DTST17
  233. DTST20:
  234.     LD    HL,$SECF    ; Initialize sector limits
  235.     LD    (SECF),HL
  236.     LD    HL,$SECL
  237.     LD    (SECL),HL
  238. DTST22:
  239.     LD    DE,DTSTM    ; Use all sectors of each track
  240.     CALL    GETYN
  241.     CP    'y'        ; y=use all sectors
  242.     JR    Z,DTST26    ; n=user wants to specify
  243. DTST24:
  244.     LD    DE,DTSTN    ; Enter first sector to test
  245.     CALL    GETN
  246.     LD    (SECF),HL    ; Save it
  247.     LD    DE,DTSTO    ; Enter last sector to test
  248.     CALL    GETN
  249.     LD    (SECL),HL    ; Save it
  250.     LD    DE,(SECF)    ; Make sure first
  251.     OR    A        ; ..sector<=last sector
  252.     SBC    HL,DE
  253.     CALL    C,QUERY
  254.     JR    C,DTST24    ; Error, start again
  255. DTST26:                ; All variables set up now --
  256.     LD    DE,DTSTP    ; ..how many test passes
  257.     CALL    GETN        ; ..should be made?
  258.     LD    (PASSL),HL    ; Save # of passes
  259.     LD    DE,DTSTT    ; Print advisory message
  260.     LD    C,9        ; ..as test begins
  261.     CALL    CPM
  262.     LD    DE,DTSTU    ; Remind user whether he is
  263.     LD    A,(RESTOR)    ; ..using restore mode
  264.     OR    A
  265.     JR    Z,DTST32
  266.     LD    DE,DTSTV
  267. DTST32:
  268.     LD    C,9
  269.     CALL    CPM
  270. DTST40:                ; Begin a pass
  271.     LD    HL,(TRKF)
  272.     LD    (TRK),HL    ; Initialize current track
  273. DTST42:                ; Process next track
  274.     LD    C,6        ; Check for interruption
  275.     LD    E,0FFH
  276.     CALL    CPM        ; ..from console
  277.     OR    A
  278.     JP    NZ,DTST94    ; Break detected, quit
  279.     LD    A,(RESTOR)
  280.     OR    A        ; Is this restore mode?
  281.     JR    Z,DTST45    ; No jump
  282.     LD    HL,BUFF3    ; Yes, save current disk
  283.     LD    DE,MERR1    ; ..contents
  284.     CALL    RDBUF
  285. DTST45:
  286.     LD    A,(LOCKIO)
  287.     CP    1        ; Is this lock on read?
  288.     JR    Z,DTST47    ; Yes jump
  289.     LD    HL,BUFF1    ; Set up test pattern
  290.     LD    DE,$BPT
  291.     CALL    BUFPAT
  292.     LD    HL,BUFF1    ; Write test pattern
  293.     LD    DE,MERR2
  294.     CALL    WTBUF
  295. DTST47:
  296.     LD    A,(LOCKIO)
  297.     CP    2        ; Is this lock on write?
  298.     JR    Z,DTST70    ; Yes, jump
  299.     LD    HL,BUFF2    ; Read back test pattern
  300.                 ; (or just read existing data
  301.                 ; ..if locked on read)
  302.     LD    DE,MERR3
  303.     CALL    RDBUF
  304. DTST50:
  305.     LD    A,(LOCKIO)
  306.     OR    A        ; Is this lock on read or write
  307.     JR    NZ,DTST70    ; Yes, jump
  308.                 ; No, compare test data
  309.     LD    HL,BUFF1    ; ..written, to data read
  310.     LD    DE,BUFF2    ; ..back from disk. If
  311.     LD    BC,MERR4    ; ..difference found,
  312.     CALL    BUFCMP        ; ..print error message
  313. DTST70:
  314.     LD    A,(RESTOR)
  315.     OR    A        ; Using restore mode?
  316.     JR    Z,DTST80    ; No, jump
  317.                 ; Yes, write back user's data
  318.     LD    HL,BUFF3
  319.     LD    DE,MERR6
  320.     CALL    WTBUF
  321.     LD    HL,BUFF1    ; Verify that
  322.     LD    DE,MERR7    ; ..it was rewritten OK
  323.     CALL    RDBUF
  324.     LD    HL,BUFF1
  325.     LD    DE,BUFF3
  326.     LD    BC,MERR5    ; Check restored data
  327.     CALL    BUFCMP        ; If difference found, print
  328.                 ; ..'data cannot be restored'
  329. DTST80:
  330.     LD    DE,(TRK)    ; Advance current track
  331.     INC    DE
  332.     LD    (TRK),DE
  333.     LD    HL,(TRKL)
  334.     OR    A        ; Done with all tracks?
  335.     SBC    HL,DE
  336.     JP    NC,DTST42    ; No, process another
  337. DTST90:                ; End of pass
  338.     LD    BC,(PASS)
  339.     INC    BC        ; Count passes
  340.     LD    (PASS),BC
  341.     LD    HL,DTSTR1
  342.     CALL    CONV        ; Convert pass #
  343.     LD    BC,(ERRORS)
  344.     LD    HL,DTSTR2
  345.     CALL    CONV        ; Convert error count
  346.     LD    DE,DTSTR    ; Print pass and errors
  347.     LD    C,9        ; ..on console
  348.     CALL    CPM
  349.     LD    A,(LIST)    ; Also using printer?
  350.     OR    A
  351.     JR    Z,DTST92    ; No, jump
  352.                 ; Yes, also send pass and error
  353.                 ; ..count to printer
  354.     LD    HL,DTSTR
  355.     CALL    PERR9
  356. DTST92:                ; Reset error count
  357.     XOR    A
  358.     LD    (ERRORS),A
  359.     LD    (ERRORS+1),A
  360.     LD    HL,(PASS)
  361.     LD    DE,(PASSL)
  362.     OR    A        ; Are enough passes done?
  363.     SBC    HL,DE
  364.     JP    C,DTST40    ; Not yet, loop done with all
  365. DTST94:                ; ..passes
  366.     LD    DE,DTSTW    ; Ask whether to exit
  367.     CALL    GETL        ; ..or to continue test
  368.     CP    'c'        ; c=continue
  369.     JP    Z,DTST
  370.     CP    'e'        ; e=exit
  371.     JR    NZ,DTST94    ; If no match, try again
  372.     LD    DE,DTSTX    ; Print goodbye
  373.     LD    C,9
  374.     CALL    CPM        ; ..and return control
  375.     JP    WBOOT        ; ..to CP/M
  376. ;
  377. ; Routines to read and write up to one track
  378. ;
  379. RDBUF:                ; Read current track from
  380.                 ; ..secf to secl
  381.                 ; Call hl=buffer base addr
  382.                 ; ..   de=error msg addr
  383.     LD    (RDBUFA),DE    ; Save message address
  384.     LD    (BUFFER),HL    ; Save buffer address
  385.     LD    HL,0        ; Initialize transfer byte
  386.     LD    (IOLEN),HL    ; ..count
  387.     CALL    SELDSK        ; Select disk
  388.     LD    HL,(SECF)
  389.     LD    (SEC),HL    ; Initialize current sector
  390. RDBUF1:
  391.     CALL    SETIO        ; Setup track, sector, memory
  392.     CALL    READ        ; Now request transfer
  393.     OR    A        ; Was I/O successful?
  394.     JR    Z,RDBUF2    ; No error, jump
  395.     LD    DE,(RDBUFA)
  396.     CALL    PERR        ; I/O error, audit it
  397. RDBUF2:
  398.     CALL    RWADV        ; Advance sector address
  399.     JR    NC,RDBUF1    ; Not done, read another
  400.     RET            ; Back to caller
  401. ;
  402. RDBUFA:    DW    0        ; Address of error message
  403. ;
  404. WTBUF:                ; Write current track
  405.                 ; ..from secf to secl
  406.                 ; Call de=error msg addr
  407.                 ; ..   hl=buffer base addr
  408.     LD    (WTBUFA),DE    ; Save message address
  409.     LD    (BUFFER),HL    ; Save memory addr
  410.     LD    HL,0        ; Initialize transfer
  411.     LD    (IOLEN),HL    ; ..byte count
  412.     CALL    SELDSK        ; Select disk drive
  413.     LD    HL,(SECF)
  414.     LD    (SEC),HL    ; Initialize current sector
  415. WTBUF1:
  416.     CALL    SETIO        ; Set track, sector, memory
  417.     CALL    WRITE        ; Request disk write
  418.     OR    A        ; Any I/O errors?
  419.     JR    Z,WTBUF2    ; No, jump
  420.     LD    DE,(WTBUFA)
  421.     CALL    PERR        ; Error, audit it
  422. WTBUF2:
  423.     CALL    RWADV        ; Advance sector address
  424.     JR    NC,WTBUF1    ; Not done, write another
  425.     RET            ; Back to caller
  426. ;
  427. WTBUFA    EQU    RDBUFA        ; Save address of error msg
  428. ;
  429. RWADV:                ; Advance sector and memory addr
  430.     LD    DE,$BPS        ; de<--bytes per sector
  431.     LD    HL,(BUFFER)
  432.     ADD    HL,DE        ; Update buffer address
  433.     LD    (BUFFER),HL
  434.     LD    HL,(IOLEN)
  435.     ADD    HL,DE        ; Count bytes transferred
  436.     LD    (IOLEN),HL
  437.     LD    DE,(SEC)    ; Advance current sector
  438.     INC    DE
  439.     LD    (SEC),DE
  440.     LD    HL,(SECL)
  441.     OR    A        ; Done with all sectors?
  442.     SBC    HL,DE        ; Exit with carry set if done
  443.     RET
  444. ;
  445. ; Set up buffer with test pattern
  446. ;
  447. BUFPAT:                ; Call hl=buffer base address
  448.                 ; ..   de=byte length to set up
  449.     LD    A,(LOCKPT)
  450.     OR    A        ; Are we locked on user specified
  451.                 ; ..data pattern?
  452.     JR    NZ,BUFPA2    ; Yes, jump
  453. BUFPA1:
  454.     LD    A,R        ; Read refresh register
  455.     XOR    H
  456.     ADD    A,L        ; Make data a function of memory
  457.                 ; ..address
  458.     LD    (HL),A        ; ..and store it
  459.     INC    HL        ; Advance buffer address
  460.     DEC    DE        ; Count bytes stored
  461.     LD    A,D        ; Done yet?
  462.     OR    E
  463.     JR    NZ,BUFPA1    ; No, loop
  464.     RET
  465. BUFPA2:
  466.     LD    A,(PATTRN)    ; User specified parrern
  467.     LD    (HL),A        ; Store one byte
  468.     INC    HL        ; Advance buffer pointer
  469.     DEC    DE        ; Count bytes stored
  470.     LD    A,D        ; Done yet?
  471.     OR    E
  472.     JR    NZ,BUFPA2    ; Not done, loop
  473.     RET            ; Exit
  474. ;
  475. ;Compare specified buffer and print error message if difference found
  476. ;
  477. BUFCMP:                ; Call bc=error msg addr
  478.                 ; ..   de=1st buffer addr
  479.                 ; ..   hl=2nd buffer addr
  480.     LD    (BUFCMA),BC    ; Save message addr
  481.     LD    (BUFCMB),HL    ; Save base of buffer
  482.     LD    BC,(IOLEN)    ; Length to compare
  483. BUFCM1:
  484.     LD    A,(DE)        ; Fetch byte from 1st buffer
  485.     CP    (HL)        ; Compare it to 2nd buffer
  486.     JR    NZ,BUFCM3    ; Difference found, jump
  487. BUFCM2:
  488.     INC    HL        ; Advance buffer addresses
  489.     INC    DE
  490.     DEC    BC        ; Count bytes
  491.     LD    A,B        ; Done yet?
  492.     OR    C
  493.     JR    NZ,BUFCM1    ; No, loop
  494.     RET            ; Back to caller
  495. BUFCM3:                ; Difference found, print
  496.                 ; ..error audit trail
  497.     PUSH    BC        ; First save registers
  498.     PUSH    DE
  499.     PUSH    HL
  500.     LD    DE,(BUFCMB)
  501.     OR    A
  502.     SBC    HL,DE        ; Find a buffer offset
  503.     PUSH    HL        ; Now divide by bytes per
  504.     POP    BC        ; ..sector to find relative
  505.     LD    DE,$BPS        ; ..sector number
  506.     CALL    DIV
  507.     LD    HL,(SECF)
  508.     ADD    HL,BC        ; Add relative sector to first
  509.                 ; ..sector to find actual
  510.                 ; ..address for use by PERR
  511.     LD    (SEC),HL
  512.     LD    DE,(BUFCMA)
  513.     CALL    PERR        ; Now audit error
  514.     POP    HL        ; Restore registers
  515.     POP    DE
  516.     POP    BC
  517. BUFCM4:                ; Advance memory address out of
  518.                 ; ..this sector where an error
  519.                 ; ..was found
  520.     INC    HL        ; Bump buffer addresses
  521.     INC    DE
  522.     DEC    BC        ; Done with all data area?
  523.     LD    A,B
  524.     OR    C
  525.     RET    Z        ; Yes, exit compare routine
  526.     LD    A,L        ; Check if on new sector
  527.     AND    $BPS-1        ; ..boundary
  528.     JR    Z,BUFCM1    ; Found it, go compare more data
  529.     JR    BUFCM4        ; Keep adv until sector boundary
  530. ;
  531. BUFCMA:    DW    0        ; Address of error message
  532. BUFCMB:    DW    0        ; Base buffer addresses
  533. ;
  534. ; Error printing routine, prints pass, drive, track, sector
  535. ;  and message specified by caller on the console device.
  536. ;
  537. PERR:                ; Call de=error message address
  538.     LD    A,(BYPASS)
  539.     OR    A        ; Is error itemization bypass set
  540.     JR    NZ,PERR2    ; Yes, skip printing and go count
  541.     LD    (PERRA),DE    ; Save message address
  542.     LD    BC,(PASS)
  543.     INC    BC
  544.     LD    HL,PERRC    ; Convert current pass
  545.     CALL    CONV
  546.     LD    A,(DRV)        ; Form drive name
  547.     ADD    A,'A'
  548.     LD    (PERRD),A
  549.     LD    BC,(TRK)    ; Convert current track
  550.     LD    HL,PERRE
  551.     CALL    CONV
  552.     LD    BC,(SEC)    ; Convert current sector
  553.     LD    A,(SKEW)    ; Is skew in effect?
  554.     OR    A
  555.     JR    Z,PERR0        ; No
  556.     CALL    SECTRAN        ; Yes, translate sector
  557. PERR0:
  558.     LD    HL,PERRF
  559.     CALL    CONV
  560.     LD    A,(LIST)    ; Should output be on
  561.     OR    A        ; ..console or printer?
  562.     JR    NZ,PERR3    ; Jump, use printer, fall thru
  563.     LD    HL,(ERRORS)    ; ..use console
  564.     LD    A,H        ; Is this the first error?
  565.     OR    L
  566.     JR    NZ,PERR1    ; No, jump
  567.     LD    DE,DTSTQ    ; Print title for errors
  568.     LD    C,9
  569.     CALL    CPM
  570. PERR1:
  571.     LD    DE,PERRB    ; Print disk address
  572.     LD    C,9
  573.     CALL    CPM
  574.     LD    DE,(PERRA)    ; Print error type
  575.     LD    C,9
  576.     CALL    CPM
  577. PERR2:
  578.     LD    HL,(ERRORS)    ; Count errors
  579.     INC    HL
  580.     LD    (ERRORS),HL
  581.     RET            ; Back to caller
  582. PERR3:                ; Errors to printer
  583.     LD    HL,(ERRORS)
  584.     LD    A,H        ; Is this 1st error to be
  585.     OR    L        ; ..printed this pass?
  586.     JR    NZ,PERR4    ; No, jump
  587.     LD    HL,DTSTQ    ; Yes, print title
  588.     CALL    PERR9
  589. PERR4:
  590.     LD    HL,PERRB    ; Print disk address
  591.     CALL    PERR9
  592.     LD    HL,(PERRA)
  593.     CALL    PERR9        ; Print error type
  594.     JR    PERR2        ; Go count errors
  595. PERR9:                ; Send a string terminated by
  596.                 ; ..'$' to list device
  597.     LD    A,(HL)        ; Fetch next character
  598.     CP    '$'        ; Is it terminator?
  599.     RET    Z        ; Yes, exit
  600.     PUSH    HL        ; Save string address
  601.     LD    E,A        ; Send this character
  602.     LD    C,5
  603.     CALL    CPM
  604.     POP    HL        ; Restore string address
  605.     INC    HL        ; ..and increment it
  606.     JR    PERR9        ; Check next character
  607. ;
  608. PERRA:    DW    0        ; Addrs of msg describing error
  609. PERRB:    DB    CR,LF
  610. PERRC:    DB    'nnnn    '    ; Pass #
  611. PERRD:    DB    'n     '    ; Drive
  612. PERRE:    DB    'nnnn   '    ; Track
  613. PERRF:    DB    'nnnn   $'    ; Sector
  614. ;
  615. ; Disk interface to CP/M BIOS
  616. ;
  617. SELDSK:
  618.     LD    A,(DRV)        ; Select disk drive
  619.     LD    C,A
  620.     LD    DE,24
  621. JPBIOS:                ; This routine links to the
  622.     LD    HL,(WBOOT+1)    ; ..desired routine through
  623.     ADD    HL,DE        ; ..the standard CP/M
  624.     JP    (HL)        ; ..BIOS jump table
  625. SETTRK:
  626.     LD    BC,(TRK)    ; Select track
  627.     LD    DE,27
  628.     JR    JPBIOS
  629. SETSEC:
  630.     LD    BC,(SEC)    ; Select sector
  631.     LD    DE,30
  632.     LD    A,(SKEW)    ; Use sector skew?
  633.     OR    A
  634.     JR    Z,JPBIOS    ; No
  635.     CALL    SECTRAN        ; Translate sector addr
  636.     JR    JPBIOS
  637. SETDMA:
  638.     LD    BC,(BUFFER)    ; Set memory addr
  639.     LD    DE,33
  640.     JR    JPBIOS
  641. SETIO:
  642.     CALL    SETTRK        ; Set up track, sector,
  643.     CALL    SETSEC        ; ..and memory address
  644.     CALL    SETDMA        ; ..for subsequent read
  645.     RET            ; ..or write
  646. READ:
  647.     LD    DE,36        ; Read one disk sector
  648.     JR    JPBIOS
  649. WRITE:
  650.     LD    DE,39        ; Write one disk sector
  651.     JR    JPBIOS
  652. SECTRAN:            ; Translate logical to physical
  653.                 ; Call bc=logical sector
  654.                 ; ..   hl=physical sector
  655.     PUSH    HL
  656.     LD    HL,SECTRB-1
  657.     ADD    HL,BC
  658.     LD    C,(HL)
  659.     POP    HL
  660.     RET
  661. ;
  662. SECTRB:        DB    1,7,13,19,25    ; Table built
  663.         DB    5,11,17,23    ; ..with skew
  664.         DB    3,9,15,21    ; ..factor = 6
  665.         DB    2,8,14,20,26    ; 128 byte sector
  666.         DB    6,12,18,24
  667.         DB    4,10,16,22
  668. ;
  669. ; Messages for test initialization and error printing
  670. ;
  671. DTSTA:        DB    CR,LF,LF
  672.         DB    'Z-80 Floppy Disk '
  673.         DB    'Test version '
  674.         DB    $VER+'0','.'
  675.         DB    $REV+'0',CR,LF
  676.         DB    '(c) 1980 Laboratory '
  677.         DB    'Microsystems',CR,LF,'$'
  678. DTSTB:        DB    CR,LF,'Itemize '
  679.         DB    'errors?    $'
  680. DTSTC:        DB    CR,LF,'Use '
  681.         DB    'console or printer'
  682.         DB    '? (C/P) $'
  683. DTSTD:        DB    CR,LF,'Lock on read '
  684.         DB    'or write? (N/R/W) $'
  685. DTSTE:        DB    CR,LF,'Restore '
  686.         DB    'original data? $'
  687. DTSTF:        DB    CR,LF,'Lock on '
  688.         DB    'data pattern? $'
  689. DTSTG:        DB    CR,LF,'Enter data '
  690.         DB    'pattern, hex 00-FF$'
  691. DTSTH:        DB    CR,LF,'Drive '
  692.         DB    'to be tested '
  693.         DB    '(',$DRVF+'A','-'
  694.         DB    $DRVL+'A',') $'
  695. DTSTI:        DB    CR,LF,'Confirm: test drive '    
  696. DTSTI1:        DB    'X ? $'
  697. DTSTJ:        DB    CR,LF,'Test all '
  698.         DB    'tracks?    $'
  699. DTSTK:        DB    CR,LF,'First '
  700.         DB    'track to test      $'
  701. DTSTL:        DB    CR,LF,'Last '
  702.         DB    'track to test      $'
  703. DTSTM:        DB    CR,LF,'Test all '
  704.         DB    'sectors?    $'
  705. DTSTN:        DB    CR,LF,'First '
  706.         DB    'sector to test    $'
  707. DTSTO:        DB    CR,LF,'Last '
  708.         DB    'sector to test    $'
  709. DTSTP:        DB    CR,LF,'How many '
  710.         DB    'test passes?    $'
  711. DTSTQ:        DB    CR,LF,LF,'Pass  '
  712.         DB    'Drive  Track  '
  713.         DB    'Sector  Error-type'
  714.         DB    CR,LF,'$'
  715. DTSTR:        DB    CR,LF,LF,'Pass '
  716. DTSTR1:        DB    'nnnn complete, '
  717. DTSTR2:        DB    'nnnn errors.'
  718.         DB    CR,LF,'$'
  719. DTSTS:        DB    CR,LF,'Not enough '
  720.         DB    'memory to execute.'
  721.         DB    CR,LF,'$'
  722. DTSTT:        DB    CR,LF,LF,'Beginning '
  723.         DB    'disk test - push '
  724.         DB    'any key to abort '
  725.         DB    'program. ',CR,LF,'$'
  726. DTSTU:        DB    'WARNING: user data '
  727.         DB    'will not be '
  728.         DB    'restored. ',CR,LF,'$'
  729. DTSTV:        DB    'User data will be '
  730.         DB    'restored. ',CR,LF,'$'
  731. DTSTW:        DB    CR,LF,'Continue or '
  732.         DB    'exit test? (C/E)$'
  733. DTSTX:        DB    CR,LF,LF
  734.         DB    'Goodbye. ',CR,LF,'$'
  735. DTSTY:        DB    CR,LF,'Use sector '
  736.         DB    'skew?  $'
  737. DTSTZ:        DB    CR,LF,'Need CP/M 2.x '
  738.         DB    'to execute. ',CR,LF,'$'
  739. MERR1:        DB    'read error - original data$'
  740. MERR2:        DB    'write error - test pattern$'
  741. MERR3:        DB    'read error - test pattern$'
  742. MERR4:        DB    'compare error - test pattern$'
  743. MERR5:        DB    'original data cannot '
  744.         DB    'be restored$'
  745. MERR6:        DB    'write error - restore phase$'
  746. MERR7:        DB    'read error - restore phase$'
  747. ;
  748. ; Utility and console input routines
  749. ;
  750. GETYN:                ; Get y or n response from operator
  751.                 ; Call de= address of cue
  752.                 ; ..    a=y or n
  753.     PUSH    DE        ; Save cue address
  754.     LD    C,9        ; Print cue message
  755.     CALL    CPM
  756.     LD    DE,GETYNA    ; Print possible answers
  757.     LD    C,9
  758.     CALL    CPM
  759.     CALL    GETCHAR        ; Get a character from console
  760.     OR    20H        ; Fold to lowercase
  761.     POP    DE        ; Restore cue address
  762.                 ; ..in case needed again
  763.     CP    'y'        ; Make sure response is OK
  764.     RET    Z        ; Exit if y
  765.     CP    'n'
  766.     RET    Z        ; Exit if n
  767.     PUSH    DE
  768.     CALL    QUERY        ; Print '?' if not
  769.     POP    DE        ; ..y or n, try again
  770.     JR    GETYN
  771. ;
  772. GETYNA:    DB    '(Y/N) ',TAB,'> $'
  773. ;
  774. GETL:                ; Get any response from operator
  775.                 ; Call de=cue address
  776.                 ; ..    a=ASCII character
  777.     LD    C,9        ; Print cue message
  778.     CALL    CPM
  779.     LD    DE,GETLA    ; Tab and print
  780.     LD    C,9        ; ..cue mark
  781.     CALL    CPM
  782.     CALL    GETCHAR        ; Read console
  783.     OR    20H        ; Fold lowercase
  784.     RET
  785. ;
  786. GETLA:    DB    TAB,'> $'
  787. ;
  788. GETN:                ; Get a decimal # from the console
  789.                 ; Call de=cue address
  790.                 ; ..return hl=number
  791.     PUSH    DE        ; Save cue message address
  792.     LD    C,9
  793.     CALL    CPM        ; Print cue message
  794.     LD    DE,GETNA    ; Print tab and cue mark
  795.     LD    C,9
  796.     CALL    CPM
  797.     LD    HL,0        ; Initialize forming answer
  798.     LD    A,(DIGITS)
  799.     LD    B,A        ; Total chars allowed to be input
  800. GETN1:
  801.     PUSH    HL        ; Save answer
  802.     PUSH    BC        ; Save char count
  803.     CALL    GETCHAR        ; Read console
  804.     POP    BC        ; Restore char count
  805.     POP    HL        ; Restore forming answer
  806.     CP    CR        ; Is this return?
  807.     JR    Z,GETN9        ; Yes, exit with answer
  808.     CP    '0'        ; Is this legal char.?
  809.     JR    C,GETN3        ; No, jump
  810.     CP    '9'+1        ; Is this legal char.?
  811.     JR    NC,GETN3    ; No, jump
  812.     AND    0FH        ; Isolate bottom 4 bits
  813.     PUSH    HL        ; Previous data * 10
  814.     POP    DE
  815.     ADD    HL,HL        ; *2
  816.     ADD    HL,HL        ; *4
  817.     ADD    HL,DE        ; *5
  818.     ADD    HL,HL        ; *10
  819.     LD    E,A        ; Now add in this digit
  820.     LD    D,0
  821.     ADD    HL,DE
  822.     DJNZ    GETN1        ; Count characters accepted
  823.     JR    GETN9        ; Enough accepted, exit
  824. GETN3:                ; Illegal character detected
  825.     CALL    QUERY        ; Print '?' and
  826.     POP    DE        ; ..restart input
  827.     JR    GETN
  828. GETN9:                ; Input complete, clean
  829.     POP    DE        ; ..stack and exit with
  830.     RET            ; ..answer in (hl)
  831. ;
  832. GETNA:    DB    TAB,'> $'
  833. GETNB:    DB    '?$'
  834. ;
  835. GETH:                ; Get $dig hex digits from kbd
  836.                 ; Call de=cue address
  837.                 ; Return a=lower 8 bits of #
  838.                 ; ..    hl=entire 16 bit #
  839.     PUSH    DE        ; Save cue address
  840.     LD    C,9
  841.     CALL    CPM        ; Print cue message
  842.     LD    DE,GETHA    ; Print tab and cue mark
  843.     LD    C,9
  844.     CALL    CPM
  845.     LD    HL,0        ; Initialize forming answer
  846.     LD    A,(DIGITS)
  847.     LD    B,A        ; Max digits to accept
  848. GETH1:
  849.     PUSH    BC        ; Save registers
  850.     PUSH    HL
  851.     CALL    GETCHAR        ; Read console
  852.     POP    HL
  853.     POP    BC        ; Restore registers
  854.     CP    CR        ; If <CR> exit
  855.     JR    Z,GETH25
  856.     CP    '0'        ; Make sure its legal
  857.     JR    C,GETH3        ; No, jump
  858.     CP    '9'+1        ; If alpha fold to
  859.     JR    C,GETH15    ; ..lowercase
  860.     OR    20H
  861. GETH15:
  862.     CP    'f'+1        ; Make sure its legal
  863.     JR    NC,GETH3    ; No, jump
  864.     CP    'a'        ; Check if alpha
  865.     JR    C,GETH2        ; Jump if 0-9
  866.     ADD    A,9        ; Add correction
  867. GETH2:
  868.     AND    0FH
  869.     ADD    HL,HL        ; Previous data *16
  870.     ADD    HL,HL        ; (Left shift 4 bits)
  871.     ADD    HL,HL
  872.     ADD    HL,HL
  873.     ADD    A,L        ; Add this char to it
  874.     LD    L,A        ; ..forming result
  875.     DJNZ    GETH1        ; Keep reading console
  876. GETH25:
  877.     POP    DE        ; Clean up stack
  878.     LD    A,L        ; Put lower 8 bits of answer
  879.                 ; ..in 'A'. (incase exit by <CR>)
  880.     RET
  881. GETH3:
  882.     CALL    QUERY        ; Print '?'
  883.     POP    DE        ; ..then restart input
  884.     JR    GETH
  885. ;
  886. GETHA:    DB    TAB,'> $'
  887. ;
  888. QUERY:
  889.     PUSH    AF        ; Save flags
  890.     LD    C,9        ; Print '?'
  891.     LD    DE,QUERYA
  892.     CALL    CPM
  893.     POP    AF        ; Restore flags
  894.     RET
  895. ;
  896. QUERYA:    DB    ' ?$'
  897. ;
  898. GETCHAR:            ; Get 1 char from console via
  899.                 ; ..raw input mode. Do not echo
  900.                 ; ..<CR>
  901.     LD    E,0FFH        
  902.     LD    C,6
  903.     CALL    CPM        ; Read console
  904.     OR    A        ; Anything there?
  905.     JR    Z,GETCHAR    ; No, try again
  906.     CP    CR        ; Is it <CR>?
  907.     RET    Z        ; Yes
  908.     PUSH    AF        ; No, echo it
  909.     LD    E,A
  910.     LD    C,6
  911.     CALL    CPM
  912.     POP    AF        ; Restore 'A' and exit
  913.     RET
  914. CONV:                ; Convert binary to decimal ASCII
  915.                 ; Call bc=binary, in range 0000-9999
  916.                 ; ..   hl=first byte addr to store
  917.     LD    DE,1000
  918.     CALL    DIV
  919.     CALL    CONV9        ; Thousands digit
  920.     LD    DE,100
  921.     CALL    DIV
  922.     CALL    CONV9        ; Hundreds digit
  923.     LD    DE,10
  924.     CALL    DIV
  925.     CALL    CONV9        ; Tens digit
  926.     CALL    CONV9        ; Units
  927.     RET            ; Back to caller
  928. CONV9:
  929.     LD    A,C        ; Turn quotient into
  930.     ADD    A,'0'        ; ..ASCII char and
  931.     LD    (HL),A        ; ..store it
  932.     INC    HL        ; Bump output pointer
  933.     PUSH    DE        ; bc<--remainder
  934.     POP    BC
  935.     RET
  936. DIV:                ; Single precision divide
  937.                 ; Call bc=numerator
  938.                 ; ..   de=divisor
  939.                 ; Return bc=quotient
  940.                 ; ..     de=remainder
  941.     PUSH    HL
  942.     LD    HL,0
  943.     OR    A
  944.     SBC    HL,DE
  945.     EX    DE,HL
  946.     LD    HL,0
  947.     LD    A,17
  948. DIV0:
  949.     PUSH    HL
  950.     ADD    HL,DE
  951.     JR    NC,DIV1
  952.     EX    (SP),HL
  953. DIV1:
  954.     POP    HL
  955.     PUSH    AF
  956.     RL    C
  957.     RL    B
  958.     RL    L
  959.     RL    H
  960.     POP    AF
  961.     DEC    A
  962.     JR    NZ,DIV0
  963.     OR    A
  964.     RR    H
  965.     RR    L
  966.     EX    DE,HL
  967.     POP    HL
  968.     RET
  969. ;
  970. BUFF1        EQU    1000H        ; Disk buffers
  971. BUFF2        EQU    $BPT*2+BUFF1
  972. BUFF3        EQU    $BPT*2+BUFF2
  973. BUFFEND        EQU    $BPT*2+BUFF3
  974. ;
  975.         END    100H
  976.