home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
CPM
/
UTILS
/
DIRUTL
/
ERADIR10.LBR
/
ERADIR.ZQ0
/
ERADIR.Z80
Wrap
Text File
|
2000-06-30
|
14KB
|
685 lines
; ERADIR.Z80 Vers 1.0 26Aug86
; (c) 1986 by W. Brimhall - Znode #52 (602)996-8739
; This program can be distributed free for non-commerical use.
; ERADIR erases the directory of any CP/M 2.2 compatible disk by
; writing E5h to each byte of all sectors in the directory. This
; program must be used with caution since any data that was on the
; drive will be next to impossible to recover. One of the primary
; uses for ERADIR is to initalize a RAM disk after power up.
;Enter this command line to display the builtin help info:
;
; ERADIR /
;Enter this command line to Assemble & link:
;
; ZAS ERADIR ; ZLINK ERADIR,SYSLIB/
;Syslib routines:
ext cin ; input console to reg a
ext bist ; bdos console input status
ext bout ; bdos output reg a to console
ext bbline ; bdos line input
ext crlf ; output crlf to console
ext print ; print inline message
ext phldc ; print hl in dec on con
bdos equ 5
cr set 0dh
lf set 0ah
; + + + + ilprn + + + +
;This macro displays an inline string terminated with 0h
;on the console without loosing control when tw tracing
;with a debugger. It is used with the ilprn@ subroutine
;located at the end of the program.
ilprn macro
call ilprn@
ret
endm
;-----------------------------
; COM file entry point @ 100h
;-----------------------------
jp main
;--------------
; Help routine
;--------------
help: ilprn
db cr,lf
db 'ERADIR Vers 1.0 26Aug86',cr,lf
db ' CP/M directory erase program.',cr,lf
db ' (c) 1986 by W.Brimhall Znode 52 (602) 996-8739',cr,lf
db ' (This program can be distributed free for '
db 'non-commerical use.)',cr,lf,lf
db ' ERADIR erases the directory of any '
db 'CP/M 2.2 compatible disk by',cr,lf
db ' writing E5h to each byte of all sectors '
db 'in the directory. This',cr,lf
db ' program must be used with caution since '
db 'any data that was on the',cr,lf
db ' drive will be next to impossible to recover. '
db 'ERADIR is especially',cr,lf
db ' suited for initalizing RAM disks '
db 'after power up.',cr,lf,lf
db ' Command Line Syntax:',cr,lf,lf
db ' ERADIR / ;Display this help info.',cr,lf
db ' ERADIR d ;Erase directory on drive "d" '
db '(A thru P).',cr,lf
db ' ERADIR ;Prompt user for drive.',cr,lf,lf
db ' Information about the selected '
db 'drive is displayed and you are given',cr,lf
db ' a chance to abort before the actual '
db 'directory erase is performed.',cr,lf,lf,0
jp exit
;------------------
; dbug entry point
;------------------
dbug: call main ;ddt entry point
rst 38h ;return to ddt
;--------------
; main program
;--------------
main: ld (stack),sp ;save ccp sp
ld sp,stack ;set up new stack
ld c,0ch
call bdos ;check cp/m version
ld a,l
cp 22h
jp nc,verok
ilprn
db cr,lf,'++Must have CP/M vers 2.2 or later...',0
jp abort
verok: call bjmps ;set up local bios jumps
;Check for command line parameters.
ld a,(80h) ;a= command line length
or a
jr z,enter ;prompt user if nul command line tail
ld a,(82h)
cp '/'
jp z,help ;display help info if /
call valid ;check for valid drive
jr nc,logdrv ;jmp if A thru P
;Prompt user for drive.
enter: ilprn
db cr,lf,'Logical drive (A: thru P:) ? ',0
or -1 ;select upper case input
call bbline ;input line (syslib)
or a
jp z,abort ;exit if cr only
call crlf
ld a,(hl) ;a= selected logical drive
call valid ;check for valid drive
jp c,error ;jmp if bad
;Log in the selected drive.
logdrv: sub 'A' ;convert to drive number
ld (drive),a ;save drive number
call getsp ;login & get trk & sec parms
jr nz,drvok ;jmp if valid drive
error: ilprn
db '++Illegal drive name specified...',cr,lf,0
jp enter
;Display disk parameters and make double shure we want
;to continue...
drvok: call dirgps ;calculate number of directory groups
call stats ;display drive statistics
ilprn
db cr,lf,lf,'OK to erase directory on drive ',0
ld a,(drive)
add a,'A'
call bout ;display drive letter
ilprn
db ': (y/n, CR=n) ? ',0
or -1 ;select upper case input
call bbline ;input line from console
or a
jp z,abort ;abort if cr only
ld a,(hl) ;get 1st char
cp 'Y'
jp nz,abort ;abort if not Y
;Now that a drive has been successfully selected & verified
;we can go ahead and erase its directory.
ilprn
db cr,lf,lf,'Erasing directory',lf,0
call filbfr ;fill default dma buffer with e5h
call group0 ;set track & sector for group 0
nxtrec: ld bc,dskbfr ;bc--> disk write buffer
call lsdma ;set dma address
ilprn
db cr,'Track ',0
ld hl,(curtrk)
call phldc
ilprn
db ' Sector ',0
ld hl,(physec)
call phldc
call wrtsec ;write 1 sector
call nxtsec ;advance to next sector within group
jr nc,nxtrec ;loop til end of group
ld hl,group
inc (hl) ;group=group+1
ld a,(dgrps) ;a=number of dir groups
cp (hl)
jp nz,nxtrec ;loop til end of directory
call crlf ;output crlf to console (syslib)
ld hl,(count)
ld a,h
or l
jr z,dirok ;jmp if no write errors
call phldc ;display error count
ilprn
db ' Media errors in directory, Reformat and try again...'
jr exit ;exit
dirok: ilprn
db cr,lf,'Successful Directory erase',cr,lf,0
jr exit
; + + + + abort & exit + + + +
;Exit back to the CCP.
abort: ilprn
db cr,lf,'++ERADIR aborted...',cr,lf,0
exit: ld bc,80h ;bc--> default dma buffer
call lsdma ;restore dma address to default buffer
ld a,(4) ;get current drive
ld c,a ;c= drive
ld e,1 ;reset "new select" flag
call lseldk ;restore original drive selection
ld sp,(stack) ;restore CCP sp
ret
; + + + valid + + +
;Return cf reset if reg A contains a drive name from 'a' to 'p'
valid: and 5fh ;convert drive to upper case
cp 'A'
ret c ;cf=set if drive < 'a'
cp 'P'+1
ccf
ret ;cf=set if drive > 'p'
; + + + getsp + + +
;Get track and sector parameters for drive.
;Return zf set if drive is not in system.
getsp: ld a,(drive)
ld c,a ;c=current drive
ld e,0 ;set "new select" flag
call lseldk ;select disk through bios to get dph
ld a,h
or l
ret z ;ret if select error
ld e,(hl) ;get the sector table pntr
inc hl
ld d,(hl)
inc hl
ex de,hl
ld (sectbl),hl
ld hl,8 ;offset to dpbptr
add hl,de
ld a,(hl)
inc hl
ld h,(hl)
ld l,a ;hl --> dpb start (source)
ld de,dpb ;de --> local area for dpb (dest)
ld bc,14 ;bc= bytes to move
;fill in disk params
ldir ;move dpb into local area
ld hl,grpdsp
ld a,(blm) ;blm=sectors per group
ld (hl),a ;grpdsp=max
ld hl,(dsm) ;dsm=total groups
ld (group),hl ;group=max
call gtksec ;compute last track & sector on drive
ld hl,(cursec)
ld (maxsec),hl
ld hl,(curtrk)
ld (maxtrk),hl
or -1
ret ;a= -1, zf=reset
; + + + filbfr + + +
;Fill dskbfr with E5h.
filbfr: ld hl,dskbfr ;hl--> dma buffer
ld c,80h ;c= 80h= byte count
filbf1: ld (hl),0e5h ;load a byte
inc hl
dec c
jr nz,filbf1 ;loop til c=0
ret
; + + + group0 + + +
;Set track & sector for group 0.
group0: ld hl,0
ld (group),hl ;group=0
ld a,0
ld (grpdsp),a ;displacement=0
call gtksec ;set track & sector
ret
; + + + dirgps + + +
;Calculate the number of directory groups
;and store at dgrps.
dirgps: ld hl,(al0) ;hl=dir group allocation bits
ld c,16 ;c=loop count
ld b,0 ;b=group count
dirg1: call rotrhl
jp nc,notset ;jmp if bit is not set
inc b
notset: dec c
jp nz,dirg1
ld a,b
ld (dgrps),a ;store directory groups
ret
; + + + stats + + +
;Print disk statistics
stats: ilprn
db cr,lf,'Disk information for drive ',0
ld a,(drive)
add 'A'
call bout
ilprn
db ':',cr,lf,' tracks:',9,0
ld hl,(maxtrk)
inc hl
call phldc
ilprn
db cr,lf,' sys tracks:',9,0
ld hl,(systrk)
call phldc
ilprn
db cr,lf,' recs/trk:',9,0
ld hl,(spt)
call phldc
ilprn
db cr,lf,' recs/group:',9,0
ld a,(blm)
inc a
ld l,a
ld h,0
call phldc
ilprn
db cr,lf,' tot grps:',9,0
ld hl,(dsm)
call phldc
ilprn
db cr,lf,' dir entries:',9,0
ld hl,(drm)
inc hl
call phldc
ilprn
db cr,lf,' dir groups:',9,0
ld hl,(dgrps)
ld h,0
call phldc
ret
; + + + report + + +
;Report error information on consol
report: ilprn
db cr,lf,'media error : track ',0
ld hl,(curtrk)
call phldc
ilprn
db ' physical sector ',0
ld hl,(physec)
call phldc
call crlf
ret
; + + + nxtsec + + +
;advance to next sector.
;ret cf set when next group is reached
nxtsec: ld a,(grpdsp) ;a=sector within group
inc a
ld (grpdsp),a ;bump to next sector
ld d,a ;save in d
ld a,(blm) ;a=sectors per group
cp d
ret nc ;ret cf=0 if same group
xor a
ld (grpdsp),a ;else make displacement=0
scf
ret ;ret cf set
; + + + settrk + + +
;Set track # to value stored at curtrk.
settrk: ld hl,(curtrk)
ld b,h
ld c,l
call lstrk ;local bios set track call
ret
; + + + setsec + + +
;Set the physical sector number through bios by taking the
;logical sector value stored at cursec and using the sector
;translation table to convert it to its physical value.
setsec: push hl
ld hl,(cursec)
ex de,hl
push de
ld hl,(systrk)
ex de,hl
ld hl,(curtrk)
call subde
pop bc
ld h,b
ld l,c
jp nc,notsys
ld a,(first0) ;see if first sec 0
or a
jp nz,sets1 ;no, jump away
dec hl ;yes, so decrement
jp sets1 ;requested, then go
notsys: ld hl,(sectbl)
ex de,hl
dec bc
call lsectn
ld a,(spt+1) ;if spt<256 (hi-ord = 0)
or a ;then force 8-bit translation
jp nz,sets1 ;else keep all 16 bits
ld h,a
sets1: ld (physec),hl
ld b,h
ld c,l
call lssec
pop hl
ret
; + + + gtksec + + +
;Convert group & displacement to track & sector.
gtksec: ld hl,(group) ;hl = group #
ld a,(bsh)
gloop: add hl,hl
dec a
jp nz,gloop
ld a,(grpdsp)
add a,l ;can't carry
ld l,a
;Divide by # of sectors, quotient=track, remainder=sector
ex de,hl
ld hl,(spt)
call neg
ex de,hl
ld bc,0
divlp: inc bc
add hl,de
jp c,divlp
dec bc
ex de,hl
ld hl,(spt)
add hl,de
push hl
ld hl,(systrk)
add hl,bc
ld (curtrk),hl
pop hl
inc hl
ld (cursec),hl
ret
; + + + wrtsec + + +
;Write sector to disk.
wrtsec: xor a
call gtksec ;convert group to track & sector
call setsec ;set sector
call settrk ;set track
call lwrite ;local bios disk write
or a
ret z ;ret if good write
ld hl,(count)
inc hl
ld (count),hl ;inc error count
rdsec1: call report ;report error on consol
ret
; + + + prndrv + + +
;print current drive name on consol
prndrv: ld a,(drive) ;get current drive number
add 'a' ;convert to ascii name
call bout
ld a,':'
call bout
ret
; + + + bjmps + + +
;This subroutine sets up local jumps to the bios
bjmps: ld hl,(1)
ld de,3
add hl,de
ld (lconst+1),hl
add hl,de
ld (lconin+1),hl
add hl,de
ld (lbout+1),hl
add hl,de
ld (llist+1),hl
add hl,de ;punch
add hl,de ;reader
add hl,de
ld (lhome+1),hl
add hl,de
ld (lseldk+1),hl
add hl,de
ld (lstrk+1),hl
add hl,de
ld (lssec+1),hl
add hl,de
ld (lsdma+1),hl
add hl,de
ld (lread+1),hl
add hl,de
ld (lwrite+1),hl
add hl,de
add hl,de
ld (lsectn+1),hl
ret
lconst: jp $-$ ;filled in by bjmps routine
lconin: jp $-$
lbout: jp $-$
llist: jp $-$
lhome: jp $-$
lseldk: jp $-$
lstrk: jp $-$
lssec: jp $-$
lsdma: jp $-$
lread: jp $-$
lwrite: jp $-$
lsectn: jp $-$
; + + + neg + + +
;2's complement hl ==> hl
neg: ld a,l
cpl
ld l,a
ld a,h
cpl
ld h,a
inc hl
ret
; + + + rotrhl + + +
;hl/2 ==> hl
rotrhl: or a
ld a,h
rra
ld h,a
ld a,l
rra
ld l,a
ret
; + + + subde + + +
;hl-de ==> hl
subde: ld a,l
sub e
ld l,a
ld a,h
sbc a,d
ld h,a
ret
; + + + mult + + +
;quick kludge multiply
;hl=de ==> hl
mult: push bc
push de
ex de,hl
ld b,d
ld c,e
ld a,b
or c
jp nz,mulcon
ld hl,0 ;filter special case
jp mldone ; of multiply by 0
mulcon: dec bc
ld d,h
ld e,l
multlp: ld a,b
or c
jp z,mldone
add hl,de
dec bc
jp multlp
mldone: pop de
pop bc
ret
; * * * * ilprn@ * * * *
;Special inline string print subroutine that will
;not lose control when tw tracing with Zsid. this
;routine returns to the instruction following the
;ilprn@ which must be a ret. Zsid places a
;break point at that address. the address of the
;instruction following the inline string is calculated
;and returned on the stack.
;destroys: a,d,e & flags
ilprn@: ld (hlsave),hl ;save hl
pop hl ;hl= return address
push hl ;put back on stack
inc hl ;hl --> inline string
ilp1: ld a,(hl)
or a
jr z,ilp2 ;jmp if end of string
call bout
inc hl
jp ilp1
ilp2: inc hl ;hl= next instruction address
ex (sp),hl ;(sp)= next instruction address,
;hl= return address
push hl ;(sp)= return address
ld hl,(hlsave) ;restore hl
ret ;return to "ret" instruction
;following "ilprn@"
; * * * data area * * *
hlsave: ds 2 ;temp storage for hl
drive: ds 1 ;current drive
dgrps: ds 1 ;directory groups
dmaptr: ds 2 ;dma buffer pointer
group dw 0 ;current cp/m group number
grpdsp db 0 ;sector displacement within group
count dw 0 ;write error counter
saveflg db 0
curtrk dw 0
cursec dw 1
physec dw 1
filect dw 0
qflag db 0 ;quiet? (0=no)
first0 db 0 ;sets to 0 if first sec # is 0
maxtrk dw 0
maxsec dw 0
ver2fl db 0
sectbl dw 0 ;pointer to sector skew table
;The disk parameter block is moved here from cp/m
dpb: equ $ ;disk parameter block (copy)
spt: ds 2 ;sectors per track
bsh: ds 1
blm: ds 1 ;group size -1
exm: ds 1
dsm: ds 2 ;total groups
drm: ds 2 ;directory entries -1
al0: ds 1 ;dir group allocation bits
al1: ds 1
cks: ds 2
systrk: ds 2 ;system tracks
dskbfr: ds 128 ;disk sector write buffer
ds 128
stack: ds 2
end