mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-25 17:34:06 +00:00
602 lines
21 KiB
Plaintext
602 lines
21 KiB
Plaintext
;
|
||
;*****************************************************************
|
||
;*****************************************************************
|
||
;** **
|
||
;** B a s i c D i s k O p e r a t i n g S y s t e m **
|
||
;** **
|
||
;*****************************************************************
|
||
;*****************************************************************
|
||
;
|
||
selerror:
|
||
;report select error
|
||
LEA BX,seler ;
|
||
;
|
||
;
|
||
goerr:
|
||
;BX = .errorhandler,call subr.
|
||
JMP w[bx] ;to subroutine
|
||
;
|
||
;
|
||
;
|
||
; local subroutines for bios interface
|
||
;
|
||
move:
|
||
;move data length of length CL from source DX to
|
||
;destination given by BX
|
||
push cx
|
||
mov ch,0
|
||
mov si,dx
|
||
mov di,bx
|
||
rep movs al,al
|
||
pop cx
|
||
ret
|
||
;
|
||
;
|
||
selectdisk:
|
||
;select the disk drive given by curdsk, and fill
|
||
;the base addresses curtrka - alloca, then fill
|
||
;the values of the disk parameter block
|
||
;
|
||
MOV cl,curdsk ;current disk# to CL
|
||
;lsb of DL = 0 if not yet
|
||
;logged in
|
||
CALL seldskf ;BX filled by call
|
||
;BX = 0000 if error,
|
||
;otherwise disk headers
|
||
cmp bx,0
|
||
jz ret4 ;rz
|
||
MOV DX,[bx]
|
||
add bx,2
|
||
MOV cdrmaxa,BX
|
||
add bx,2
|
||
MOV curtrka,BX
|
||
add bx,2
|
||
MOV curreca,BX
|
||
add bx,2
|
||
;DX still contains .tran
|
||
xchg bx,dx
|
||
MOV tranv,bx ;.tran vector
|
||
LEA BX,buffa ;DX= source for move, BX=dest
|
||
MOV CL,addlist
|
||
CALL move ;addlist filled
|
||
;now fill the disk
|
||
;parameter block
|
||
MOV dx,dpbaddr
|
||
LEA BX,sectpt ;BX is destination
|
||
MOV CL,dpblist
|
||
CALL move ;data filled
|
||
;set single/double map mode
|
||
MOV al,byte ptr maxall+1 ;largest allocation number
|
||
LEA BX,single
|
||
MOV b[bx],true ;assume a=00
|
||
OR AL,AL
|
||
JZ retselect
|
||
;high order of maxall not
|
||
;zero, use double dm
|
||
MOV b[bx],false
|
||
retselect:
|
||
MOV AL,true
|
||
OR AL,AL
|
||
ret4: RET ;select disk function ok
|
||
;
|
||
home:
|
||
;move to home position, then offset to start of dir
|
||
CALL homef
|
||
;first directory pos. selected
|
||
XOR AX,AX ;constant zero to accumulator
|
||
MOV BX,curtrka
|
||
MOV [bx],ax ;curtrk=0000
|
||
;curtrk, currec both set to 0
|
||
RET
|
||
;
|
||
rdbuff:
|
||
;read buffer and check if ok
|
||
CALL readf ;current drive, track,....
|
||
jmps diocomp ;check for i/o errors
|
||
;
|
||
wrbuff:
|
||
;write buffer and check condition
|
||
;write type (wrtype) is in register CL
|
||
;wrtype = 0 => normal write operation
|
||
;wrtype = 1 => directory write operation
|
||
;wrtype = 2 => start of new block
|
||
CALL writef ;current drive, track, ...
|
||
diocomp: ;check for disk errors
|
||
OR AL,AL
|
||
jz ret4 ;rz
|
||
LEA BX,pererr
|
||
JMP goerr
|
||
;
|
||
seekdir:
|
||
;seek the record containing the current dir entry
|
||
MOV BX,dcnt ;directory counter to BX
|
||
MOV CL,dskshf
|
||
shr bx,cl ;value to BX
|
||
MOV arecord,BX
|
||
MOV drec,BX ;ready for seek
|
||
; jmp seek
|
||
;ret
|
||
;
|
||
seek:
|
||
;seek the track given by arecord (actual record)
|
||
;
|
||
;
|
||
mov ax,arecord ;compute track/sector
|
||
mov dx,0
|
||
div sectpt ;dx=sector, ax=track
|
||
push dx
|
||
mov cx,ax ;update curtrk
|
||
mov si,curtrka
|
||
mov [si],cx
|
||
add cx,offsetv ;set BIOS track
|
||
call settrkf
|
||
pop cx ;set BIOS sector
|
||
mov dx,tranv
|
||
call sectran
|
||
mov cx,bx
|
||
jmp setsecf
|
||
;ret
|
||
;
|
||
;
|
||
; utility functions for file access
|
||
;
|
||
dmposition:
|
||
;compute disk map position for vrecord to BX
|
||
lea bx,blkshf
|
||
MOV CL,[bx] ;shift count to CL
|
||
MOV AL,lvrecord ;current virtual record to A
|
||
shr al,cl
|
||
;A = shr(vrecord,blkshf) = vrecord/2**(sect/block)
|
||
MOV CH,AL ;save it for later addition
|
||
MOV cl,7
|
||
SUB cl,[bx]
|
||
MOV AL,extval ;extent value ani extmsk
|
||
;
|
||
;blkshf = 3,4,5,6,7
|
||
;CL=4,3,2,1,0
|
||
;shift is 4,3,2,1,0
|
||
shl al,cl
|
||
;arrive here with A = shl(ext and extmsk,7-blkshf)
|
||
ADD AL,CH ;add the previous
|
||
;shr(vrecord,blkshf) value
|
||
;AL 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 CX
|
||
MOV BX,info ;base address of file
|
||
;file control block
|
||
ADD BX,dskmap ;bx=.diskmap
|
||
ADD BX,CX ;index by asingle byte value
|
||
cmp single,0 ;single byte/map entry?
|
||
JZ getdmd ;get disk map single byte
|
||
MOV BL,[bx]
|
||
MOV BH,0
|
||
RET ;with BX=00bb
|
||
getdmd:
|
||
ADD BX,CX ;bx=.fcb(dm+1*2)
|
||
;return double precision value
|
||
MOV bx,[bx]
|
||
RET
|
||
;
|
||
index:
|
||
;compute disk block number from current FCB
|
||
CALL dmposition ;0...15 in register AL
|
||
MOV CL,AL
|
||
MOV CH,0
|
||
CALL getdm ;value to BX
|
||
MOV arecord,BX
|
||
RET
|
||
;
|
||
alloct:
|
||
;called following index to see if block allocated
|
||
MOV BX,arecord
|
||
or bx,bx
|
||
RET
|
||
;
|
||
atran:
|
||
;compute actual record address, assuming index called
|
||
MOV cl,blkshf ;shift count to reg AL
|
||
MOV BX,arecord
|
||
shl bx,cl
|
||
MOV ablock,BX ;save shifted block #
|
||
MOV AL,lvrecord
|
||
AND AL,blkmsk ;masked value in AL
|
||
OR bl,al
|
||
MOV arecord,BX ;arecord=BX or
|
||
;(vrecord and blkmsk)
|
||
RET
|
||
;
|
||
getexta:
|
||
;get current extent field address to AL
|
||
MOV BX,info
|
||
add bx,extnum ;bx=.fcb(extnum)
|
||
mov al,[bx]
|
||
RET
|
||
;
|
||
gtfcba:
|
||
;compute reccnt and nxtrec addresses for get/setfcb
|
||
MOV DX,reccnt
|
||
add dx,info ;DX=.fcb(reccnt)
|
||
MOV BX,(nxtrec-reccnt)
|
||
ADD BX,DX ;bx=.fcb(nxtrec)
|
||
RET
|
||
;
|
||
getfcb:
|
||
;set variables from currently addressed FCB
|
||
CALL gtfcba ;addresses in DX, BX
|
||
MOV AL,[bx]
|
||
MOV lvrecord,al ;vrecord=fcb(nxtrec)
|
||
XCHG BX,DX
|
||
MOV AL,[bx]
|
||
MOV rcount,AL ;rcount=fcb(reccnt)
|
||
CALL getexta ;BX=.fcb(extnum)
|
||
MOV AL,extmsk ;extent mask to a
|
||
AND AL,[bx] ;fcb(extnum) and extmsk
|
||
MOV extval,AL
|
||
RET
|
||
;
|
||
setfcb:
|
||
;place values back into current fcb
|
||
CALL gtfcba ;addresses to DX, BX
|
||
MOV AL,seqio
|
||
CMP AL,02
|
||
JNZ setfc1
|
||
XOR AL,AL ;check ranfill
|
||
setfc1:
|
||
;=1 if sequential i/o
|
||
add AL,lvrecord
|
||
MOV [bx],al ;fcb(nxtrec)=vrecord+seqio
|
||
XCHG BX,DX
|
||
MOV AL,rcount
|
||
MOV [bx],al ;fcb(reccnt)=rcount
|
||
RET
|
||
;
|
||
;
|
||
cmpecs:
|
||
;compute checksum for current directory buffer
|
||
MOV cx,recsiz ;size of directory buffer
|
||
MOV BX,buffa ;current directory buffer
|
||
XOR AL,AL ;clear checksum value
|
||
cmpec0:
|
||
ADD AL,[bx]
|
||
INC BX
|
||
loop cmpec0
|
||
RET ;with checksum in A
|
||
;
|
||
setcdisk:
|
||
;set a "1" value in curdsk position of CX
|
||
PUSH CX ;save input parameter
|
||
MOV cl,curdsk
|
||
MOV BX,1 ;number to shift
|
||
shl bx,cl ;BX = mask to integrate
|
||
POP CX ;original mask
|
||
or bx,cx ;BX = mask or rol(1,curdsk)
|
||
RET
|
||
;
|
||
nowrite:
|
||
;return true if dir checksum difference occurred
|
||
MOV ax,rodsk
|
||
MOV cl,curdsk
|
||
shr ax,cl
|
||
AND AL,1
|
||
RET ;non zero if nowrite
|
||
;
|
||
setro:
|
||
;set current disk to read only
|
||
mov cx,rodsk
|
||
CALL setcdisk ;sets bit to 1
|
||
MOV rodsk,BX
|
||
;high water mark in directory
|
||
;goes to max
|
||
MOV dx,dirmax
|
||
INC dx
|
||
MOV BX,cdrmaxa ;BX = .cdrmax
|
||
MOV [bx],dx ;cdrmax = dirmax
|
||
RET
|
||
;
|
||
ckrodir:
|
||
;check current directory element for read/only status
|
||
CALL getdptra ;address of element
|
||
;
|
||
ckrofile:
|
||
;check current buff(dptr) or fcb(0) for r/o status
|
||
MOV DX,rofile
|
||
ADD BX,DX ;offset to r/o bit
|
||
MOV AL,[bx]
|
||
RCL AL,1
|
||
jae ret5 ;rnc
|
||
LEA BX,rofer
|
||
JMP goerr ;
|
||
; jmp roferror ;exit to read only disk message
|
||
;
|
||
;
|
||
checkwrite:
|
||
;check for write protected disk
|
||
CALL nowrite
|
||
jz ret5 ;rz
|
||
LEA BX,roderr
|
||
JMP goerr
|
||
; jmp roderror ;read only disk error
|
||
;
|
||
getdptra:
|
||
;compute the address of a directory element at
|
||
;positon dptr in the buffer
|
||
MOV BX,buffa
|
||
MOV AL,dptr
|
||
addh:
|
||
;BX = BX + AL
|
||
mov ah,0
|
||
add bx,ax
|
||
ret5: ret
|
||
;
|
||
;
|
||
getmodnum:
|
||
;compute the address of the module number
|
||
;bring module number to accumulator
|
||
;(high order bit is fwf (file write flag)
|
||
MOV BX,info
|
||
add bx,modnum
|
||
MOV AL,[bx]
|
||
RET ;AL=fcb(modnum)
|
||
;
|
||
clrmodnum:
|
||
;clear the module number field for user open/make
|
||
CALL getmodnum
|
||
MOV b[bx],0 ;fcb(modnum)=0
|
||
RET
|
||
;
|
||
setfwf:
|
||
CALL getmodnum ;BX=.fcb(modnum),
|
||
;AL=fcb(modnum)
|
||
;set fwf(file write flag) to 1
|
||
OR AL,fwfmsk
|
||
MOV [bx],al ;fcb(modnum)=fcb(modnum) + 80h
|
||
;also returns non zero
|
||
;in accumulator
|
||
RET
|
||
;
|
||
;
|
||
compcdr:
|
||
;return cy if cdrmax > dcnt
|
||
MOV dx,dcnt ;DX = directory counter
|
||
MOV BX,cdrmaxa ;BX=.cdrmax
|
||
cmp dx,[bx]
|
||
;condition dcnt - cdrmax
|
||
;produces cy if cdrmax>dcnt
|
||
ret6: RET
|
||
;
|
||
setcdr:
|
||
;if not (cdrmax > dcnt) then cdrmax = dcnt+1
|
||
CALL compcdr
|
||
jb ret6 ;return if cdrmax > dcnt
|
||
;otherwise, BX = .cdrmax+1,
|
||
;DX = dcnt
|
||
INC DX
|
||
MOV [bx],dx
|
||
RET
|
||
;
|
||
subdh:
|
||
;compute BX = DX - BX
|
||
push dx
|
||
sub dx,bx
|
||
mov bx,dx
|
||
pop dx
|
||
RET
|
||
;
|
||
newchecksum:
|
||
;drop through to compute new checksum
|
||
MOV CL,true
|
||
checksum:
|
||
;compute current checksum record and update the
|
||
;directory element if CL=true, or check for = if not
|
||
;drec < chksiz?
|
||
MOV DX,drec
|
||
MOV BX,chksiz
|
||
CALL subdh ;DX-BX
|
||
jae ret6 ;skip checksum if past
|
||
;checksum vector size
|
||
;drec < chksiz, so continue
|
||
PUSH CX ;save init flag
|
||
CALL cmpecs ;check sum value to AL
|
||
MOV BX,drec ;value of drec
|
||
ADD BX,checka ;bx=.check(drec)
|
||
POP CX ;recall true or false to CL
|
||
INC CL ;true produces zero flag
|
||
JZ initcs
|
||
;not initializing, compare
|
||
CMP AL,[bx] ;compute$cs=check(drec)?
|
||
jz ret7 ;no message if ok
|
||
;checksum error, are we beyond
|
||
;the end of the disk?
|
||
CALL compcdr
|
||
jae ret7 ;no message if so
|
||
CALL setro ;read/only disk set
|
||
RET
|
||
initcs:
|
||
;initializing the checksum
|
||
MOV [bx],al
|
||
ret7: RET
|
||
;
|
||
;
|
||
wrdir:
|
||
;write the current directory entry, set checksum
|
||
CALL newchecksum ;initialize entry
|
||
CALL setdir ;directory dma
|
||
MOV CL,1 ;indicates a write directory
|
||
CALL wrbuff ;write the buffer
|
||
JMP setdata ;to data dma address
|
||
;ret
|
||
;
|
||
rddirbuf:
|
||
;read a directory entry into the directory buffer
|
||
CALL setdir ;directory dma
|
||
CALL rdbuff ;directory record loaded
|
||
; jmp setdata
|
||
; ret
|
||
;
|
||
setdata:
|
||
;set data dma address
|
||
mov cx,dmabase
|
||
call setdmbf ;set BIOS disk I/O base
|
||
LEA BX,dmaad
|
||
jmps setdma ;to complete the call
|
||
;
|
||
setdir:
|
||
;set directory dma address
|
||
mov cx,ds
|
||
call setdmbf ;set BIOS disk I/O base
|
||
LEA BX,buffa ;jmp setdma to complete call
|
||
;
|
||
setdma:
|
||
;BX=.dma address to set (i.e., buffa or dmaad)
|
||
MOV CX,[bx] ;parameter ready
|
||
JMP setdmf
|
||
;
|
||
;
|
||
dirtouser:
|
||
;copy the directory entry to the user buffer
|
||
;after call to search or searchn by user code
|
||
MOV DX,buffa ;source is directory buffer
|
||
MOV BX,dmaad ;destination is user dma addr.
|
||
MOV CL,recsiz ;copy entire record
|
||
push es ;move to user segment
|
||
mov es,parametersegment
|
||
call move
|
||
pop es
|
||
ret
|
||
;ret
|
||
;
|
||
endofdir:
|
||
;return zero flag if at end of director, non zero
|
||
;if not at end (end of dir if dcnt = 0ffffh)
|
||
LEA BX,dcnt
|
||
MOV AL,[bx] ;may be 0ffh
|
||
INC BX
|
||
CMP AL,[bx] ;low(dcnt) = high(dcnt)?
|
||
jnz ret8 ;return non zero if different
|
||
;high and low the same,= 0ffh?
|
||
INC AL ;0ffh becomes 00 if so
|
||
ret8: RET
|
||
;
|
||
setenddir:
|
||
;set dcnt to the end of the directory
|
||
MOV BX,enddir
|
||
MOV dcnt,bx
|
||
RET
|
||
;
|
||
rddir:
|
||
;read next directory entry, with CL=true if initializing
|
||
MOV DX,dirmax ;in preparation for subtract
|
||
MOV BX,dcnt
|
||
INC BX
|
||
MOV dcnt,bx ;dcnt=dcnt+1
|
||
;continue while dirmax >= dcnt
|
||
;(dirmax-dcnt no cy)
|
||
CALL subdh ;DX-BX
|
||
JAE rddir0
|
||
;yes, set dcnt to end
|
||
;of directory
|
||
jmps setenddir
|
||
; ret
|
||
rddir0:
|
||
;not at end of directory, seek next element
|
||
;CL=initialization flag
|
||
MOV AL,ldcnt
|
||
AND AL,dskmsk ;low(dcnt) and dskmsk
|
||
push cx
|
||
MOV cl,fcbshf ;to multiply by fcb size
|
||
shl al,cl
|
||
pop cx
|
||
;A = (low(dcnt) and dskmsk)
|
||
;shl fcbshf
|
||
MOV dptr,AL ;ready for next dir operation
|
||
OR AL,AL
|
||
jnz ret71 ;return if not a new record
|
||
PUSH CX ;save initialization flag CL
|
||
CALL seekdir ;seek proper record
|
||
CALL rddirbuf ;read the directory record
|
||
POP CX ;recall initialization flag
|
||
JMP checksum ;checksum the directory elt
|
||
;ret
|
||
;
|
||
;
|
||
getallocbit:
|
||
;given allocation vector
|
||
;position on CX, return byte
|
||
;containing CX shifted so that the least significant
|
||
;bit is in the low order accumulator position. BX is
|
||
;the address of the byte for
|
||
;possible replacement in
|
||
;memory upon return, and DH contains the number of shifts
|
||
;required to place the returned value back into position
|
||
;
|
||
MOV dl,CL
|
||
AND dl,111b
|
||
INC dl
|
||
MOV DH,dl
|
||
;dh and dl both contain the
|
||
;number of bit positions to
|
||
;shift
|
||
MOV AL,CL
|
||
mov cl,3
|
||
ror al,cl
|
||
AND AL,11111b
|
||
MOV CL,AL ;CL shr 3 to CL
|
||
push cx
|
||
mov cl,5
|
||
shl al,cl
|
||
pop cx
|
||
or CL,AL ;bbbccccc to CL
|
||
MOV AL,CH
|
||
ROR AL,1
|
||
ROR AL,1
|
||
ROR AL,1
|
||
AND AL,11111b
|
||
MOV CH,AL ;CX shr 3 to CX
|
||
MOV BX,alloca ;base addr. of alloc. vector
|
||
ADD BX,CX
|
||
;byte to A, hl =
|
||
MOV AL,[bx] ;.alloc(CX shr 3)
|
||
;now move the bit to the
|
||
;low order position of AL
|
||
push cx
|
||
mov cl,dl
|
||
rol al,cl
|
||
pop cx
|
||
ret71: RET
|
||
;
|
||
;
|
||
setallocbit:
|
||
;CX is the bit position of ALLOC to set or reset. The
|
||
;value of the bit is in register DL.
|
||
PUSH DX
|
||
CALL getallocbit ;shifted val AL,count in DL
|
||
AND AL,11111110b ;mask low bit to zero
|
||
;(may be set)
|
||
POP CX
|
||
OR AL,CL ;low bit of CL masked into AL
|
||
; jmp rotr
|
||
; ret
|
||
rotr:
|
||
;byte value from ALLOC is in register AL, with shift count
|
||
;in register CH (to place bit back into position), and
|
||
;target ALLOC position in registers BX, rotate and replace
|
||
;
|
||
push cx
|
||
mov cl,ch
|
||
ror al,cl
|
||
mov [bx],al
|
||
pop cx
|
||
ret
|
||
;
|
||
;************* end BDOS filesystem part 1 **************
|
||
end
|
||
|