home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-10-26 | 23.5 KB | 1,082 lines |
- ; 'Z-80 Floppy Disk Test'
- ; Floppy Disk Test for Z-80 CP/M Systems
- ;
- ; version 1.0 16 December 1980
- ; version 1.1 2 January 1984 DmC
- ;
- ; Resale of this program is PROHIBITED
- ;
- ; Copyright (c) 1980 by
- ; Ray Duncan
- ; Laboratory Microsystems
- ; 4147 Beethoven Street
- ; Los Angeles, CA 90066
- ;
- ; Modified for the Kaypro Computer Line
- ; By Micro Cornucopia Magazine
- ;
-
- aseg
- .z80
- org 100h
- ;
- cpm equ 5 ;references to
- wboot equ 0 ;operating system
- ;
- ; references to ASCII char
- cr equ 0dh
- lf equ 0ah
- ff equ 0ch
- tab equ 09h
- ;
- ; parameters for disk
- ;
- ;
- $drvf equ 0 ;first drive to allow
- ;testing (0=A,1=B,etc)
- $drvl equ 1 ;last drive to allow
- ;testing
- $trkf equ 0 ;first track
- $trkl equ 39 ;last track
- $secf equ 0 ;first sector
- $secl equ 39 ;last sector
- $bps equ 128 ;bytes per sector
- $bpt equ 5120 ;bytes per track
- ;
- ;number of digits to
- ;accept in track and
- ;sector assignments
- $dig equ 3 ;(should be set larger
- ; for devices having
- ; track or sector
- ; numbers >99 )
- ;
- ; program identification
- $ver equ 1 ;version
- $rev equ 1 ;revision (kaypro is rev 1 DmC)
- ;
-
- jp dtst ;enter from CP/M
-
-
- ; global variables for use by all routines
- ;
- pass: dw 0 ;current pass number
- errors: dw 0 ;error count for pass
- ;
- ;the following variables
- ;are used by RDBUF and
- ;WTBUF to address the
- ;disk, and by PERR to
- ;display failing disk
- ;addresses ---
- drv: db 0 ;drive to test
- trk: dw 0 ;current track
- sec: dw 0 ;current sector
- buffer: dw 0 ;current memory address
- iolen: dw 0 ;bytes last transferred
- ;
- ;the following variables
- ;define the area to be
- ;tested on the selected
- ;disk drive ---
- trkf: dw 0 ;first track to test
- trkl: dw 0 ;last track to test
- secf: dw 0 ;first sector to test
- secl: dw 0 ;last sector to test
- ;
- ;the following variables
- ;define the test mode ---
- ;
- bypass: db 0 ;0=do not bypass error
- ;itemization, 1=bypass
- ;error itemization,print
- ;total errors per pass
- ;only.
- ;
- skew: db 0 ;0=no sector skew
- ;1=use sector skew for
- ; increased test speed
- ;
- list: db 0 ;0=print errors on
- ;terminal, 1=print errors
- ;on list device.
- ;
- lockio: db 0 ;0=no lock
- ;1=lock on read
- ;2=lock on write
- ;
- restor: db 0 ;0=do not restore original
- ;data, 1=restore original
- ;data on diskette
- ;
- lockpt: db 0 ;0=use variable test
- ;data pattern, 1=lock on
- ;user supplied data pattern
- ;
- pattrn: db 0 ;contains user supplied
- ;8 bit data pattern
- ;
- passl: dw 0 ;last pass to do on this
- ;test run
- ;
- digits: db $dig ;maximum number of digits
- ;to be accepted during
- ;decimal or hexadecimal
- ;numeric input.
- ;
- xtran: dw sectrb ;address of sector
- ;translation table
- ;
- ; disk test --- main control
- ;
- dtst: ;entry from CP/M
- ld de,dtsta ;print program title
- ld c,9
- call cpm
- ld hl,(cpm+1)
- ld de,buffend
- or a ;make sure enough user
- sbc hl,de ;memory to execute test
- jr nc,dtst01
- ld de,dtsts ;not enough memory,
- ld c,9 ;print warning and exit.
- call cpm
- jp wboot
- dtst01: ld c,12 ;check CP/M version
- call cpm
- ld a,l ;make sure 2.x
- and 0f0h
- cp 20h
- jr z,dtst02
- ld de,dtstz ;not CP/M 2.x, print
- ld c,9 ;error message and exit
- call cpm
- jp wboot
- dtst02: xor a ;initialize variables
- ld (bypass),a
- ld (skew),a
- ld (list),a
- ld (lockio),a
- ld (restor),a
- ld (lockpt),a
- ld (pass),a
- ld (pass+1),a
- ld (errors),a
- ld (errors+1),a
- ;now set up test
- ;configuration
- ld de,dtstb
- call getyn ;itemize errors?
- cp 'y'
- jr z,dtst03 ;yes
- ld a,1 ;no
- ld (bypass),a
- jr dtst04 ;skip query for output
- ;device, since errors
- ;will not be listed
- dtst03: ld de,dtstc ;audit errors on console
- call getl ;or line printer?
- cp 'c'
- jr z,dtst04 ;c=use console
- cp 'p'
- call nz,query
- jr nz,dtst03 ;no match,try again
- ld a,1 ;p=use line printer
- ld (list),a
- dtst04: ld de,dtstd ;lock on read or write?
- call getl
- cp 'n' ;n=no locks
- jr z,dtst06
- cp 'r' ;r=lock on read
- jr nz,dtst05
- ld a,1
- ld (lockio),a
- jr dtst12 ;bypass querys about
- ;restore mode and
- ;data pattern: since
- ;we are locked in read
- ;mode, they are
- ;irrelevant.
- ;
- dtst05: cp 'w' ;w=lock on write
- call nz,query
- jr nz,dtst04 ;no match,try again
- ld a,2
- ld (lockio),a
- jr dtst08 ;bypass restore question,
- ;since we are locked in
- ;write mode.
- ;
- dtst06: ld de,dtste ;restore user data?
- call getyn
- cp 'y' ;y=restore
- jr nz,dtst08
- ld a,1 ;n=do not restore
- ld (restor),a
- dtst08: ld de,dtstf ;lock on data pattern?
- call getyn
- cp 'n'
- jr z,dtst12 ;n=use variable pattern
- ld a,1 ;y=lock on pattern
- ld (lockpt),a ;supplied by operator
- ld de,dtstg ;accept data pattern
- call geth ;from keyboard
- ld (pattrn),a
- dtst12: ld de,dtsth ;select drive to be
- call getl ;used for test
- sub 'a' ;convert to logical #
- cp $drvf ;make sure its legal
- call c,query
- jr c,dtst12 ;too small,try again
- cp $drvl+1
- call nc,query
- jr nc,dtst12 ;too large,try again
- ld (drv),a ;save drive assignment
- add a,'A' ;also format for output
- ld (dtsti1),a
- ld de,dtsti ;confirm selected drive?
- call getyn
- cp 'n'
- jr z,dtst12 ;not confirmed,try again
- ;
- ;initialize track
- ;limits
- ld hl,$trkf
- ld (trkf),hl
- ld hl,$trkl
- ld (trkl),hl
- dtst15: ld de,dtstj ;test all tracks?
- call getyn
- cp 'y' ;y=use all of them
- jr z,dtst20 ;n=user wants to specify
- ; range of tracks
- dtst17: ld de,dtstk ;enter first track
- call getn ;to test
- ld (trkf),hl ;save it
- ld de,dtstl ;enter last track
- call getn ;to test
- ld (trkl),hl ;save it
- ld de,(trkf) ;make sure first
- or a ;track<=last track
- sbc hl,de
- call c,query ;wrong,start over
- jr c,dtst17
- dtst20: ;initialize sector
- ;limits
- ld hl,$secf
- ld (secf),hl
- ld hl,$secl
- ld (secl),hl
- dtst22: ld de,dtstm ;use all sectors
- call getyn ;of each track?
- cp 'y'
- jr z,dtst26 ;y=use all sectors
- ;n=user wants to specify
- ;range of sectors
- dtst24: ld de,dtstn ;enter first sector
- call getn ;to test.
- ld (secf),hl ;save it.
- ld de,dtsto ;enter last sector
- call getn ;to test.
- ld (secl),hl ;save it.
- ld de,(secf) ;make sure first
- or a ;sector<=last sector
- sbc hl,de
- call c,query
- jr c,dtst24 ;error,start over
- ;
- ;all variables set up
- ;now --- how many
- dtst26: ld de,dtstp ;test passes should be
- call getn ;made?
- ld (passl),hl ;save # of passes
- ;
- ;print advisory message
- ld de,dtstt ;as test begins
- ld c,9
- call cpm
- ld de,dtstu ;remind user whether he
- ld a,(restor) ;is using restore
- or a ;mode
- jr z,dtst32
- ld de,dtstv
- dtst32: ld c,9
- call cpm
- ;
- dtst40: ;begin a pass
- ld hl,(trkf)
- ld (trk),hl ;initialize current track
- ;
- dtst42: ;process next track
- ld c,6 ;check for interruption
- ld e,0ffh
- call cpm ;from console
- or a
- jp nz,dtst94 ;break detected,quit
- ld a,(restor)
- or a ;is this restore mode?
- jr z,dtst45 ;no,jump
- ld hl,buff3 ;yes, save current
- ld de,merr1 ;disk contents
- call rdbuf
- dtst45: ld a,(lockio)
- cp 1 ;is this lock on read?
- jr z,dtst47 ;yes,jump
- ld hl,buff1 ;set up test pattern
- ld de,$bpt
- call bufpat
- ld hl,buff1 ;write test pattern
- ld de,merr2
- call wtbuf
- dtst47: ld a,(lockio)
- cp 2 ;is this lock on write?
- jr z,dtst70 ;yes,jump
- ld hl,buff2 ;read back test pattern
- ;(or just read existing
- ; data if locked on read)
- ld de,merr3
- call rdbuf
- dtst50: ld a,(lockio)
- or a ;is this lock on
- ;read or write?
- jr nz,dtst70 ;yes,jump
- ;no, compare test data
- ld hl,buff1 ;written to data read
- ld de,buff2 ;back from disk. If
- ld bc,merr4 ;difference found,
- call bufcmp ;print error message
- dtst70: ld a,(restor)
- or a ;using restore mode?
- jr z,dtst80 ;no,jump
- ;yes,write back user's
- ;data
- ld hl,buff3
- ld de,merr6
- call wtbuf
- ld hl,buff1 ;verify that
- ld de,merr7 ;it was rewritten ok
- call rdbuf
- ld hl,buff1
- ld de,buff3
- ld bc,merr5 ;check restored data
- call bufcmp
- ;if difference found,
- ;print 'data cannot
- ;be restored'
- ;
- dtst80: ;advance current track
- ld de,(trk)
- inc de
- ld (trk),de
- ld hl,(trkl)
- or a ;done with all tracks?
- sbc hl,de
- jp nc,dtst42 ;no,process another
- ;
- dtst90: ;end of pass
- ld bc,(pass)
- inc bc ;count passes
- ld (pass),bc
- ld hl,dtstr1
- call conv ;convert pass #
- ld bc,(errors)
- ld hl,dtstr2
- call conv ;convert error count
- ld de,dtstr ;print pass and errors
- ld c,9 ;on console
- call cpm
- ld a,(list) ;also using printer?
- or a
- jr z,dtst92 ;no,jump
- ;yes,also send pass
- ;and error count to
- ;list device
- ld hl,dtstr
- call perr9
- dtst92: ;reset error count
- xor a
- ld (errors),a
- ld (errors+1),a
- ld hl,(pass)
- ld de,(passl)
- or a ;are enough passes done?
- sbc hl,de
- jp c,dtst40 ;not yet,loop
- dtst94: ;done with all passes
- ld de,dtstw ;ask whether to exit
- call getl ;or to continue test
- cp 'c' ;c=continue
- jp z,dtst
- cp 'e' ;e=exit
- jr nz,dtst94 ;if no match,try again
- ld de,dtstx ;print goodbye
- ld c,9
- call cpm ;and return control
- jp wboot ;to CP/M
- ;
- ;
- ; routines to read and write up to one track
- ;
- rdbuf: ;read current track from
- ;secf to secl
- ;
- ;call hl=buffer base addr
- ; de=error msg addr
- ld (rdbufa),de ;save message address
- ld (buffer),hl ;save buffer address
- ld hl,0 ;initialize transfer byte
- ld (iolen),hl ;count
- call seldsk ;select disk
- ld hl,(secf)
- ld (sec),hl ;initialize current sector
- rdbuf1: call setio ;set up track,sector,memory
- call read ;now request transfer
- or a ;was i/o successful?
- jr z,rdbuf2 ;no error,jump
- ld de,(rdbufa)
- call perr ;i/o error, audit it
- rdbuf2: call rwadv ;advance sector address
- jr nc,rdbuf1 ;not done,read another
- ret ;back to caller
- rdbufa: dw 0 ;address of error message
- ;
- wtbuf: ;write current track
- ;from secf to secl
- ;
- ;call de=error msg addr
- ; hl=buffer base addr
- ;
- ld (wtbufa),de ;save message addr
- ld (buffer),hl ;save memory addr
- ld hl,0 ;initialize transfer
- ld (iolen),hl ;byte count
- call seldsk ;select disk drive
- ld hl,(secf)
- ld (sec),hl ;initialize current sector
- wtbuf1: call setio ;set track,sector,memory
- call write ;request disk write
- or a ;any i/o errors?
- jr z,wtbuf2 ;no,jump
- ld de,(wtbufa)
- call perr ;error, audit it
- wtbuf2: call rwadv ;advance sector address
- jr nc,wtbuf1 ;not done,write another
- ret ;back to caller
-
- wtbufa equ rdbufa ;save address of error
- ;message
- ;
- rwadv: ;advance sector and
- ;memory addresses
- ;
- ld de,$bps ; de <- bytes per sector
- ld hl,(buffer)
- add hl,de ;update buffer address
- ld (buffer),hl
- ld hl,(iolen)
- add hl,de ;count bytes transferred
- ld (iolen),hl
- ld de,(sec)
- inc de ;advance current sector
- ld (sec),de
- ld hl,(secl)
- or a ;done with all sectors?
- sbc hl,de ;exit with carry set if
- ;done
- ret
- ;
- ; set up buffer with test pattern
- ;
- bufpat: ;call hl=address of base
- ; of buffer
- ; de=byte length of
- ; area to set up
- ld a,(lockpt)
- or a ;are we locked on user
- ;specified data pattern?
- jr nz,bufpa2 ;yes,jump
- bufpa1: ld a,r ;read refresh register
- xor h
- add a,l
- ;make data a function of
- ;memory address
- ld (hl),a ;and store it
- inc hl ;advance buffer address
- dec de ;count bytes stored
- ld a,d ;done yet?
- or e
- jr nz,bufpa1 ;no,loop
- ret
-
- ; user specified pattern
-
- bufpa2: ld a,(pattrn)
- ld (hl),a ;store one byte
- inc hl ;advance buffer address
- dec de ;count bytes stored
- ld a,d ;done yet?
- or e
- jr nz,bufpa2 ;not done,loop
- ret ;exit
- ;
- ;
- ;
- ; compare specified buffer and print error
- ; message if difference found
- ;
- ;
- bufcmp: ;compare buffers
- ;
- ;call bc=address of
- ; error message
- ; de=address 1st buffer
- ; hl=address 2nd buffer
- ;
- ld (bufcma),bc ;save msg address
- ld (bufcmb),hl ;save base of buffer
- ld bc,(iolen) ;length to compare
- bufcm1: ld a,(de) ;fetch byte from 1st buffer
- cp (hl) ;compare it to 2nd buffer
- jr nz,bufcm3 ;difference found,jump
- bufcm2: inc hl ;advance buffer addresses
- inc de
- dec bc ;count bytes
- ld a,b ;done yet?
- or c
- jr nz,bufcm1 ;no,loop
- ret ;back to caller
- ;
- bufcm3: ;difference found, print
- ;error audit trail
- push bc ;first save registers
- push de
- push hl
- ld de,(bufcmb)
- or a
- sbc hl,de ;find a buffer offset
- push hl ;now divide by bytes per
- pop bc ;sector to find relative
- ld de,$bps ;sector number
- call div
- ld hl,(secf)
- add hl,bc ;add relative sector to
- ;first sector to find
- ;actual address for use
- ;by PERR
- ld (sec),hl
- ld de,(bufcma)
- call perr ;now audit error
- pop hl ;restore registers
- pop de
- pop bc
- bufcm4: ;advance memory address
- ;out of this sector where
- ;an error was found.
- inc hl ;bump buffer addresses
- inc de
- dec bc ;done with all data area?
- ld a,b
- or c
- ret z ;yes,exit compare routine
- ld a,l ;check if on new sector
- and $bps-1 ;boundary
- jr z,bufcm1 ;found it, go compare
- ;more data
- jr bufcm4 ;keep advancing until
- ;sector boundary.
- ;
- bufcma: dw 0 ;address of error message
- bufcmb: dw 0 ;base buffer address
- ;
- ;
- perr: ;error printing routine,
- ;prints pass,drive,track,
- ;sector, and message
- ;specified by caller on
- ;console or list device.
- ;
- ; call with de=address
- ; of message giving
- ; type of error
- ;
- ld a,(bypass)
- or a ;is error itemization
- ;bypass flag set?
- jr nz,perr2 ;yes,skip printing
- ;and go count errors
- ld (perra),de ;save message addr.
- ld bc,(pass)
- inc bc
- ld hl,perrc ;convert current pass
- call conv
- ld a,(drv) ;form drive name
- add a,'A'
- ld (perrd),a
- ld bc,(trk) ;convert current track
- ld hl,perre
- call conv
- ld bc,(sec) ;convert current sector
- ld a,(skew) ;is skew in effect?
- or a
- jr z,perr0 ;no
- call sectran ;yes, translate sector
- perr0: ld hl,perrf
- call conv
- ld a,(list) ;should output be on
- or a ;console or printer?
- jr nz,perr3 ;jump,use printer
- ;fall thru,use console
- ld hl,(errors)
- ld a,h ;is this first error?
- or l
- jr nz,perr1 ;no,jump
- ld de,dtstq ;print title for errors
- ld c,9
- call cpm
- perr1: ld de,perrb ;print disk address
- ld c,9
- call cpm
- ld de,(perra)
- ld c,9 ;print error type
- call cpm
- ;
- perr2: ;count errors
- ld hl,(errors)
- inc hl
- ld (errors),hl
- ret ;back to caller
- ;
- perr3: ;errors to printer
- ld hl,(errors)
- ld a,h ;is this 1st error to
- or l ;be printed this pass?
- jr nz,perr4 ;no,jump
- ld hl,dtstq ;yes,print title
- call perr9
- perr4: ld hl,perrb ;print disk address
- call perr9
- ld hl,(perra)
- call perr9 ;print error type
- jr perr2 ;go count errors
- ;
- perr9: ;send a string
- ;terminated by '$'
- ;to list device
- ld a,(hl) ;fetch next char
- cp '$' ;is it terminator?
- ret z ;yes,exit
- push hl ;save string addr.
- ld e,a ;send this character
- ld c,5
- call cpm
- pop hl ;restore string addr
- inc hl ;and increment it
- jr perr9 ;check next char.
- ;
- perra: dw 0 ;addr of message
- ;describing error type
- perrb: db cr,lf
- perrc: db 'nnnn ' ;pass #
- perrd: db 'n ' ;drive
- perre: db 'nnnn ' ;track
- perrf: db 'nnnn $' ;sector
- ;
- ;
- ;
- ; disk interface to CP/M BIOS
- ;
- seldsk: ld a,(drv) ;select disk drive
- ld c,a
- ld de,24
- ;this routine links
- ;to the desired routine
- ;through the standard
- ;CP/M BIOS jump table
- jpbios: ld hl,(wboot+1)
- add hl,de
- jp (hl)
- ;
- settrk: ld bc,(trk);select track
- ld de,27
- jr jpbios
- ;
- setsec: ld bc,(sec);select sector
- ld de,30
- ld a,(skew);use sector skew?
- or a
- jr z,jpbios;no
- call sectran ;translate sector addr.
- jr jpbios
- ;
- setdma: ld bc,(buffer) ;set memory addr.
- ld de,33
- jr jpbios
- ;
- setio: call settrk ;set up track,sector,
- call setsec ;and memory address
- call setdma ;for subsequent read
- ret ;or write
- ;
- read: ;read one disk sector
- ld de,36
- jr jpbios
- ;
- write: ;write one disk sector
- ld de,39
- jr jpbios
- ;
- sectran: ;translate logical to
- ;physical sector number
- ;
- ;call bc=logical sector
- ;return bc=physical sector
- push hl
- ld hl,sectrb-1
- add hl,bc
- ld c,(hl)
- pop hl
- ret
- sectrb:
- db 1,2,3,4,5,6,7,8,9
- ;
- ; messages for test initialization and
- ; error printing
- ;
- dtsta: db cr,lf,lf
- db 'Z80 Disk Diagnostic '
- db 'Test version '
- db $ver+'0','.'
- db $rev+'0',cr,lf
- db ' Modified for the Kaypro 2 ',cr,lf
- db ' By Micro Cornucopia Magazine',cr,lf,lf
- db 'Original Version '
- db '(c) 1980 Laboratory '
- db 'Microsystems',cr,lf,'$'
- dtstb: db cr,lf,'Itemize '
- db 'errors? $'
- dtstc: db cr,lf,'Use '
- db 'console or printer'
- db '? (C/P) $'
- dtstd: db cr,lf,'Lock on read '
- db 'or write? (N/R/W) $'
- dtste: db cr,lf,'Restore '
- db 'original data? $'
- dtstf: db cr,lf,'Lock on '
- db 'data pattern? $'
- dtstg: db cr,lf,'Enter data '
- db 'pattern, hex 00-FF$'
- dtsth: db cr,lf,'Drive '
- db 'to be tested '
- db '(',$drvf+'A','-'
- db $drvl+'A',') $'
- dtsti: db cr,lf,'Confirm: test drive '
- dtsti1: db 'X ? $'
- dtstj: db cr,lf,'Test all '
- db 'tracks? $'
- dtstk: db cr,lf,'First '
- db 'track to test $'
- dtstl: db cr,lf,'Last '
- db 'track to test $'
- dtstm: db cr,lf,'Test all '
- db 'sectors? $'
- dtstn: db cr,lf,'First '
- db 'sector to test $'
- dtsto: db cr,lf,'Last '
- db 'sector to test $'
- dtstp: db cr,lf,'How many '
- db 'test passes? $'
- dtstq: db cr,lf,lf,'Pass '
- db 'Drive Track '
- db 'Sector Error-type'
- db cr,lf,'$'
- dtstr: db cr,lf,lf,'Pass '
- dtstr1: db 'nnnn complete, '
- dtstr2: db 'nnnn errors.'
- db cr,lf,'$'
- dtsts: db cr,lf,'Not enough '
- db 'memory to execute.'
- db cr,lf,'$'
- dtstt: db cr,lf,lf,'Beginning '
- db 'disk test - push '
- db 'any key to abort '
- db 'program.',cr,lf,'$'
- dtstu: db 'Warning: user '
- db 'data will not be '
- db 'restored.',cr,lf,'$'
- dtstv: db 'User data will be '
- db 'restored.',cr,lf,'$'
- dtstw: db cr,lf,'Continue or '
- db 'exit test? (C/E)$'
- dtstx: db cr,lf,lf
- db 'Goodbye.',cr,lf,'$'
- dtsty: db cr,lf,'Use sector '
- db 'skew? $'
- dtstz: db cr,lf,'Need CP/M 2.x '
- db 'to execute.',cr,lf,'$'
-
-
- merr1: db 'read error - original data$'
- merr2: db 'write error - test pattern$'
- merr3: db 'read error - test pattern$'
- merr4: db 'compare error - test pattern$'
- merr5: db 'original data cannot '
- db 'be restored$'
- merr6: db 'write error - restore phase$'
- merr7: db 'read error - restore phase$'
- ;
- ;
- ;
- ; utility and console input routines
- ;
- getyn: ;get y or n response
- ;from operator.
- ;
- ;call de=address of cue
- ;return acc=y or n
- push de ;save cue address
- ld c,9 ;print cue message
- call cpm
- ld de,getyna
- ld c,9 ;print possible answers
- call cpm
- call getchar ;get a character
- ;from console
- or 20h ;fold to lower case
- pop de ;restore cue address
- ;in case needed again
- cp 'y' ;make sure response
- ;is ok
- ret z ;exit if y
- cp 'n'
- ret z ;exit if n
- push de
- call query ;print question mark if
- pop de ;not y or n, try again
- jr getyn ;
- getyna: db '(Y/N) ',tab,'> $'
- ;
- ;
- getl: ;get any letter response
- ;from operator.
- ;
- ;call de=address of cue
- ;return acc=ASCII char.
- ld c,9 ;print cue message
- call cpm
- ld de,getla ;tab and print
- ld c,9 ;cue mark
- call cpm
- call getchar ;read console
- or 20h ;fold to lower case
- ret
- getla: db tab,'> $'
- ;
- ;
- getn: ;get a decimal number
- ;from the console.
- ;
- ;call de=address of cue
- ;return hl=number
- push de ;save cue message address
- ;in case needed later
- ld c,9
- call cpm ;print cue message
- ld de,getna ;print tab and cue mark
- ld c,9
- call cpm
- ld hl,0 ;initialize forming
- ;answer
- ld a,(digits)
- ld b,a ;total characters allowed
- ;to be input
- getn1: push hl ;save answer
- push bc ;save char. count
- call getchar ;read console
- pop bc ;restore char. count
- pop hl ;restore forming answer
- cp cr ;is this return?
- jr z,getn9 ;yes,exit with answer
- cp '0' ;is this legal char.?
- jr c,getn3 ;no, jump
- cp '9'+1 ;is this legal char.?
- jr nc,getn3 ;no,jump
- and 0fh ;isolate bottom 4 bits
- ;previous data * 10
- push hl
- pop de
- add hl,hl ;(*2)
- add hl,hl ;(*4)
- add hl,de ;(*5)
- add hl,hl ;(*10)
- ld e,a ;now add in this digit
- ld d,0
- add hl,de
- djnz getn1 ;count characters accepted
- jr getn9 ;enough accepted,exit
- getn3: ;illegal character detected.
- call query ;print question mark and
- pop de ;restart input
- jr getn
- getn9: ;input complete,clean
- ;stack and exit with
- ;answer in (hl)
- pop de
- ret
- getna: db tab,'> $'
- getnb: db '?$'
- ;
- ;
- geth: ;get $dig hex digits
- ;from keyboard
- ;
- ;call de=addr of cue
- ;return acc=lower 8 bits
- ; of entered number,
- ; hl=entire 16 bit no.
- ;
- push de ;save cue address
- ;in case needed again
- ld c,9
- call cpm ;print cue message
- ld de,getha ;print tab and cue mark
- ld c,9
- call cpm
- ld hl,0 ;initialize forming
- ;answer
- ld a,(digits)
- ld b,a ;max digits to accept
- geth1: push bc ;save registers
- push hl
- call getchar ;read console
- pop hl
- pop bc ;restore registers
- cp cr ;if carriage return exit
- jr z,geth25
- cp '0' ;make sure its legal
- jr c,geth3 ;no,jump
- cp '9'+1 ;if alpha fold to
- jr c,geth15 ;lower case
- or 20h
- geth15: cp 'f'+1 ;make sure its legal
- jr nc,geth3 ;no,jump
- cp 'a' ;check if alpha
- jr c,geth2 ;jump if 0-9
- add a,9 ;add correction
- geth2: and 0fh
- add hl,hl ;previous data *16
- add hl,hl ;(left shift 4 bits)
- add hl,hl
- add hl,hl
- add a,l ;add this char. to
- ld l,a ;forming result
- djnz geth1 ;keep reading console
- geth25: pop de ;clean up stack
- ld a,l ;put lower 8 bits
- ;of answer in acc.
- ;(in case exit by
- ; carriage return)
- ret
- geth3: call query ;print question mark
- pop de ;then restart input
- jr geth
- getha: db tab,'> $'
- ;
- ;
- query: push af ;save flags
- ld c,9 ;print question mark
- ld de,querya
- call cpm
- pop af ;restore flags
- ret
- querya: db ' ?$'
- ;
- ;
- getchar: ;get 1 character from
- ;console via raw input
- ;mode. do not echo a
- ;carriage return.
- ld e,0ffh
- ld c,6
- call cpm ;read console
- or a ;anything there?
- jr z,getchar ;no,try again
- cp cr ;is it a carriage return?
- ret z ;yes
- push af ;no,echo it
- ld e,a
- ld c,6
- call cpm
- pop af ;restore acc. and exit
- ret
- ;
- ;
- conv: ;convert binary to
- ;decimal ascii
- ;
- ;call bc=binary data, in
- ; range 0000-9999.
- ; hl=first byte addr
- ; to store output
- ;
- ld de,1000
- call div
- call conv9 ;thousands digit
- ld de,100
- call div
- call conv9 ;hundreds digit
- ld de,10
- call div
- call conv9 ;tens digit
- call conv9 ;units
- ret ;back to caller
- conv9: ld a,c ;turn quotient into
- add a,'0' ;ASCII character
- ld (hl),a ;and store it
- inc hl ;bump output pointer
- push de ;bc <- remainder
- pop bc
- ret
- ;
- ;
- div: ;single precision divide
- ;call bc=numerator
- ; de=divisor
- ;return bc=quotient
- ; de=remainder
- push hl
- ld hl,0
- or a
- sbc hl,de
- ex de,hl
- ld hl,0
- ld a,17
- div0: push hl
- add hl,de
- jr nc,div1
- ex (sp),hl
- div1: pop hl
- push af
- rl c
- rl b
- rl l
- rl h
- pop af
- dec a
- jr nz,div0
- or a
- rr h
- rr l
- ex de,hl
- pop hl
- ret
- ;
- ;
- buff1 equ 1000h ;disk buffers
- buff2 equ $bpt*2+buff1
- buff3 equ $bpt*2+buff2
- buffend equ $bpt*2+buff3
- ;
- ;
- end