mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2936 lines
66 KiB
2936 lines
66 KiB
title 'bdos interface, bdos, version 2.2 feb. 1980'
|
|
;
|
|
;*******************************************************************
|
|
;*******************************************************************
|
|
;** **
|
|
;** B A S I C D I S K O P E R A T I N G S Y S T E M **
|
|
;** **
|
|
;** I N T E R F A C E M O D U L E **
|
|
;** **
|
|
;*******************************************************************
|
|
;*******************************************************************
|
|
;
|
|
; Copyright (c) 1978, 1979, 1980
|
|
; Digital Research
|
|
; Box 579, Pacific Grove
|
|
; California
|
|
;
|
|
;
|
|
; 20 January 1980
|
|
;
|
|
;
|
|
on equ 0ffffh
|
|
off equ 0000h
|
|
test equ off
|
|
;
|
|
if test
|
|
org 0dc00h
|
|
else
|
|
org 0d800h
|
|
endif
|
|
;
|
|
; bios value defined at end of module
|
|
;
|
|
ssize equ 24 ;24 level stack
|
|
;
|
|
; low memory locations
|
|
;
|
|
reboot equ 0000h ;reboot system
|
|
ioloc equ 0003h ;i/o byte location
|
|
bdosa equ 0006h ;address field of jmp bdos
|
|
;
|
|
; bios access constants
|
|
;
|
|
bootf set bios+3*0 ;cold boot function
|
|
wbootf set bios+3*1 ;warm boot function
|
|
constf set bios+3*2 ;console status function
|
|
coninf set bios+3*3 ;console input function
|
|
conoutf set bios+3*4 ;console output function
|
|
listf set bios+3*5 ;list output function
|
|
punchf set bios+3*6 ;punch output function
|
|
readerf set bios+3*7 ;reader input function
|
|
homef set bios+3*8 ;disk home function
|
|
seldskf set bios+3*9 ;select disk function
|
|
settrkf set bios+3*10 ;set track function
|
|
setsecf set bios+3*11 ;set sector function
|
|
setdmaf set bios+3*12 ;set dma function
|
|
readf set bios+3*13 ;read disk function
|
|
writef set bios+3*14 ;write disk function
|
|
liststf set bios+3*15 ;list status function
|
|
sectran set bios+3*16 ;sector translate
|
|
;
|
|
; equates for now graphic characters
|
|
;
|
|
ctlc equ 03h ;control c
|
|
ctle equ 05h ;physical eol
|
|
ctlh equ 08h ;backspace
|
|
ctlp equ 10h ;prnt toggle
|
|
ctlr equ 12h ;repeat line
|
|
ctls equ 13h ;stop/start screen
|
|
ctlu equ 15h ;line delete
|
|
ctlx equ 18h ;=ctl-u
|
|
ctlz equ 1ah ;end of file
|
|
rubout equ 7fh ;char delete
|
|
tab equ 09h ;tab char
|
|
cr equ 0dh ;carriage return
|
|
lf equ 0ah ;line feed
|
|
ctl equ 5eh ;up arrow
|
|
;
|
|
db 0,0,0,0,0,0
|
|
;
|
|
; enter here from the user's program with function number in c
|
|
; and information address in d,e
|
|
;
|
|
jmp bdose ;past parameter block
|
|
;
|
|
; ************************************************
|
|
; *** relative locations 0009 - 000E ***
|
|
; ************************************************
|
|
;
|
|
pererr: dw persub ;permanent error subroutine
|
|
selerr: dw selsub ;select error subroutine
|
|
roderr: dw rodsub ;ro disk error subroutine
|
|
roferr: dw rofsub ;ro file error subroutine
|
|
;
|
|
;
|
|
bdose: ;arrive here from user programs
|
|
xchg
|
|
shld info
|
|
xchg ;info=de, de=info
|
|
mov a,e
|
|
sta linfo ;linfo = low(info) - don't equ
|
|
lxi h,0
|
|
shld aret ;return value defaults to 0000
|
|
;save user's stack pointer, set to local stack
|
|
dad sp
|
|
shld entsp ;entsp = stackptr
|
|
lxi sp,lstack ;local stack setup
|
|
xra a
|
|
sta fcbdsk
|
|
sta resel ;fcbdsk,resel=false
|
|
lxi h,goback ;return here after all functions
|
|
push h ;jump goback equivalent to ret
|
|
mov a,c
|
|
cpi nfuncs
|
|
rnc ;skip if invalid #
|
|
mov c,e ;possible output character to c
|
|
lxi h,functab
|
|
mov e,a
|
|
mvi d,0 ;de=func, hl=.ciotar
|
|
dad d
|
|
dad d
|
|
mov e,m
|
|
inx h
|
|
mov d,m ;de=functar(func)
|
|
lhld info ;info in de for later xchg
|
|
xchg
|
|
pchl ;dispatched
|
|
;
|
|
; dispatch table for functions
|
|
;
|
|
functab:
|
|
dw wbootf, func1, func2, func3
|
|
dw punchf, listf, func6, func7
|
|
dw func8, func9, func10, func11
|
|
;
|
|
diskf equ ($-functab)/2 ;disk funcs
|
|
;
|
|
dw func12, func13, func14, func15
|
|
dw func16, func17, func18, func19
|
|
dw func20, func21, func22, func23
|
|
dw func24, func25, func26, func27
|
|
dw func28, func29, func30, func31
|
|
dw func32, func33, func34, func35
|
|
dw func36, func37, func38, func39
|
|
dw func40
|
|
;
|
|
nfuncs equ ($-functab)/2
|
|
;
|
|
; error subroutines
|
|
;
|
|
persub: ;report permanent error
|
|
lxi h,permsg
|
|
call errflg ;to report the error
|
|
cpi ctlc
|
|
jz reboot ;reboot if response is otlc
|
|
ret ;and ignore the error
|
|
;
|
|
selsub: ;report select error
|
|
lxi h,selmsg
|
|
jmp wait$err ;wait console before boot
|
|
;
|
|
rodsub: ;report write to read/only disk
|
|
lxi h,rodmsg
|
|
jmp wait$err ;wait console
|
|
;
|
|
rofsub: ;report read/only file
|
|
lxi h,rofmsg ;drop through to wait for console
|
|
;
|
|
Wait$err:
|
|
;wait for response before boot
|
|
call errflg
|
|
jmp reboot
|
|
;
|
|
; error messages
|
|
;
|
|
dskmsg: db 'BDOS err on '
|
|
dskerr: db ' : $' ;filled in by errflg
|
|
permsg: db 'Bad sector$'
|
|
selmsg: db 'Select$'
|
|
rofmsg: db 'File '
|
|
rodmsg: db 'R/O$'
|
|
;
|
|
;
|
|
errflg:
|
|
;report error to console, message address in hl
|
|
push h
|
|
call crlf ;stack mssg address, new line
|
|
lda curdsk
|
|
adi 'A'
|
|
sta dskerr ;current disk name
|
|
lxi b,dskmsg
|
|
call print ;the error message
|
|
pop b
|
|
call print ;error mssage tail
|
|
;jmp conin
|
|
;to get the input character
|
|
;(drop through to conin)
|
|
;ret
|
|
;
|
|
; console handlers
|
|
;
|
|
conin:
|
|
;read console character to a
|
|
lxi h,kbchar
|
|
mov a,m
|
|
mvi m,0
|
|
ora a
|
|
rnz ;no previous keyboard character ready
|
|
jmp coninf ;get character externally
|
|
;ret
|
|
conech: ;read character with echo
|
|
call conin
|
|
call echoc
|
|
rc ;echo character
|
|
;character must be echoed before return
|
|
push psw
|
|
mov c,a
|
|
call tabout
|
|
pop psw
|
|
ret ;with character in a
|
|
;
|
|
echoc: ;echo character if graphic
|
|
;cr, lf, tab or backspace
|
|
cpi cr
|
|
rz ;carriage return
|
|
cpi lf
|
|
rz ;line feed
|
|
cpi tab
|
|
rz ;tab
|
|
cpi ctlh
|
|
rz ;backspace
|
|
cpi ' '
|
|
ret ;carry set if non graphic
|
|
;
|
|
conbrk: ;check for character ready
|
|
lda kbchar
|
|
ora a
|
|
jnz conb1 ;skip if active kbchar
|
|
;no active kbchar, check external break
|
|
call constf
|
|
ani 1
|
|
rz ;return if no character ready
|
|
;character ready, read it
|
|
call coninf ;to a
|
|
cpi ctls
|
|
jnz conb0 ;check stop screen function
|
|
;found cls, read next character
|
|
call coninf ;to a
|
|
cpi ctlc
|
|
jz reboot ;ctlc implies reboot
|
|
;not a reboot, act as if nothing happened
|
|
xra a
|
|
ret ;with zero in accumulator
|
|
;
|
|
conb0: ;character in accum, save it
|
|
sta kbchar
|
|
;
|
|
conb1: mvi a,1 ;return with true set in accumulator
|
|
ret
|
|
;
|
|
conout: ;compute character position/write console
|
|
;character from c
|
|
;compcol = true if computing column position
|
|
lda compcol
|
|
ora a
|
|
jnz compout ;write the character, then compute the column
|
|
;write console character from c
|
|
push b
|
|
call conbrk ;check for screen stop function
|
|
pop b
|
|
push b ;recall/save character
|
|
call conoutf ;externally, to console
|
|
pop b
|
|
push b ;recall/save character
|
|
;may be copying to the list device
|
|
lda listcp
|
|
ora a
|
|
cnz listf ;to printer, if so
|
|
pop b ;recall character
|
|
;
|
|
compout:
|
|
mov a,c ;recall the character
|
|
;and compute the column position
|
|
lxi h,column ;a = character, hl = .column
|
|
cpi rubout
|
|
rz ;no column change if nulls
|
|
inr m ;column = column + 1
|
|
cpi ' '
|
|
rnc ;return if graphic
|
|
;not graphic, reset column position
|
|
dcr m ;column = column - 1
|
|
mov a,m
|
|
ora a
|
|
rz ;return if at zero
|
|
;not at zero, may be backspace or end line
|
|
mov a,c ;character back to a
|
|
cpi ctlh
|
|
jnz notbacksp
|
|
;backspace character
|
|
dcr m ;column = column - 1
|
|
ret
|
|
;
|
|
notbacksp:
|
|
;not a backspace character, eol7
|
|
cpi lf
|
|
rnz ;return if not
|
|
;end of line, column = 0
|
|
mvi m,0 ;column = 0
|
|
ret
|
|
;
|
|
ctlout:
|
|
;send c character with possible
|
|
;preceding up-arrow
|
|
mov a,c
|
|
call echoc ;cy if not graphic (or special case)
|
|
jnc tabout ;skip if graphic, tab, cr, lf, or ctlh
|
|
;send preceding up arrow
|
|
push psw
|
|
mvi c,ctl
|
|
call conout ;up arrow
|
|
pop psw
|
|
ori 40h ;becomes graphic letter
|
|
mov c,a ;ready to print
|
|
;(drop through to tabout)
|
|
;
|
|
tabout:
|
|
;expand tabs to console
|
|
mov a,c
|
|
cpi tab
|
|
jnz conout ;direct to conout if not
|
|
;tab encountered, move to next tab position
|
|
tab0:
|
|
mvi c,' '
|
|
call conout ;another blank
|
|
lda column
|
|
ani 111b ;column mod 8 = 0 7
|
|
jnz tab0 ;back for another if not
|
|
ret
|
|
;
|
|
;
|
|
backup:
|
|
;back-up one screen position
|
|
call pctlh
|
|
mvi c,' '
|
|
call conoutf ;(drop through to pctlh)
|
|
;
|
|
pctlh: ;send ctlh to console without
|
|
;affecting column count
|
|
mvi c,ctlh
|
|
jmp conoutf ;ret
|
|
;
|
|
crlfp: ;print #, cr, lf for ctlx, ctlu, ctlr functions
|
|
;then move to strtcol (starting column)
|
|
mvi c,'#'
|
|
call conout
|
|
call crlf ;column = 0, move to position strtcol
|
|
;
|
|
crlfp0:
|
|
lda column
|
|
lxi h,strtcol
|
|
cmp m
|
|
rnc ;stop when column reaches strtcol
|
|
mvi c,' '
|
|
call conout ;print blank
|
|
jmp crlfp0
|
|
;
|
|
crlf:
|
|
;carriage return line feed sequence
|
|
mvi c,cr
|
|
call conout
|
|
mvi c,lf
|
|
jmp conout ;ret
|
|
;
|
|
print: ;print message until m(bc) = '$'
|
|
ldax b
|
|
cpi '$'
|
|
rz ;stop on $, more to print
|
|
inx b
|
|
push b
|
|
mov c,a ;char to c
|
|
call tabout ;another character printed
|
|
pop b
|
|
jmp print
|
|
;
|
|
read: ;read to info address
|
|
;(max length, current length, buffer)
|
|
lda column
|
|
sta strtcol ;save start for ctl-x, ctl-h
|
|
lhld info
|
|
mov c,m
|
|
inx h
|
|
push h
|
|
mvi b,0 ;b = current buffer length,
|
|
;c = maximum buffer length,
|
|
;hl = next to fill - 1
|
|
readnx: ;read next character, bc, hl active
|
|
push b
|
|
push h ;blen, cmax, hl saved
|
|
;
|
|
readn0:
|
|
call conin ;next char in a
|
|
ani 7fh ;mask parity bit
|
|
pop h
|
|
pop b ;reactivate counters
|
|
cpi cr
|
|
jz readen ;end of line?
|
|
cpi lf
|
|
jz readen ;also end of line
|
|
cpi ctlh
|
|
jnz noth ;backspace?
|
|
;do we have any characters to back over?
|
|
mov a,b
|
|
ora a
|
|
jz readnx ;characters remain in buffer, backup one
|
|
dcr b ;remove one character
|
|
lda column
|
|
sta compcol ;col > 0
|
|
;compcol > 0 marks repeat as length comput
|
|
jmp linelen ;uses same code as repeat
|
|
|
|
noth: ;not a backspace
|
|
cpi rubout
|
|
jnz notrub ;rubout char 7
|
|
;rubout encountered, rubout if possible
|
|
mov a,b
|
|
ora a
|
|
jz readnx ;skip if len = 0
|
|
;buffer has characters, resend las char
|
|
mov a,m
|
|
dcr b
|
|
dcx h ;a = last char
|
|
;blen=blen-1, next to fill - 1 decremented
|
|
jmp rdech1 ;act like this is an echo
|
|
;
|
|
notrub: ;not a rubout character, check end line
|
|
cpi ctle
|
|
jnz note ;physical end line?
|
|
;yes, save active counters and force eol
|
|
push b
|
|
push h
|
|
call crlf
|
|
xra a
|
|
sta strtcol ;start position = 00
|
|
jmp readn0 ;for another character
|
|
;
|
|
note: ;not end of line, list toggle?
|
|
cpi ctlp
|
|
jnz notp ;skip if not ctlp
|
|
;list toggle - change parity
|
|
push h ;save next to fill - 1
|
|
lxi h,listcp ;hl=.listcp flag
|
|
mvi a,1
|
|
sub m ;true-listop
|
|
mov m,a ;listcp - not listcp
|
|
pop h
|
|
jmp readnx ;for another char
|
|
;
|
|
notp: ;not a ctlp, line delete?
|
|
cpi ctlx
|
|
jnz notx
|
|
pop h ;discard start position
|
|
;loop while column > strtcol
|
|
;
|
|
backx:
|
|
lda strtcol
|
|
lxi h,column
|
|
cmp m
|
|
jnc read ;start again
|
|
dcr m ;column = column - 1
|
|
call backup ;one position
|
|
jmp backx
|
|
;
|
|
notx: ;not a control x, control u?
|
|
;not control-x, control-u?
|
|
cpi ctlu
|
|
jnz notu ;skip if not
|
|
;delete line (ctlu)
|
|
call crlfp ;physical eol
|
|
pop h ;discard starting position
|
|
jmp read ;to start all over
|
|
;
|
|
notu: ;not line delete, repeat line?
|
|
cpi ctlr
|
|
jnz notr
|
|
;
|
|
linelen: ;repeat line, or compute line len (ctlh)
|
|
;if compcol > 0
|
|
push b
|
|
call crlfp ;save line length
|
|
pop b
|
|
pop h
|
|
push h
|
|
push b
|
|
;bcur, cmax active, beginning buff at hl
|
|
rep0:
|
|
mov a,b
|
|
ora a
|
|
jz rep1 ;count len to 00
|
|
inx h
|
|
mov c,m ;next to print
|
|
dcr b
|
|
push b
|
|
push h ;count length down
|
|
call ctlout ;character echoed
|
|
pop h
|
|
pop b ;recall remaining count
|
|
jmp rep0 ;for the next character
|
|
;
|
|
rep1:
|
|
;end of repeat, recall lenghts
|
|
;original bc still remains pushed
|
|
push h ;save next to fill
|
|
lda compcol
|
|
ora a ;>0 if computing length
|
|
jz readn0 ;for another char if so
|
|
;column position computed for ctlh
|
|
lxi h,column
|
|
sub m ;diff > 0
|
|
sta compcol ;count down below
|
|
;move back compcol-column spaces
|
|
;
|
|
backsp: ;move back one more space
|
|
call backup ;one space
|
|
lxi h,compcol
|
|
dcr m
|
|
jnz backsp
|
|
jmp readn0 ;for next character
|
|
;
|
|
notr: ;not a ctlr, place into buffer
|
|
rdecho:
|
|
inx h
|
|
mov m,a ;character filled to mem
|
|
inr b ;blen = blen + 1
|
|
;
|
|
rdech1: ;look for a random control character
|
|
push b
|
|
push h ;active values saved
|
|
mov c,a ;ready to print
|
|
call ctlout ;may be up-arrow c
|
|
pop h
|
|
pop b
|
|
mov a,m ;recall char
|
|
cpi ctlc ;set flags for reboot test
|
|
mov a,b ;move length to a
|
|
jnz notc ;skip if not a control c
|
|
cpi 1 ;control c, must be length 1
|
|
jz reboot ;reboot if blen = 1
|
|
;length not one, so skip reboot
|
|
;
|
|
notc: ;not reboot, are we at end of buffer?
|
|
cmp c
|
|
jc readnx ;go for another if not
|
|
;
|
|
readen: ;end of read operation, store blen
|
|
pop h
|
|
mov m,b ;m(current len) = b
|
|
mvi c,cr
|
|
jmp conout ;return carriage, ret
|
|
;
|
|
func1: ;return console character with echo
|
|
call conech
|
|
jmp sta$ret
|
|
;
|
|
func2: equ tabout
|
|
;write console character with tab expansion
|
|
;
|
|
func3: ;return reader character
|
|
call readerf
|
|
jmp sta$ret
|
|
;
|
|
;func4: equated to punchf
|
|
;write punch character
|
|
;
|
|
;func5: equated to listf
|
|
;write list character
|
|
;write to list device
|
|
;
|
|
func6: ;direct console i/o - read if 0ffh
|
|
mov a,c
|
|
inr a
|
|
jz dirinp ;0ffh = > 00H, means input mode
|
|
inr a
|
|
jz constf ;0feh in c for status
|
|
;direct output function
|
|
jmp conoutf ;
|
|
;
|
|
dirinp:
|
|
call constf ;status check
|
|
ora a
|
|
jz retmon ;skip, return 00 if not ready
|
|
;character is ready, get it
|
|
call coninf ;to a
|
|
jmp sta$ret
|
|
;
|
|
func7: ;return io byte
|
|
lda ioloc
|
|
jmp sta$ret
|
|
;
|
|
func8: ;set i/o byte
|
|
lxi h,ioloc
|
|
mov m,c
|
|
ret ;jmp coback
|
|
;
|
|
func9: ;write line until $ encountered
|
|
xchg ;was lhld info
|
|
mov c,l
|
|
mov b,h ;bc=string address
|
|
jmp print ;out to console
|
|
;
|
|
func10: equ read
|
|
;read a buffered console line
|
|
;
|
|
func11: ;check console status
|
|
call conbrk ;(drop through to sta$ret)
|
|
;
|
|
sta$ret: ;store the a register to aret
|
|
sta aret
|
|
;
|
|
func$ret:
|
|
ret ;jmp goback (pop stack for non cp/m functions)
|
|
;
|
|
setlret1: ;set lret = 1
|
|
mvi a,1
|
|
jmp sta$ret
|
|
;
|
|
; data areas
|
|
;
|
|
compcol:db 0 ;true if computing column position
|
|
strtcol:db 0 ;starting column position after read
|
|
column: db 0 ;column position
|
|
listcp: db 0 ;listing toggle
|
|
kbchar: db 0 ;initial key char = 00
|
|
entsp: ds 2 ;entry stack pointer
|
|
ds ssize*2 ;stack size
|
|
lstack:
|
|
;
|
|
; end of basic i/o system
|
|
;
|
|
;*************************************************************************
|
|
;*************************************************************************
|
|
;
|
|
; common values shared between bdos1 and bdos
|
|
;
|
|
usrcode:db 0 ;current user number
|
|
curdsk: db 0 ;current disk number
|
|
info: ds 2 ;information address
|
|
aret: ds 2 ;address value to return
|
|
lret equ aret ;low (aret)
|
|
;
|
|
;*************************************************************************
|
|
;*************************************************************************
|
|
;** **
|
|
;** B A S I C D I S K O P E R A T I N G S Y S T E M **
|
|
;** **
|
|
;*************************************************************************
|
|
;*************************************************************************
|
|
;
|
|
dvers equ 22H ;version 2.2
|
|
;
|
|
; module addresses
|
|
;
|
|
; literal constants
|
|
;
|
|
true equ 0ffh ;constant true
|
|
false equ 000h ;constant false
|
|
enddir equ 0ffffh ;end of directory
|
|
byte equ 1 ;number of bytes for "byte" type
|
|
word equ 2 ;number of bytes for "byte" type
|
|
;
|
|
; fixed addresses in low memory
|
|
;
|
|
tfcb equ 005ch ;default fcb location
|
|
tbuff equ 0080h ;default buffer location
|
|
;
|
|
; fixed addresses referenced in bios module are
|
|
; pererr (0009), selerr (000c), roderr (000f)
|
|
;
|
|
; error message handlers
|
|
;
|
|
;per$error: ;report permanent error to user
|
|
; lxi h,pererr
|
|
; jmp goerr
|
|
;
|
|
;rod$error: ;report read/only file error
|
|
; lxi h,roferr ;jmp goerr
|
|
;
|
|
sel$error: ;report select error
|
|
lxi h,selerr
|
|
;
|
|
goerr: ;hl = .errorhandler, call subroutine
|
|
mov e,m
|
|
inx h
|
|
mov d,m ;address of routine in de
|
|
xchg
|
|
pchl ;to subroutine
|
|
;
|
|
;
|
|
; local subroutines for bios interface
|
|
;
|
|
move:
|
|
;move data length of length c from source de to
|
|
;destination give by hl
|
|
inr c ;in case it is zero
|
|
move0:
|
|
dcr c
|
|
rz ;more to move
|
|
ldax d
|
|
mov m,a ;one byte moved
|
|
inx d
|
|
inx h ;to next byte
|
|
jmp move0
|
|
;
|
|
selectdisk: ;select the disk drive given by
|
|
;curdsk, and fill
|
|
;the base addresses curtrka - alloca, then fill
|
|
;the values of the disk parameter block
|
|
lda curdsk
|
|
mov c,a ;current disk# to c
|
|
;lsb of e = 0 of not yet logged - in
|
|
call seldskf ;hl filled by call
|
|
;hl = 0000 if error, otherwise disk headers
|
|
mov a,h
|
|
ora l
|
|
rz ;return with 0000 in hl and z flag
|
|
;disk header block address in hl
|
|
mov e,m
|
|
inx h
|
|
mov d,m
|
|
inx h ;de = .tran
|
|
shld cdrmaxa
|
|
inx h
|
|
inx h ;.cdrmax
|
|
shld curtrka
|
|
inx h
|
|
inx h ;hl = .currec
|
|
shld curreca
|
|
inx h
|
|
inx h ;hl=.buffa
|
|
;de still contains .tran
|
|
xchg
|
|
shld tranv ;.tran vector
|
|
lxi h,buffa ;de=source for move, hl=dest
|
|
mvi c,addlist
|
|
call move ;addlist filled
|
|
;now fill the disk parameter block
|
|
lhld dpbaddr
|
|
xchg ;de is source
|
|
lxi h,sectpt ;hl is destination
|
|
mvi c,dpblist
|
|
call move ;data filled
|
|
;now set single/double map mode
|
|
lhld maxall ;largest allocation number
|
|
mov a,h ;00 indicates < 255
|
|
lxi h,single
|
|
mvi m,true ;assume a=00
|
|
ora a
|
|
jz retselect
|
|
;high order of maxall no zero, use double dm
|
|
mvi m,false
|
|
;
|
|
retselect:
|
|
mvi a,true
|
|
ora a
|
|
ret ;select disk function ok
|
|
;
|
|
home: ;move to home position,
|
|
;then offset to start of dir
|
|
call homef ;move to track 00, sector 00 reference
|
|
;lxi h, offset
|
|
;mov c,m
|
|
;inx h
|
|
;mov b,m
|
|
;call settrkf
|
|
;first directory position selected
|
|
xra a ;constant zero to accumlator
|
|
lhld curtrka
|
|
mov m,a
|
|
inx h
|
|
mov m,a ;curtrak=0000
|
|
lhld curreca
|
|
mov m,a
|
|
inx h
|
|
mov m,a ;currec=0000
|
|
;curtrk, currec both set to 0000
|
|
ret
|
|
;
|
|
rdbuff: ;read buffer and check condition
|
|
call readf ;current drive, track, sector, dma
|
|
jmp diocomp ;check for i/o errors
|
|
;
|
|
wrbuff:
|
|
;write buffer and check condition
|
|
;write type (wrtype) is in register c
|
|
;wrtype = 0 = > normal write operation
|
|
;wrtype =1 = > directory write operation
|
|
;wrtype = 2 = > start of new block
|
|
call writef ;current drive, track, sector, dma
|
|
;
|
|
diocomp: ;check for disk errors
|
|
ora a
|
|
rz
|
|
lxi h,pererr
|
|
jmp goerr
|
|
;
|
|
seekdir: ;seek the record containing
|
|
;the current dir entry
|
|
lhld dcnt ;directory counter to counter
|
|
mvi c,dskshf
|
|
call hlrotr ;value to hl
|
|
shld arecord
|
|
shld drec ;ready for seek
|
|
; jmp seek ;
|
|
;ret
|
|
;
|
|
;
|
|
seek: ;seek the track given by
|
|
;arecord (actual record)
|
|
;local equates for registers
|
|
arech equ b
|
|
arecl equ c ;arecord = bc
|
|
crech equ d
|
|
crecl equ e ;currec = de
|
|
ctrkh equ h
|
|
ctrkl equ l ;curtrk = hl
|
|
tcrech equ h
|
|
tcrecl equ l ;tcurrec = hl
|
|
;load the registers from memory
|
|
lxi h,arecord
|
|
mov arecl,m
|
|
inx h
|
|
mov arech,m
|
|
lhld curreca
|
|
mov crecl,m
|
|
inx h
|
|
mov crech,m
|
|
lhld curtrka
|
|
mov a,m
|
|
inx h
|
|
mov ctrkh,m
|
|
mov ctrkl,a
|
|
;loop while arecord < currec
|
|
seek0:
|
|
mov a,arecl
|
|
sub crecl
|
|
mov a,arech
|
|
sbb crech
|
|
jnc seek1 ;skip if arecord > = currec
|
|
;currec = currec = sectpt
|
|
push ctrkh
|
|
lhld sectpt
|
|
mov a,crecl
|
|
sub l
|
|
mov crecl,a
|
|
mov a,crech
|
|
sbb h
|
|
mov crech,a
|
|
pop ctrkh
|
|
;curtrk = curtrk - 1
|
|
dcx ctrkh
|
|
jmp seek0 ;for another try
|
|
;
|
|
seek1: ;look while arecord > = (t:currec + sectpt)
|
|
push ctrkh
|
|
lhld sectpt
|
|
dad crech ;hl = currec + sectpt
|
|
jc seek2 ;can be >ffffh
|
|
mov a,arecl
|
|
sub tcrecl
|
|
mov a,arech
|
|
sbb tcrech
|
|
jc seek2 ;skip if t > arecord
|
|
;currec = t
|
|
xchg ;curtrk = curtrk + 1
|
|
pop ctrkh
|
|
inx ctrkh
|
|
jmp seek1 ;for another try
|
|
;
|
|
seek2: pop ctrkh ;arrive here with updated values
|
|
;in each register
|
|
push arech
|
|
push crech
|
|
push ctrkh ;to stack for later
|
|
;stack contains (lowest) bc=arecord,
|
|
;de=currec, hl=curtrk
|
|
xchg
|
|
lhld offset
|
|
dad d ;hl = curtrk + offset
|
|
mov b,h
|
|
mov c,l
|
|
call settrkf ;track set up
|
|
;note that bc - curtrk is difference
|
|
;to move in bios
|
|
pop d ;recall curtrk
|
|
lhld curtrka
|
|
mov m,e
|
|
inx h
|
|
mov m,d ;curtrk updated
|
|
;now compute sector as arecord-currec
|
|
pop crech ;recall currec
|
|
lhld curreca
|
|
mov m,crecl
|
|
inx h
|
|
mov m,crech
|
|
pop arech ;bc=arecord, de=currec
|
|
mov a,arecl
|
|
sub crecl
|
|
mov arecl,a
|
|
mov a,arech
|
|
sbb crech
|
|
mov arech,a
|
|
lhld tranv
|
|
xchg ;bc=sector#, de=.tran
|
|
call sectran ;hl = tran (sector)
|
|
mov c,l
|
|
mov b,h ;bc = tran (sector)
|
|
jmp setsecf ;sector selected
|
|
;ret
|
|
;
|
|
; file control block (fcb) constants
|
|
;
|
|
empty equ 0e5h ;empty directory entry
|
|
lstrec equ 127 ;last record # in extent
|
|
recsiz equ 128 ;record size
|
|
fcblen equ 32 ;file control block size
|
|
dirrec equ recsiz/fcblen ;directory elts/record
|
|
dskshf equ 2 ;log2(dirrec)
|
|
dskmsk equ dirrec-1
|
|
fcbshf equ 5 ;log2(fcblen)
|
|
;
|
|
extnum equ 12 ;extent number field
|
|
maxext equ 31 ;largest extent number
|
|
ubytes equ 13 ;unfilled bytes field
|
|
modnum equ 14 ;data module number
|
|
maxmod equ 15 ;largest module number
|
|
fwfmsk equ 80h ;file write flag is high order modnum
|
|
namlen equ 15 ;name length
|
|
reccnt equ 15 ;record count field
|
|
dskmap equ 16 ;disk map field
|
|
lstfcb equ fcblen-1
|
|
nxtrec equ fcblen
|
|
ranrec equ nxtrec + 1 ;random record field (2 bytes)
|
|
;
|
|
; reserved file indications
|
|
;
|
|
rofile equ 9 ;high order of first type char
|
|
invis equ 10 ;invisible file in dir command
|
|
; equ 11 ;reserved
|
|
;
|
|
; utility functions for file access
|
|
;
|
|
dm$position: ;compute disk map position for vrecord to hl
|
|
lxi h,blkshf
|
|
mov c,m ;shift count to c
|
|
lda vrecord ;current virtual record to a
|
|
dmpos0:
|
|
ora a
|
|
rar
|
|
dcr c
|
|
jnz dmpos0 ;a = sbr(vrecord,blkshf) =
|
|
; vrecord/2**(sect/block)
|
|
mov b,a ;save it for later addition
|
|
mvi a,8
|
|
sub m ;8-blkshf to accumulator
|
|
mov c,a ;extent shift count in register c
|
|
lda extval ;extent value ani extmsk
|
|
;
|
|
dmpos1: ;blkshf = 3,4,5,6,7, c=5,4,3,2,1
|
|
;shift is 4,3,2,1,0
|
|
dcr c
|
|
jz dmpos2
|
|
ora a
|
|
ral
|
|
jmp dmpos1
|
|
dmpos2: ;arrive here with a = shl(ext and extmsk,
|
|
; 7-blkshf)
|
|
add b ;add the previous shr(vrecord,blkshf) value
|
|
;a is one of the following values,
|
|
; depending upon alloc bks blkshf
|
|
;1k 3 v/8 + extval * 16
|
|
;2k 4 v/16 + extval * 8
|
|
;4K 5 v/32 + extval * 4
|
|
;8k 6 v/64 + extval * 2
|
|
;16k 7 v/128 + extval * 1
|
|
ret ;with dm$position in a
|
|
;
|
|
getdm: ;return disk map value from position
|
|
;given by bc
|
|
lhld info ;base address of file control block
|
|
lxi d,dskmap
|
|
dad d ;hl = .diskmap
|
|
dad b ;index by a single byte value
|
|
lda single ;single byte/map entry?
|
|
ora a
|
|
jz getdmd ;get disk map single byte
|
|
mov l,m
|
|
mvi h,0
|
|
ret ;with hl=00bb
|
|
;
|
|
getdmd:
|
|
dad b ;hl = .fcb(dm+i*2)
|
|
;double precision value returned
|
|
mov e,m
|
|
inx h
|
|
mov d,m
|
|
xchg
|
|
ret
|
|
;
|
|
index: ;compute disk block number from current fcb
|
|
call dm$position ;0...15 in register a
|
|
mov c,a
|
|
mvi b,0
|
|
call getdm ;value to hl
|
|
shld arecord
|
|
ret
|
|
;
|
|
allocated: ;called following index to see
|
|
; if block allocated
|
|
lhld arecord
|
|
mov a,l
|
|
ora h
|
|
ret
|
|
;
|
|
atran: ;compute actual record address,
|
|
; assuming index called
|
|
lda blkshf ;shift count to reg a
|
|
lhld arecord
|
|
;
|
|
atran0:
|
|
dad h
|
|
dcr a
|
|
jnz atran0 ;shl(arecord,blkshf)
|
|
shld arecord1 ;save shifted block #
|
|
lda blkmsk
|
|
mov c,a ;mask value to c
|
|
lda vrecord
|
|
ana c ;masked value in a
|
|
ora l
|
|
mov l,a ;to hl
|
|
shld arecord ;arecord = hl or (vrecord and blkmsk)
|
|
ret
|
|
;
|
|
getexta: ;get current extent field address to a
|
|
lhld info
|
|
lxi d,extnum
|
|
dad d ;hl = .fcb (extnum)
|
|
ret
|
|
;
|
|
getfcba: ;compute reccnt and nxtrec
|
|
; addresses for get/setfcb
|
|
lhld info
|
|
lxi d,reccnt
|
|
dad d
|
|
xchg ;de=.fcb(nxtrec)
|
|
lxi h,(nxtrec-reccnt)
|
|
dad d ;hl = .fcb(nxtrec)
|
|
ret
|
|
;
|
|
getfcb: ;set variables from currently addressed fcb
|
|
call getfcba ;addresses in de, hl
|
|
mov a,m
|
|
sta vrecord ;vrecord = fcb(nxtrec)
|
|
xchg
|
|
mov a,m
|
|
sta rcount ;rcount=fcb(reccnt)
|
|
call getexta ;hl = .fcb (extnum)
|
|
lda extmsk ;extent mask to a
|
|
ana m ;fcb(extnum) and extmsk
|
|
sta extval
|
|
ret
|
|
;
|
|
setfcb: ;place values back into current fcb
|
|
call getfcba ;addresses to de, hl
|
|
lda seqio
|
|
cpi 02
|
|
jnz setfcb1
|
|
xra a ;check ranfill
|
|
;
|
|
setfcb1:
|
|
mov c,a ; = 1 if sequential i/o
|
|
lda vrecord
|
|
add c
|
|
mov m,a ;fcb(nxtrec) = vrecord +seqio
|
|
xchg
|
|
lda rcount
|
|
mov m,a ;fcb(reccnt)=rcount
|
|
ret
|
|
;
|
|
hlrotr: ;hl rotate right by amount c
|
|
inr c ;in case zero
|
|
;
|
|
hlrotr0:
|
|
dcr c
|
|
rz ;return when zero
|
|
mov a,h
|
|
ora a
|
|
rar
|
|
mov h,a ;high byte
|
|
mov a,l
|
|
rar
|
|
mov l,a ;low byte
|
|
jmp hlrotr0
|
|
;
|
|
compute$cs: ;compute checksum for current directory buffer
|
|
mvi c,recsiz ;size of directory buffer
|
|
lhld buffa ;current directory buffer
|
|
xra a ;clear checksum value
|
|
;
|
|
computecs0:
|
|
add m
|
|
inx h
|
|
dcr c ;cs=cs+buff(recs 1z-c)
|
|
jnz computecs0
|
|
ret ;with checksum in a
|
|
;
|
|
hlrotl: ;rotate the mask in hl by amount in c
|
|
inr c ;may be zero
|
|
;
|
|
hlrotl0:
|
|
dcr c
|
|
rz ;return if zero
|
|
dad h
|
|
jmp hlrotl0
|
|
;
|
|
set$cdisk: ;set a "1" value in curdsk position of bc
|
|
push b ;save input parameter
|
|
lda curdsk
|
|
mov c,a ;ready parameter for shift
|
|
lxi h,1
|
|
call hlrotl ;hl = mask to integrate
|
|
pop b ;original mask
|
|
mov a,c
|
|
ora l
|
|
mov l,a
|
|
mov a,b
|
|
ora h
|
|
mov h,a ;hl = mask or rol(1,curdsk)
|
|
ret
|
|
;
|
|
nowrite: ;return true if dir checksum
|
|
; difference occurred
|
|
lhld rodsk
|
|
lda curdsk
|
|
mov c,a
|
|
call hlrotr
|
|
mov a,l
|
|
ani 1b
|
|
ret ;now zero if nowrite
|
|
;
|
|
set$ro: ;set current disk to read only
|
|
lxi h,rodsk
|
|
mov c,m
|
|
inx h
|
|
mov b,m
|
|
call set$cdisk ;sets bit to 1
|
|
shld rodsk ;high water mark in directory goes to max
|
|
lhld dirmax
|
|
inx h
|
|
xchg ;de = directory max
|
|
lhld cdrmaxa ;hl = .cdrmax
|
|
mov m,e
|
|
inx h
|
|
mov m,d ;cdrmax =dirmax
|
|
ret
|
|
;
|
|
check$rodir: ;check current directory element
|
|
; for read/only status
|
|
call getdptra ;address of element
|
|
;
|
|
check$rofile: ;check current buff(dptr) or fcb(0)
|
|
; for r/o status
|
|
lxi d,rofile
|
|
dad d ;offset to ro bit
|
|
mov a,m
|
|
ral
|
|
rnc ;return if not set
|
|
lxi h,roferr
|
|
jmp goerr
|
|
; jmp rof$error ;exit to read only disk message
|
|
;
|
|
;
|
|
check$write: ;check for write protected disk
|
|
call nowrite
|
|
rz ;ok to write if not rodsk
|
|
lxi h,roderr
|
|
jmp goerr
|
|
; jmp rod$error ;read only disk error
|
|
;
|
|
getdptra: ;compute the address of a directory element at
|
|
;position dptr in the buffer
|
|
lhld buffa
|
|
lda dptr
|
|
addh: ;hl = hl + a
|
|
add l
|
|
mov l,a
|
|
rnc ;overflow to h
|
|
inr h
|
|
ret
|
|
;
|
|
getmodnum: ;compute the address of the module number
|
|
;bring module number to accumulator
|
|
;(high order bit is fwf(file write flag)
|
|
lhld info
|
|
lxi d,modnum
|
|
dad d ;hl = .fcb(modnum)
|
|
mov a,m
|
|
ret ;a = fcb(modnum)
|
|
;
|
|
clrmodnum: ;clear the module number field for
|
|
; user open/make
|
|
call getmodnum
|
|
mvi m,0 ;fcb(modnum) = 0
|
|
ret
|
|
;
|
|
setfwf:
|
|
call getmodnum ;hl = .fcb(modnum), a = fcb(modnum)
|
|
;set fwf (file write flag) to "1"
|
|
ori fwfmsk
|
|
mov m,a ;fcb(modnum) = fcb(modnum) or 80h
|
|
;also returns non zero in accumulator
|
|
ret
|
|
;
|
|
;
|
|
compcdr: ;return cy if cdrmaz > dcnt
|
|
lhld dcnt
|
|
xchg ;de = directory counter
|
|
lhld cdrmaxa ;hl = .cdrmax
|
|
mov a,e
|
|
sub m ;low(dcnt) - low(cdrmax)
|
|
inx h ;hl = .cdrmax + 1
|
|
mov a,d
|
|
sbb m ;hig(dcnt) - hig(cdrmax)
|
|
;condition dcnt - cdrmax produces cy
|
|
; if cdrmax > dcnt
|
|
ret
|
|
;
|
|
setcdr: ;if not (cdrmax > dcnt) then cdrmax = dcnt + 1
|
|
call compcdr
|
|
rc ;return if cdrmax > dcnt
|
|
;otherwise, hl = .cdrmax + 1, de = dcnt
|
|
inx d
|
|
mov m,d
|
|
dcx h
|
|
mov m,e
|
|
ret
|
|
;
|
|
subdh: ;compute hl = de - hl
|
|
mov a,e
|
|
sub l
|
|
mov l,a
|
|
mov a,d
|
|
sbb h
|
|
mov h,a
|
|
ret
|
|
;
|
|
newchecksum:
|
|
mvi c,true ;drop through to compute new checksum
|
|
;
|
|
checksum: ;compute current checksum record and update the
|
|
;directory element if c=true, or
|
|
; check for = if not
|
|
;drec < chksiz?
|
|
lhld drec
|
|
xchg
|
|
lhld chksiz
|
|
call subdh ;de-hl
|
|
rnc ;skip checksum if past checksum vector size
|
|
;drec < chksiz, so continue
|
|
push b ;save init flag
|
|
call compute$cs ;check sum value to a
|
|
lhld checka ;address of check sum vector
|
|
xchg
|
|
lhld drec ;value of drec
|
|
dad d ;hl = .check(drec)
|
|
pop b ;recall true=0ffh or false=00 to c
|
|
inr c ;0ffh produces zero flag
|
|
jz initial$cs ;not initializing, compare
|
|
cmp m ;compute$cs - check(drec)7
|
|
rz ;no message if ok
|
|
;checksum error, ask we beyond
|
|
;the end of the disk?
|
|
call compcdr
|
|
rnc ;no message if so
|
|
call set$ro ;read/only disk set
|
|
ret
|
|
;
|
|
initial$cs: ;initializing the checksum
|
|
mov m,a
|
|
ret
|
|
;
|
|
;
|
|
wrdir: ;write the current directory entry set checksum
|
|
call newchecksum ;initialize entry
|
|
call setdir ;directory dma
|
|
mvi c,1 ;indicates a write directory operation
|
|
call wrbuff ;write the buffer
|
|
jmp setdata ;to data dma address
|
|
;ret
|
|
;
|
|
rd$dir: ;read a directory entry into the
|
|
; directory buffer
|
|
call setdir ;directory dma
|
|
call rdbuff ;directory record loaded
|
|
;jmp setdata to data dma address
|
|
;ret
|
|
;
|
|
setdata: ;set data dma address
|
|
lxi h,dmaad
|
|
jmp setdma ;to complete the call
|
|
;
|
|
setdir: ;set directory dma address
|
|
lxi h,buffa ;jmp setdma to complete call
|
|
;
|
|
setdma: ;hl=.dma address to set (i.e., buffa or dmaad)
|
|
mov c,m
|
|
inx h
|
|
mov b,m ;parameter ready
|
|
jmp setdmaf
|
|
;
|
|
;
|
|
dir$to$user: ;copy the directory entry to the user buffer
|
|
;after call to search or searchn by user code
|
|
lhld buffa
|
|
xchg ;source is directory buffer
|
|
lhld dmaad ;destination is user dma address
|
|
mvi c,recsiz ;copy entire record
|
|
jmp move
|
|
;ret
|
|
;
|
|
end$of$dir: ;return zero flag if at end of directory,
|
|
; non zero
|
|
;if not at end (end of dir if dcnt = 0ffffh)
|
|
lxi h,dcnt
|
|
mov a,m ;may be 0ffh
|
|
inx h
|
|
cmp m ;low(dcnt) = high (dcnt) ?
|
|
rnz ;now zero returned if different
|
|
;high and low the same, = 0ffh?
|
|
inr a ;0ffh becomes 00 if so
|
|
ret
|
|
;
|
|
set$end$dir: ;set dcnt to the end of the directory
|
|
lxi h,enddir
|
|
shld dcnt
|
|
ret
|
|
;
|
|
read$dir: ;read next directory entry, with
|
|
; c=true if initializing
|
|
lhld dirmax
|
|
xchg ;in preparation for subtract
|
|
lhld dcnt
|
|
inx h
|
|
shld dcnt ;dcnt = dcnt + 1
|
|
;continue while dirmax > = dcnt
|
|
; (dirmax-dcnt no cy)
|
|
call subdh ;de-hl
|
|
jnc read$dir0
|
|
;yes, set dcnt to end of directory
|
|
jmp set$end$dir
|
|
; ret
|
|
;
|
|
read$dir0: ;not at end of directory, seek next element
|
|
;initialization flag is in c
|
|
lda dcnt
|
|
ani dskmsk ;low (dcnt) and dskmsk
|
|
mvi b,fcbshf ;to multiply by fcb size
|
|
;
|
|
read$dir1:
|
|
add a
|
|
dcr b
|
|
jnz read$dir1 ;a =(low(dcnt) and dskmsk) shl fcbshf
|
|
sta dptr ;ready for next dir operation
|
|
ora a
|
|
rnz ;return if not a new record
|
|
push b ;save initialization flag c
|
|
call seek$dir ;seek proper record
|
|
call rd$dir ;read the directory record
|
|
pop b ;recall initialization flag
|
|
jmp checksum ;checksum the directory elt
|
|
;ret
|
|
;
|
|
getallocbit: ;given allocation vector position bc,
|
|
; return with byte
|
|
;containing bc shifted so that the
|
|
; least significant
|
|
;bit is in the low order accumlator
|
|
; position. hl is
|
|
;the address of the byte for possible
|
|
; replacement in
|
|
;memory upon return, and d contains
|
|
; the number of shifts
|
|
;required to place the returned
|
|
; value back into position
|
|
mov a,c
|
|
ani 111b
|
|
inr a
|
|
mov e,a
|
|
mov d,a ;d and e both contain the number
|
|
; of bit positions to shift
|
|
mov a,c
|
|
rrc
|
|
rrc
|
|
rrc
|
|
ani 11111b
|
|
mov c,a ;c shr 3 to c
|
|
mov a,b
|
|
add a
|
|
add a
|
|
add a
|
|
add a
|
|
add a ;b shl 5
|
|
ora c
|
|
mov c,a ;bbbccccc to c
|
|
mov a,b
|
|
rrc
|
|
rrc
|
|
rrc
|
|
ani 11111b
|
|
mov b,a ;bc shr 3 to
|
|
lhld alloca ;base address of allocation vector
|
|
dad b
|
|
mov a,m ;byte to a, hl = .alloc(bc shr 3)
|
|
;now move the bit to the low
|
|
; order position of a
|
|
rotl: rlc
|
|
dcr e
|
|
jnz rotl
|
|
ret
|
|
;
|
|
setallocbit: ;bc is the bit position of alloc
|
|
;to set or reset. the
|
|
;value of the bit is in register e.
|
|
push d
|
|
call getallocbit ;shifted val a, count in d
|
|
ani 1111$1110B ;mask low bit to zero (may be set)
|
|
pop b
|
|
ora c ;low bit of c is masked into a
|
|
; jmp rotr ;to rotate back into proper position
|
|
;ret
|
|
rotr: ;byte value from alloc is in register a,
|
|
; with shift count
|
|
rrc ;in register c (to place bit back into
|
|
dcr d ; position), and
|
|
jnz rotr ;target alloc position in registers hl,
|
|
; rotate and replace
|
|
mov m,a ;back to alloc
|
|
ret
|
|
;
|
|
scandm: ;scan the disk map addressed by
|
|
; dptr for non-zero
|
|
;entries, the allocation vector
|
|
; entry corresponding
|
|
;to a non-zero entry is set to the
|
|
; value of c (0,1)
|
|
call getdptra ;hl = buffa + dptr
|
|
;hl addresses the beginning of
|
|
; the directory entry
|
|
lxi d,dskmap
|
|
dad d ;hl now addresses the disk map
|
|
push b ;save the 0/1 bit to set
|
|
mvi c,fcblen-dskmap+1
|
|
;size of single byte disk map + 1
|
|
;
|
|
scandm0: ;loop once for each disk map entry
|
|
pop d ;recall bit parity
|
|
dcr c
|
|
rz ;all done scanning?
|
|
;no, get next entry for scan
|
|
push d ;replace bit parity
|
|
lda single
|
|
ora a
|
|
jz scandm1 ;single byte scan operation
|
|
push b ;save counter
|
|
push h ;save map address
|
|
mov c,m
|
|
mvi b,0 ;bc=block#
|
|
jmp scandm2
|
|
;
|
|
scandm1: ;double byte scan operation
|
|
dcr c ;count for double byte
|
|
push b ;save counter
|
|
mov c,m
|
|
inx h
|
|
mov b,m ;bc=block#
|
|
push h
|
|
;
|
|
scandm2: ;arrive here with bc=block#, e=0/1
|
|
mov a,c
|
|
ora b ;skip if = 0000
|
|
jz scanm3
|
|
lhld maxall ;check invalid index
|
|
mov a,l
|
|
sub c
|
|
mov a,h
|
|
sbb b ;maxall - bl
|
|
cnc set$alloc$bit
|
|
;bit set to 0/1
|
|
scanm3:
|
|
pop h
|
|
inx h ;to next bit position
|
|
pop b ;recall counter
|
|
jmp scandm0 ;for another item
|
|
;
|
|
initialize: ;initialize the current disk
|
|
;lret = false
|
|
;set to true if $ file exists
|
|
;compute the length of the
|
|
;allocation vector - 2
|
|
lhld maxall
|
|
mvi c,3 ;perform maxall/8
|
|
;number of bytes in alloc vector
|
|
; is (maxall/8) + 1
|
|
call hlrotr
|
|
inx h ;hl = maxall/8 + 1
|
|
mov b,h
|
|
mov c,l ;count down bc til zero
|
|
lhld alloca ;base of allocation vector
|
|
;fill the allocation vector with zeros
|
|
initial0:
|
|
mvi m,0
|
|
inx h ;alloc (i) = 0
|
|
dcx b ;count length down
|
|
mov a,b
|
|
ora c
|
|
jnz initial0 ;set the reserved space for the directory
|
|
lhld dirblk
|
|
xchg
|
|
lhld alloca ;hl=.alloc()
|
|
mov m,e
|
|
inx h
|
|
mov m,d ;sets reserved directory blks
|
|
;allocation vector initialized, home disk
|
|
call home
|
|
;cdrmax = 3 (scans at least one
|
|
; directory record)
|
|
lhld cdrmaxa
|
|
mvi m,3
|
|
inx h
|
|
mvi m,0
|
|
;cdrmax = 0000
|
|
call set$end$dir ;dcnt = enddir
|
|
;read directory entries and check
|
|
; for allocated storage
|
|
initial2:
|
|
mvi c,true
|
|
call read$dir
|
|
call end$of$dir
|
|
rz ;return if end of directory
|
|
;not end of directory, valid entry?
|
|
call getdptra ;hl = buffa + dptr
|
|
mvi a,empty
|
|
cmp m
|
|
jz initial2 ;go get another item
|
|
;not empty, user ode the same?
|
|
lda usrcode
|
|
cmp m
|
|
jnZ pdollar
|
|
;same user code, check for '$' submit
|
|
inx h
|
|
mov a,m ;first character
|
|
sui '$' ;dollar file?
|
|
jnz pdollar
|
|
;dollar file found, mark in lret
|
|
dcr a
|
|
sta lret ;lret = 255
|
|
;
|
|
pdollar: ;now scan the disk map for allocated blocks
|
|
mvi c,1 ;set to allocated
|
|
call scandm
|
|
call setcdr ;set cdrmax to dcnt
|
|
jmp initial2 ;for another entry
|
|
;
|
|
copy$dirloc: ;copy directory location to lret following
|
|
;delete, rename, ... ops
|
|
lda dirloc
|
|
jmp sta$ret
|
|
; ret
|
|
;
|
|
compext: ;compare extent# in a with that in c,
|
|
; return nonzero
|
|
;if they do not match
|
|
push b ;save c's original value
|
|
push psw
|
|
lda extmsk
|
|
cma
|
|
mov b,a
|
|
;b has negated form of extent mask
|
|
mov a,c
|
|
ana b
|
|
mov c,a ;low bits removed from c
|
|
pop psw
|
|
ana b ;low bits removed from a
|
|
sub c
|
|
ani maxext ;set flags
|
|
pop b ;restore original values
|
|
ret
|
|
;
|
|
search: ;search for directory element of
|
|
; length c at info
|
|
mvi a,0ffh
|
|
sta dirloc ;changed if actually found
|
|
lxi h,searchl
|
|
mov m,c ;searchl = c
|
|
lhld info
|
|
shld searcha ;searcha = info
|
|
call set$end$dir ;dcnt = endir
|
|
call home ;to start at the beginning
|
|
;(drop through to searchn)
|
|
;
|
|
searchn: ;search for the next directory element,
|
|
; assuming
|
|
;a previous call on search which
|
|
; sets searcha and
|
|
;searchl
|
|
mvi c,false
|
|
call read$dir ;read next dir element
|
|
call end$of$dir
|
|
jz search$fin ;skip to end if so
|
|
;not end of directory, scan for match
|
|
lhld searcha
|
|
xchg ;de=beginning of user fcb
|
|
ldax d ;first character
|
|
cpi empty ;keep scanning if empty
|
|
jz searchnext
|
|
;not empty, may be end of logical directory
|
|
push d ;save search address
|
|
call compcdr ;past logical end?
|
|
pop d ;recall addres
|
|
jnc search$fin ;artificial stop
|
|
;
|
|
searchnext:
|
|
call getdptra ;hl = buffa + dptr
|
|
lda searchl
|
|
mov c,a ;length of search to c
|
|
mvi b,0 ;b counts up, c counts down
|
|
;
|
|
searchloop:
|
|
mov a,c
|
|
ora a
|
|
jz endsearch
|
|
ldax d
|
|
cpi '?'
|
|
jz searchok ;? matches all
|
|
;scan next character if not ubytes
|
|
mov a,b
|
|
cpi ubytes
|
|
jz searchok
|
|
;not the ubytes field, extent field?
|
|
cpi extnum ;may be extent field
|
|
ldax d ;fcb character
|
|
jz searchext ;skip to search extent
|
|
sub m
|
|
ani 7fh ;mask-out flags/extent module
|
|
jnz searchn ;skip if not matched
|
|
jmp searchok ;matched character
|
|
;
|
|
searchext: ;a has fcb character
|
|
;attempt an extent # match
|
|
push b ;save counters
|
|
mov c,m ;directory character to c
|
|
call compext ;compare user/dir char
|
|
pop b ;recall counters
|
|
jnz searchn ;skip if no match
|
|
;
|
|
searchok: ;current character matches
|
|
inx d
|
|
inx h
|
|
inr b
|
|
dcr c
|
|
jmp searchloop
|
|
;
|
|
endsearch: ;entire name matches, return dir position
|
|
lda dcnt
|
|
ani dskmsk
|
|
sta lret ;lret = low (dcnt) and 11B
|
|
lxi h,dirloc
|
|
mov a,m
|
|
ral
|
|
rnc ;dirloc=0ffh
|
|
;yes, change it to 0 to mark as found
|
|
xra a
|
|
mov m,a ;dirloc=0
|
|
ret
|
|
;
|
|
search$fin: ;end of directory, or empty name
|
|
call set$end$dir ;may be artificial end
|
|
mvi a,255
|
|
jmp sta$ret ;
|
|
;
|
|
delete: ;delete the currently addressed file
|
|
call check$write ;write protected?
|
|
mvi c,extnum
|
|
call search ;search through file type
|
|
;
|
|
delete0: ;loop while directory matches
|
|
call end$of$dir
|
|
rz ;stop if ned
|
|
;set each non zero disk map entry to 0
|
|
;in the allocation vector
|
|
;may be r/o file
|
|
call check$rodir ;ro disk error if found
|
|
call getdptra ;hl = .buff(dptr)
|
|
mvi m,empty
|
|
mvi c,0
|
|
call scandm ;alloc elts set to 0
|
|
call wrdir ;write the directory
|
|
call searchn ;to next element
|
|
jmp delete0 ;for another record
|
|
;
|
|
get$block: ;given allocation vector position
|
|
; bc, find the zero bit
|
|
;closest to this position by
|
|
; searching lef and right.
|
|
;if found, set the bit to one
|
|
; and return the bit position
|
|
;in hl. if not found (i.e. we pass
|
|
; 0 on the left, or
|
|
;maxall on the right), return 0000 in hl
|
|
mov d,b
|
|
mov e,c ;copy of starting position to de
|
|
;
|
|
lefttst:
|
|
mov a,c
|
|
ora b
|
|
jz righttst ;skip if left=0000
|
|
;left not at position zero, bit zero?
|
|
dcx b
|
|
push d
|
|
push b ;left, right pushed
|
|
call getallocbit
|
|
rar
|
|
jnc retblock ;return block number if zero
|
|
;bit is one, so try the right
|
|
pop b
|
|
pop d ;left, right restored
|
|
;
|
|
righttst:
|
|
lhld maxall ;value of maximum allocation#
|
|
mov a,e
|
|
sub l
|
|
mov a,d
|
|
sbb h ;right=maxall?
|
|
jnc retblock0 ;return block 0000 if so
|
|
inx d
|
|
push b
|
|
push d ;left,right pushed
|
|
mov b,d
|
|
mov c,e ;ready right for call
|
|
call getallocbit
|
|
rar
|
|
jnc retblock ;return block number if zero
|
|
pop d
|
|
pop b ;restore left and right pointers
|
|
jmp lefttst ;for another attempt
|
|
;
|
|
retblock:
|
|
ral
|
|
inr a ;bit back into position and set to 1
|
|
;d contains the number of
|
|
;shifts required to reposit
|
|
call rotr ;move bit back to position and store
|
|
pop h
|
|
pop d ;hl returned value, de discarded
|
|
ret
|
|
;
|
|
retblock0: ;cannot find an available bit, return 0000
|
|
mov a,c ;
|
|
ora b
|
|
jnz lefttst ;also at beginning
|
|
lxi h,0000h
|
|
ret
|
|
;
|
|
copy$fcb: ;copy the entire file control block
|
|
mvi c,0
|
|
mvi e,fcblen ;start at 0, to fcblen-1
|
|
; jmp copy$dir
|
|
;
|
|
copy$dir: ;copy fcb information starting at c for e bytes
|
|
;into the currently addressed directory entry
|
|
push d ;save length for later
|
|
mvi b,0 ;double index to bc
|
|
lhld info ;hl = source for data
|
|
dad b
|
|
xchg ;de = .fcb(c), source for copy
|
|
call getdptra ;hl = .buff(dptr), destination
|
|
pop b ;de=source, hl=dest, c = length
|
|
call move ;data moved
|
|
;
|
|
seek$copy: ;enter from close to seek and
|
|
; copy current element
|
|
call seek$dir ;to the directory element
|
|
jmp wrdir ;write the directory element
|
|
;ret
|
|
;
|
|
rename: ;rename the file described by the first half of
|
|
;the currently addressed file control
|
|
; block. The
|
|
;new name is contained in the last half of the
|
|
;currently addressed file control block.
|
|
; The file
|
|
;name and type are changed, but the reel number
|
|
;is ignored. The user number is identical
|
|
call check$write ;may be write protected
|
|
;search up to the extent field
|
|
mvi c,extnum
|
|
call search
|
|
;copy position 0
|
|
lhld info
|
|
mov a,m ;hl=.fcb(0), a=fcb(0)
|
|
lxi d,dskmap
|
|
dad d ;hl=.fcb(dskmap)
|
|
mov m,a ;fcb(dskmap)=fcb(0)
|
|
;assume the same disk drive for new named fiel
|
|
rename0:
|
|
call end$of$dir
|
|
rz ;stop at end of dir
|
|
;not end of directory, rename next element
|
|
call check$rodir ;may be read-only file
|
|
;element renamed, move to next
|
|
mvi c,dskmap
|
|
mvi e,extnum
|
|
call copy$dir
|
|
call searchn
|
|
jmp rename0
|
|
;
|
|
indicators: ;set file indicators for current fcb
|
|
mvi c,extnum
|
|
call search ;through file type
|
|
;
|
|
indic0:
|
|
call end$of$dir
|
|
rz ;stop at end of dir
|
|
;not end of directory, continue to change
|
|
mvi c,0
|
|
mvi e,extnum ;copy name
|
|
call copy$dir
|
|
call searchn
|
|
jmp indic0
|
|
;
|
|
open: ;search for the directory entry, copy to fcb
|
|
mvi c,namlen
|
|
call search
|
|
call end$of$dir
|
|
rz ;return with lret=255 if end
|
|
;not end of directory. copy fcb information
|
|
open$copy: ;(referenced below to copy fcb info)
|
|
call getexta
|
|
mov a,m
|
|
push psw
|
|
push h ;save extent#
|
|
call getdptra
|
|
xchg ;de = .buff (dptr)
|
|
lhld info ;hl=.fcb(0)
|
|
mvi c,nxtrec ;lenght of move operation
|
|
push d ;save .buff (dptr)
|
|
call move ;from .buff(dptr) to .fcb(0)
|
|
;note that entire fcb is copied,
|
|
; including indicators
|
|
call setfwf ;sets file write flag
|
|
pop d
|
|
lxi h, extnum
|
|
dad d ;hl=.buff(dptr+extnum)
|
|
mov c,m ;c = directory extent number
|
|
lxi h,reccnt
|
|
dad d ;hl = .buff (dptr + reccnt)
|
|
mov b,m ;b holds directory record count
|
|
pop h
|
|
pop psw
|
|
mov m,a ;restore extent number
|
|
;hl = .user extent #, b - dir rec cnt,
|
|
; c - dir extent #
|
|
;if user ext < dir ext then user :
|
|
; = 128 records
|
|
;if user ext = dir ext then user :
|
|
; - dir records
|
|
;if user ext > dir ext then user: = 0 records
|
|
mov a,c
|
|
cmp m
|
|
mov a,b ;ready dir reccnt
|
|
jz open$rcnt ;if same, user gets dir reccnt
|
|
mvi a,0
|
|
jc open$rcnt ;user is larger
|
|
mvi a,128 ;directory is larger
|
|
;
|
|
open$rcnt: ;a has record count to fill
|
|
lhld info
|
|
lxi d,reccnt
|
|
dad d
|
|
mov m,a
|
|
ret
|
|
;
|
|
mergezero: ;hl = .fcb1(I), de= .fcb2(I)
|
|
;if fcb1(i) = 0 then fcb1(i) :=fcb2(i)
|
|
mov a,m
|
|
inx h
|
|
ora m
|
|
dcx h
|
|
rnz ;return if = 0000
|
|
ldax d
|
|
mov m,a
|
|
inx d
|
|
inx h ;low byte copied
|
|
ldax d
|
|
mov m,a
|
|
dcx d
|
|
dcx h ;back to input form
|
|
ret
|
|
;
|
|
close: ;locate the directory element and re-write it
|
|
xra a
|
|
sta lret
|
|
sta dcnt
|
|
sta dcnt+1
|
|
call nowrite
|
|
rnz ;skip close if r/o disk
|
|
;check file write flag - 0 indicates written
|
|
call getmodnum ;fcb(modnum) in a
|
|
ani fwfmsk
|
|
rnz ;return if bit remains set
|
|
mvi c,namlen
|
|
call search ;locate file
|
|
call end$of$dir
|
|
rz ;return if not found
|
|
;merge the disk map at info with
|
|
; that at buff(dptr)
|
|
lxi b,dskmap
|
|
call getdptra
|
|
dad b
|
|
xchg ;de is .buff(dptr+16)
|
|
lhld info
|
|
dad b ;de = .buff(dptr+16), hl = .fcb(16)
|
|
mvi c,(fcblen-dskmap)
|
|
;length of single byte dm
|
|
merge0:
|
|
lda single
|
|
ora a
|
|
jz merged ;skip to double
|
|
;this is a single byte map
|
|
;if fcb(i) = 0 then fcb (i) = buff(i)
|
|
;if buff(i) = 0 then buff(i) = fcb(i)
|
|
;if fcb(i) <> buff(i) then error
|
|
mov a,m
|
|
ora a
|
|
ldax d
|
|
jnz fcbnzero
|
|
;fcb(i) = 0
|
|
mov m,a ;fcb(i) = buff(i)
|
|
;
|
|
fcbnzero:
|
|
ora a
|
|
jnz buffnzero ;buff(i) = 0
|
|
mov a,m
|
|
stax d ;buff(i)=fcb(i)
|
|
;
|
|
buffnzero:
|
|
cmp m
|
|
jnz mergerr ;fcb(i) = buff(i)?
|
|
jmp dmset ;if merge ok
|
|
;
|
|
merged: ;this is a double byte merge operation
|
|
call mergezero ;buff=fcb if buff 0000
|
|
xchg
|
|
call mergezero
|
|
xchg ;fcb = buff if fcb 0000
|
|
;they should be identical at this point
|
|
ldax d
|
|
cmp m
|
|
jnz mergerr ;low same?
|
|
inx d
|
|
inx h ;to high byte
|
|
ldax d
|
|
cmp m
|
|
jnz mergerr ;high same?
|
|
;merge operation ok for this pair
|
|
dcr c ;extra count for double byte
|
|
;
|
|
dmset:
|
|
inx d
|
|
inx h ;to next byte position
|
|
dcr c
|
|
jnz merge0 ;for more
|
|
;end of disk map merge, check record count
|
|
;de = .buff(dptr) = 32, hl = .fcb(32)
|
|
lxi b,-(fcblen-extnum)
|
|
dad b
|
|
xchg
|
|
dad b
|
|
;de = .fcr(extnum), hl = .buff(dptr+extnum)
|
|
ldax d ;current user extent number
|
|
;if fcb(ext) > = buff(fcb) then
|
|
;buff (ext) : = fcb(ext), buff(rec) :
|
|
;= fcb (rec)
|
|
cmp m
|
|
jc endmerge ;fcb extent number >= dir extent number
|
|
mov m,a ;buff(ext) = fcb(ext)
|
|
;update directory record count field
|
|
lxi b,(reccnt-extnum)
|
|
dad b
|
|
xchg
|
|
dad b
|
|
;de = .buff(reccnt), hl=.fcb(reccnt)
|
|
mov a,m
|
|
stax d ;buff(reccnt)=fcb(reccnt)
|
|
;
|
|
endmerge:
|
|
mvi a,true
|
|
sta fcb$copied ;mark as copied
|
|
jmp seek$copy ;ok to "wrdir" here - 1.4 compat
|
|
; ;
|
|
mergerr: ;elements did not merge correctly
|
|
lxi h,lret
|
|
dcr m ;=255 non zero flag set
|
|
ret
|
|
;
|
|
make: ;create a new file by creating
|
|
; a directory entry
|
|
;then opening the file
|
|
call check$write ;may be write protected
|
|
lhld info
|
|
push h ;save fcb address, look for e5
|
|
lxi h,efcb
|
|
shld info ;info = .empty
|
|
mvi c,1
|
|
call search ;length 1 match on empty entry
|
|
call end$of$dir ;zero flag set if no space
|
|
pop h ;recall info address
|
|
shld info ;in case we return here
|
|
rz ;return with error condition 255 if not found
|
|
xchg ;de = info address
|
|
;clear the remainder of the fcb
|
|
lxi h,namlen
|
|
dad d ;hl=.fcb(namlen)
|
|
mvi c,fcblen-namlen ;number of bytes to fill
|
|
xra a ;clear accumulator to 00 for fill
|
|
;
|
|
make0:
|
|
mov m,a
|
|
inx h
|
|
dcr c
|
|
jnz make0
|
|
lxi h,ubytes
|
|
dad d ;hl = .fcb(ubytes)
|
|
mov m,a ;fcb(ubytes) = 0
|
|
call setcdr ;may have extended the directory
|
|
;now copy entry to the directory
|
|
call copy$fcb ;and set the file write flag to "1"
|
|
jmp setfwf
|
|
;ret
|
|
;
|
|
open$reel: ;close the current extent, and
|
|
; open the next one
|
|
;if possible. rmf is true if in read mode
|
|
xra a
|
|
sta fcb$copied ;set true if actually copied
|
|
call close ;close current extent
|
|
;lret remains at enddir if we
|
|
; cannot open the next e
|
|
call end$of$dir
|
|
rz ;return if end
|
|
;increment extent number
|
|
lhld info
|
|
lxi b,extnum
|
|
dad b ;hl = .fcb(extnum)
|
|
mov a,m
|
|
inr a
|
|
ani maxext
|
|
mov m,a ;fcb(extnum) = ++1
|
|
jz open$mod ;move to next module if zero
|
|
;may be in the same extent group
|
|
mov b,a
|
|
lda extmsk
|
|
ana b
|
|
;if result is zero, then not in the same group
|
|
lxi h,fcb$copied ;true if the fcb was copied to directory
|
|
ana m ;produces a 00 in accumulator if not written
|
|
jz open$reel0 ;go to next physical extent
|
|
;result is now zero, so we must
|
|
; be in same logical ext
|
|
jmp open$reel1 ;to copy fcb information
|
|
|
|
open$mod: ;extent number overflow, go to next module
|
|
lxi b,(modnum-extnum)
|
|
dad b ;hl = .fcb(modnum)
|
|
inr m ;fcb(modnum) = ++1
|
|
;module number incremented, check for overflow
|
|
mov a,m
|
|
ani maxmod ;mask high order bits
|
|
jz open$r$err ;cannot overflow to zero
|
|
;otherwise, ok to continue with new module
|
|
open$reel0:
|
|
mvi c,namlen
|
|
call search ;next extent found?
|
|
call end$of$dir
|
|
jnz open$reel1
|
|
;end of file encountered
|
|
lda rmf
|
|
inr a ;0ffh becomes 00 if read
|
|
jz open$r$err ;with lret = 1
|
|
call make ;cannot be end of directory
|
|
call end$of$dir
|
|
jz open$r$err ;with lret = 1
|
|
jmp open$reel2
|
|
;
|
|
open$reel1: ;not end of file, open
|
|
call open$copy
|
|
;
|
|
open$reel2:
|
|
call getfcb ;set parameters
|
|
xra a
|
|
jmp sta$ret ;lret = 0 ;
|
|
; ret ;with lret = 0
|
|
;
|
|
open$r$err: ;cannot move to next extent of this file
|
|
call setlret1 ;lret = 1
|
|
jmp setfwf ;ensure that it will not be closed
|
|
;ret
|
|
;
|
|
seqdiskread: ;sequential disk read operation
|
|
mvi a,1
|
|
sta seqio
|
|
;drop through to diskread
|
|
;
|
|
diskread ;(may enter from seqdiskread)
|
|
mvi a,true
|
|
sta rmf ;read mode flag = true (open$reel)
|
|
;read the next record from the current fcb
|
|
call getfcb ;sets parameters for the read
|
|
lda vrecord
|
|
lxi h,rcount
|
|
cmp m ;vrecord-rcount
|
|
;skip if rcount > vrecord
|
|
jc recordok ;not enough records in the extent
|
|
;record count must be 128 to continue
|
|
cpi 128 ;vrecord = 1287
|
|
jnz diskeof ;skip if vrecord <> 128
|
|
call open$reel ;go to next extent if so
|
|
xra a
|
|
sta vrecord ;vrecord=00
|
|
;now check for open ok
|
|
lda lret
|
|
ora a
|
|
jnz diskeof ;stoop at eof
|
|
;
|
|
recordok: ;arrive with fcb addressing a record to read
|
|
call index
|
|
;error 2 if reading unwritten data
|
|
;(returns 1 to be compatible with 1.4)
|
|
call allocated ;arecord=00007
|
|
jz diskeof ;record has been allocated, reat it
|
|
call atran ;arecord now a disk address
|
|
call seek ;to proper track, sector
|
|
call rdbuff ;to dma address
|
|
jmp setfcb ;replace parameter
|
|
; ret ;
|
|
;
|
|
diskeof:
|
|
jmp setlret1 ;lret = 1
|
|
;ret
|
|
;
|
|
seqdiskwrite:
|
|
;sequential disk write
|
|
mvi a,1
|
|
sta seqio ;drop through to diskwrite
|
|
;
|
|
diskwrite: ;(may enter here from seqdiskwrite above)
|
|
mvi a,false
|
|
sta rmf ;read mode flag
|
|
;write record to currently selected file
|
|
call check$write ;in case write protected
|
|
lhld info ;hl = .fcb (0)
|
|
call check$rofile ;may be a read-only file
|
|
call getfcb ;to set local parameters
|
|
lda vrecord
|
|
cpi lstrec+1 ;vrecord-128
|
|
;skip if vrecord >lstrec
|
|
;vrecord = 128, cannot open next extent
|
|
jnc setlret1 ;lret=1 ;
|
|
;
|
|
diskwr0: ;can write the next record, so continue
|
|
call index
|
|
call allocated
|
|
mvi c,0 ;marked as normal write operation for wrbuff
|
|
jnz diskwr1 ;not allocated
|
|
;the argument to getblock is the starting
|
|
;position for the disk search, and should be
|
|
;the last allocated block for this file, or
|
|
;the value 0 if no space has been allocated
|
|
call dm$position
|
|
sta dminx ;save for later
|
|
lxi b,0 ;may use block zero
|
|
ora a
|
|
jz nopblock ;skip if no previous block
|
|
;previous block exists at a
|
|
mov c,a
|
|
dcx b ;previous block # in bc
|
|
call getdm ;previous block # to hl
|
|
mov b,h
|
|
mov c,l ;bc-prev block #
|
|
;
|
|
nopblock: ;bc = 0000, or previous block #
|
|
call get$block ;block # to Hl
|
|
;arrive here with block # or zero
|
|
mov a,l
|
|
ora h
|
|
jnz blockok ;cannot find a block to allocate
|
|
mvi a,2
|
|
jmp sta$ret ;lret=2
|
|
;
|
|
blockok: ;allocated block number is in hl
|
|
shld arecord
|
|
xchg ;block number to de
|
|
lhld info
|
|
lxi b,dskmap
|
|
dad b ;hl=.fcb(dskmap)
|
|
lda single
|
|
ora a ;set flags for single byte dm
|
|
lda dminx ;recall dm index
|
|
jz allocwd ;skip if allocating word
|
|
;allocating a byte value
|
|
call addh
|
|
mov m,e ;single byte alloc
|
|
jmp diskwru ;to continue
|
|
;
|
|
allocwd: ;allocate a word value
|
|
mov c,a
|
|
mvi b,0 ;double (dminx)
|
|
dad b
|
|
dad b ;hl = .fcb(dminx*2)
|
|
mov m,e
|
|
inx h
|
|
mov m,d ;double wd
|
|
;
|
|
diskwru: ;disk write to previously unallocated block
|
|
mvi c,2 ;marked as unallocated write
|
|
;
|
|
diskwr1: ;continue the write operation
|
|
; of no allocation error
|
|
;c = 0 if normal write, 2 if to
|
|
; prev unalloc block
|
|
lda lret
|
|
ora a
|
|
rnz ;stop if non zero returned value
|
|
push b ;save write flag
|
|
call atran ;arecord set
|
|
lda seqio
|
|
dcr a
|
|
dcr a
|
|
jnz diskwr11
|
|
pop b
|
|
push b
|
|
mov a,c
|
|
dcr a
|
|
dcr a
|
|
jnz diskwr11 ;old allocation
|
|
push h ;arecord in hl ret from atran
|
|
lhld buffa
|
|
mov d,a ;zero buffa & fill
|
|
;
|
|
fill0:
|
|
mov m,a
|
|
inx h
|
|
inr d
|
|
jp fill0
|
|
call setdir
|
|
lhld arecord1
|
|
mvi c,2
|
|
;
|
|
fill1:
|
|
shld arecord
|
|
push b
|
|
call seek
|
|
pop b
|
|
call wrbuff ;write fill record
|
|
lhld arecord
|
|
;restore last record
|
|
mvi c,0 ;change allocate flag
|
|
lda blkmsk
|
|
mov b,a
|
|
ana l
|
|
cmp b
|
|
inx h
|
|
jnz fill1 ;cont until cluster is zeroed
|
|
pop h
|
|
shld arecord
|
|
call setdata
|
|
;
|
|
diskwr11:
|
|
call seek ;to proper file position
|
|
pop b
|
|
push b ;restore/save write flag (c=2 if new block)
|
|
call wrbuff ;written to disk
|
|
pop b ;c = 2 if a new block was allocated, 0 if not
|
|
;increment record count if rcount<=vrecord
|
|
lda vrecord
|
|
lxi h,rcount
|
|
cmp m ;vrecord-rcount
|
|
jc diskwr2 ;rcount<=vrecord
|
|
mov m,a
|
|
inr m ;rcount = vrecord + 1
|
|
mvi c,2 ;mark as record count incremented
|
|
;
|
|
diskwr2: ;a has vrecord, c=2 if new block or
|
|
; new record #
|
|
; WW: DRI Patch 01 Start
|
|
nop ; dcr c
|
|
nop ; dcr c
|
|
lxi h,0 ; jnz noupdate
|
|
; WW: DRI Patch 01 End
|
|
push psw ;save vrecord value
|
|
call getmodnum ;hl=.fcb(modnum),a=fcb(modnum)
|
|
;reset the file write flag to mark
|
|
;as written fcb
|
|
ani (not fwfmsk) and 0ffH
|
|
;bit reset
|
|
mov m,a ;fcb(modnum) = fcp(modnum) and 7fh
|
|
pop psw ;restore vrecord
|
|
;
|
|
noupdate:
|
|
;check for end of extent,
|
|
; if found attempt to open
|
|
;next extent in preparation for next write
|
|
cpi lstrec ;vrecord=lstrec7
|
|
jnz diskwr3 ;skip if not
|
|
;may be random access write, if so we are done
|
|
;change next
|
|
lda seqio
|
|
cpi 1
|
|
jnz diskwr3 ;skip next extent open op
|
|
;update current fcb before going to next extent
|
|
call setfcb
|
|
call open$reel ;rmf-false
|
|
;vrecord remains at lstrec causing eof if
|
|
;no more directory space is available
|
|
lxi h,lret
|
|
mov a,m
|
|
ora a
|
|
jnz nospace ;space available, set vrecord = 255
|
|
dcr a
|
|
sta vrecord ;goes to 00 next time
|
|
;
|
|
nospace:
|
|
mvi m,0 ;lret=00 for returned value
|
|
;
|
|
diskwr3:
|
|
jmp setfcb ;replace parameters
|
|
;ret
|
|
;
|
|
rseek: ;random access seek operation,
|
|
; c=0ffh if read mode
|
|
;fcb is assumed to address an
|
|
; active file control block
|
|
;(modnum has been set to 1100$0000b
|
|
; if previous bad seek)
|
|
xra a
|
|
sta seqio ;marked as random access operation
|
|
;
|
|
rseek1:
|
|
push b ;save r/w flag
|
|
lhld info
|
|
xchg ;de will hold base of fcb
|
|
lxi h,ranrec
|
|
dad d ;hl=.fcb(ranrec)
|
|
mov a,m
|
|
ani 7fh
|
|
push psw ;record number
|
|
mov a,m
|
|
ral ;cy-lsb of extent #
|
|
inx h
|
|
mov a,m
|
|
ral
|
|
ani 11111b ;a=ext#
|
|
mov c,a ;c holds extent number, record stacked
|
|
mov a,m
|
|
rar
|
|
rar
|
|
rar
|
|
rar
|
|
ani 1111b ;mod #
|
|
mov b,a ;b holds module#, c holds ext #
|
|
pop psw ;recall sought record #
|
|
;check to insure that high byte of ran rec = 00
|
|
inx h
|
|
mov l,m ;l=high byte (must be 00)
|
|
inr l
|
|
dcr l
|
|
mvi l,6 ;zero flag, l=6
|
|
;produce error 6, seek past physical eod
|
|
jnz seekerr
|
|
;otherwise, high byte = 0, a = sought record
|
|
|
|
lxi h,nxtrec
|
|
dad d ;hl= .fcb(nxtrec)
|
|
mov m,a ;sought rec# stored away
|
|
;arrive here with b=mod#, C=ext#,
|
|
; de-.fcb, rec stored
|
|
;the r/w flag is still stacked.
|
|
; compare for values
|
|
lxi h,extnum
|
|
dad d
|
|
mov a,c ;a-seek ext#
|
|
sub m
|
|
jnz ranclose ;tests for = extents
|
|
;extents match, check mod #
|
|
lxi h,modnum
|
|
dad d
|
|
mov a,b ;b=seek mod #
|
|
;could be overflow at eof, producing module#
|
|
;of 90h or 10h, so compare all but fwf
|
|
sub m
|
|
ani 7fh
|
|
jz seekok
|
|
;
|
|
ranclose:
|
|
push b
|
|
push d ;recall parameters and fill
|
|
call close ;current extent failed
|
|
pop d
|
|
pop b ;recall parameters and fill
|
|
mvi l,3 ;cannot close error # 3
|
|
lda lret
|
|
inr a
|
|
jz badseek
|
|
lxi h,extnum
|
|
dad d
|
|
mov m,c ;fcb(extnum)-ext#
|
|
lxi h,modnum
|
|
dad d
|
|
mov m,b ;fcb(modnum)=mod#
|
|
call open ;is the file present?
|
|
lda lret
|
|
inr a
|
|
jnz seekok ;open successful?
|
|
;cannot open the file, read mode?
|
|
pop b ;r/w flag to c (=0ffh if read)
|
|
push b ;everyone expects this item stacked
|
|
mvi l,4 ;seek to unwritten extent # 4
|
|
inr c ;becomes 00 if read operation
|
|
jz badseek ;skip to error if read operation
|
|
;write operation, make new extent
|
|
call make
|
|
mvi l,5 ;cannot create new extent # 5
|
|
lda lret
|
|
inr a
|
|
jz badseek ;no dir space
|
|
;file make operation successful
|
|
seekok:
|
|
pop b ;discard r/w flag
|
|
xra a
|
|
jmp sta$ret ;with zero set
|
|
;
|
|
badseek:
|
|
;fcb no longer contains a valid fcb, mark
|
|
;with 1100$000b in modnum field so that it
|
|
;appears as overflow with file write flag set
|
|
push h ;save error flag
|
|
call getmodnum ;hl = .modnum
|
|
mvi m,1100$0000b
|
|
pop h ;and drop through
|
|
;
|
|
seekerr:
|
|
pop b ;discard r/w flag
|
|
mov a,l
|
|
sta lret ;lret = #, nonzero
|
|
;setfwf returns non-zero accumulator for err
|
|
jmp setfwf ;flag set, so subsequent close ok, ret
|
|
;
|
|
randiskread: ;random disk read operation
|
|
mvi c,true ;marked as read operation
|
|
call rseek
|
|
cz diskread ;if seek successful
|
|
ret
|
|
;
|
|
randiskwrite: ;random disk write operation
|
|
mvi c,false ;marked as write operation
|
|
call rseek
|
|
cz diskwrite ;if seek successful
|
|
ret
|
|
;
|
|
compute$rr: ;compute random record position for getfile
|
|
;size/setrandom
|
|
xchg
|
|
dad d ;de = .buf(dprt) or .fcb (0), hl =
|
|
; .f(nxtrec/reccnt)
|
|
mov c,m
|
|
mvi b,0 ;bc = 0000 0000 ?RRR RRRR
|
|
lxi h,extnum
|
|
dad d
|
|
mov a,m
|
|
rrc
|
|
ani 80h ;a = E000 0000
|
|
add c
|
|
mov c,a
|
|
mvi a,0
|
|
adc b
|
|
mov b,a ;bc = 0000 000? ERRRR RRRR
|
|
mov a,m
|
|
rrc
|
|
ani 0fh
|
|
add b
|
|
mov b,a ;bc = 000? EEEE ERRRR RRRR
|
|
lxi h,modnum
|
|
dad d
|
|
mov a,m ;a = xxx? MMMM
|
|
add a
|
|
add a
|
|
add a
|
|
add a ;cy = ? a = MMMM 0000
|
|
push psw
|
|
add b
|
|
mov b,a ;cy = ? bc = MMMM EEEE ERRR RRRR
|
|
push psw ;possible second carry
|
|
pop h ;cy = lsb of L
|
|
mov a,l ;cy = lsb of A
|
|
pop h ;cy = lsb of L
|
|
ora l ;cy/cy = lsb of A
|
|
ani 1 ;A = 0000 000? possible carry out
|
|
ret
|
|
;
|
|
getfilesize: ;compute logical file size for current fcb
|
|
mvi c,extnum
|
|
call search ;zero the receiving ranrec field
|
|
lhld info
|
|
lxi d,ranrec
|
|
dad d
|
|
push h ;save position
|
|
mov m,d
|
|
inx h
|
|
mov m,d
|
|
inx h
|
|
mov m,d ;00 00 00
|
|
;
|
|
getsize:
|
|
call end$of$dir
|
|
jz setsize ;current fcb addressed by dptr
|
|
call getdptra
|
|
lxi d,reccnt ;ready for compute size
|
|
call compute$rr ;a = 0000 000? bc = MMMM EEEE ERRR RRRR
|
|
;compare with memory, larger
|
|
pop h
|
|
push h ;recall, replace .fcb(ranrec)
|
|
mov e,a ;save cy
|
|
mov a,c
|
|
sub m
|
|
inx h ;ls byte
|
|
mov a,b
|
|
sbb m
|
|
inx h ;middle byte
|
|
mov a,e
|
|
sbb m ;carry if .fcb(ranrec) > directory
|
|
jc getnextsize ;for another try
|
|
;fcb is less or equal, fill from directory
|
|
mov m,e
|
|
dcx h
|
|
mov m,b
|
|
dcx h
|
|
mov m,c
|
|
;
|
|
getnextsize:
|
|
call searchn
|
|
jmp getsize
|
|
;
|
|
setsize:
|
|
pop h ;discard .fcb(ranrec)
|
|
ret
|
|
;
|
|
setrandom: ;set random record from the current fcb
|
|
lhld info
|
|
lxi d,nxtrec ;ready params for computesize
|
|
call compute$rr ;de = info, a = cy, bc = MMMM EEEE ERRR RRRR
|
|
lxi h,ranrec
|
|
dad d ;hl = .fcb(ranrec)
|
|
mov m,c
|
|
inx h
|
|
mov m,b
|
|
inx h
|
|
mov m,a ;to ranrec
|
|
ret
|
|
;
|
|
select: ;select disk info for subsequent
|
|
;input or output operations
|
|
lhld dlog
|
|
lda curdsk
|
|
mov c,a
|
|
call hlrotr
|
|
push h
|
|
xchg ;save it for test below, send to seldsk
|
|
call selectdisk
|
|
pop h ;recall dlog vector
|
|
cz sel$error ;returns true if select ok
|
|
;is the disk logged in?
|
|
mov a,l
|
|
rar
|
|
rc ;return if bit set
|
|
;disk not logged in, set bit and initialize
|
|
lhld dlog
|
|
mov c,l
|
|
mov b,h ;call ready
|
|
call set$cdisk
|
|
shld dlog ;dlog=set$cdisk(dlog)
|
|
jmp initialize
|
|
; ret
|
|
;
|
|
curselect:
|
|
lda linfo
|
|
lxi h,curdsk
|
|
cmp m
|
|
rz ;skip in linfo = curdsk
|
|
mov m,a ;curdsk=info
|
|
jmp select
|
|
;
|
|
reselect: ;check current fcb to see if reselection
|
|
;necessary
|
|
mvi a,true
|
|
sta resel ;mark possible reselect
|
|
lhld info
|
|
mov a,m ;drive select code
|
|
ani 1$1111b ;non zero is auto drive select
|
|
dcr a ;drive code normalized to 0..30, or 255
|
|
sta linfo ;save the drive code
|
|
cpi 30
|
|
jnc noselect ;auto select function, save curdsk
|
|
lda curdsk
|
|
sta olddsk ;olddsk = curdsk
|
|
mov a,m
|
|
sta fcbdsk ;save drive code
|
|
ani 1110$0000b
|
|
mov m,a ;preserve hi bits
|
|
call curselect
|
|
;
|
|
noselect: ;set user code
|
|
lda usrcode ;0...31
|
|
lhld info
|
|
ora m
|
|
mov m,a
|
|
ret
|
|
;
|
|
; individual function handlers
|
|
;
|
|
func12: ;return version number
|
|
mvi a,dvers
|
|
jmp sta$ret ;lret = dvers (high = 00)
|
|
; ret ;jmp goback
|
|
;
|
|
;
|
|
func13: ;reset disk system - initialize to disk 0
|
|
lxi h,0
|
|
shld rodsk
|
|
shld dlog
|
|
xra a
|
|
sta curdsk ;note that user code remains unchanged
|
|
lxi h,tbuff
|
|
shld dmaad ;dmaad = tbuff
|
|
call setdata ;to data dma address
|
|
jmp select ;ret ;jmp goback
|
|
;
|
|
;
|
|
func14: equ curselect ;select disk info
|
|
;
|
|
;
|
|
func15: ;open file
|
|
call clrmodnum ;clear the module number
|
|
call reselect
|
|
jmp open
|
|
;
|
|
;
|
|
func16: ;close file
|
|
call reselect
|
|
jmp close
|
|
;
|
|
;
|
|
func17:
|
|
;search for first occurance of a file
|
|
mvi c,0 ;length assuming '?' true
|
|
xchg ;was lhld info
|
|
mov a,m
|
|
cpi '?' ;no reselect if ?
|
|
jz qselect ;skip reselect if so
|
|
;normal search
|
|
call getexta
|
|
mov a,m
|
|
cpi '?'
|
|
cnz clrmodnum ;module number zeroed
|
|
call reselect
|
|
mvi c,namlen
|
|
;
|
|
qselect:
|
|
call search
|
|
jmp dir$to$user ;copy directory entry to user
|
|
;
|
|
;
|
|
func18: ;search for next occurance of filename
|
|
lhld searcha
|
|
shld info
|
|
call reselect
|
|
call searchn
|
|
jmp dir$to$user ;copy directory entry to user
|
|
;
|
|
;
|
|
func19: ;delete a file
|
|
call reselect
|
|
call delete
|
|
jmp copy$dirloc
|
|
;
|
|
;
|
|
func20: ;read a file
|
|
call reselect
|
|
jmp seqdiskread
|
|
;
|
|
;
|
|
func21: ;write a file
|
|
call reselect
|
|
jmp seqdiskwrite
|
|
;
|
|
;
|
|
func22: ;make a file
|
|
call clrmodnum
|
|
call reselect
|
|
jmp make
|
|
;
|
|
;
|
|
func23: ;rename a file
|
|
call reselect
|
|
call rename
|
|
jmp copy$dirloc
|
|
;
|
|
;
|
|
func24: ;return the login vector
|
|
lhld dlog
|
|
jmp sthl$ret
|
|
;
|
|
;
|
|
func25: ;return the selected disk number
|
|
lda curdsk
|
|
jmp sta$ret
|
|
;
|
|
;
|
|
func26: ;set the subsequent dma address to info
|
|
xchg ;was lhld info
|
|
shld dmaad ;dmaad = info
|
|
jmp setdata ;to data dma address
|
|
;
|
|
;
|
|
func27: ;return the login vector address
|
|
lhld alloca
|
|
jmp sthl$ret
|
|
;
|
|
;
|
|
func28: equ set$ro ;write protect current disk
|
|
;
|
|
;
|
|
func29: ;return r/o bit vector
|
|
lhld rodsk
|
|
jmp sthl$ret
|
|
;
|
|
;
|
|
func30: ;set file indicators
|
|
call reselect
|
|
call indicators
|
|
jmp copy$dirloc ;lret = dirloc
|
|
;
|
|
;
|
|
func31: ;return address of disk parameter block
|
|
lhld dpbaddr
|
|
;
|
|
sthl$ret:
|
|
shld aret
|
|
ret
|
|
;
|
|
;
|
|
func32: ;set user code
|
|
lda linfo
|
|
cpi 0ffh
|
|
jnz setusrcode ;interrogate user code instead
|
|
lda usrcode
|
|
jmp sta$ret ;lret=usrcode
|
|
; ret
|
|
;
|
|
setusrcode:
|
|
ani 1fh
|
|
sta usrcode
|
|
ret
|
|
;
|
|
;
|
|
func33: ;random disk read operation
|
|
call reselect
|
|
jmp randiskread ;to perform the disk read
|
|
;
|
|
;
|
|
func34: ;random disk write operation
|
|
call reselect
|
|
jmp randiskwrite ;to perform the disk write
|
|
;
|
|
;
|
|
func35: ;return file size
|
|
call reselect
|
|
jmp getfilesize
|
|
;
|
|
;
|
|
func36: equ setrandom ;set random record
|
|
;
|
|
;
|
|
func37:
|
|
lhld info
|
|
mov a,l
|
|
cma
|
|
mov e,a
|
|
mov a,h
|
|
cma
|
|
lhld dlog
|
|
ana h
|
|
mov d,a
|
|
mov a,l
|
|
ana e
|
|
mov e,a
|
|
lhld rodsk
|
|
xchg
|
|
shld dlog
|
|
mov a,l
|
|
ana e
|
|
mov l,a
|
|
mov a,h
|
|
ana d
|
|
mov h,a
|
|
shld rodsk
|
|
ret
|
|
;
|
|
;
|
|
goback: ;arrive here at end of processing to return
|
|
; to user
|
|
lda resel
|
|
ora a
|
|
jz retmon ;reselection may have taken place
|
|
lhld info
|
|
mvi m,0 ;fcb(0) = 0
|
|
lda fcbdsk
|
|
ora a
|
|
jz retmon ;restore disk number
|
|
mov m,a ;fcb(0) = fcbdsk
|
|
lda olddsk
|
|
sta linfo
|
|
call curselect
|
|
;
|
|
; return from the disk monitor
|
|
;
|
|
retmon:
|
|
lhld entsp
|
|
sphl ;user stack restored
|
|
lhld aret
|
|
mov a,l
|
|
mov b,h ;ba = hl = aret
|
|
ret
|
|
;
|
|
func38: equ func$ret
|
|
func39: equ func$ret
|
|
;
|
|
;
|
|
func40: ;random disk write with zero fill of
|
|
; unallocated block
|
|
call reselect
|
|
mvi a,2
|
|
sta seqio
|
|
mvi c,false
|
|
call rseek1
|
|
cz diskwrite ;if seek successful
|
|
ret
|
|
;
|
|
;
|
|
; data areas
|
|
;
|
|
; initialized data
|
|
;
|
|
efcb: db empty ;0e5h=available dir entry
|
|
rodsk: dw 0 ;read only disk vector
|
|
dlog: dw 0 ;logged in disks
|
|
dmaad: dw tbuff ;initial dma address
|
|
;
|
|
;
|
|
; curtrka - alloca are set upon disk select
|
|
; (data must be adjacent, do not insert variables)
|
|
; (address of translate vector, not used)
|
|
;
|
|
cdrmaxa:ds word ;pointer to cur dir max value
|
|
curtrka:ds word ;current track address
|
|
curreca:ds word ;current record address
|
|
buffa: ds word ;pointer to directory dma address
|
|
dpbaddr:ds word ;current disk parameter block address
|
|
checka: ds word ;current checksum vector address
|
|
alloca: ds word ;current allocation vector address
|
|
addlist equ $-buffa ;address list size
|
|
;
|
|
; sectpt - offset obtained from disk parm block at dpbaddr
|
|
;
|
|
sectpt: ds word ;sectors per track
|
|
blkshf: ds byte ;block shift factor
|
|
blkmsk: ds byte ;block mask
|
|
extmsk: ds byte ;extent mask
|
|
maxall: ds word ;maximum allocation number
|
|
dirmax: ds word ;largest directory number
|
|
dirblk: ds word ;reserved allocation bits for directory
|
|
chksiz: ds word ;size of checksum vector
|
|
offset: ds word ;offset tracks at beginning
|
|
dpblist equ $-sectpt ;size of area
|
|
;
|
|
; local variables
|
|
;
|
|
tranv: ds word ;address of translate vector
|
|
;
|
|
fcb$copied:
|
|
ds byte ;set true if copy$fcb called
|
|
rmf: ds byte ;read mode flag for open$reel
|
|
dirloc: ds byte ;directory flag in rename, etc.
|
|
seqio: ds byte ;1 if sequential i/o
|
|
linfo: ds byte ;low(info)
|
|
dminx: ds byte ;local for diskwrite
|
|
searchl:ds byte ;search length
|
|
searcha:ds word ;search address
|
|
tinfo: ds word ;temp for info in 'make'
|
|
single: ds byte ;set true if single byte allocation map
|
|
resel: ds byte ;reselection flag
|
|
olddsk: ds byte ;disk on entry to bdos
|
|
fcbdsk: ds byte ;disk named in fcb
|
|
rcount: ds byte ;record count in current fcb
|
|
extval: ds byte ;extent number and extmsk
|
|
vrecord:ds word ;current virtual record
|
|
arecord:ds word ;current actual record
|
|
arecord1:
|
|
ds word ;current actual block # * blkmsk
|
|
;
|
|
; local variables for directory access
|
|
;
|
|
dptr: ds byte ;directory pointer 0, 1, 2, 3
|
|
dcnt: ds word ;directory counter 0, 1, ... dirmax
|
|
drec: ds word ;directory record 0, 1, ... dirmax/4
|
|
;
|
|
bios equ ($ and 0ff00h)+100h ;next module
|
|
end
|
|
|