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
/
BDOS
/
DOSPLSOR.ARK
/
DOSPLUS.MAC
< prev
next >
Wrap
Text File
|
1986-12-08
|
78KB
|
2,733 lines
title 'DOS+ Disk Operating System 2.5'
;
ver equ 5; 3 thru 15 allowable
;
; ***************************************************************
; * *
; * D O S + Z80 replacement Disk Operating System Version 2.5 *
; * *
; * Copyright (c) 1986 by *
; * C.B. Falconer, 680 Hartford Tpk., (203) 281-1438 *
; * Hamden, Conn. 06517, USA *
; * all rights reserved *
; ***************************************************************
;
; DOS+ is designed for general usage, and is an improved replacement
; for CPM 2.2. DOS+ requires a Z80 cpu. DOS+ has comprehensive
; provisions for RCPM security, especially when used with CCP+ (the
; supplied CCP), and is virtually impregnable with BYERSX. The system
; allows extension with user installable RSXs (Resident System Exten-
; sions), which are used for print spool/unspoolers, the XJOB utility,
; and others. These RSX's may be dynamically installed and removed,
; for optimum memory usage. DSKDRIVE (the foreign disk driver) and
; BYERSX (the communications system) must be installed for the target
; system before use. See below.
;
; Some of the code is quite tricky, in order to pack the features into
; the available space. The tricks are usually commented.
;
; Revisions:
; 2.5 (86/12/06) cbf. Prevented permanent lockout of random read
; files after a bad seek (can now re-seek, aborted Turbo Pascal).
; If the bios supports it (by returning an appropriate value in
; HL on console output calls) DCIO output calls (function 6) will
; return that value as the current X/Y screen position. GETINFO
; arguments 3, 4 & 5 return List, Punch, and Reader status resp-
; ectively (punch/reader only when customization addresses set).
; A special vector at offset 01Eh now controls the exit point for
; aborts, either from DOS errors, or CTL-C (breaks enabled) from
; the console. If used, the vector resets itself to a warm-boot.
; 2.4 (86/11/05) cbf. Console buffer read simplified. No CTL-R,
; rub equivalent to bs, CTL-U equivalent to CTL-X. No reg. save
; Improved error reports. Compatibility flag bit. Setting
; break inhibit also prevents ^C break on call 10 (cons. input)
; and when exiting from CTL-S output pause. R/O files are not
; stamped for access time. Extended calls GETINFO and TDEC.
; 2.3 (86/09/20) cbf. Flags expanded to control time access method.
; Time routine may be a pointer to storage. File timestamps for
; creation, update, and access (incompatible with CPM3). Access
; stamping controlled separately, allows for disk wrt-protect.
; Set/Get time bdos calls changed for compatibility with CPM3
; Initial link at bdos+11, compatible with dos finder routines.
; Console input modified to make DCIO compatible with other ops.
; SYSTEM files, user 0, are visible to all users (for read).
; Removed path restriction to SYSTEM files. Applies to all read
; Paths only apply to FCBs with a default drive specification.
; User break on any DOS call available. DCIO enabled separately.
; Corrected wrt_rand_zero_fill (40) call. Corrected file system
; so SUBMIT/JOB files work. File alteration now resets the
; $ARC bit (T3) for proper operation of archiving utilities.
; The CPM3 method (via set file attributes) of recording exact
; file length in bytes is available (using F6). Wild cards
; rejected for rename, file size, set attributes.
;
; 2.1/2 Based on Mr. Ten-Brugges original P2DOS release, which made
; this development practical. Uses CCP+ for best results.
;
; New features of DOS+ (over CPM2.2) are:
; - Console status call always checks physical input, so that it is
; always possible to abort a program by the sequence CTL-S CTL-C.
; (assuming the program is making console calls other than DCIO
; and that breaks are enabled in the flag byte).
; - DCIO calls (function 6) are now compatible with all other console
; calls, so that a mixture of functions can be used. The abilities
; are such that direct bios calls are no longer needed.
; - DCIO provides the CPM3 conin_wait call (0fdh), and a "lookahead"
; call (0fch) so programs may examine input chars without using
; them. The lookahead call also returns the console column (as
; viewed by DOS, not the bios) in the h (and b) registers. This may
; not be accurate if tabs or cursor positioning sequences etc. have
; been used. If no char is ready lookahead returns 0 (which, if
; the status call (0feh) has returned true, is really a ready nul).
; The output call (any value less than 0fch in e) returns any value
; returned in hl by the bios. If implemented in the bios, this
; should describe the current row (in h) and column (in l) of the
; cursor, with an offset of 020h added. Applications can now intel-
; ligently control the cursor for windowing, status lines, etc.
; - User break on "brkchr" (except DCIO calls, enabled separately).
; This can abort a runaway program, provided it makes DOS calls.
; - Error routines are more informative, including DOS call number.
; DOS+ ERROR ON D: disk I/O
; bad drive
; file R/O
; R/O
; Fn=XXX (FILE =FILENAME.TYP)
; The option 'FILE =FILENAME.TYP' is displayed only when the DOS
; function uses a filename. After all errors a warm boot is done,
; except bad sectors, which allow retry/ignore/abort options.
; Provisions exist (separate documentation) for applications to
; intercept errors, and to detect where the DOS+ call would have
; returned if successful.
; - Search path is implemented to find files on other drives. The
; files must be specified by their exact name. This takes effect
; only after the file is not found on the current default drv/usr,
; thus there is no point to a $$ entry in the path string. If the
; FCB specifies a drive no path is searched.
; - Any file stored on USER 0 with the $SYS attribute set, is visible
; to all other users for read (but not write or erase). Such files
; can be erased from user 0, but not written into.
; - Automatic date and time stamp is implemented. The creation date
; is set when the function MAKE is executed. The update date and
; time is set as the file is closed (when modified). The access
; date and time is is set whenever the file is opened, UNLESS the
; file is marked R/O or the TACESS flags bit is reset. To enable
; this feature you need to have a real time clock and the correct
; DOS+ driver (or reserved memory area). You must also initialize
; directories for time stamps (every 4th entry = 021h,0,0....0),
; i.e 3,7.. (0 based). INITDIR utility performs this operation.
; - File R/O error message occurs if one of the following file types
; is active and a write is attempted:
; File R/O (T1) (also prevents erase)
; System file (T2) (erasable from base user)
; - Disk sizes up to 65536 * 16K = 1 048 576 K BYTE = 1 G BYTE.
; - File sizes up to 32 * 64 * 16K = 32 768K BYTE = 32 M BYTE.
; - CPM3 function GET TIME (105) is implemented to get the correct
; date and time. Entry DE is address to put time. The date and
; time record has the following layout:
; date: ds 2; date = 1 (Sun 1978-Jan-01)
; date = 65535 (Sun 2157-Jun-05)
; hour: ds 1; hour in BCD
; min: ds 1; minute in BCD
; Functions only if suitable bios function call is installed.
; - CPM3 function SET TIME (104) is implemented to set the correct
; date and time. Entry DE is address new time. The date and time
; layout is as above. System seconds field is zeroed. Functions
; only if suitable bios function call is installed.
; - BDOS function GETINFO (210) returns system info, on (e) value
; e = 0 Returns pointer to Serial # area (BDOS base)
; e = 1 Returns current setting of DMA
; e = 2 Returns 0, Flushes any pending console input
; e = 3 Returns list device status (ready/not ready)
; e = 4 Returns punch " " "
; e = 5 Returns reader " " "
; e = other Reserved for future. Returns 0.
; (operands 4 and 5 function only if suitable connector addresses
; have been installed at offsets 01ah and 01ch respectively. Else
; these functions return 0, i.e. device not ready)
; - BDOS function TDEC (211) writes de as unsigned decimal to the
; console, with leading zero suppression.
; - Offset 01eh can be set to a trap address after any abort.
;
; Possible DOS+ Incompatibilities with CPM 2.2
; - The IX and IY registers are used, and restored to user values
; on function exit. Bios calls from DOS+ are protected. DOS+
; does not use the alternate register set. Interrupt systems
; that modify and do not restore IX & IY will cause failure.
; - SYS (T2) attribute automatically marks files non-writable.
; - The CTL-S pause mechanism always works. Programs that depend
; on 2 char input buffering (DOS buffer and hardware) may fail.
; - Console output chars 0fch and 0fdh are now input on function 6.
; Compatibility mode inhibits this feature.
; - Buffered console input (function 10) treats DEL/RUBOUT as BS,
; and does not implement the ^R repeat line operation. Will not
; end a line when full, refuses chars until <cr> entered. Marks
; line end with a 0 byte. Thus max length 1 less than original.
; - Version returned is 2x, where x is DOS+ revision (4 up). Values
; in hex. This allows discrimination against CPM2.2, and avoids
; confusion with CPM3. The compatibility bit forces 2.2 value.
; Note that call #210 with e = 0 will always return a non-zero
; value, so that DOS+ can be detected in compatibility mode.
; - Files written with more than 65536 records will not be legible
; to CPM2.2 systems (but will be to CPM3 systems).
; - Time stamp directory entries may appear as peculiar file names
; on user 33 to some utilities. CPM2 and 3 will not access them.
; - The date/time file stamp format is INCOMPATIBLE with CPM3.
; dates will be garbage data if read there (and vice-versa).
; This is caused by maintenance of 3 (not 2) dates with DOS+
; NOTE: The following do not agree with CPM2.2, but DO agree with
; Digital Researchs CPM 2.2 documentation
; - Console status call returns 0ffh for ready, rather than 01
; - SYS files on user area 0 are visible to all users
;
; Added features can be enabled/disabled by the following data:
; - Enable PATH by putting address of PATH in offset 14H. If this
; value is 0 no path is used. Suggested value 046H.
; NOTE power-on cold-boot should clear the PATH string (0 at Path^)
; - Enable DOS+ time and date stamping with a suitable (non-zero)
; data address at offset 16H. Suggested value 040h (5 bytes used).
; - Enable other features with the flag byte at offset 18h:
; MSB 76543210 LSB
; ^^^^^ ^---- 1 = Echo console to list. ^P complements
; ||||| (this locn allows applications to control)
; ||||^------- 1 = compatibility bit. Causes verno call to
; |||| return 2.2. Disables fc/fd operand on DCIO
; |||^-------- 1 = do file access time stamp (timeat <> 0)
; ||| (disable caters to wrt-protected disks)
; ||^--------- 1 = enable break on DCIO (if following bit)
; |^---------- 1 = enable user break, 0 = disable (see 19h)
; | When disabled ^C will not abort either.
; ^----------- 0 = time address is location of time array
; 1 = time address is location of routine
; (when non-0 address in offset 16h only)
; (value x10x1000b for maximum CPM2 compatibility)
; - If user breaks enabled, the char at offset 19h will break.
; - CCP+ can access wheel byte, suggested location 045h. This allows
; path/wheel to be initialized by "lxi h,0ffh; shld 45" in bios.
;
; -------------
;
; NOTE - All features can be controlled in the file DOS.LIB
;
; Change with assembler. Allows for SLRMAC or M80. The M80 include
; statement must be changed to MACLIB for RMAC, with other changes.
; This allows for the widest range of assemblers, even ASM with manual
; macro expansion by editing.
;
; Following must be upper case for M80.
; SLRMAC can use "maclib z80" and/or dispense with Z80.LIB file
INCLUDE Z80.LIB
;
; SLRMAC v1.0 bug fix - mvix/mviy operands interchanged
mvix macro disp,value
db 0ddh,036h,disp,value
endm
;
true equ -1
false equ not true
empty equ 0e5h; mark for vacant directory entries
tmstamp equ 021h; mark for time-stamp directory entries
;
; Following must be upper case for M80.
; Specifies base/path/ramlow/timesystem/debug
INCLUDE DOS.LIB
;
; Ascii control char. definitions
etx equ 03h; key to generate warm boot
enq equ 05h; break line
bel equ 07h; bell
bs equ 08h; backspace
tab equ 09h; tab
lf equ 0ah; line feed
cr equ 0dh; carriage return
dle equ 10h; set/reset print flag
dc3 equ 13h; pause console output
nak equ 15h; delete line
can equ 18h; delete line (backspaces)
rubout equ 7fh; delete last char
;
; FCB description. Like CPM3, we reserve bits f7 and f8 for internal
; use. Caller should initialize to off, and never alter them.
f.usr equ 0; usage in directory. 5 bits
f.drv equ f.usr; alternate use for field in FCB
f.name equ 1; 8 char field
f.ifc6 equ 6; hi bit, sfattr interface control
f.type equ 9; 3 char field
f.ro equ f.type; hi bit
f.sys equ 10; "
f.arc equ 11; "
f.exlo equ 12; 5 low bits
f.s1 equ 13
f.exhi equ 14; 6 low bits
f.clean equ f.exhi; hi bit
f.rc equ 15; Records in last FCB extent
f.dm equ 16; 16 bytes/8 words
f.next equ 32; next recd, FCB only
f.rrno equ 33; 3 bytes, FCB only
;
; Flag byte bit definitions
fb.tcal equ 80h; Timer is routine, not data area
fb.ubrk equ 40h; Implement console break
fb.bcio equ 20h; also on DCIO calls
fb.tacc equ 10h; Do file access time stamps
fb.comp equ 08h; Compatibility bit
fb.lflg equ 01h; Echo console output to lister
;
; bit settings via DOS.LIB
tcal equ tfunct AND fb.tcal
ubrk equ usrbrk AND fb.ubrk
bcio equ dciobk AND fb.bcio
tacc equ acctim AND fb.tacc
;
; A standard CPM 2.2 Bios arrangement
; This linkage allows debugging using pre-existing bios.
;extrn boot; 0 boot none none
extrn wboot; 1 wboot " "
extrn const; 2 console status " A=0FFH ready
; =0 not ready
extrn conin; 3 console input " A=console char
extrn conout; 4 console output C=console char option xy posn
extrn list; 5 list output C=list char "
extrn punch; 6 punch output C=punch char "
extrn reader; 7 reader input none A=reader char
;extrn home; 8 home disk " option sysadr.
extrn seldsk; 9 select disk C=drv # (0..15) HL=^Disk table
extrn settrk; 10 select track BC=track # none
extrn setsec; 11 select sector BC=sector # "
extrn setdma; 12 set DMA address BC=DMA address "
extrn read; 13 read 128 bytes none A = 0 no error
; A <> 0 error
extrn write; 14 write 128 bytes; C=0 write data A = 0 no error
; C=1 wrt dir. A <> 0 error
; C=2 wrt unalloc
extrn listst; 15 list status none A = 0ffh ready
; A = 0 not ready
extrn sectrn; 16 sector translate BC = sect HL = sector #
; DE = ^table
; (from select)
; XX time BC =0 get pointer only HL=pointer to time array
; BC <> 0 allows hard- HL+0^ date LSB days since
; ware to be updated HL+1^ date MSB (1=1978/1/1)
; if a routine call. HL+2^ hour (bcd)
; ignored if timead HL+3^ minute (bcd)
; is purely an address. HL+4^ seconds (bcd)
; BC^ time to set. (no secs)
; CARRY clear, NZ on exit.
;
; Start of BDOS module
serial: ds 6,0; Serial number not implemented
;
; Linkage for function calls
start: jmp entry; To location 11, for DOSfinders
;
; Error trap vector. Programs can alter error traps here
stbdsc: dw badsec; Bad sector
stsel: dw selerr; Select error
stro: dw rdonly; Drive read only
sfilro: dw filro; File read only
;
; Connector so DOSfinder routines work. The jump at location
; bdos+6 must be to bdos+11h. The above error vector must not
; be moved or programs that trap BDOS errors will fail.
entry: jmp dos
;
; -------------------------
; The following area is patchable. DOS.LIB sets initial values
;
; Location of external path for open file command
path: dw pathat
;
; Time address. 0 disables all time operations. Array or routine
timead: dw timeat; Routine addr. for time/date stamps
;
; Flags for specials
flags: db tcal+ubrk+bcio+tacc
brkch: db brkchr; char. for user breaks
; " "
; If non-zero, address of bios routines. (a): 0ffh=ready, 0=not ready
rdrsta: dw 0; rdr status routine ptr
punsta: dw 0; pun status routine ptr
;
; This specifies control transfer after fatal errors or CTL-C exits
; when breaks are enabled. CAUTION: must point to a valid connector.
; Automatically reset to ramlow if used.
abtrap: dw ramlow; destination on aborts
;
; -------------------------
;
; Entry point DOS+ function calls
dos: mov a,c; function number
sta funct
sspd spsave; Save user SP
lxi sp,stack; Switch stacks
pushiy
pushix; Save
push d; Save parameter
popix; in IX
lxi h,flags
mov a,m
ani fb.ubrk
cnz userbk; User break enabled, check it
xra a
sta drvflg; Reset drive select done flag
sta rdwr; and read/write flag
mov h,a
mov l,a; lxi h,0
shld fvalue; Clear exit value (default)
mvi a,maxcmd-1
cmp c
jrc dos1; above command table, use last entry
mov a,c; else use specified
dos1: lxi h,ctable
call jinx; execute
; " "
; DOS+ exit routine
lda drvflg; test drive select used flag
ora a
cnz drvfix; restore entry drive if modified
popix
popiy
lspd spsave; restore saved on entry
lhld fvalue; Get exit code
mov a,l; Copy exit code to ba
mov b,h
ret
;
; Jump indexed to (hl + 2 * a). Max entry a = 127
; a,f,h,l
jinx: add a; * 2, words
add l
mov l,a
adc h
sub l
mov h,a; hl := hl+a
; " "
; indirect transfer to hl^
; a,f,h,l
jind: mov a,m
inx h
mov h,m
mov l,a; hl := (hl)
xpchl: pchl; implements "call hl"
;
; Function 210, Get info, e specifies details.
; This can perform anything that does not require input parameters.
getinf: mov a,e
lxi h,inftbl
cpi maxinf
rnc
jr jinx
;
inftbl: dw @serial; 0 pointer to serial dos+/serial # area
dw rtndma; 1 current dma setting
dw cflush; 2 flush console input buffers
dw lsta; 3 list device status (ready/not ready)
dw psta; 4 punch device status " "
dw rsta; 5 reader device status " "
maxinf equ ($-inftbl) /2
;
; Main Command table. Covers the contiguous opcodes.
; DOS+ returns values in HL, with BA a copy. Thus 8 bit values are
; also returned in A. Function 0 ignores the pointer at 1, and can
; be used to force system reloading if bios unaltered.
ctable: dw wboot; warm boot
dw cin; console input
dw coute; console output
dw rin; reader input
dw pout; punch output
dw lout; list output
dw dcio; direct console I/O
dw giobyt; get I/O byte
dw siobyt; set I/O byte
dw mesg; print string
dw rdbuf; read console buffer
dw cstat; get console status
dw cmnd12; get CPM version. num
dw cmnd13; reset disk system
dw cmnd14; select disk
dw cmnd15; open file
dw cmnd16; close file
dw cmnd17; search for first
dw cmnd18; search for next
dw cmnd19; delete file
dw cmnd20; read sequential
dw cmnd21; write sequential
dw cmnd22; make file
dw cmnd23; rename file
dw cmnd24; Get login vector
dw cmnd25; Get current disk
dw cmnd26; Set DMA address
dw cmnd27; get address allocation vector
dw cmnd28; write protect disk
dw cmnd29; Get R/O vector
dw cmnd30; Set file attributes
dw cmnd31; Get addr. disk parameter header (DPH)
dw cmnd32; Get/set user code
dw cmnd33; Read random
dw cmnd34; Write random
dw cmnd35; Compute file size
dw cmnd36; Set random recordd
dw cmnd37; reset individual drive(s)
dw other; last entry, check extensions
maxcmd equ (($-ctable)/2); Number of valid DOS commands
;
; Check function in auxiliary table
other: lxi h,auxtbl
; " "
; Search table hl^ up for index c. last (default) entry is 0ffh
; execute result.
; a,f,h,l + executed code
tblchk: mov a,m; get id byte
cmp c
inx h; point to operand field
jrz jind; found, hl points to exec adr.
inr a
jrz jind; last entry, use as default
inx h
inx h; skip operand
jr tblchk; go check next
;
; Define table entry format
dt macro op,adr
db op
dw adr
endm
;
; Auxiliary table. 1st entry found fastest. 0ffh terminator
; This structure allows for unused opcodes.
auxtbl: dt 40, cmnd40; write random w/zero fill
dt 104, settim; set time
dt 105, gettim; get time
dt 210, getinf; return data, e specifies what
dt 211, cmd211; write de in decimal, zero suppress
dt 0ffh, dummy; end marker, null operation
;
; ***********************
; * *
; * Device I/O routines *
; * *
; ***********************
;
; Read reader. BDOS function 3
rin: call reader
jr exit; return rdr char. to caller
;
; Write punch. BDOS function 4
pout: mov c,e
jmp punch; Char. to punch device
;
; Write list. BDOS function 5
lout: mov c,e
; " "
; list from console echo mechanism
listx: jmp list; Char. to list device
;
; list status
lsta: call listst
jr exit
;
; reader status
rsta: lhld rdrsta
jr biosx
;
; punch status
psta: lhld punsta
; " "
; Execute routine hl^ if hl non zero, else return 0
biosx: mov a,h
ora l
cnz xpchl; non-zero, call it
jr exit
;
; Read Char. from console and echo if in [cr, lf, tab, bs, >= blank]
; BDOS function 1
cin: call getch; get it
call tstch
cnc couta; echo cr, lf, tab, bs, >= blank
exit: jmp rtnbyt
;
; Get I/O status byte. BDOS function 7
giobyt: lda ramlow+3
jr exit; return it to caller
;
; Set I/O status byte. BDOS function 8
siobyt: mov a,e
sta ramlow+3; Save new value in RAM
ret
;
; Test console status. BDOS function 11
cstat: call qwait; Get console status, check pause
jr exit; and return it
;
; Direct console input/output. BDOS function 6
; input E : 0ffh - get char or 0 if not ready
; 0feh - get console status
; 0fdh - console input, wait for it (CPM3 usage)
; 0fch - get buffered char, without flushing
; (so still available for console input)
; (DOS+ also sets b=h=column count)
; This now co-operates with the 1 char input buffering, and thus can
; be used intermixed with other console functions. Output here cannot
; be paused with CTL-S. Output via other functions will flush any
; incoming CTL-S. This status call (argument = 0feh) will not pause
; on incoming CTL-S. Note that a nul input can be detected by calling
; status (argument 0feh), and if ready then calling input (arg 0ffh)
; or input-wait (arg 0fdh) or look-ahead (arg 0fch). This allows
; discrimination between no_char ready and nul ready. However,
; console output may not track columns correctly. Compatibility bit
; disables arguments 0fch and 0fdh (become output).
; IF the bios co-operates, console output calls return an indicator
; of the x/y screen position. H describes row, L describes column.
dcio: mov c,e; Possible output char.
inr e
jrz dcio5; 0ffh, do input
inr e
jrz dcio4; 0feh, get status
lda flags
ani fb.comp; compatibility bit
jrnz dcio3; inhibits extra operations over 2.2
inr e
jrz dcio6; 0fdh, console input, wait
inr e
dcio3: mov a,c
lhld lastch; assumes status called before
xchg
cnz coraw; <> 0fch, output char.
xchg
jmp rtnwd; h is column value
dcio4: call csta; Get console status
jr exit; and return it to caller
dcio5: call csta; Get console status
rz; Exit if no char. available
dcio6: call getch; else get char.
jr exit; and return it to caller
;
; Call #211, write in decimal to console
cmd211: xchg
jr tdzs
;
; output (a) in decimal to console, leading zero suppress. Recursive
; a,f,b,c,d,e,h,l
tadzs: mov l,a
mvi h,0
; " "
; output (hl) in decimal to console, leading zero suppress. Recursive
; a,f,b,c,d,e,h,l
tdzs: lxi b,0100ah; c=divisor=10, b=iter cnt=16
xra a; clear
tdzs1: dad h; (hl) := (hl)/10; rdr to (a)
ral; shift off into (a)
cmp c; test
jrc tdzs2; no bit
sub c; bit = 1
inx h
tdzs2: djnz tdzs1; not done
push psw; save output digit
mov a,h
ora l
cnz tdzs; not left digit, recursive
pop psw; last unlisted digit
adi '0'
; " "
; couta, preserving bcdehl
co: push b
push d
push h
call couta
pop h
pop d
pop b
ret
;
; cr/lf to console
; a,f,b,c,d,e,h,l
crlf: mvi a,cr
call cout
mvi a,lf
jr cout
;
; Blank to console
; a,f,b,c,d,e,h,l
blk: mvi a,' '
; " "
; Console output A, no tab expansion. Preserve A. Check for pause
; However a tab records appropriate column advance here.
; Column confusion results if hi bit is set in char. or if
; cursor movement sequences are used.
; b,c,d,e,h,l
cout: push psw; Save non tab
call qwait; Check for user pause
pop psw; Get char back
; " "
; Raw console output, attempting to track output column, and
; implementing any list echo in effect. Guard against evil bioses.
; If the bios performs, de returns indicating the current x/y posn.
; b,c,d,e,h,l
coraw: mov c,a
push psw
pushix
pushiy
push b
call conout; output it
pop b; get char back to ck
push h; save bios return (x/y posn)
lda flags; Get printer echo flag
rrc; test fb.lflg
cc listx; bit set, output char to printer
pop d; may be x/y posn
popiy
popix
pop psw; restore char.
; " "
; Count chars. in line
; f,h,l
countc: cpi rubout
rz; non-print, no column update
lxi h,column; Pointer
inr m; advance
cpi ' '
rnc; printing char, exit
dcr m; control, cancel column advance
cpi bs
jrz count3; bs, decrement column
cpi cr
rnz; Not tab char, ignore for count
mvi m,1; will become 0, for cr
count3: inr m
dcr m
rz; don't reduce past zero
dcr m; reduce, for bs
ret
;
; Backup if column > 0. Called only from delch, thus rdbuf
; a,f,b,c,d,e,h,l (because bios)
bakup: lxi h,column
mov a,m
ora a
rz; at lh column, absorb
call bakup1; write backspace (in c)
call blk; write space
bakup1: mvi a,bs
jr coraw
;
; Get char. from console, using look ahead buffer. Wait for it
; a,f,b,c,d,e,h,l (because bios)
getch: lxi h,bufull
mov a,m; flag
mvi m,0; Reset buffer full flag
inx h; point to lastch at bufull+1
ora a
mov a,m; buffer contents (lastch)
mvi m,0; and reset it to nul
rnz; lastch was valid
; " "
; conin protected against evil bioses
; a,f,b,c,d,e,h,l (because bios)
cinx: lxi h,conin
; " "
; Guard against a bios that clobbers ix/iy (e.g. Osborne 1).
; Call (hl)^, saving and restoring ix and iy
; a,f,b,c,d,e,h,l (because bios)
xbios: pushix
pushiy
call xpchl
popiy
popix
ret
;
; Get console status to a and z flag, using look ahead buffer.
; When char. ready lastch buffer is loaded.
; a,f,b,c,d,e,h,l (because bios)
csta: lda bufull
ora a
mvi a,0ffh
rnz; buffer is non-empty
call cstax; Physical console status
ora a
rz; nothing read, return 0
call cinx
sta lastch; get char and save
ori 0ffh; return true
sta bufull; mark char in buffer
ret
;
; protected const
; a,f,b,c,d,e,h,l (because bios)
cstax: lxi h,const
jr xbios
;
; Test character
; reset carry : cr, lf, tab, bs, OR >= space
; set carry : all others
; f
tstch: cpi cr
rz
cpi lf
rz
cpi tab
rz
cpi bs
rz
cpi ' '; test >= space
ret
;
; Output message. BDOS function 9
; a,f,d,e
mesg: ldax d
cpi '$'
rz; End of string
inx d; point to next char.
call co; output
jr mesg; more
;
; Delete char. Called only from rdbuf
; Entry : HL = ^ last char in buffer
; B = Char. counter
; Exit : hl decremented, b decremented, z flag on b
; a,f,b,d,e,h,l
delch: mov a,b
ora a
rz; empty, nothing to do
push b
push h
call bakup
pop h
push h
mov a,m
cpi ' '
cc bakup; control, wipe out 2 pos'ns
pop h
pop b
dcx h
dcr b; Char counter
ret
;
; Read buffer IX^. BDOS function 10 ENTRY below
rdbuf0: call delch; Delete last char in line
jrnz rdbuf0; more to remove
; " "
rdbuf: pushix; buffer start addr. << ENTRY here
pop h; to HL
mov c,m; Max. line length
inx h; Adv. to actual line lgh position
mvi b,0; Clear line length counter
rdbuf1: push h
push b
rdbuf2: call getch
pop b
pop h
ani 07fh; Mask char
cpi enq
jrnz rdbuf5; Not CTL-E
push h; SAVE
push b
call crlf; newln; Move cursor to next line
jr rdbuf2; and get next char
rdbuf4: call delch; Delete char
jr rdbuf1; Get next char.
rdbuf5: cpi bs
jrz rdbuf4; backspace
cpi rubout
jrz rdbuf4; rubout
cpi dle
jrnz rdbuf6; not CTL-P (print enable/disable)
lda flags; Complement print flag
xri fb.lflg
sta flags; flip fb.lflg
jr rdbuf1; and get next char
rdbuf6: cpi nak
jrz rdbuf0; CTL-U, delete line
cpi can
jrz rdbuf0; CTL-X, delete line
cpi cr
jrz rdbufx; cr, exit
cpi lf
jrz rdbufx; lf, exit
inx h; incr. pointer
mov m,a; and save char.
inr b; incr. line counter
mov a,c
cmp b
jrnz rdbuf8
dcx h; line end, refuse char
dcr b
mvi a,bel
call co
jr rdbuf1
rdbuf8: mov a,m
call outch; Echo char.
cpi etx
mov a,b; Get line count
jrnz rdbuf1; Not CTL-C
dcr a; If 1st char in line then
cz abtchk; abort if breaks enabled
jr rdbuf1; else just another char.
rdbufx: inx h
mvi m,0; mark line end for user
stx b,+1; save line counter
mvi e,cr; force carriage return
; " "
; Write console. BDOS function 2
coute: mov a,e; Char
; " "
; Write char A to console, expand tabs. Preserves A
couta: cpi tab
jnz cout; not tab
couta1: call blk; expand tab to spaces, 1 or more
lda column
ani 7
jrnz couta1; Not done, repeat
mvi a,tab; return tab
ret
;
; Output char (Control char displays ^CHAR)
outch: call tstch
jnc co; cr,lf,tab,bs or >= space
push psw
mvi a,'^'
call co; write '^'
pop psw
push psw
adi 'A'-1; add offset
call co; output it
pop psw; restore chanr.
ret
;
; *******************************
; * *
; * ERROR ROUTINES etc. *
; * *
; *******************************
;
; Check for user pause (CTL-S). Always uses key depression.
; Returns current console status in a and z flag
qwait: call cstax; bios
ora a
jrz qwait1; No key, check buffer
xra a
sta bufull; flush buffer on physical input
qwait1: call csta
rz; no input
lda lastch; what was it
cpi dc3
mvi a,0ffh; to return status=ready
rnz; not pause
call getch; flush the DC3
call getch; and get the next input
cpi etx
jrz abtchk; reboot on CTL-C
xra a; set status = not ready
ret
;
; Check breaks enabled, and abort if so. Else return 0 and z flag
; a,f
abtchk: lda flags
ani fb.ubrk
rz; breaks disabled
jr abort
;
; Check for user break. At entry hl points to flags
; a,f,h,l
userbk: mov a,m
ani fb.bcio
jrnz ubk1; enabled for DCIO
mov a,c
cpi 6
rz; Not for DCIO call
ubk1: push b
push d
call csta
pop d
pop b
rz; no input, no break
lda lastch; look ahead
lxi h,brkch
cmp m
rnz
; " "
; Check operator for abort.
; a,f,h,l
qabort: push d
push b
lxi d,brkmsg
call mesg
call cflush; purge char and input buffer
call cin; Get user response
push psw
call crlf
pop psw
pop b
pop d
ani 05fh; upshift any 'y'
cpi 'Y'
rz; ignore non Y
jr abort; abort
;
; Bad sector error
badsec: lxi d,mbadsc; bad sector message
xra a; not file r/o
call error; display, flush input stream
retry: lxi d,qretry
call mesg
call cin
ani 05fh
cpi 'R'
rz; with z flag for "retry"
cpi 'A'
jrz abort; else abort
cpi 'I'
jrnz retry
ora a
ret; with n/z flag for ignore
;
; Select error
selerr: lxi d,msel; Select error message
jr abterr; go display error & abort
;
; File read only error
filro: lxi d,mfilro; File R/O message
mvi a,0ffh; Set file R/O message flag
; " "
; Abort error, no option to retry
abtro: call error; display error
call getch; get operator response
; " "
; Errors and user breaks abort through here.
; Restore input arguments and stack for any debugger.
abort: lda funct
mov c,a; restore fnct
pushix
pop d; restore argument
lspd spsave; callers stack
lhld abtrap; usually 0, reboot
push h
lxi h,ramlow+0
shld abtrap; reset for next time
ret
;
; Drive read only error
rdonly: lxi d,mro; Drive R/O messaage
; " "
abterr: xra a; not file r/o
jr abtro
;
qretry: db cr,lf,'A)bort I)gnore R)etry?$'
brkmsg: db cr,lf,'Resume (y/N)?$'
;
; Display Error Message
; DOS+ error on D: ERROR MESSAGE
; FUNCTION = NN [FILE = FILENAME.TYP]
error: mov c,a; Save file R/O message flag
push b
push d; Save error message pointer
lda defdrv; get current drive
adi 'A'; make Ascii
sta mdrive; modify message
lxi d,mberr; "DOS+ ERROR ON D:"
call mesg; display message
pop d; Get error message pointer
call mesg; display it
lxi d,mbfunc; "FUNCTION ="
call mesg; display it
lda funct; Get function number
push psw
call tadzs; display number
pop psw; restore function number
pop b; Get file R/O flag
cpi 15; Test FCB used in command
jrc cflush; no
cpi 24
jrc error1; yes
cpi 30
jrz error1; yes
cpi 33
jrc cflush; no
cpi 37
jrc error1; yes
cpi 40
jrnz cflush; no
error1: pushix; yes, display "FILE ="
sui 19
jrnz error2; Not delete file function
ora c
jrz error2; not file r/o error
call caldir; Get FCB from directory buffer
xthl; save it
error2: lxi d,mfile; " FILE ="
call mesg; Display it
pop h; ^FCB
mvi b,8; 1st 8 chars.
call filenm
mvi a,'.'
call co; write '.'
mvi b,3; last 3 chars
call filenm
; " "
; Flush any incoming console chars
; a,f,b,c,d,e,h,l (because bios)
cflush: call csta
rz; nothing ready
call getch; purge it
jr cflush
;
; Display hl^ for (b) chars, suppress blanks
filenm: inx h; adv pointer
mov a,m
ani 07fh; remove any attributes
cpi ' '
cnz co; write
djnz filenm; more
ret
;
; *******************************
; * *
; * DISK FUNCTIONS *
; * *
; *******************************
;
; Return Version Number
cmnd12: lda flags
ani fb.comp
mvi a,22h
jrnz rtnbyt; return 2.2 in compatibility mode
mvi a,020h+ver; act like 2.2 compatible, not 3.0
jr rtnbyt; exit
;
; Reset disk system
cmnd13: lxi d,ramlow+080h; Set default DMA address
call cmnd26; SETDMA, so bios agrees
xra a; Default drive 'A'
sta defdrv
mov l,a
mov h,a; lxi h,0
shld login; All drives logged out
shld dskro; " " read/write
call seldk; Select drive 'A'
lda subflg; return submit flag
jr rtnbyt; exit
;
; Search for file
cmnd17: call seldrv; from FCB
ldx a,f.drv
sui '?'
jrz cmd17b; '?' in drv field, all entries match
ldx a,f.exhi; Get system byte
cpi '?'
jrz cmd17a; is '?'
mvix f.exhi,0; Else set it to zero
cmd17a: mvi a,14; Test 1st 15 bytes in FCB
cmd17b: inr a; allow for the zero from above
call search; do the search. (leaves result code)
; " "
cpydir: lhld @dirbuf; Copy directory buffer
lded dma; To dma addr.
lxi b,128; for 128 bytes
ldir
ret
;
; Seach for next occurence of file
cmnd18: lixd dcopy; last FCB used by search
call seldrv; from FCB
call searcn; Search next file match
jr cpydir; and copy directory to DMA addr.
;
; Delete file
cmnd19: call seldrv; from FCB
call delete
; " "
; Return search result (found/not found)
srchcd: lda searex; Get exit byte 00=file found, 0FFH not
jr rtnbyt; and exit
;
; Rename file
cmnd23: call seldrv; From FCB
call renam
jr srchcd; and exit with code
;
; Call 212 getinfo, subcall 0.
; Return pointer to serial # area of executing system.
; (offsets from here can access configuration tables)
; In compatibility mode this non-zero value indicates DOS+
@serial:
lxi h,serial
jr rtnwd
;
; Return login vector
cmnd24: lhld login
; " "
; Return word value HL
rtnwd: shld fvalue
; " "
dummy: ret; label for null operations
;
; Return current drive
cmnd25: lda defdrv; Get current drive
; " "
; Return byte value A
rtnbyt: sta fvalue
ret
;
; Return pointer to ALV vector
cmnd27: lhld @alv
jr rtnwd; and exit
;
; Return disk R/O vector
cmnd29: lhld dskro
jr rtnwd; and exit
;
; Change status of file (attributes)
cmnd30: call seldrv; from FCB
call sfattr; Change status
jr srchcd; and exit
;
; Return pointer to drive table
cmnd31: lhld @ixp
jr rtnwd; and exit
;
; Set/get user code. Return current user code
cmnd32: mov a,e; argument
inr e
jrz cmd32a; get only, arg 0ffh
ani 01fh; mask
sta user
cmd32a: lda user
jr rtnbyt
;
; Compute file size
cmnd35: call seldrv; from FCB
; " "
; Compute file size
filsz: lxi b,0; Reset file size length
mov d,c
call ldrrc; in FCB+33,34,35
call nowild; initial search, check wild cards
rnz; wild card, illegal, error set
call tstfct
rz; Not found, exit with search result
filsz2: call caldir; Get directory entry to hl & iy
xchg; copy to de
lxi h,f.rc; Offset to next record
call calrrc; Calculate random record count
mov a,d; Test LSB < (IX+33)
subx f.rrno
mov a,c; Test ISB < (IX+34)
sbcx f.rrno+1
mov a,b; Test MSB < (IX+35)
sbcx f.rrno+2
cnc ldrrc; Write new maximum
call searcn; next file
call tstfct
jrnz filsz2; and test it
jr rtnbyt; set 0, file found
;
; Set random record count
cmnd36: lxi h,f.next; pointer to next record
call calrrc; calculate
; " "
; Store bcd (3 bytes) in FCB IX^ random rcd field
ldrrc: stx d,f.rrno
stx c,f.rrno+1
stx b,f.rrno+2
ret
;
; Calculate random record from f.rc or f.next (on entry hl)
; Entry HL = offset in FCB; DE = FCB pointer
; Exit B,C,D = <MSB> random record <LSB>
calrrc: dad d; Point to FCB+15 or FCB+32
mov a,m
lxi h,f.exlo; Offset to extent number
dad d
mov d,a; Save record # to use
mov a,m; extent byte
ani 01fh; Mask it
ralr d; Shift MSB in carry
aci 0; add carry
rar; Shift 1 time (16 bits)
rarr d
mov c,a; save ISB
inx h; exhi, FCB+14
inx h
mov a,m; Get exhi
rrc; Shift 4 times
rrc
rrc
rrc
push psw; Save
ani 03h; Mask MSB
mov b,a; Save
pop psw; Get LSB
ani 0f0h; Mask
add c; Add with ISB
mov c,a; Save ISB
rnc; No carry, return
inr b; Incr. MSB
ret
;
; Reset specified drives. No files should be open
cmnd37: mov a,e
cma; Complement input vector
mov e,a
mov a,d
cma
mov d,a
lhld login
mov a,e; mask login vector
ana l
mov l,a
mov a,d
ana h
mov h,a
shld login; Save resultant login vector
xchg; use result as mask
lhld dskro; for drive R/O vector
mov a,e
ana l
mov l,a
mov a,d
ana h
mov h,a
shld dskro; Save resultant drive R/O vector
ret
;
; *******************************
; * *
; * Subroutines and functions *
; * *
; *******************************
;
; Select disk from FCB. Save 0th byte in FCB0 and set to current user.
seldrv: mvi a,0ffh; Set disk select done flag
sta drvflg
lda defdrv
sta drive; Save current drive
mov e,a; and to (e)
ldx a,f.drv; Get drive from FCB
sta fcb0; save
cpi '?'
jrz cmnd14; '?', select drive from (e)
ani 01fh; mask drive
mov a,e
jrz seldr0; 0=default, select drive from (e)
ldx a,f.drv; else get drive from FCB
dcr a; normalize to 0..maxdrv
seldr0: call seldk
lda user; set current user in 1st FCB byte
stx a,f.usr; (for directory searches)
ret
;
; select error occured
slkter: lhld stsel; error message address
pchl; go display error
;
; restore entry drive. Used only on exit
drvfix: lda fcb0; Get FCB byte 0
stx a,f.drv; restore it in FCB
lda drive; Get old drive number
mov e,a
; " "
; Select disk e
cmnd14: mov a,e; drive number
; " "
; select disk a
seldk: ani 0fh; mask
mov b,a; to b
lded login
ora a
jrz seldk1; Drive 'A'
seldk0: rarr d; Rotate login vector
rarr e; until bit 0 of (e)
djnz seldk0; represents current drive
seldk1: lxi h,defdrv
bit 0,e
jrz seldk2; Not logged in
cmp m
rz; Already selected, no effort needed
seldk2: mov m,a; save new current drive
push d; save logged in flag (e)
mov c,a; copy drive number
lxi h,seldsk; bios select, e bit 0 specifies reset
call xbios; bad bios guard
mov a,h
ora l
jrz slkter; Error, illegal drive
mov e,m; Get translation vector
inx h
mov d,m
inx h
sded @trans; and save
shld @filect; save addr. temp0
lxi d,6
dad d; ignore temp1, temp2
lxi d,@dirbuf; point to dirbuf
lxi b,8; copy 8 bytes
ldir
lhld @ixp; Get drive parameter addr.
mvi c,15; copy 15 bytes
ldir
pop d; restore drive logged in flag
bit 0,e
rnz; drive was logged in, return
lhld login
call sdrvb; Set drive bit in login vector
shld login
; " "
; Init drive. Set up ALV bit buffer for blocks assigned. SUBFLG
; indicates if drive holds any '$*.*' file on user 0.
initdr: lded maxblk; Get length ALV buffer-1 (bits)
mvi a,3; / 8
initd0: srlr d; to get bytes
rarr e
dcr a
jrnz initd0
inx d; +1, so all bits are cleared
lhld @alv; point to ALV buffer
push h
initd1: mvi m,0; clear 8 bits
inx h
dcx d
mov a,d
ora e
jrnz initd1; more
pop h; restore ALV pointer
lded ndir0; Get 1st 2 bytes ALV buffer (directory)
mov m,e
inx h
mov m,d; save
lhld @filect; Clear number of files on this drive
xra a
mov m,a
inx h
mov m,a
sta subflg; Clear submit flag (Reset disk command)
call setfct; Set file count
initd2: mvi a,0ffh; update directory checksum
call rddir; read FCB'S from directory
call tstfct
rz; last FCB, exit
call caldir; Point to entry point FCB, get 0th byte
cpi empty
jrz initd2; Empty dir entry, get next FCB
cpi tmstamp
jrz initd2; Time stamp entry, get next FCB
ora a
jrnz initd3; Not on user 0
inx h; point to filename
mov a,m
sui '$'
jrnz initd3; 1st filename char <> '$'
dcr a; i.e. 0ffh
sta subflg; to SUBFLG, may be a submit file active
initd3: call allocb; Set bits from FCB in ALV buffer
call setlf; update last file count
jr initd2; and get next FCB
;
; Set drive bit in HL for defdrv
; a,f,d,e,h,l
sdrvb: xchg; de := hl
lxi h,1
lda defdrv; Get current drive
ora a
jrz sdrvb1; Drive 'A', hl is set
sdrvb0: dad h; left shift bit
dcr a
jrnz sdrvb0; not positioned yet
sdrvb1: mov a,d; hl := hl OR de
ora h
mov h,a
mov a,e
ora l
mov l,a
ret
;
; Calculate and set sector/track for directory entry # filcnt
; a,f,b,c,d,e,h,l
stdir: lhld filcnt; Directory FCB counter
srlr h; / 4
rarr l; (4 FCB'S / sector)
srlr h
rarr l
shld recdir; Save (used by checksum)
xchg; de := hl
lxi h,0; hl := 0
; " "
; Calculate sector/track
; Entry : HL, DE = sector number (128 byte sector)
; Result set track = HL,DE / maxsec
; set sector = HL,DE MOD maxsec
; a,f,b,c,d,e,h,l
calst: lbcd maxsec; sectors/track
mvi a,17; init loop counter
calst1: ora a; divide by maxsec.
dsbc b
jrnc calst2; hl >= bc
dad b; hl < bc, restore hl, set carry
calst2: cmc
ralr e; shift left result in DE
ralr d
dcr a
jrz calst3; divide done
dadc h; shift next bit (left) in hl
jr calst1; continue
calst3: push h; Save sector num.
lhld nftrk
dad d; add 1st track offset
mov b,h; to BC for bios
mov c,l
lxi h,settrk
call xbios; bad bios guard
pop b; sector number
lded @trans; Get translation table addr.
lxi h,sectrn
call xbios; bad bios guard
mov b,h; result to BC
mov c,l
lxi h,setsec
jmp xbios; bad bios guard
;
; Get disk map block number for FCB f.next entry
; Exit: HL = Address of FCB DM entry
; DE = DM entry
; BC = offset in DM
; a,f,b,c,d,e,h,l
getdm: ldx c,f.next; c := next record
lda nblock; a := number of blocks
mov b,a; to b
getdm1: srlr c; shift next_record
djnz getdm1; number_of_blocks times
cma
adi 1+8
mov b,a; B := 8-number of blocks
lda nextnd; Get extent mask
andx f.exlo; mask with extent
rrc
getdm2: rlc
djnz getdm2; 8-number of blocks times
add c; Add the 2 values to get entry FCB
; " "
; Get block no. for diskmap entry (a) of FCB ix^ (b=0 on entry)
; a,f,c,d,e,h,l
getbk: pushix; FCB addr.
pop h
mvi c,f.dm; Offset 16 to point to DM
dad b
mov c,a; add entry FCB
dad b
lda maxblk+1
ora a; Test 8/16 bits FCB entry
mov e,m; Get 8 bit value
mov d,a; zero if 8 bits / entry
rz; 8 bits per entry only
dad b; add twice (16 bit values)
mov e,m; load 16 bit value
inx h
mov d,m
dcx h; restore pointer
ret
;
; Calculate dirbuf entry point. Set hl and iy pointers
; Return a := directory entry user code (0th byte)
; a,f,h,l,iy
caldir: lhld @dirbuf; hl := dirbuf + secpnt
lda secpnt
add l
mov l,a
adc h
sub l
mov h,a
push h; Set iy pointer
popiy
mov a,m
ret
;
; Init file count
; h,l
setfct: lxi h,-1
shld filcnt
ret
;
; Test file count = -1, z flag if so
; a,f,h,l
tstfct: lhld filcnt
mov a,h
ana l
inr a; z if -1
ret
;
; Set last file
; a,f,d,e,h,l
setlf: call tstlf; Test last file
rc; No, exit
inx d; incr. last file
jr sdem; Save it in filect
;
; Test last file
; a,f,d,e,h,l
tstlf: lhld @filect; get pointer to last file
lded filcnt; get file counter
mov a,e; DE-(HL)
sub m
inx h
mov a,d
sbb m
ret
;
; Get next FCB from drive
; Entry : A=0 Check checksum, A=0FFH update checksum
; a,f,b,c,d,e,h,l
rddir: mov c,a; Save checksum flag
lhld filcnt
inx h; advance file counter
shld filcnt
lded nfiles; get max number of files
ora a; clear cy
dsbc d
dad d; leaves dsbc flags, restore hl
jrz rddir1; Not last file
jrnc setfct; last file, set file count 0FFFFH
rddir1: mov a,l; Get file count LSB
rrc; *32, around the bend
rrc
rrc
ani 060h; Mask
sta secpnt; Save for later use
rnz; Not first FCB sector
push b; save checksum flag
call stdir; calculate sector/track directory
call dmadir; Set DMA for directory
call rdrcd; Read dir. record from drive
call stdma; Set DMA for user
pop b; checksum flag
; " "
; Update/Check directory checksum
; Entry : C=0 Check checksum, C=0FFH update checksum
; a,f,b,c,d,e,h,l
chkdir: lhld ncheck; number of checked records
lded recdir; get current record
ora a
dsbc d; test current record
rz
rc; >= ncheck, exit
lhld @dirbuf
mvi b,128; Set up counter
xra a; Clear checksum
chkdr0: add m; Add checksum
inx h
djnz chkdr0; 128 times
lhld @csv; pointer to directory checksum
dad d; add current record
inr c; test checksum flag
jrnz chkdr2; 0, setup checksum
mov m,a; 0ffh, update checksum
chkdr2: cmp m; test checksum
rz; ok or setting, exit
; " "
; Set write protect disk command
cmnd28: lhld dskro; get disk R/O vector
call sdrvb; include drive bit
shld dskro
lded nfiles; Get max number of files - 1
inx d
lhld @filect; point to disk parameter block
; " " and set max number of files
; Store de in hl^
; h,l
sdem: mov m,e
inx h
mov m,d
ret
;
; Read sector from drive
; a,f,b,c,d,e,h,l
rdrcd: lxi h,read
call xbios; guard against bad bios
ora a
rz
call rwerr
jrz rdrcd; retry if error handler returns z
ret; ignore if error handler returns nz
;
; Write sector to drive
; a,f,b,c,d,e,h,l
wrtrcd: lxi h,write
call xbios; guard against bad bios
ora a
rz; no error
call rwerr
mvi c,1; retries must put to disk
jrz wrtrcd; retry if error handler returns z
ret; ignore if error handler returns nz
;
; read/write error handler
rwerr: lhld stbdsc; Bad sector message pointer
pchl; DOS+ Error on D: disk I/O
;
; Set DMA address command.
; a,f,b,c,d,e,h,l
cmnd26: sded dma; Save DMA address
call stdma
; " "
; return current dma setting
rtndma: lhld dma; echo back setting
jmp rtnwd
;
; Set DMA Address for user
; a,f,b,c,d,e,h,l
stdma: lbcd dma
jr dmaset; do bios call
;
; Set DMA Addr. for directory
; a,f,b,c,d,e,h,l
dmadir: lbcd @dirbuf; Get DMA Addr. for directory
; " "
; protected setdma
dmaset: lxi h,setdma
jmp xbios; guard against bad bios
;
; Get bit from ALV buffer
; Entry : DE = block number
; EXIT : A = bit IN LSB (rotated, other bits meaningful)
; B = bitnumber in A
; HL = pointer in ALV buffer
; a,f,b,c,d,e,h,l
getbit: mov a,e; Get bit number
ani 7; mod 8
inr a; +1
mov b,a; to b
mov c,a; and c
srlr d; Get byte number
rarr e; DE = DE/8
srlr d
rarr e
srlr d
rarr e
lhld @alv; Get start addr. ALV buffer
dad d; + byte number
mov a,m; Get 8 bits
getbt0: rlc; select correct bit
djnz getbt0
mov b,c; restore bit number
ret
;
; Set/reset bit in ALV buffer
; ENTRY : DE = block number
; C = 0 reset bit, C=1 set bit
; a,f,b,c,d,e,h,l
setbit: push b
call getbit; Get bit
ani 0feh; mask it (reset bit)
pop d; Get set/reset bit
ora e; set/reset bit
; " "
; position bit and save
; a,f,b
bitset: rrc; rotate bit to correct position
djnz bitset
mov m,a; save 8 bits
ret
;
; Mark allocated blocks from FCB in dirbuf
allocb: mvi c,1
; " "
; Fill bit buffer from FCB in dirbuf
; Entry : C = 0 reset bit, C=1 set bit
fillbb: call caldir; Get directory entry
lxi d,f.dm; offset to DM block
dad d
mov b,e; Get block counter
fillb0: mov e,m; Get block number, 8 bits extened
inx h; advance
lda maxblk+1
ora a
mov d,a; 0 if < 256 blocks present
jrz fillb1; < 256 blocks present
dcr b; Decr. block counter, 256 or more
mov d,m; Get correct MSB
inx h; advance
fillb1: mov a,d
ora e
jrz fillb2; block number = 0, Get next block
push h; Save pointer
push b; counter and set/reset bit
lhld maxblk; get max length ALV buffer
ora a
dsbc d
cnc setbit; de <= max length, insert bit
pop b; counter and set/reset bit
pop h; pointer
fillb2: djnz fillb0; repeat over all DM entries
ret
;
; Check file R/O, get DIR entry to hl & iy
chkfro: call caldir; Get DIR entry to hl & iy
; " "
; Check file iy^ for r/o
; f
ckfyro: bity 7,f.sys
jrnz fronly; $SYS file, error
; " "
; For erase, allows SYS files to be erased
rochk: bity 7,f.ro
rz; not $R/O file, ok
; " "
; File read/only error
fronly: lhld sfilro; Pointer to FILE R/O error handler
pchl; Error trap
;
; Check drive read only
chkro: lhld dskro; Drive R/O vector
call sdrvb; Set drive bit
dsbc d; test extra bit added
rnz; Yes, then drive not R/O
lhld stro; Pointer to DRIVE R/O error handler
pchl; error trap
;
; Get free block from ALV buffer
; Entry : DE = old block number
; Exit : DE = new block number (0 if no free block)
; HL counts up, DE counts down
getfre: mov h,d; hl := old block
mov l,e
getfr0: mov a,d
ora e
jrz getfr1; down counter = 0
dcx d; decrement
push h; Save up/down counters
push d
call getbit; from ALV buffer
rar
jrnc getfr3; 0, found empty block
pop d; Get up/down counters
pop h
getfr1: lbcd maxblk; get max ALV length-1 to BC
ora a
dsbc b; Test HL >= length ALV -1
dad b; restore HL (Flags not changed)
jrnc getfr2; End Buffer
inx h; Incr up counter
push d; Save counters
push h
xchg; Up counter to DE
call getbit; from ALV buffer
rar
jrnc getfr3; 0, found empty block
pop h; Get counters
pop d
jr getfr0; and test next block
getfr2: mov a,d
ora e
jrnz getfr0; not last block, test next block
ret; Exit (DE=0)
getfr3: stc
ral; Sst block number used
call bitset; put bit in ALV buffer
pop d; Get correct counter
pop h; restore stack pointer
ret; Exit (DE=block number)
;
; Search for file name, for read/directory operations
srchrd: mvi a,15; bytes to match
; " "
; Search for file name
; Entry : A : number of bytes to match
search: sta searnb; Save number of bytes
mvi a,0ffh; Set exit code 0FFH (not found)
sta searex
sixd dcopy; copy FCB pointer to RAM (search next)
call setfct; init. file counter
; " "
; Search next file name
searcn: xra a; check checksum directory
call rddir; Get FCB from directory
call tstfct
jrz nofile; past last entry
lded dcopy; Get FCB pointer
ldax d; user byte
cpi empty
jrz searc1; empty directory entry
push d; FCB pointer
call tstlf
pop d
jrnc nofile; last file on this drive
searc1: call caldir; hl := iy := dir entry, a := 0th byte
cpi tmstamp
jrz searcn; time stamp, get next directory entry
xra a
sta wildcd; no wild card detected yet
mov c,a; i.e. a zero
lda searnb; get number of bytes to match (to b)
mov b,a; save input (a) for search length
; " "
; If dir entry (hl=iy)^ has the sys attribute set, and is stored under
; user 0, ignore the user number during the directory search by
; advancing the indices appropriately. At entry a contains the length
; of the directory entry to be matched, and de points to the input FCB
; (i.e. the searchee name). IY^ is the candidate dir entry.
sui 15; differentiate from erase searches
jrc searc4; not looking for name, orig. algorithm
bity 7,f.sys; test system bit
jrz searc4; not (sys) file, original algorithm
mov a,m
ora a
jrnz searc4; not on user 0, original algorithm
searc2: sta wildcd; set/reset wild card found flag
searc3: inx d
inx h; skip over the user id
inr c
djnz searc4; if more bytes to match
; " "
; All bytes matched.
call setlf; update last file count (empty FCB)
lda filcnt; Get file counter
ani 3; mask it
sta fvalue; and set exit code
xra a; clear exit code search
sta searex
ret
;
; Check for match.
searc4: ldax d; Get byte from FCB
sui '?'
cma; If zero then a holds 0ffh
jrz searc2; set wild card found, matches any
mov a,c; FCB char posn
sui f.s1
jrz searc3; s1 scratch, then no test
inr a; cpi f.exlo; test if extent number
ldax d
jrz searc7; Special case if extent number
xra m; compare to directory entry
ani 07fh; on mask
searc6: jrnz searcn; not equal on mask, get next entry
jr searc3; test next byte
;
; Special handling for extent number
searc7: push b; save counters
xra m; test extents
mov b,a
lda nextnd
cma; complement extent mask
ani 01fh
ana b; mask extents
pop b; restore counters
jr searc6; and test result
;
nofile: call setfct; error set file counter
; " "
rtnerr: mvi a,0ffh; and set return value
jmp rtnbyt
;
; delete file
delete: call chkro; check disk R/O
mvi a,12; count of bytes to match
call search; for file
del0: call tstfct
rz; not found, exit
call caldir; get entry point directory to iy, hl
call rochk; allow $SYS files to be erased.
mvi m,empty; remove file
mvi c,0; remove bits ALV buffer (recycle space)
call fillbb
call wrtdir; write dir buffer to disk
call searcn; search next entry
jr del0; and test it
;
; Rename file
renam: call schbgn; Check disk R/O, no wild cards, etc.
rnz; wild cards
renam0: call tstfct; iy points to dir entry
rz; Not found, exit
call chkfro; Check file R/O, set iy^ dir entry
lxi b,12*256+16; Copy FCB+16 to Directory+0 12 times
call wrfcb; and write dir to disk
call searcn; search next file
jr renam0; and test it
;
; Change status file
sfattr: call schbgn; Check disk R/O, no wild cards etc.
rnz; wild cards
sfatr1: call tstfct; iy points to dir entry
rz; Not found, exit
bitx 7,f.ifc6
jrz sfatr2; No byte count update requested
ldx a,f.next
sty a,f.s1; set byte count
sfatr2: lxi b,12*256+0; Copy FCB+0 to directory+0 12 times
call wrfcb; and write dir to disk
call searcn; search next file
jr sfatr1; and test it
;
; Set up for search on name field. From sfattr and renam
; Error if wild cards specified (nz flag) or r/o disk (abort)
schbgn: call chkro; Check disk R/O
; " "
; Initial search on name field.
; nz for wild cards specified when exit errors set
nowild: mvi a,12; Count of bytes to match
call search; file. iy points to dir entry
lda wildcd
ora a
rz; No wild cards found, ok
sta searex; attrib & rename return this
jr rtnerr; a is 0ffh
;
; Open file command
cmnd15: call seldrv; from FCB
mvix f.exhi,0; clear hi extent
call findf; find file (using PATH name)
call tstfct
rz; Not found, exit
call fopen
ldx a,f.next
inr a
rnz; Not 0ffh on entry
ldx a,f.s1
stx a,f.next; else return byte count
ret
;
; Open file/extent, directory entry loaded
fopen: ldx a,f.exlo; Get extent number from FCB
push psw
call caldir; Get dir entry, hl & iy
pushix
pop d; FCB entry to de
lxi b,32; Number of bytes to move
ldir; Move directory to FCB
setx 7,f.clean; Set FCB/FILE not modified
ldx b,f.exlo; Get extent number
ldx c,f.rc; Get next record number
pop psw; old extent number
stx a,f.exlo; Save it
cmp b
jrz fopen1; old and new extent numbers same
mvi c,0; Set next record count 0
jrnc fopen1; old extent >= new extent
mvi c,80h; Set next record count to maximum
fopen1: stx c,f.rc; Save next record count
lda flags
ani fb.tacc
rz; access stamping disabled
bitx 7,f.ro
mvi e,8
cz stime; not r/o, set access time stamp
rc; timer system disabled
rnz; No time stamps, this disk
jr wrtdir; else time stamp updated
;
; write FCB to disk directory entry
; c is offset into FCB to copy from, b is byte count to copy
wrfcb: call caldir; Get dir entry to iy, hl, a := usr code
xchg; in DE
pushix; Save FCB entry
pop h; to hl
push b
mvi b,0
dad b; add offset into FCB
pop b
mov c,b; Get number of bytes to move
mvi b,0; 0 extend
ldir; Move
resy 7,f.ifc6; Reset any interface bit
sty a,f.usr; Restore user code
; " "
; Write directory entry to drive
wrtdir: call stdir; Calculate sector/track directory
mvi c,0ffh; Update dir checksum
call chkdir
call dmadir; Set DMA for directory
mvi c,1; Write directory flag
call wrtrcd; write
jmp stdma; Set DMA for user & exit
;
; Close file command
cmnd16: call seldrv; from FCB
; " "
; close file
close: bitx 7,f.clean
rnz; FCB/FILE not modified, no close req'd
call chkro; test disk R/O
call srchrd; file, match 15 bytes
call tstfct
rz; file not present, exit
call chkfro; Check file R/O, get directory entry
resy 7,f.arc; and reset any archive bit
lxi b,f.dm; Offset to DM block
dad b
xchg; to de
pushix
pop h; FCB pointer to HL
dad b; Add offset
lda maxblk+1
ora a
jrz close0; number of blocks < 256
dcr b; Set flag
close0: call copydm; Copy and test blocks
xchg; exchange copy direction
call copydm; Copy and test blocks
xchg; Exchange copy direction
jnz rtnerr; Block not the same, error
inx h; incr FCB pointer
inx d; incr DIR pointer
bit 0,b
jrz close1; number of blocks < 256
inx h; incr FCB pointer
inx d; incr DIR pointer
dcr c; decr counter
close1: dcr c; decr counter
jrnz close0; not ready
lxi h,f.exlo-f.next; Add -20, point to extent no.
dad d
ldx a,f.exlo; Get extent number FCB
cmp m; Compare with extent number DIR
jrc close3; FCB < DIRECTORY THEN JUMP
mov m,a; Save extent number in directory
inx h; Get pointer record count
inx h
inx h
ldx a,f.rc; Get FCB record count in case
mov m,a; entry lgh changed (+ normal, - submit)
close3: call updatm; set last update time
jr wrtdir; Write FCB on disk
;
; Copy and test disk map
; Entry : HL : pointer to 1st FCB
; DE : pointer to 2nd FCB
; B : 000H < 256 blocks
; 0FFH >= 256 blocks
; Exit : ZERO : 1 Blocks are the same
; 0 Blocks are not the same
copydm: mov a,m; Get byte 1st FCB
bit 0,b
jrz copyd0; number of blocks < 256
inx h; adv. pointer
ora m; test byte = 0
dcx h; restore pointer
copyd0: ora a; Test block number is zero
jrnz copyd1; no, compare blocks
ldax d; Copy block from other FCB
mov m,a; in empty location
bit 0,b
rz; number of blocks < 256, exit
inx h; incr to MSB block numbers
inx d
ldax d; Copy block from other FCB
mov m,a; in empty location
jr copyd2; JUMP TRICK TO SAVE SPACE
copyd1: ldax d; Get block number 1st FCB
sub m
rnz; not the same
ora b
rz; < 256 blocks, return
inx h; incr to MSB block numbers
inx d
copyd2: ldax d; Get block number 1st FCB
sub m; test if the same
dcx h; Decr. block FCB pointers
dcx d
ret
;
; Find file, using path. Only default and current user entries apply
findf: call srchrd; for read file. Match 15 bytes
call tstfct
rnz; found, exit
lda fcb0
ora a
rnz; drive specified, ignore path
lhld path; get PATH address
mov a,h
ora l
rz; 0, no path, exit
findf2: lda drive
mov b,a; keep handy. 0..maxdrv
mov a,m; Get 1st entry PATH name
inx h; adv. pointer
ora a
inx h
jz nofile; last entry, not found exit
cpi '$'
jrz findf2; current drive already searched
dcr a; put in 0..maxdrv range
ani 0fh
cmp b
jrz findf2; current drive already searched
dcx h
push h; Different drive, so..
call seldk; Select drive
pop h; PATH pointer
lda user; keep handy
mov b,a
mov a,m; Get user number
inx h; adv. pointer
cpi '$'
jrz findf5; current user, ok, search
xra b
ani 01fh; Mask user no. area only
jrnz findf2; Path entry not for this user, skip
findf5: push h; path pointer
call srchrd; file, match 15 bytes
call tstfct
pop h; path pointer
jrz findf2; file not present, test next path entry
call caldir; Get directory entry
lda defdrv; Get now current drive
inr a; in range 1..
sta fcb0; save it in exit FCB0
ret
;
; Make file command
cmnd22: call seldrv; from FCB
mvix f.exhi,0; Clear high extent #
call fdirty; ensure archive bit reset
; " "
; Make file
make: call chkro; Check drive r/o
ldx a,f.usr
push psw; Save user id for file
mvix f.usr,empty; Set 1st byte to empty file
mvi a,1; Search for 1 byte
call search; for empty DIR space. Sets result code
pop psw
stx a,f.usr; Restore user id for file
call tstfct
rz; No empty entry found, return error
xra a; clear last record byte count
stx a,f.s1
pushix
pop h; copy FCB pointer to HL
lxi d,f.rc; Prepare offset
dad d
mvi b,17; Set loop counter
make0: mov m,a; Clear rc and dm area
inx h
djnz make0
call caldir; Get directory entry
ldx a,f.usr; Get first byte FCB & save in
mov m,a; directory (write FCB needs this)
mvi e,2; Set creation date
call stime
call updatm; Set last update date/time
mvi e,8; Set last access date/time
call stime
lxi b,32*256+0; Copy FCB+0 to directory+0 32 times
call wrfcb; write FCB to disk
setx 7,f.clean; Mark FCB/FILE not modified
ret
;
; Open next extent
openex: bitx 7,f.clean
jrnz openx5; FCB/FILE not modified (write)
call close; Current FCB. Reads/loads dir entry.
lda fvalue; exit code from close
inr a
rz; error, exit
call calnex; Calculate next extent
jrc openx3; error
jrnz openx6; FCB present from close (wrt, dir read)
openx1: call srchrd; for file, match 15 bytes
call tstfct
jrnz openx6; file found
lda rdwr
ora a
jrz openx3; read flag, error (no extent)
call make; new extent (is write)
call tstfct
jrnz openx7; successful, exit
openx3: setx 7,f.clean; Set FCB/FILE not modified
jmp nofile; Set exit code for error
openx5: call calnex; Calculate next extent
jrc openx3; error
jr openx1; use same routine
;
openx6: call fopen; open file
openx7: xra a; and clear exit code
; " "
bytrtn: jmp rtnbyt
;
; Calculate next extent
; exit: carry => overflow detectedd
; zflag => search next extent
; nzflag => next extent present in FCB (close)
; (A single directory/FCB entry can hold multiple extents)
calnex: ldx c,f.exlo; Get extent number
ldx b,f.exhi; Get high portion
bit 6,b; Test error bit random record
stc
rnz; Non-zero, error exit, cy set
inr c; Incr. extent number
mov a,c
ani 01fh; mask extent number
mov c,a; to b
jrnz calnx1; non-zero extent
inr b; Incr. high order extent
mov a,b
ani 03fh; mask it (c is zero)
mov b,a; Save it in c
stc
rz; file overflow, error flag (cy) set
; " " since c is 0 following returns z flag
; " " for "not same dir entry"
calnx1: lda nextnd; Get next extent mask
ana c; Test if same dir entry (close)
; " "
; Set FCB extent bytes from bc (high/low). Preserve flags.
; Return bc = old values
xchext: ldx a,f.exlo
stx c,f.exlo; Save extent number
mov c,a
ldx a,f.exhi
stx b,f.exhi; and high portion
mov b,a
ret
;
; Read random record command
cmnd33: call seldrv; from FCB
xra a; set read/write flag
call ldfcb; Load random record in FCB
rnz; Return error
jr reads; no error, go read sector
;
; Read sequential
cmnd20: call seldrv; from FCB
; " "
; Read sector
reads: xra a; set read/write flag
sta rdwr; save it
ldx a,f.next; Get record counter
cpi 080h
jrnz reads1; Not last rcd of this extent
call openex; Open next extent
lda fvalue; get exit code
ora a
jrnz eofull; end of file
stx a,f.next; Clear record counter
jr reads2
reads1: cmpx f.rc; illegal rcd ctr fields cause eof
jrnc eofull; signal EOF
reads2: call getdm; Get block number from DM in FCB
mov a,d
ora e
jrz eofull; block number = 0, end file
call calsec; Calculate sector number (128 bytes)
call calst; Calculate sector/track number
call rdrcd; Read data
lda funct; Get function number
cpi 20
rnz; Not read sequential, return
inrx f.next; incr. next record counter
ret
;
; Signal eof or full
eofull: mvi a,1; Set EOF flag
jr bytrtn; and return to caller
;
; Calculate sector number from start of data area in HLDE
; Entry : DE = block number from FCB
; a,f,b,d,e,h,l
calsec: lxi h,0; clear MSB sector number
lda nblock; get loop counter
mov b,a; to b
calsc1: slar e; shift L,D,E
ralr d
ralr l
djnz calsc1; B times
lda nmask; Get sector mask
andx f.next; and with next record
ora e; Set up LSB sector number
mov e,a
ret
;
; Write random sector (with zero fill command 40 done in "writes")
cmnd34:
cmnd40: call seldrv; from FCB
mvi a,0ffh; Set read/write flag
call ldfcb; Load FCB from random record
rnz; return error
jr writes; no error, write record
;
; Mark file modified
fdirty: resx 7,f.clean; reset FCB/FILE modified
ret
;
; Write sequential
cmnd21: call seldrv; from FCB
; " "
; Write sector
writes: mvi a,0ffh; Set read/write flag
sta rdwr; and save it
call chkro; Check disk R/O
pushix
popiy; FCB pointer to iy
call ckfyro; Check file iy^ R/O
ldx a,f.next; Get record count
cpi 080h
jrc writs0; not end of this extent
call openex; open next extent
lda fvalue; error code
ora a
jrnz eofull; error, directory full
stx a,f.next; Clear record counter
writs0: call getdm; Get block number from FCB
mov a,d
ora e
jrnz writs5; Not 0, write sector
push h; save pointer to block number
mov a,c
ora a
jrz writs1; 1st block number in extent
dcr a; Decr pointer to block number
call getbk; Get prev. blocknumber
writs1: call getfre; Get nearest free block
pop h; Get pointer to block number
mov a,d
ora e
mvi a,2
jz rtnbyt; blocknumber = 0, disk full error
call fdirty; reset FCB/FILE modified
mov m,e; Save blocknumber
lda maxblk+1
ora a
jrz writs2; blocksize < 256
inx h; adv. to MSB blocknumber
mov m,d; Save MSB blocknumber
writs2: mvi c,2; Set write new block flag
lda funct; Get function number
sui 40
jrnz writs6; Not writeranrcd with zero fill
push d; save blocknumber
lhld @dirbuf; use directory buffer for zero fill
mvi b,128; bytes to clear
writs3: mov m,a; Clear directory buffer
inx h
djnz writs3; more
call calsec; Calculate sector number (128 bytes)
lda nmask; Get sector mask
mov b,a; to b
inr b; Increment to get number of writes
cma; Complement sector mask
ana e; Mask sector number
mov e,a; and save it
mvi c,2; Set write new block flag
writs4: push h; Save registers
push d
push b
call calst; Calculate sector/track
call dmadir; Set DMA directory buffer
pop b; Get write new block flag
push b; Save it again
call wrtrcd; Write record to disk
pop b; Restore registers
pop d
pop h
mvi c,0; Clear write new block flag
inr e; Incr. sector number
djnz writs4; Write all blocks
call stdma; Set user DMA address
pop d; Get block number
writs5: mvi c,0; Clear write new block flag
writs6: call fdirty; Reset FCB/FILE unmodified flag
push b
call calsec; Calculate sector number (128 bytes)
call calst; Calculate sector/track
pop b; write new block flag
call wrtrcd; Write record to disk
ldx a,f.next; Get record counter
cmpx f.rc; next record
jrc writs7; record counter < next record
inr a; incr. record count
stx a,f.rc; Save on next record position
writs7: lda funct; Get function number
cpi 21
rnz; not write sequential, return
inrx f.next; incr. record count
ret
;
; Load FCB for random read/write. NZ flag for error.
; Entry a=0 for read, 0ffh for write
ldfcb: sta rdwr; save read/write flag
ldx a,f.rrno; Get 1st byte random record
mov d,a; to d
res 7,d; Rest MSB to get next record
ral; Shift MSB to carry
ldx a,f.rrno+1; Load next byte
ral; Shift carry
push psw; Save
ani 01fh; Mask next extent
mov c,a; Save it in C
pop psw; Get byte
ral; Shift 4 times
ral
ral
ral
ani 0fh; Mask
mov b,a; Save FCB+14
ldx a,f.rrno+2; Get next byte random record
mvi e,6; Set random record too large flag
cpi 4
jrnc ldfcb7; error, random record too large
rlc; address extent (actually div 16)
rlc
rlc
rlc
add b; add byte
mov b,a; Save FCB+14 in B
stx d,f.next; Set next record count
ldx d,f.exhi; Get FCB+14
bit 6,d
jrnz ldfcb7; error, earlier random record write
mov a,c; Get new extent number
cmpx f.exlo; Compare with FCB
jrnz ldfcb1; not equal, open next extent
mov a,b; Get new FCB+14
xorx f.exhi; Compare with FCB+14
ani 03fh; Mask it
jrz ldfcb5; FCB at appropriate extent, return
ldfcb1: bit 7,d
jrnz ldfcb2; FCB not modified (not written)
push d
push b
call close; extent
pop b
pop d
mvi e,3; Set close error in case
lda fvalue; Get exit code
inr a
jrz ldfcb6; close error, exit
ldfcb2: call xchext; Save new extent # (bc=high/low)
push b
call srchrd; search file, match 15 bytes
pop b; previous value for extent fields
lda fvalue; Get error code
inr a
jrnz ldfcb4; No error, exit
lda rdwr; Get read/write flag
inr a
jrz ldfcb3; write, go make it
call xchext; read, restore the extent bytes
mvi a,4; Error, reading empty record
jr ldfcb9; and exit
ldfcb3: call make; make new FCB
mvi e,5; make error code
lda fvalue; error ?
inr a
jrz ldfcb6; make error exit
jr ldfcb5; No error exit (zero set)
ldfcb4: call fopen; open file
ldfcb5: xra a; Set Z flag and clear error code
jr ldfcb9
;
ldfcb6: mvix f.exhi,0c0h; Set random record error
ldfcb7: setx 7,f.clean; Set FCB/FILE not modified
mov a,e; error code
ldfcb9: sta fvalue; save error code
ora a; Clear/set zero flag
ret
;
; Set update time
updatm: mvi e,4
; " "
; Set time and date
; Entry : E = 2 : Set creation date
; 4 : Set last update time/date
; 8 : Set last access time/date
; Exit : cy for timer disabled
; nz for no time stamp on drive
; z and nc for directory updated
stime: lhld @dirbuf; Get directory entry
lxi b,060h; offset entry point time/date stamp
dad b; Add offset
mov a,m; Get byte
sui tmstamp
rnz; No time stamp present, return
mov d,a; 0, clear D
dad d; Add entry (create/update/access)
push d; save field id
lda secpnt; Get sector pointer (0, 32, 64
rrc; Divide / 4
rrc
mov e,a; 0, 8, 16
rrc; divide 4 = 0, 2, 4
rrc
add e; Add it (A=0,10,20)
mov e,a; Save in e
dad d; point to appropriate field
push h
call getbtm; point to system time array
pop d; field pointer
pop b; restore field id
rc; timer system disabled
mov a,c
cpi 2; no carry for valid field id
jrz mvdate; 2 byte field for creation
; " "
; Move 4 byte time array hl^ to de^, avoid interrupts
; b,c,d,e,h,l
mvtime: lxi b,4
; " "
; entry for 2/4 byte fields, bc = length on entry
; b,c,d,e,h,l
mvdate: di
ldir; store it
ei
xra a; z/nc for good exits
ret
;
; Get time
gettim: push d; Save address to put time
call getbtm; get system time adr.
pop d; Restore address to put time
mvi a,0ffh; If disabled return error
jrc getim2
lxi b,4
call mvdate; if timer enabled
mov a,m; seconds field
getim2: jmp rtnbyt
;
; Set time
settim: push d; keep source time ptr
push d
pop b; if hardware must be accessed to set
call btime; get system ptr
pop d
rc; timer system disabled
rnz; Bios did it all
xchg
call mvtime; sets a := 0
stax d; set seconds field 0
ret
;
; Specification for any bios timer routine. Leaves carry clear, NZ flg
; Input Output (always)
; BC = 0 get pointer HL=pointer to time array
; BC <> 0 allows hard- HL+0^ date LSB days since 1977 Dec. 31
; ware to be updated HL+1^ date MSB (1=1978/1/1) (0=nodate)
; if a routine call. HL+2^ hour (bcd)
; ignored if timead HL+3^ minute (bcd)
; is purely an address. HL+4^ seconds (bcd)
; BC^ is time to set.
; Carry and Z flags reset.
;
; Get time from bios system
getbtm: lxi b,0; so hardware not updated
; " "
; Execute BIOS time routine.
; bc = 0 to get time, <> 0 to set hardware, when bc points to time
; to set. This is used only when hardware ports accessed.
; flags 80h bit = 0 for timead = address of array
; = 1 for timead = pointer to routine
; net result is to return hl pointer to array
; i.e. at exit hl always points to the system array
; The routine call allows for interrogation of hardware ports.
; The bios routine may leave interrupts disabled, they will be
; re-enabled when the time value has been copied.
; carry set on exit means timer disabled.
; Z flag set on exit if timead is a pointer only
btime: lhld timead; Get address time routine
mov a,h
ora l; check disabled
stc
rz; disabled, do nothing
lda flags
ani fb.tcal
rz; timead is address of array only
pchl; is address of routine, execute
;
; Error messages
mbadsc: db 'Disk I/O$'
msel: db 'No drive$'
mfilro: db 'File '
mro: db 'R/O$'
;
mbfunc: db cr,lf,'Fn: $'
mfile: db ' File: $'
;
mberr: db cr,lf,'DOS+ error '; Last area checksummable
mdrive: db 0,': $'; modified
;
; RAM AREA. Note mdrive above is a variable
;
dma: dw 080h; DMA address
dskro: dw 0; Disk R/O vector
login: dw 0; Login vector
;
; Console i/o variables. Keep these 3 in this order (wired into code)
bufull: db 0; Lastch contains unused char.
lastch: db 0; Last console input char.
column: db 0; Current console output column
;
; Copied in from Bios tables on drive selection
@trans: dw 0; ^Translation vector, 0 for none
@filect: dw 0; ^Number of files on drive
ds 4; temp1, temp2 not used
@dirbuf: dw 0; ^directory buffer
@ixp: dw 0; ^Disk parameter block
@csv: dw 0; ^Check sum vector
@alv: dw 0; ^Allocation vector
;
; Copied in from Disk Parameter table on drive selection
maxsec: dw 0; Maximum number of sectors/track
nblock: db 0; Number of blocks
nmask: db 0; Mask number of blocks
nextnd: db 0; Extent mask
maxblk: dw 0; Maximum block number -1
nfiles: dw 0; Maximum number of files - 1
ndir0: db 0,0; First two entries ALV buffer
ncheck: dw 0; Number of checksum entries
nftrk: dw 0; First track number
;
funct: db 0; Function number
fvalue: dw 0; Exit code
drvflg: db 0; Drive select used flag
fcb0: db 0; FCB byte 0 (save for exit)
;
rdwr: db 0; Read/write flag
wildcd: db 0; Search question mark used
;
user: db 0; User number
drive: db 0; Drive number
defdrv: db 0; Default drive number
subflg: db 0; Submit flag (Reset disk command)
;
recdir: dw 0; Record directory (checksum)
filcnt: dw 0; File counter
secpnt: db 0; Sector pointer
;
dcopy: dw 0; Copy address FCB
searex: db 0; Exit code for search
searnb: db 0; Search number of bytes
;
; 64 minimum byte stack area. Copyright re-used for stack.
stktop: db 'Copyright (c) 1986 C.B. Falconer (203) 281-1438'
ds 64-($-stktop)
;
; Macro for storage allocation messages only, SLRMAC specific
px macro v, xmsg
.printx v&xmsg
endm
;
left equ serial+0dfeh-$
if left ge 8000h; negative
+++ ERROR DOS+ too big +++
px %(-left), < too many bytes used>
else
px %left, < bytes still available>
if left gt 0
ds left; space that's left
endif
; Put stack at end of segment. Error trappers expect spsave there.
stack:
spsave: dw 0; Entry stack pointer save at end
endif
;
end
τ╬