ocean-240.2/ROMs/Sources/ROM-FDC/bdos.asm

2785 lines
61 KiB
NASM

; =======================================================
; Ocean-240.2
; CP/M BDOS at 0xC800:D5FF
;
; Disassembled by Romych 2025-09-09
; ======================================================
INCLUDE "io.inc"
INCLUDE "equates.inc"
INCLUDE "external_ram.inc"
IFNDEF BUILD_ROM
OUTPUT bdos.bin
ENDIF
MODULE BDOS
ORG 0xC800
bdos_start:
LD SP, HL
LD D, 0x00
NOP
NOP
LD L, E
bdos_enter:
JP bdos_entrance
bdos_pere_addr: dw bdos_persub
bdos_sele_addr: dw bdos_selsub
bdos_rode_addr: dw bdos_rodsub
bdos_rofe_addr: dw bdos_rofsub
; -------------------------------------------------------
; BDOS Handler
; Inp: C - func no
; DE - parameter
; Out: A or HL - result
; -------------------------------------------------------
bdos_entrance:
EX DE, HL
LD (TM_VARS.bdos_info), HL
EX DE, HL
LD A, E
LD (TM_VARS.bdos_linfo), A
LD HL, 0x00 ; return val default = 0
LD (TM_VARS.bdos_aret), HL
; Save user's stack pointer, set to local stack
ADD HL,SP
LD (TM_VARS.bdos_entsp), HL
LD SP, TM_VARS.bdos_usercode ; local stack setup
XOR A
LD (TM_VARS.bdos_fcbdsk), A ; fcbdsk,resel=false
LD (TM_VARS.bdos_resel), A
LD HL, bdos_goback
PUSH HL ; jmp goback equivalent to ret
LD A, C
CP BDOS_NFUNCS
RET NC
LD C, E ; possible output character to C
LD HL, functab ; DE=func, HL=.ciotab
LD E, A
LD D, 0x00
ADD HL, DE
ADD HL, DE
LD E, (HL)
INC HL
LD D, (HL) ; DE=functab(func)
LD HL, (TM_VARS.bdos_info) ; info in DE for later xchg
EX DE, HL
JP (HL) ; dispatched
; -------------------------------------------------------
; BDOS function handlers address table
; -------------------------------------------------------
functab:
dw BIOS.wboot_f
dw bdos_func1
dw bdos_tabout
dw bdos_func3
dw BIOS.punch_f
dw BIOS.list_f
dw bdos_func6
dw bdos_func7
dw bdos_func8
dw bdos_func9
dw bdos_read
dw bdos_func11
dw bdos_get_version
dw bdos_reset_disks
dw bdos_select_disk
dw bdos_open_file
dw bdos_close_file
dw bdos_search_first
dw bdos_search_next
dw bdos_rm_dir
dw bdos_read_file
dw bdos_write_file
dw bdos_make_file
dw bdos_ren_file
dw bdos_get_login_vec
dw bdos_get_cur_drive
dw bdos_set_dma_addr
dw bdos_get_logvect
dw bdos_set_ro
dw bdos_wr_protect
dw bdos_set_ind
dw bdos_get_dpb
dw bdos_set_user
dw bdos_rand_read
dw bdos_rand_write
dw bdos_compute_fs
dw bdos_set_random
dw bdos_reset_drives
dw bdos_not_impl
dw bdos_not_impl
dw bdos_rand_write_z
; -------------------------------------------------------
; Report permanent error
; -------------------------------------------------------
bdos_persub:
LD HL,permsg ; = 'B'
CALL bdos_errflag
CP BDOS_CTLC
JP Z, EXT_RAM.JP_WBOOT
RET
; -------------------------------------------------------
; Report select error
; -------------------------------------------------------
bdos_selsub:
LD HL,selmsg ;= 'S'
JP bdos_wait_err
; -------------------------------------------------------
; Report write to read/only disk
; -------------------------------------------------------
bdos_rodsub:
LD HL,rodmsg ;= 'R'
JP bdos_wait_err
; -------------------------------------------------------
; Report read/only file
; -------------------------------------------------------
bdos_rofsub:
LD HL,rofmsg ;= 'F'
; -------------------------------------------------------
; Wait for response before boot
; -------------------------------------------------------
bdos_wait_err:
CALL bdos_errflag
JP EXT_RAM.JP_WBOOT
; -------------------------------------------------------
; Error messages
; -------------------------------------------------------
dskmsg:
db 'Bdos Err On '
dskerr:
db " : $"
permsg:
db "Bad Sector$"
selmsg:
db "Select$"
rofmsg:
db "File "
rodmsg:
db "R/O$"
; -------------------------------------------------------
; Report error to console, message address in HL
; -------------------------------------------------------
bdos_errflag:
PUSH HL
CALL bdos_crlf
LD A, (TM_VARS.bdos_curdsk)
ADD A,'A'
LD (dskerr), A ;= ' '
LD BC,dskmsg ;= 'B'
CALL bdos_print
POP BC
CALL bdos_print
; -------------------------------------------------------
; Console handlers
; Read console character to A
; -------------------------------------------------------
bdos_conin:
LD HL, TM_VARS.bdos_kbchar
LD A, (HL)
LD (HL), 0x00
OR A
RET NZ
;no previous keyboard character ready
JP BIOS.conin_f
; -------------------------------------------------------
; Read character from console with echo
; -------------------------------------------------------
bdos_conech:
CALL bdos_conin
CALL bdos_echoc
RET C
PUSH AF
LD C, A
CALL bdos_tabout
POP AF
RET
; -------------------------------------------------------
; Echo character if cr, lf, tab, or backspace
; -------------------------------------------------------
bdos_echoc:
CP ASCII_CR
RET Z
CP ASCII_LF
RET Z
CP ASCII_TAB
RET Z
CP ASCII_BS
RET Z
CP ' '
RET
; -------------------------------------------------------
; check for character ready
; -------------------------------------------------------
bdos_conbrk:
LD A, (TM_VARS.bdos_kbchar)
OR A
JP NZ,conb1 ; skip if active kbchar
CALL BIOS.const_f
AND 0x1
RET Z ; return if no char ready
CALL BIOS.conin_f
CP CTLS
JP NZ,conb0
CALL BIOS.conin_f
CP CTLC
JP Z, EXT_RAM.JP_WBOOT
XOR A
RET
conb0:
LD (TM_VARS.bdos_kbchar), A ; character in A, save it
conb1:
LD A, 0x1 ; return with true set in accumulator
RET
bdos_conout:
LD A, (TM_VARS.bdos_compcol) ; Compute character position/write con...
; compcol = true if computing column ...
OR A
JP NZ,compout
PUSH BC
CALL bdos_conbrk
POP BC
PUSH BC
CALL BIOS.conout_f
POP BC
PUSH BC
; May be copying to the list device
LD A, (TM_VARS.bdos_listcp)
OR A
CALL NZ, BIOS.list_f
POP BC
; -------------------------------------------------------
; Compute column position
; -------------------------------------------------------
compout:
LD A, C
; recall the character
; and compute column position
LD HL, TM_VARS.bdos_column
CP RUB_OUT
RET Z
INC (HL)
CP ' '
RET NC
; not graphic, reset column position
DEC (HL)
LD A, (HL)
OR A
RET Z
LD A, C
CP ASCII_BS
JP NZ, notbacksp
; backspace character
DEC (HL)
RET
notbacksp:
CP ASCII_LF
RET NZ
LD (HL), 0x00
RET
; -------------------------------------------------------
; Send C character with possible preceding up-arrow
; -------------------------------------------------------
bdos_ctlout:
LD A, C
CALL bdos_echoc ; cy if not graphic (or special case)
JP NC, bdos_tabout ; skip if graphic, tab, cr, lf, or ctlh
PUSH AF
LD C, CTL
CALL bdos_conout ; up arrow
POP AF
OR 0x40 ; becomes graphic letter
LD C, A ; ready to print
; (drop through to tabout)
bdos_tabout:
LD A, C
; Expand tabs to console
CP ASCII_TAB
JP NZ, bdos_conout
bpc_no_tabpos:
LD C,' '
CALL bdos_conout
LD A, (TM_VARS.bdos_column)
AND 00000111b ; column mod 8 = 0 ?
JP NZ, bpc_no_tabpos
RET
; -------------------------------------------------------
; Back-up one screen position
; -------------------------------------------------------
bdos_backup:
CALL bdos_pctlh
LD C, ' '
CALL BIOS.conout_f
; -------------------------------------------------------
; Send ctlh to console without affecting column count
; -------------------------------------------------------
bdos_pctlh:
LD C, ASCII_BS
JP BIOS.conout_f
; -------------------------------------------------------
; print #, cr, lf for ctlx, ctlu, ctlr functions
; then move to strtcol (starting column)
; -------------------------------------------------------
bdos_crlfp:
LD C, '#'
CALL bdos_conout
CALL bdos_crlf
crlfp0:
LD A, (TM_VARS.bdos_column)
LD HL, TM_VARS.bdos_strtcol
CP (HL)
RET NC
LD C, ' '
CALL bdos_conout
JP crlfp0
; -------------------------------------------------------
; Out carriage return line feed sequence
; -------------------------------------------------------
bdos_crlf:
LD C, ASCII_CR
CALL bdos_conout
LD C, ASCII_LF
JP bdos_conout
; -------------------------------------------------------
; Print $-ended message BC -> str
; -------------------------------------------------------
bdos_print:
LD A, (BC)
CP '$'
RET Z
INC BC
PUSH BC
LD C, A
CALL bdos_tabout
POP BC
JP bdos_print
; -------------------------------------------------------
; Buffered console input
; Reads characters from the keyboard into a memory buffer
; until RETURN is pressed.
; Inp: C=0Ah
; DE=address or zero
; -------------------------------------------------------
bdos_read:
LD A, (TM_VARS.bdos_column)
LD (TM_VARS.bdos_strtcol), A
LD HL, (TM_VARS.bdos_info)
LD C, (HL)
INC HL
PUSH HL
LD B, 0x00
; B = current buffer length,
; C = maximum buffer length,
; HL= next to fill - 1
readnx:
PUSH BC
PUSH HL
readn1:
CALL bdos_conin
AND 0x7f
POP HL
POP BC
CP 0xd
JP Z,readen
CP 0xa
JP Z,readen
CP 0x8
JP NZ,noth
LD A, B
OR A
JP Z,readnx
DEC B
LD A, (TM_VARS.bdos_column)
LD (TM_VARS.bdos_compcol), A
JP linelen
noth:
CP 0x7f ; not a backspace
JP NZ, notrub
LD A, B
OR A
JP Z, readnx
LD A, (HL)
DEC B
DEC HL
JP rdech1
notrub:
CP 0x5
JP NZ, note
PUSH BC
PUSH HL
CALL bdos_crlf
XOR A
LD (TM_VARS.bdos_strtcol), A
JP readn1
note:
CP 0x10
JP NZ,notp
PUSH HL
LD HL, TM_VARS.bdos_listcp
LD A, 0x1
SUB (HL)
LD (HL), A
POP HL
JP readnx
notp:
CP 0x18
JP NZ, notx
POP HL
backx:
LD A, (TM_VARS.bdos_strtcol)
LD HL, TM_VARS.bdos_column
CP (HL)
JP NC, bdos_read
DEC (HL)
CALL bdos_backup
JP backx
notx:
CP 0x15
JP NZ, notu
CALL bdos_crlfp
POP HL
JP bdos_read
notu:
CP 0x12
JP NZ, rdecho
linelen:
PUSH BC
CALL bdos_crlfp
POP BC
POP HL
PUSH HL
PUSH BC
rep0:
LD A, B
OR A
JP Z, rep1
INC HL
LD C, (HL)
DEC B
PUSH BC
PUSH HL
CALL bdos_ctlout
POP HL
POP BC
JP rep0
rep1:
PUSH HL
LD A, (TM_VARS.bdos_compcol)
OR A
JP Z, readn1
LD HL, TM_VARS.bdos_column
SUB (HL)
LD (TM_VARS.bdos_compcol), A
; move back compcol-column spaces
backsp:
CALL bdos_backup
LD HL, TM_VARS.bdos_compcol
DEC (HL)
JP NZ, backsp
JP readn1
rdecho:
INC HL
LD (HL), A
INC B
rdech1:
PUSH BC
PUSH HL
LD C, A
CALL bdos_ctlout
POP HL
POP BC
LD A, (HL)
CP 0x3
LD A, B
JP NZ, notc
CP 0x1
JP Z, EXT_RAM.JP_WBOOT
notc:
CP C
JP C,readnx
; End of read operation, store blen
readen:
POP HL
LD (HL), B
LD C, 0xd
JP bdos_conout
; -------------------------------------------------------
; Console input with echo (C_READ)
; Out: A=L=character
; -------------------------------------------------------
bdos_func1:
CALL bdos_conech
JP bdos_ret_a
; -------------------------------------------------------
; Console input chartacter
; Out: A=L=ASCII character
; -------------------------------------------------------
bdos_func3:
CALL BIOS.reader_f
JP bdos_ret_a
; -------------------------------------------------------
; Direct console I/O
; Inp: E=code.
; E=code. Returned values (in A) vary.
; 0xff Return a character without echoing if one is
; waiting; zero if none
; 0xfe Return console input status. Zero if no
; character is waiting
; Out: A
; -------------------------------------------------------
bdos_func6:
LD A, C
INC A
JP Z, dirinp ; ff?
INC A
JP Z, BIOS.const_f ; fe?
JP BIOS.conout_f ; con out otherwise
dirinp:
CALL BIOS.const_f
OR A
JP Z, bdos_ret_mon
CALL BIOS.conin_f
JP bdos_ret_a
; -------------------------------------------------------
; Get I/O byte
; Out: [3] = I/O byte.
; -------------------------------------------------------
bdos_func7:
LD A, (EXT_RAM.bdos_ioloc)
JP bdos_ret_a
; -------------------------------------------------------
; Set I/O byte
; Inp: E=I/O byte.
; -------------------------------------------------------
bdos_func8:
LD HL, EXT_RAM.bdos_ioloc
LD (HL), C
RET
; -------------------------------------------------------
; Out $-ended string
; Inp: DE -> string.
; -------------------------------------------------------
bdos_func9:
EX DE, HL
LD C,L
LD B, H
JP bdos_print
; -------------------------------------------------------
; Get console status
; Inp: A=L=status
; -------------------------------------------------------
bdos_func11:
CALL bdos_conbrk
bdos_ret_a:
LD (TM_VARS.bdos_aret), A
bdos_not_impl:
RET
setlret1:
LD A, 0x1
JP bdos_ret_a
; -------------------------------------------------------
; Report select error
; -------------------------------------------------------
bdos_sel_error:
LD HL, bdos_sele_addr ;= C8A5h
bdos_goerr:
LD E, (HL) ;= C8A5h
INC HL
LD D, (HL) ; ->bdos_sele_addr+1
EX DE, HL
JP (HL) ; ->bdos_selsub
; -------------------------------------------------------
; Move C bytes from [DE] to [HL]
; -------------------------------------------------------
bdos_move:
INC C
bmove_nxt:
DEC C
RET Z
LD A, (DE)
LD (HL), A
INC DE
INC HL
JP bmove_nxt
; -------------------------------------------------------
; Select the disk drive given by curdsk, and fill
; the base addresses curtrka - alloca, then fill
; the values of the disk parameter block
; -------------------------------------------------------
dbos_selectdisk:
LD A, (TM_VARS.bdos_curdsk)
LD C, A
CALL BIOS.seldsk_f ; HL filled by call
; HL = 0000 if error, otherwise disk headers
LD A, H
OR L
RET Z
LD E, (HL)
INC HL
LD D, (HL)
INC HL
LD (TM_VARS.bdos_cdrmaxa), HL
INC HL
INC HL
LD (TM_VARS.bdos_curtrka), HL
INC HL
INC HL
LD (TM_VARS.bdos_curreca), HL
INC HL
INC HL
EX DE, HL
LD (TM_VARS.bdos_tranv), HL ; .tran vector
LD HL, TM_VARS.bdos_buffa ; DE= source for move, HL=dest
LD C, ADDLIST
CALL bdos_move
; Fill the disk parameter block
LD HL, (TM_VARS.bdos_dpbaddr)
EX DE, HL
LD HL, TM_VARS.dbos_sectpt
LD C, DBPLIST
CALL bdos_move
; Set single/double map mode
LD HL, (TM_VARS.bdos_maxall) ; largest allocation number
LD A, H
LD HL, TM_VARS.bdos_single
LD (HL), 0xFF
OR A
JP Z, retselect
LD (HL), 0x00
retselect:
LD A, 0xff
OR A
RET
; -------------------------------------------------------
; Move to home position, then offset to start of dir
; -------------------------------------------------------
bdos_home:
CALL BIOS.home_f
XOR A
LD HL, (TM_VARS.bdos_curtrka)
LD (HL), A
INC HL
LD (HL), A
LD HL, (TM_VARS.bdos_curreca)
LD (HL), A
INC HL
LD (HL), A
RET
; -------------------------------------------------------
; Read buffer and check condition
; -------------------------------------------------------
bdos_rdbuff:
CALL BIOS.read_f
JP diocomp ; check for i/o errors
; -------------------------------------------------------
; Write buffer and check condition
; Inp: C - write type
; 0 - normal write operation
; 1 - directory write operation
; 2 - start of new block
; -------------------------------------------------------
bdos_wrbuff:
CALL BIOS.write_f
; -------------------------------------------------------
; Check for disk errors
; -------------------------------------------------------
diocomp:
OR A
RET Z
LD HL, bdos_pere_addr ;= C899h
JP bdos_goerr
; -------------------------------------------------------
; Seek the record containing the current dir entry
; -------------------------------------------------------
bdos_seekdir:
LD HL, (TM_VARS.bdos_dcnt)
LD C, DSK_SHF
CALL bdos_hlrotr
LD (TM_VARS.bdos_arecord), HL
LD (TM_VARS.bdos_drec), HL
; -------------------------------------------------------
; Seek the track given by arecord (actual record)
; local equates for registers
; -------------------------------------------------------
bdos_seek:
LD HL, TM_VARS.bdos_arecord
LD C, (HL)
INC HL
LD B, (HL)
LD HL, (TM_VARS.bdos_curreca)
LD E, (HL)
INC HL
LD D, (HL)
LD HL, (TM_VARS.bdos_curtrka)
LD A, (HL)
INC HL
LD H, (HL)
LD L, A
bseek_l0:
LD A, C
SUB E
LD A, B
SBC A, D
JP NC, bseek_l1
PUSH HL
LD HL, (TM_VARS.dbos_sectpt)
LD A, E
SUB L
LD E, A
LD A, D
SBC A, H
LD D, A
POP HL
DEC HL
JP bseek_l0
bseek_l1:
PUSH HL
LD HL, (TM_VARS.dbos_sectpt)
ADD HL, DE
JP C, bseek_l2
LD A, C
SUB L
LD A, B
SBC A, H
JP C, bseek_l2
EX DE, HL
POP HL
INC HL
JP bseek_l1
bseek_l2:
POP HL
PUSH BC
PUSH DE
PUSH HL
; Stack contains (lowest) BC=arecord, DE=currec, HL=curtrk
EX DE, HL
LD HL, (TM_VARS.bdos_offset)
ADD HL, DE
LD B, H
LD C,L
CALL BIOS.settrk_f
POP DE
LD HL, (TM_VARS.bdos_curtrka)
LD (HL), E
INC HL
LD (HL), D
POP DE
LD HL, (TM_VARS.bdos_curreca)
LD (HL), E
INC HL
LD (HL), D
POP BC
LD A, C
SUB E
LD C, A
LD A, B
SBC A, D
LD B, A
LD HL, (TM_VARS.bdos_tranv)
EX DE, HL
CALL BIOS.sectran_f
LD C,L
LD B, H
JP BIOS.setsec_f
; -------------------------------------------------------
; Compute disk map position for vrecord to HL
; -------------------------------------------------------
bdos_dm_position:
LD HL, TM_VARS.bdos_blkshf
LD C, (HL)
LD A, (TM_VARS.bdos_vrecord)
dmpos_l0:
OR A
RRA
DEC C
JP NZ, dmpos_l0
; A = shr(vrecord, blkshf) = vrecord/2**(sect/block)
LD B, A
LD A, 0x8
SUB (HL)
LD C, A
LD A, (TM_VARS.bdos_extval)
dmpos_l1:
DEC C
JP Z, dmpos_l2
OR A
RLA
JP dmpos_l1
dmpos_l2:
ADD A, B
RET ; with dm_position in A
; -------------------------------------------------------
; Return disk map value from position given by BC
; -------------------------------------------------------
dbos_getdm:
LD HL, (TM_VARS.bdos_info)
LD DE, DSK_MAP
ADD HL, DE
ADD HL, BC
LD A, (TM_VARS.bdos_single)
OR A
JP Z,getdmd
LD L, (HL)
LD H, 0x00
RET
getdmd:
ADD HL, BC
LD E, (HL)
INC HL
LD D, (HL)
EX DE, HL
RET
; -------------------------------------------------------
; Compute disk block number from current FCB
; -------------------------------------------------------
bdos_index:
CALL bdos_dm_position
LD C, A
LD B, 0x00
CALL dbos_getdm
LD (TM_VARS.bdos_arecord), HL
RET
; -------------------------------------------------------
; Called following index to see if block allocated
; -------------------------------------------------------
bdos_allocated:
LD HL, (TM_VARS.bdos_arecord)
LD A,L
OR H
RET
; -------------------------------------------------------
; Compute actual record address, assuming index called
; -------------------------------------------------------
bdos_atran:
LD A, (TM_VARS.bdos_blkshf)
LD HL, (TM_VARS.bdos_arecord)
bdatarn_l0:
ADD HL, HL
DEC A
JP NZ, bdatarn_l0
LD (TM_VARS.bdos_arecord1), HL
LD A, (TM_VARS.bdos_blmsk)
LD C, A
LD A, (TM_VARS.bdos_vrecord)
AND C
OR L
LD L, A
LD (TM_VARS.bdos_arecord), HL
RET
; -------------------------------------------------------
; Get current extent field address to A
; -------------------------------------------------------
bdos_getexta:
LD HL, (TM_VARS.bdos_info)
LD DE, EXT_NUM
ADD HL, DE ; HL -> .fcb(extnum)
RET
; -------------------------------------------------------
; Compute reccnt and nxtrec addresses for get/setfcb
; -------------------------------------------------------
bdos_getfcba:
LD HL, (TM_VARS.bdos_info)
LD DE,REC_CNT
ADD HL, DE
EX DE, HL
LD HL, 0x11 ; (nxtrec-reccnt)
ADD HL, DE
RET
; -------------------------------------------------------
; Set variables from currently addressed fcb
; -------------------------------------------------------
bdos_getfcb:
CALL bdos_getfcba
LD A, (HL)
LD (TM_VARS.bdos_vrecord), A
EX DE, HL
LD A, (HL)
LD (TM_VARS.bdos_rcount), A
CALL bdos_getexta
LD A, (TM_VARS.bdos_extmsk)
AND (HL)
LD (TM_VARS.bdos_extval), A
RET
; -------------------------------------------------------
; Place values back into current fcb
; -------------------------------------------------------
bdos_setfcb:
CALL bdos_getfcba
LD A, (TM_VARS.bdos_seqio)
CP 0x2
JP NZ, bsfcb_l0
XOR A
bsfcb_l0:
LD C, A
LD A, (TM_VARS.bdos_vrecord)
ADD A, C
LD (HL), A
EX DE, HL
LD A, (TM_VARS.bdos_rcount)
LD (HL), A
RET
; -------------------------------------------------------
; Rotate HL right by C bits
; -------------------------------------------------------
bdos_hlrotr:
INC C
bhlr_nxt:
DEC C
RET Z
LD A, H
OR A
RRA
LD H, A
LD A,L
RRA
LD L, A
JP bhlr_nxt
; -------------------------------------------------------
; Compute checksum for current directory buffer
; -------------------------------------------------------
bdos_compute_cs:
LD C, REC_SIZ ; size of directory buffer
LD HL, (TM_VARS.bdos_buffa)
XOR A
bcompcs_l0:
ADD A, (HL)
INC HL
DEC C
JP NZ, bcompcs_l0
RET
; -------------------------------------------------------
; Rotate HL left by C bits
; -------------------------------------------------------
bdos_hlrotl:
INC C
brothll_nxt:
DEC C
RET Z
ADD HL, HL
JP brothll_nxt
; -------------------------------------------------------
; Set a "1" value in curdsk position of BC
; -------------------------------------------------------
bdos_set_cdisk:
PUSH BC
LD A, (TM_VARS.bdos_curdsk)
LD C, A
LD HL, 0x1
CALL bdos_hlrotl
POP BC
LD A, C
OR L
LD L, A
LD A, B
OR H
LD H, A
RET
; -------------------------------------------------------
; Return true if dir checksum difference occurred
; -------------------------------------------------------
bdos_nowrite:
LD HL, (TM_VARS.bdos_rodsk)
LD A, (TM_VARS.bdos_curdsk)
LD C, A
CALL bdos_hlrotr
LD A,L
AND 0x1
RET
; -------------------------------------------------------
; Temporarily set current drive to be read-only;
; attempts to write to it will fail
; -------------------------------------------------------
bdos_set_ro:
LD HL, TM_VARS.bdos_rodsk
LD C, (HL)
INC HL
LD B, (HL)
CALL bdos_set_cdisk
LD (TM_VARS.bdos_rodsk), HL
; high water mark in directory goes to max
LD HL, (TM_VARS.bdos_dirmax)
INC HL
EX DE, HL
LD HL, (TM_VARS.bdos_cdrmaxa)
LD (HL), E
INC HL
LD (HL), D
RET
; -------------------------------------------------------
; Check current directory element for read/only status
; -------------------------------------------------------
bdos_check_rodir:
CALL bdos_getdptra
; -------------------------------------------------------
; Check current buff(dptr) or fcb(0) for r/o status
; -------------------------------------------------------
bdos_check_rofile:
LD DE,RO_FILE
ADD HL, DE
LD A, (HL)
RLA
RET NC
LD HL, bdos_rofe_addr ;= C8B1h
JP bdos_goerr
; -------------------------------------------------------
; Check for write protected disk
; -------------------------------------------------------
bdos_check_write:
CALL bdos_nowrite
RET Z
LD HL, bdos_rode_addr ;= C8ABh
JP bdos_goerr
; -------------------------------------------------------
; Compute the address of a directory element at
; positon dptr in the buffer
; -------------------------------------------------------
bdos_getdptra:
LD HL, (TM_VARS.bdos_buffa)
LD A, (TM_VARS.bdos_dptr)
; -------------------------------------------------------
; HL = HL + A
; -------------------------------------------------------
bdos_hl_add_a:
ADD A,L
LD L, A
RET NC
INC H
RET
; -------------------------------------------------------
; Compute the address of the module number
; bring module number to accumulator
; (high order bit is fwf (file write flag)
; -------------------------------------------------------
bdos_getmodnum:
LD HL, (TM_VARS.bdos_info)
LD DE, MOD_NUM
ADD HL, DE
LD A, (HL)
RET
; -------------------------------------------------------
; Clear the module number field for user open/make
; -------------------------------------------------------
bdos_clr_modnum:
CALL bdos_getmodnum
LD (HL), 0x00
RET
; -------------------------------------------------------
; Set fwf (file write flag)
; -------------------------------------------------------
setfwf:
CALL bdos_getmodnum
OR FWF_MASK
LD (HL), A
RET
; -------------------------------------------------------
; Return cy if cdrmax > dcnt
; -------------------------------------------------------
bdos_compcdr:
LD HL, (TM_VARS.bdos_dcnt)
EX DE, HL ; DE = directory counter
LD HL, (TM_VARS.bdos_cdrmaxa) ; HL=.cdrmax
LD A, E
SUB (HL)
INC HL
LD A, D
SBC A, (HL)
;Condition dcnt - cdrmax produces cy if cdrmax>dcnt
RET
; -------------------------------------------------------
; If not (cdrmax > dcnt) then cdrmax = dcnt+1
; -------------------------------------------------------
bdos_setcdr:
CALL bdos_compcdr
RET C
INC DE
LD (HL), D
DEC HL
LD (HL), E
RET
; -------------------------------------------------------
; HL = DE - HL
; -------------------------------------------------------
bdos_de_sub_hl:
LD A, E
SUB L
LD L, A
LD A, D
SBC A, H
LD H, A
RET
bdos_newchecksum:
LD C, TRUE
bdos_checksum:
LD HL, (TM_VARS.bdos_drec)
EX DE, HL
LD HL, (TM_VARS.BYTE_ram_ba66)
CALL bdos_de_sub_hl
RET NC
PUSH BC
CALL bdos_compute_cs
LD HL, (TM_VARS.BYTE_ram_ba57)
EX DE, HL
LD HL, (TM_VARS.bdos_drec)
ADD HL, DE
POP BC
INC C
JP Z, initial_cs
CP (HL)
RET Z
CALL bdos_compcdr
RET NC
CALL bdos_set_ro
RET
initial_cs:
LD (HL), A
RET
; -------------------------------------------------------
; Write the current directory entry, set checksum
; -------------------------------------------------------
bdos_wrdir:
CALL bdos_newchecksum
CALL bdos_setdir
LD C, 0x1
CALL bdos_wrbuff
JP bdos_setdata
; -------------------------------------------------------
; Read a directory entry into the directory buffer
; -------------------------------------------------------
bdos_rd_dir:
CALL bdos_setdir
CALL bdos_rdbuff
; -------------------------------------------------------
; Set data dma address
; -------------------------------------------------------
bdos_setdata:
LD HL, TM_VARS.bdos_dmaad
JP bdos_set_dma
; -------------------------------------------------------
; Set directory dma address
; -------------------------------------------------------
bdos_setdir:
LD HL, TM_VARS.bdos_buffa
; -------------------------------------------------------
; HL=.dma address to set (i.e., buffa or dmaad)
; -------------------------------------------------------
bdos_set_dma:
LD C, (HL)
INC HL
LD B, (HL)
JP BIOS.setdma_f
; -------------------------------------------------------
; Copy the directory entry to the user buffer
; after call to search or searchn by user code
; -------------------------------------------------------
bdos_dir_to_user:
LD HL, (TM_VARS.bdos_buffa)
EX DE, HL
LD HL, (TM_VARS.bdos_dmaad)
LD C,REC_SIZ
JP bdos_move
; -------------------------------------------------------
; return zero flag if at end of directory, non zero
; if not at end (end of dir if dcnt = 0ffffh)
; -------------------------------------------------------
bdos_end_of_dir:
LD HL, TM_VARS.bdos_dcnt
LD A, (HL)
INC HL
CP (HL)
RET NZ
INC A
RET
; -------------------------------------------------------
; Set dcnt to the end of the directory
; -------------------------------------------------------
bdos_set_end_dir:
LD HL, ENDDIR
LD (TM_VARS.bdos_dcnt), HL
RET
; -------------------------------------------------------
; Read next directory entry, with C=true if initializing
; -------------------------------------------------------
bdos_read_dir:
LD HL, (TM_VARS.bdos_dirmax)
EX DE, HL
LD HL, (TM_VARS.bdos_dcnt)
INC HL
LD (TM_VARS.bdos_dcnt), HL
CALL bdos_de_sub_hl
JP NC, bdrd_l0
JP bdos_set_end_dir
bdrd_l0:
LD A, (TM_VARS.bdos_dcnt)
AND DSK_MSK
LD B, FCB_SHF
bdrd_l1:
ADD A, A
DEC B
JP NZ, bdrd_l1
LD (TM_VARS.bdos_dptr), A
OR A
RET NZ
PUSH BC
CALL bdos_seekdir
CALL bdos_rd_dir
POP BC
JP bdos_checksum
; -------------------------------------------------------
; Given allocation vector position BC, return with byte
; containing BC shifted so that the least significant
; bit is in the low order accumulator 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
; -------------------------------------------------------
bdos_getallocbit:
LD A, C
AND 00000111b
INC A
LD E, A
LD D, A
LD A, C
RRCA
RRCA
RRCA
AND 00011111b
LD C, A
LD A, B
ADD A, A
ADD A, A
ADD A, A
ADD A, A
ADD A, A
OR C
LD C, A
LD A, B
RRCA
RRCA
RRCA
AND 00011111b
LD B, A
LD HL, (TM_VARS.bdos_alloca) ; Base address of allocation vector
ADD HL, BC
LD A, (HL)
ga_rotl:
RLCA
DEC E
JP NZ, ga_rotl
RET
; -------------------------------------------------------
; BC is the bit position of ALLOC to set or reset. The
; value of the bit is in register E.
; -------------------------------------------------------
bdos_setallocbit:
PUSH DE
CALL bdos_getallocbit
AND 11111110b
POP BC
OR C
; -------------------------------------------------------
; Byte value from ALLOC is in register A, with shift count
; in register C (to place bit back into position), and
; target ALLOC position in registers HL, rotate and replace
; -------------------------------------------------------
bdos_sab_rotr:
RRCA
DEC D
JP NZ, bdos_sab_rotr
LD (HL), A
RET
; -------------------------------------------------------
; 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)
; -------------------------------------------------------
bdos_scandm:
CALL bdos_getdptra
; HL addresses the beginning of the directory entry
LD DE, DSK_MAP
ADD HL, DE
PUSH BC
LD C, 0x11 ; fcblen-dskmap+1 - size of single b...
scandm_l0:
POP DE
DEC C
RET Z
PUSH DE
LD A, (TM_VARS.bdos_single)
OR A
JP Z, scandm_l1
PUSH BC
PUSH HL
LD C, (HL)
LD B, 0x00
JP scandm_l2
scandm_l1:
DEC C
PUSH BC
LD C, (HL)
INC HL
LD B, (HL)
PUSH HL
scandm_l2:
LD A, C
OR B
JP Z, scandm_l3
LD HL, (TM_VARS.bdos_maxall)
LD A,L
SUB C
LD A, H
SBC A, B
CALL NC, bdos_setallocbit
scandm_l3:
POP HL
INC HL
POP BC
JP scandm_l0
; -------------------------------------------------------
; Initialize the current disk
; lret = false, set to true if $ file exists
; compute the length of the allocation vector - 2
; -------------------------------------------------------
bdos_initialize:
LD HL, (TM_VARS.bdos_maxall)
LD C, 0x3
CALL bdos_hlrotr
INC HL
LD B, H
LD C,L
LD HL, (TM_VARS.bdos_alloca)
binitial_l0:
LD (HL), 0x00
INC HL
DEC BC
LD A, B
OR C
JP NZ, binitial_l0
LD HL, (TM_VARS.bdos_dirblk)
EX DE, HL
LD HL, (TM_VARS.bdos_alloca)
LD (HL), E
INC HL
LD (HL), D
CALL bdos_home
LD HL, (TM_VARS.bdos_cdrmaxa)
LD (HL), 0x3
INC HL
LD (HL), 0x00
CALL bdos_set_end_dir
binitial_l2:
LD C, TRUE
CALL bdos_read_dir
CALL bdos_end_of_dir
RET Z
CALL bdos_getdptra
LD A, EMPTY
CP (HL)
JP Z, binitial_l2
LD A, (TM_VARS.bdos_usercode)
CP (HL)
JP NZ, sbdos_pdollar
INC HL
LD A, (HL)
SUB '$'
JP NZ, sbdos_pdollar
; dollar file found, mark in lret
DEC A
LD (TM_VARS.bdos_aret), A
sbdos_pdollar:
LD C, 0x1
CALL bdos_scandm
CALL bdos_setcdr
JP binitial_l2
; -------------------------------------------------------
; copy directory location to lret following
; delete, rename, ...
; -------------------------------------------------------
bdos_copy_dirloc:
LD A, (TM_VARS.bdos_dirloc)
JP bdos_ret_a
; -------------------------------------------------------
; Compare extent# in A with that in C, return nonzero
; if they do not match
; -------------------------------------------------------
bdos_compex:
PUSH BC
PUSH AF
LD A, (TM_VARS.bdos_extmsk)
CPL
LD B, A
LD A, C
AND B
LD C, A
POP AF
AND B
SUB C
AND MAX_EXT
POP BC
RET
; -------------------------------------------------------
; Search for directory element of length C at info
; -------------------------------------------------------
bdos_search:
LD A, 0xff
LD (TM_VARS.bdos_dirloc), A
LD HL, TM_VARS.bdos_searchl
LD (HL), C
LD HL, (TM_VARS.bdos_info)
LD (TM_VARS.bdos_searcha), HL
CALL bdos_set_end_dir
CALL bdos_home
; -------------------------------------------------------
; search for the next directory element, assuming
; a previous call on search which sets searcha and
; searchl
; -------------------------------------------------------
bdos_searchn:
LD C, FALSE
CALL bdos_read_dir
CALL bdos_end_of_dir
JP Z, bdos_search_fin
LD HL, (TM_VARS.bdos_searcha)
EX DE, HL
LD A, (DE)
CP EMPTY
JP Z, search_next
PUSH DE
CALL bdos_compcdr
POP DE
JP NC, bdos_search_fin
search_next:
CALL bdos_getdptra
LD A, (TM_VARS.bdos_searchl)
LD C, A
LD B, 0x00
search_loop:
LD A, C
OR A
JP Z, search_end
LD A, (DE)
CP 0x3f
JP Z, search_ok
LD A, B
CP 0xd
JP Z, search_ok
CP 0xc
LD A, (DE)
JP Z, search_ext
SUB (HL)
AND 0x7f
JP NZ, bdos_searchn
JP search_ok
; A has fcb character attempt an extent # match
search_ext:
PUSH BC
LD C, (HL)
CALL bdos_compex
POP BC
JP NZ, bdos_searchn
; current character matches
search_ok:
INC DE
INC HL
INC B
DEC C
JP search_loop
; entiry name matches, return dir position
search_end:
LD A, (TM_VARS.bdos_dcnt)
AND 0x3
LD (TM_VARS.bdos_aret), A
LD HL, TM_VARS.bdos_dirloc
LD A, (HL)
RLA
RET NC
XOR A
LD (HL), A
RET
; end of directory, or empty name
bdos_search_fin:
CALL bdos_set_end_dir
LD A, 0xff
JP bdos_ret_a
; -------------------------------------------------------
; Delete the currently addressed file
; -------------------------------------------------------
bdos_delete:
CALL bdos_check_write
LD C, EXT_NUM
CALL bdos_search
bdelete_l0:
CALL bdos_end_of_dir
RET Z
CALL bdos_check_rodir
CALL bdos_getdptra
LD (HL), EMPTY
LD C, 0x00
CALL bdos_scandm
CALL bdos_wrdir
CALL bdos_searchn
JP bdelete_l0
; -------------------------------------------------------
; Given allocation vector position BC, find the zero bit
; closest to this position by searching left 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
; -------------------------------------------------------
bdos_get_block:
LD D, B
LD E, C
bgb_lefttst:
LD A, C
OR B
JP Z, bgb_righttst
DEC BC
PUSH DE
PUSH BC
CALL bdos_getallocbit
RRA
JP NC, bgb_retblock
POP BC
POP DE
bgb_righttst:
LD HL, (TM_VARS.bdos_maxall)
LD A, E
SUB L
LD A, D
SBC A, H
JP NC, bgb_retblock0
INC DE
PUSH BC
PUSH DE
LD B, D
LD C, E
CALL bdos_getallocbit
RRA
JP NC, bgb_retblock
POP DE
POP BC
JP bgb_lefttst
bgb_retblock:
RLA
INC A
CALL bdos_sab_rotr
POP HL
POP DE
RET
bgb_retblock0:
LD A, C
OR B
JP NZ, bgb_lefttst
LD HL, 0x00
RET
; -------------------------------------------------------
; Copy the entire file control block
; -------------------------------------------------------
bdos_copy_fcb:
LD C, 0x00
LD E, FCB_LEN
; -------------------------------------------------------
; copy fcb information starting at C for E bytes
; into the currently addressed directory entry
; -------------------------------------------------------
dbos_copy_dir:
PUSH DE
LD B, 0x00
LD HL, (TM_VARS.bdos_info)
ADD HL, BC
EX DE, HL
CALL bdos_getdptra
POP BC
CALL bdos_move
; -------------------------------------------------------
; Enter from close to seek and copy current element
; -------------------------------------------------------
bdos_seek_copy:
CALL bdos_seekdir
JP bdos_wrdir
; -------------------------------------------------------
; 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 conrol block. the file
; name and type are changed, but the reel number
; is ignored. the user number is identical
; -------------------------------------------------------
bdos_rename:
CALL bdos_check_write
LD C, EXT_NUM
CALL bdos_search
LD HL, (TM_VARS.bdos_info)
LD A, (HL)
LD DE, 0x10
ADD HL, DE
LD (HL), A
brn_l0:
CALL bdos_end_of_dir
RET Z
CALL bdos_check_rodir
LD C, DSK_MAP
LD E, EXT_NUM
CALL dbos_copy_dir
CALL bdos_searchn
JP brn_l0
; -------------------------------------------------------
; Set file indicators for current fcb
; -------------------------------------------------------
bdos_indicators:
LD C, EXT_NUM
CALL bdos_search
bdi_l0:
CALL bdos_end_of_dir
RET Z
LD C, 0x00
LD E, EXT_NUM
CALL dbos_copy_dir
CALL bdos_searchn
JP bdi_l0
; -------------------------------------------------------
; Search for the directory entry, copy to FCB
; -------------------------------------------------------
open:
LD C,NAM_LEN
CALL bdos_search
CALL bdos_end_of_dir
RET Z
bdos_open_copy:
CALL bdos_getexta
LD A, (HL)
PUSH AF
PUSH HL
CALL bdos_getdptra
EX DE, HL
LD HL, (TM_VARS.bdos_info)
LD C, 0x20
PUSH DE
CALL bdos_move
CALL setfwf
POP DE
LD HL, 0xc
ADD HL, DE
LD C, (HL)
LD HL, 0xf
ADD HL, DE
LD B, (HL)
POP HL
POP AF
LD (HL), A
LD A, C
CP (HL)
LD A, B
JP Z, bdos_open_rcnd
LD A, 0x00
JP C, bdos_open_rcnd
LD A, 0x80
bdos_open_rcnd:
LD HL, (TM_VARS.bdos_info) ; A has record count to fill
LD DE,REC_CNT
ADD HL, DE
LD (HL), A
RET
; -------------------------------------------------------
; HL = .fcb1(i), DE = .fcb2(i),
; if fcb1(i) = 0 then fcb1(i) := fcb2(i)
; -------------------------------------------------------
bdos_mergezero:
LD A, (HL)
INC HL
OR (HL)
DEC HL
RET NZ
LD A, (DE)
LD (HL), A
INC DE
INC HL
LD A, (DE)
LD (HL), A
DEC DE
DEC HL
RET
bdos_close:
XOR A
LD (TM_VARS.bdos_aret), A
LD (TM_VARS.bdos_dcnt), A
LD (TM_VARS.bdos_dcnt_hi), A
CALL bdos_nowrite
RET NZ
CALL bdos_getmodnum
AND FWF_MASK
RET NZ
LD C,NAM_LEN
CALL bdos_search
CALL bdos_end_of_dir
RET Z
LD BC, DSK_MAP
CALL bdos_getdptra
ADD HL, BC
EX DE, HL
LD HL, (TM_VARS.bdos_info)
ADD HL, BC
LD C, 0x10 ; (fcblen-dskmap) ;length of single ...
bdos_merge0:
LD A, (TM_VARS.bdos_single)
OR A
JP Z, bdos_merge
LD A, (HL)
OR A
LD A, (DE)
JP NZ, bdm_fcbnzero
LD (HL), A
bdm_fcbnzero:
OR A
JP NZ, bdm_buffnzero
LD A, (HL)
LD (DE), A
bdm_buffnzero:
CP (HL)
JP NZ, bdm_mergerr
JP bdm_dmset ; merged ok
bdos_merge:
CALL bdos_mergezero
EX DE, HL
CALL bdos_mergezero
EX DE, HL
LD A, (DE)
CP (HL)
JP NZ, bdm_mergerr
INC DE
INC HL
LD A, (DE)
CP (HL)
JP NZ, bdm_mergerr
DEC C
bdm_dmset:
INC DE
INC HL
DEC C
JP NZ, bdos_merge0
LD BC, 0xffec ; -(fcblen-extnum)
ADD HL, BC
EX DE, HL
ADD HL, BC
LD A, (DE)
CP (HL)
JP C, bdm_endmerge
LD (HL), A
LD BC, 0x3 ; (reccnt-extnum)
ADD HL, BC
EX DE, HL
ADD HL, BC
LD A, (HL)
LD (DE), A
bdm_endmerge:
LD A, 0xff
LD (TM_VARS.bdos_fcb_copied), A
JP bdos_seek_copy
bdm_mergerr:
LD HL, TM_VARS.bdos_aret
DEC (HL)
RET
; -------------------------------------------------------
; Create a new file by creating a directory entry
; then opening the file
; -------------------------------------------------------
bdos_make:
CALL bdos_check_write
LD HL, (TM_VARS.bdos_info)
PUSH HL
LD HL, TM_VARS.bdos_efcb
; Save FCB address, look for 0xE5
LD (TM_VARS.bdos_info), HL
LD C, 0x1
CALL bdos_search
CALL bdos_end_of_dir
POP HL
LD (TM_VARS.bdos_info), HL
RET Z
EX DE, HL
LD HL, NAM_LEN
ADD HL, DE
LD C, 0x11 ; fcblen-namlen
XOR A
bdm_set0:
LD (HL), A
INC HL
DEC C
JP NZ, bdm_set0
LD HL,U_BYTES
ADD HL, DE
LD (HL), A ; Current record within extent?
CALL bdos_setcdr
CALL bdos_copy_fcb
JP setfwf
; -------------------------------------------------------
; Close the current extent, and open the next one
; if possible. RMF is true if in read mod
; -------------------------------------------------------
bdos_open_reel:
XOR A
LD (TM_VARS.bdos_fcb_copied), A
CALL bdos_close
CALL bdos_end_of_dir
RET Z
LD HL, (TM_VARS.bdos_info)
LD BC, EXT_NUM
ADD HL, BC
LD A, (HL)
INC A
AND MAX_EXT
LD (HL), A
JP Z, bor_open_mod
LD B, A
LD A, (TM_VARS.bdos_extmsk)
AND B
LD HL, TM_VARS.bdos_fcb_copied
AND (HL)
JP Z, bor_open_reel0
JP bor_open_reel1
bor_open_mod:
LD BC, 0x2 ; (modnum-extnum)
ADD HL, BC
INC (HL)
LD A, (HL)
AND MAX_MOD
JP Z, bor_oper_r_err
bor_open_reel0:
LD C,NAM_LEN
CALL bdos_search
CALL bdos_end_of_dir
JP NZ, bor_open_reel1
LD A, (TM_VARS.bdos_rfm)
INC A
JP Z, bor_oper_r_err
CALL bdos_make
CALL bdos_end_of_dir
JP Z, bor_oper_r_err
JP bor_open_reel2
bor_open_reel1:
CALL bdos_open_copy
bor_open_reel2:
CALL bdos_getfcb
XOR A
JP bdos_ret_a
bor_oper_r_err:
CALL setlret1
JP setfwf
; -------------------------------------------------------
; Sequential disk read operation
; -------------------------------------------------------
bdos_seq_disk_read:
LD A, 0x1
LD (TM_VARS.bdos_seqio), A
; drop through to diskread
bdos_disk_read:
LD A, TRUE
LD (TM_VARS.bdos_rfm), A
CALL bdos_getfcb
LD A, (TM_VARS.bdos_vrecord)
LD HL, TM_VARS.bdos_rcount
CP (HL)
JP C, bdr_recordok
CP 128
JP NZ, bdr_diskeof
CALL bdos_open_reel
XOR A
LD (TM_VARS.bdos_vrecord), A
LD A, (TM_VARS.bdos_aret)
OR A
JP NZ, bdr_diskeof
bdr_recordok:
CALL bdos_index
CALL bdos_allocated
JP Z, bdr_diskeof
CALL bdos_atran
CALL bdos_seek
CALL bdos_rdbuff
JP bdos_setfcb
bdr_diskeof:
JP setlret1
; -------------------------------------------------------
; Sequential write disk
; -------------------------------------------------------
bdos_seq_disk_write:
LD A, 0x1
LD (TM_VARS.bdos_seqio), A
bdos_disk_write:
LD A, FALSE
LD (TM_VARS.bdos_rfm), A
CALL bdos_check_write
LD HL, (TM_VARS.bdos_info)
CALL bdos_check_rofile
CALL bdos_getfcb
LD A, (TM_VARS.bdos_vrecord)
CP 0x80 ; lstrec+1
JP NC,setlret1
CALL bdos_index
CALL bdos_allocated
LD C, 0x00
JP NZ, bdw_disk_wr1
CALL bdos_dm_position
LD (TM_VARS.bdos_dminx), A
LD BC, 0x00
OR A
JP Z, bdw_nopblock
LD C, A
DEC BC
CALL dbos_getdm
LD B, H
LD C,L
bdw_nopblock:
CALL bdos_get_block
LD A,L
OR H
JP NZ, bdw_block_ok
LD A, 0x2
JP bdos_ret_a
bdw_block_ok:
LD (TM_VARS.bdos_arecord), HL
EX DE, HL
LD HL, (TM_VARS.bdos_info)
LD BC, DSK_MAP
ADD HL, BC
LD A, (TM_VARS.bdos_single)
OR A
LD A, (TM_VARS.bdos_dminx)
JP Z, bdw_alloc_w
CALL bdos_hl_add_a
LD (HL), E
JP bdw_disk_wru
bdw_alloc_w:
LD C, A
LD B, 0x00
ADD HL, BC
ADD HL, BC
LD (HL), E
INC HL
LD (HL), D
; Disk write to previously unallocated block
bdw_disk_wru:
LD C, 0x2
bdw_disk_wr1:
LD A, (TM_VARS.bdos_aret)
OR A
RET NZ
PUSH BC
CALL bdos_atran
LD A, (TM_VARS.bdos_seqio)
DEC A
DEC A
JP NZ, bdw_disk_wr11
POP BC
PUSH BC
LD A, C
DEC A
DEC A
JP NZ, bdw_disk_wr11
PUSH HL
LD HL, (TM_VARS.bdos_buffa)
LD D, A
bdw_fill0:
LD (HL), A
INC HL
INC D
JP P, bdw_fill0
CALL bdos_setdir
LD HL, (TM_VARS.bdos_arecord1)
LD C, 0x2
bdw_fill1:
LD (TM_VARS.bdos_arecord), HL
PUSH BC
CALL bdos_seek
POP BC
CALL bdos_wrbuff
LD HL, (TM_VARS.bdos_arecord)
LD C, 0x00
LD A, (TM_VARS.bdos_blmsk)
LD B, A
AND L
CP B
INC HL
JP NZ, bdw_fill1
POP HL
LD (TM_VARS.bdos_arecord), HL
CALL bdos_setdata
bdw_disk_wr11:
CALL bdos_seek
POP BC
PUSH BC
CALL bdos_wrbuff
POP BC
LD A, (TM_VARS.bdos_vrecord)
LD HL, TM_VARS.bdos_rcount
CP (HL)
JP C, bdw_disk_wr2
LD (HL), A
INC (HL)
LD C, 0x2
bdw_disk_wr2:
DEC C
DEC C
JP NZ, bwd_no_update
PUSH AF
CALL bdos_getmodnum
AND 0x7f ; (not fwfmsk) and 0ffh
LD (HL), A
POP AF
bwd_no_update:
CP LST_REC
JP NZ, bdw_disk_wr3
LD A, (TM_VARS.bdos_seqio)
CP 0x1
JP NZ, bdw_disk_wr3
CALL bdos_setfcb
CALL bdos_open_reel
LD HL, TM_VARS.bdos_aret
LD A, (HL)
OR A
JP NZ, bdw_no_space
DEC A
LD (TM_VARS.bdos_vrecord), A
bdw_no_space:
LD (HL), 0x00
bdw_disk_wr3:
JP bdos_setfcb
; -------------------------------------------------------
; 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)
; -------------------------------------------------------
bdos_rseek:
XOR A
LD (TM_VARS.bdos_seqio), A
bdos_rseek1:
PUSH BC
LD HL, (TM_VARS.bdos_info)
EX DE, HL
LD HL,RAN_REC
ADD HL, DE
LD A, (HL)
AND 7Fh
PUSH AF
LD A, (HL)
RLA
INC HL
LD A, (HL)
RLA
AND 00011111b
LD C, A
LD A, (HL)
RRA
RRA
RRA
RRA
AND 0xf
LD B, A
POP AF
INC HL
LD L, (HL)
INC L
DEC L
LD L, 0x6
JP NZ, brs_seek_err
LD HL, NXT_REC
ADD HL, DE
LD (HL), A
LD HL, 0xc
ADD HL, DE
LD A, C
SUB (HL)
JP NZ, brs_close
LD HL,MOD_NUM
ADD HL, DE
LD A, B
SUB (HL)
AND 0x7f
JP Z, brs_seek_ok
brs_close:
PUSH BC
PUSH DE
CALL bdos_close
POP DE
POP BC
LD L, 0x3 ; Cannot close error #3
LD A, (TM_VARS.bdos_aret)
INC A
JP Z, brs_bad_seek
LD HL, EXT_NUM
ADD HL, DE
LD (HL), C
LD HL, MOD_NUM
ADD HL, DE
LD (HL), B
CALL open
LD A, (TM_VARS.bdos_aret)
INC A
JP NZ, brs_seek_ok
POP BC
PUSH BC
LD L, 0x4 ; Seek to unwritten extent #4
INC C
JP Z, brs_bad_seek
CALL bdos_make
LD L, 0x5 ; Cannot create new extent #5
LD A, (TM_VARS.bdos_aret)
INC A
JP Z, brs_bad_seek
brs_seek_ok:
POP BC
XOR A
JP bdos_ret_a
brs_bad_seek:
PUSH HL
CALL bdos_getmodnum
LD (HL), 11000000b
POP HL
brs_seek_err:
POP BC
LD A,L
LD (TM_VARS.bdos_aret), A
JP setfwf
; -------------------------------------------------------
; Random disk read operation
; -------------------------------------------------------
bdos_rand_disk_read:
LD C, TRUE
CALL bdos_rseek
CALL Z, bdos_disk_read
RET
; -------------------------------------------------------
; Random disk write operation
; -------------------------------------------------------
bdos_rand_disk_write:
LD C, FALSE
CALL bdos_rseek
CALL Z, bdos_disk_write
RET
; -------------------------------------------------------
; Compute random record position for
; getfilesize/setrandom
; -------------------------------------------------------
bdos_compute_rr:
EX DE, HL
ADD HL, DE
LD C, (HL)
LD B, 0x00
LD HL, EXT_NUM
ADD HL, DE
LD A, (HL)
RRCA
AND 0x80
ADD A, C
LD C, A
LD A, 0x00
ADC A, B
LD B, A
LD A, (HL)
RRCA
AND 0xf
ADD A, B
LD B, A
LD HL,MOD_NUM
ADD HL, DE
LD A, (HL)
ADD A, A
ADD A, A
ADD A, A
ADD A, A
PUSH AF
ADD A, B
LD B, A
PUSH AF
POP HL
LD A,L
POP HL
OR L
AND 0x1
RET
; -------------------------------------------------------
; Compute logical file size for current FCB
; -------------------------------------------------------
bdos_get_file_size:
LD C, EXT_NUM
CALL bdos_search
LD HL, (TM_VARS.bdos_info)
LD DE,RAN_REC
ADD HL, DE
PUSH HL
LD (HL), D
INC HL
LD (HL), D
INC HL
LD (HL), D
bgf_get_size:
CALL bdos_end_of_dir
JP Z, bgf_set_size
CALL bdos_getdptra
LD DE,REC_CNT
CALL bdos_compute_rr
POP HL
PUSH HL
LD E, A
LD A, C
SUB (HL)
INC HL
LD A, B
SBC A, (HL)
INC HL
LD A, E
SBC A, (HL)
JP C, bgf_get_nxt_size
LD (HL), E
DEC HL
LD (HL), B
DEC HL
LD (HL), C
bgf_get_nxt_size:
CALL bdos_searchn
JP bgf_get_size
bgf_set_size:
POP HL
RET
; -------------------------------------------------------
; Set the random record count bytes of the FCB to the number
; of the last record read/written by the sequential I/O calls.
; Inp: DE -> FCB
; -------------------------------------------------------
bdos_set_random:
LD HL, (TM_VARS.bdos_info)
LD DE,NXT_REC
CALL bdos_compute_rr
LD HL,RAN_REC
ADD HL, DE ; HL = .fcb(ranrec)
LD (HL), C
INC HL
LD (HL), B
INC HL
LD (HL), A
RET
; -------------------------------------------------------
; Select disk info for subsequent input or output ops
; -------------------------------------------------------
bdos_select:
LD HL, (TM_VARS.bdos_dlog)
LD A, (TM_VARS.bdos_curdsk)
LD C, A
CALL bdos_hlrotr
PUSH HL
EX DE, HL
CALL dbos_selectdisk
POP HL
CALL Z, bdos_sel_error
LD A,L
RRA
RET C
LD HL, (TM_VARS.bdos_dlog)
LD C,L
LD B, H
CALL bdos_set_cdisk
LD (TM_VARS.bdos_dlog), HL
JP bdos_initialize
; -------------------------------------------------------
; Select disc
; Inp: E=drive number 0 for A:, 1 for B: up to 15 for P
; Out: L=A=0 - ok or 0FFh - error
; -------------------------------------------------------
bdos_select_disk:
LD A, (TM_VARS.bdos_linfo)
LD HL, TM_VARS.bdos_curdsk
CP (HL)
RET Z
LD (HL), A
JP bdos_select
; -------------------------------------------------------
bdos_reselect:
LD A, TRUE
LD (TM_VARS.bdos_resel), A
LD HL, (TM_VARS.bdos_info)
LD A, (HL)
AND 00011111b
DEC A
LD (TM_VARS.bdos_linfo), A
CP 30
JP NC, brs_noselect
LD A, (TM_VARS.bdos_curdsk)
LD (TM_VARS.bdos_olddsk), A
LD A, (HL)
LD (TM_VARS.bdos_fcbdsk), A
AND 11100000b
LD (HL), A
CALL bdos_select_disk
brs_noselect:
LD A, (TM_VARS.bdos_usercode)
LD HL, (TM_VARS.bdos_info)
OR (HL)
LD (HL), A
RET
; -------------------------------------------------------
; Return version number
; -------------------------------------------------------
bdos_get_version:
LD A, DVERS ; 0x22 - v2.2
JP bdos_ret_a
; -------------------------------------------------------
; Reset disk system - initialize to disk 0
; -------------------------------------------------------
bdos_reset_disks:
LD HL, 0x00
LD (TM_VARS.bdos_rodsk), HL
LD (TM_VARS.bdos_dlog), HL
XOR A
LD (TM_VARS.bdos_curdsk), A
LD HL, EXT_RAM.std_dma_buff
LD (TM_VARS.bdos_dmaad), HL
CALL bdos_setdata
JP bdos_select
; -------------------------------------------------------
; Open file
; Inp: DE -> FCB
; Out: BA and HL - error.
; -------------------------------------------------------
bdos_open_file:
CALL bdos_clr_modnum
CALL bdos_reselect
JP open
; -------------------------------------------------------
; Close file
; Inp: DE -> FCB
; Out: BA and HL - error.
; -------------------------------------------------------
bdos_close_file:
CALL bdos_reselect
JP bdos_close
; -------------------------------------------------------
; Search for first occurrence of a file
; Inp: DE -> FCB
; Out: BA and HL - error.
; -------------------------------------------------------
bdos_search_first:
LD C, 0x00
EX DE, HL
LD A, (HL)
CP '?'
JP Z, bsf_qselect
CALL bdos_getexta
LD A, (HL)
CP '?'
CALL NZ, bdos_clr_modnum
CALL bdos_reselect
LD C, NAM_LEN
bsf_qselect:
CALL bdos_search
JP bdos_dir_to_user
; -------------------------------------------------------
; Search for next occurrence of a file name
; Inp: DE -> FCB
; Out: BA and HL - error.
; -------------------------------------------------------
bdos_search_next:
LD HL, (TM_VARS.bdos_searcha)
LD (TM_VARS.bdos_info), HL
CALL bdos_reselect
CALL bdos_searchn
JP bdos_dir_to_user
; -------------------------------------------------------
; Remove directory
; Inp: DE -> FCB
; Out: BA and HL - error.
; -------------------------------------------------------
bdos_rm_dir:
CALL bdos_reselect
CALL bdos_delete
JP bdos_copy_dirloc
; -------------------------------------------------------
; Read next 128b record
; Inp: DE -> FCB
; Out: BA and HL - error.
; A=0 - Ok,
; 1 - end of file,
; 9 - invalid FCB,
; 10 - media changed,
; 0FFh - hardware error.
; -------------------------------------------------------
bdos_read_file:
CALL bdos_reselect
JP bdos_seq_disk_read
; -------------------------------------------------------
; Write next 128b record
; Inp: DE -> FCB
; Out: BA and HL - error.
; A=0 - Ok,
; 1 - directory full,
; 2 - disc full,
; 9 - invalid FCB,
; 10 - media changed,
; 0FFh - hardware error.
; -------------------------------------------------------
bdos_write_file:
CALL bdos_reselect
JP bdos_seq_disk_write
; -------------------------------------------------------
; Create file
; Inp: DE -> FCB.
; Out: Error in BA and HL
; A=0 - Ok,
; 0FFh - directory is full.
; -------------------------------------------------------
bdos_make_file:
CALL bdos_clr_modnum
CALL bdos_reselect
JP bdos_make
; -------------------------------------------------------
; Rename file. New name, stored at FCB+16
; Inp: DE -> FCB.
; Out: Error in BA and HL
; A=0-3 if successful;
; A=0FFh if error.
; -------------------------------------------------------
bdos_ren_file:
CALL bdos_reselect
CALL bdos_rename
JP bdos_copy_dirloc
; -------------------------------------------------------
; Return bitmap of logged-in drives
; Out: bitmap in HL.
; -------------------------------------------------------
bdos_get_login_vec:
LD HL, (TM_VARS.bdos_dlog)
JP sthl_ret
; -------------------------------------------------------
; Return current drive
; Out: A - currently selected drive. 0 => A:, 1 => B: etc.
; -------------------------------------------------------
bdos_get_cur_drive:
LD A, (TM_VARS.bdos_curdsk)
JP bdos_ret_a
; -------------------------------------------------------
; Set DMA address
; Inp: DE - address of DMA buffer
; -------------------------------------------------------
bdos_set_dma_addr:
EX DE, HL
LD (TM_VARS.bdos_dmaad), HL
JP bdos_setdata
; -------------------------------------------------------
; Return the login vector address
; Out: HL - address
; -------------------------------------------------------
bdos_get_logvect:
LD HL, (TM_VARS.bdos_alloca)
JP sthl_ret
; -------------------------------------------------------
; Temporarily set current drive to be read-only
; -------------------------------------------------------
bdos_wr_protect:
LD HL, (TM_VARS.bdos_rodsk)
JP sthl_ret
; -------------------------------------------------------
; Set file indicators
; -------------------------------------------------------
bdos_set_ind:
CALL bdos_reselect
CALL bdos_indicators
JP bdos_copy_dirloc
; -------------------------------------------------------
; Return address of disk parameter block
; -------------------------------------------------------
bdos_get_dpb:
LD HL, (TM_VARS.bdos_dpbaddr)
sthl_ret:
LD (TM_VARS.bdos_aret), HL
RET
; -------------------------------------------------------
; Get/set user number
; Inp: E - number 0-15. If E=0FFh, returns number in A.
;
; -------------------------------------------------------
bdos_set_user:
LD A, (TM_VARS.bdos_linfo)
CP 0xff
JP NZ, bsu_set_user
LD A, (TM_VARS.bdos_usercode)
JP bdos_ret_a
bsu_set_user:
AND 0x1f
LD (TM_VARS.bdos_usercode), A
RET
; -------------------------------------------------------
; Random read. Record specified in the random record count area of the FCB, at the DMA address*
; Inp: DE -> FCB
; Out: Error codes in BA and HL.
; -------------------------------------------------------
bdos_rand_read:
CALL bdos_reselect
JP bdos_rand_disk_read
; -------------------------------------------------------
; Random access write record.
; Record specified in the random record count area of the FCB, at the DMA address
; Inp: DE -> FCB
; Out: Error codes in BA and HL.
; -------------------------------------------------------
bdos_rand_write:
CALL bdos_reselect
JP bdos_rand_disk_write
; -------------------------------------------------------
; Compute file size.
; Set the random record count bytes of the FCB to the
; number of 128-byte records in the file.
; -------------------------------------------------------
bdos_compute_fs:
CALL bdos_reselect
JP bdos_get_file_size
; -------------------------------------------------------
; Selectively reset disc drives
; Inp: DE - bitmap of drives to reset.
; Out: A=0 - Ok, 0FFh if error
; -------------------------------------------------------
bdos_reset_drives:
LD HL, (TM_VARS.bdos_info)
LD A,L
CPL
LD E, A
LD A, H
CPL
LD HL, (TM_VARS.bdos_dlog)
AND H
LD D, A
LD A,L
AND E
LD E, A
LD HL, (TM_VARS.bdos_rodsk)
EX DE, HL
LD (TM_VARS.bdos_dlog), HL
LD A,L
AND E
LD L, A
LD A, H
AND D
LD H, A
LD (TM_VARS.bdos_rodsk), HL
RET
; -------------------------------------------------------
; Arrive here at end of processing to return to user
; -------------------------------------------------------
bdos_goback:
LD A, (TM_VARS.bdos_resel)
OR A
JP Z, bdos_ret_mon
LD HL, (TM_VARS.bdos_info)
LD (HL), 0x00
LD A, (TM_VARS.bdos_fcbdsk)
OR A
JP Z, bdos_ret_mon
LD (HL), A
LD A, (TM_VARS.bdos_olddsk)
LD (TM_VARS.bdos_linfo), A
CALL bdos_select_disk
; -------------------------------------------------------
; Return from the disk monitor
; -------------------------------------------------------
bdos_ret_mon:
LD HL, (TM_VARS.bdos_entsp)
LD SP, HL
LD HL, (TM_VARS.bdos_aret)
LD A,L
LD B, H
RET
; -------------------------------------------------------
; Random disk write with zero fill of
; unallocated block
; -------------------------------------------------------
bdos_rand_write_z:
CALL bdos_reselect
LD A, 0x2
LD (TM_VARS.bdos_seqio), A
LD C, FALSE
CALL bdos_rseek1
CALL Z, bdos_disk_write
RET
; -------------------------------------------------------
; Initialized data ?
; -------------------------------------------------------
filler:
db 0xF1, 0xE1
; -------------------------------------------------------
; Filler to align blocks in ROM
; -------------------------------------------------------
LAST EQU $
CODE_SIZE EQU LAST-0xC800
FILL_SIZE EQU 0xE00-CODE_SIZE
DISPLAY "| BDOS\t| ",/H,bdos_start," | ",/H,CODE_SIZE," | ",/H,FILL_SIZE," |"
FILLER
DS FILL_SIZE, 0xFF
ENDMODULE
IFNDEF BUILD_ROM
OUTEND
ENDIF