;
.include "atari.inc"
- .importzp tmp2,ptr4,sp
- .import subysp,addysp
- .export fdtoiocb
+ .include "fd.inc"
+ .importzp tmp1,tmp2,tmp3,ptr4,sp
+ .import fd_table,fd_index
+ .import fdt_to_fdi
+ .export clriocb
.export fdtoiocb_down
- .export fd_table
+ .export findfreeiocb
.export fddecusage
.export newfd
- .data
-
-fd_table:
- .byte 0,$ff,0,0
- .byte 0,$ff,0,0
- .byte 0,$ff,0,0
- .byte 0,$ff,0,0
- .byte 0,$ff,0,0
- .byte 0,$ff,0,0
- .byte 0,$ff,0,0
- .byte 0,$ff,0,0
- .byte 0,$ff,0,0
- .byte 0,$ff,0,0
- .byte 0,$ff,0,0
- .byte 0,$ff,0,0
-
-MAX_FD_VAL = (* - fd_table) / 4
-
-ft_usa = 0 ; usage counter
-ft_iocb = 1 ; iocb index (0,$10,$20,etc.), $ff for empty entry
-ft_dev = 2 ; device of open iocb
-ft_flag = 3 ; flags
- ; lower 3 bits: device number (for R: and D:)
-
.code
; gets fd in ax, decrements usage counter
cpx #0
bne inval
- cmp #MAX_FD_VAL
+ cmp #MAX_FD_INDEX
bcs inval
+ tax
+ lda fd_index,x ; get index
+ tay
+ lda #$ff
+ sta fd_index,x ; clear entry
+ tya
asl a ; create index into fd table
asl a
tax
cmp fd_table+ft_iocb,x ; entry in use?
beq inval ; no, return error
lda fd_table+ft_usa,x ; get usage counter
- beq ok_notlast ; 0?
+ beq ok_notlast ; 0? (shouldn't happen)
sec
sbc #1 ; decr usage counter
sta fd_table+ft_usa,x
tax
plp
bne cont
- php
lda #$ff
sta fd_table+ft_iocb,y ; clear table entry
- plp
+ lda fd_table+ft_flag,y
+ and #16 ; opened by app?
+ eor #16 ; return set Z if yes
cont: rts
ok_notlast:
lda #1 ; clears Z
jmp retiocb
-.endproc
+.endproc ; fdtoiocb_down
inval: ldx #$ff ; sets N
rts
-; gets fd in ax
-; return iocb index in X
-; return N bit set for invalid fd
+; clear iocb except for ICHID field
+; expects X to be index to IOCB (0,$10,$20,etc.)
; all registers destroyed
-.proc fdtoiocb
- cpx #0
- bne inval
- cmp #MAX_FD_VAL
- bcs inval
- asl a ; create index into fd table
- asl a
- tax
- lda #$ff
- cmp fd_table+ft_iocb,x ; entry in use?
- beq inval ; no, return error
- lda fd_table+ft_usa,x ; get usage counter
- beq inval ; 0? should not happen
- lda fd_table+ft_iocb,x ; get iocb
+.proc clriocb
+
+ inx ; don't clear ICHID
+ ldy #15
+ lda #0
+loop: sta ICHID,x
+ inx
+ dey
+ bne loop
rts
.endproc
+
+; find a free iocb
+; no entry parameters
+; return ZF = 0/1 for not found/found
+; index in X if found
+; all registers destroyed
+
+.proc findfreeiocb
+
+ ldx #0
+ ldy #$FF
+loop: tya
+ cmp ICHID,x
+ beq found
+ txa
+ clc
+ adc #$10
+ tax
+ cmp #$80
+ bcc loop
+ inx ; return ZF cleared
+found: rts
+
+.endproc ; findfreeiocb
+
+
; decrements usage counter for fd
; if 0 reached, it's marked as unused
; get fd index in tmp2
.proc fddecusage
lda tmp2 ; get fd
- cmp #MAX_FD_VAL
+ cmp #MAX_FD_INDEX
bcs ret ; invalid index, do nothing
+ tax
+ lda fd_index,x
+ pha
+ lda #$ff
+ sta fd_index,x
+ pla
asl a ; create index into fd table
asl a
tax
sta fd_table+ft_usa,x
bne ret ; not 0
lda #$ff ; 0, table entry unused now
- sta fd_table+ft_iocb,y ; clear table entry
+ sta fd_table+ft_iocb,x ; clear table entry
ret: rts
-.endproc
+.endproc ; fddecusage
+
; newfd
;
; called from open() function
; finds a fd to use for an open request
-; checks whether it's a device or file (file: characters following the ':')
+; checks whether it's a device or file (file: characters follow the ':')
; files always get an exclusive slot
; for devices it is checked whether the device is already open, and if yes,
; a link to this open device is returned
;
-; Calling paramteter:
+; Calling parameters:
+; tmp3 - length of filename + 1
; AX - points to filename
; Y - iocb to use (if we need a new open)
; Return parameters:
-; tmp2 - fd num
+; tmp2 - fd num ($ff and C=0 in case of error - no free slot)
; C - 0/1 for no open needed/open should be performed
; all registers preserved!
+ .bss
+
; local variables:
-; AX - 0 (A-0,X-1)
-; Y - 2
-; ptr4 - 3,4 (backup)
-; devnum - 5
-
-loc_A = 0
-loc_X = 1
-loc_Y = 2
-loc_ptr4_l = 3
-loc_ptr4_h = 4
-loc_devnum = 5
-loc_size = 6
+loc_Y: .res 1
+loc_ptr4_l: .res 1
+loc_ptr4_h: .res 1
+loc_tmp1: .res 1
+loc_devnum: .res 1
+loc_size: .res 1
+
+ .code
.proc newfd
tya
pha
- ldy #loc_size
- jsr subysp
- ldy #loc_devnum
- lda #0
- sta (sp),y ; loc_devnum
- dey
+ ldx #0
+ stx loc_devnum
+ lda tmp1
+ sta loc_tmp1
+ stx tmp1 ; init tmp1
+ stx tmp2 ; init tmp2
lda ptr4+1
- sta (sp),y ; loc_ptr4_h
- dey
+ sta loc_ptr4_h
lda ptr4
- sta (sp),y ; loc_ptr4_l
- dey
+ sta loc_ptr4_l
pla
- sta (sp),y ; loc_Y
- dey
+ sta loc_Y
pla
- sta (sp),y ; loc_X
sta ptr4+1
- dey
pla
- sta (sp),y ; loc_A
sta ptr4
; ptr4 points to filename
beq colon2
; no colon there!? OK, then we use a fresh iocb....
+ ; return error here? no, the subsequent open call should fail
-do_open:nop ; @@@TODO
- ldy #loc_size
- jsr addysp
- rts
+do_open_nd: ; do open and don't remember device
+ lda #2
+ sta tmp1
+do_open:lda tmp1
+ ora #1
+ sta tmp1 ; set flag to return 'open needed' : C = 1
+ ldx #ft_iocb
+ ldy #$ff
+srchfree:
+ tya
+ cmp fd_table,x ; check ft_iocb field for $ff
+ beq freefnd ; found a free slot
+ txa
+ clc
+ adc #ft_entrylen
+ tax
+ cmp #(MAX_FD_VAL*4)+ft_iocb ; end of table reached?
+ bcc srchfree
+; error: no free slot found
+noslot: ldx #0
+ stx tmp1 ; return with C = 0
+ dex
+ stx tmp2 ; iocb: $ff marks error
+ jmp finish
+
+; found a free slot
+freefnd:txa
+ sec
+ sbc #ft_iocb ; normalize
+ tax
+ lsr a
+ lsr a
+ sta tmp2 ; return fd
+ lda #2
+ bit tmp1 ; remember device?
+ beq l1 ; yes
+ lda #0 ; no, put 0 in field
+ beq l2
+
+l1: ldy #0
+ lda (sp),y ; get device
+l2: sta fd_table+ft_dev,x ; set device
+ lda #1
+ sta fd_table+ft_usa,x ; set usage counter
+ lda loc_Y
+ sta fd_table+ft_iocb,x ; set iocb index
+ lda loc_devnum
+ and #7 ; device number is 3 bits
+ ora #16 ; indicated a fd actively opened by the app
+ sta fd_table+ft_flag,x
+ lda tmp2
+ jsr fdt_to_fdi ; get new index
+noslot1:bcs noslot ; no one available (noslot1: helper label for branch out of range)
+ ;cmp #$ff ; no one available
+ ;beq noslot ;@@@ cleanup needed
+ sta tmp2 ; return index
+ jmp finish
+
+; string in "Xn:xxx" format
colon2: dey
- tya
- pha
lda (ptr4),y ; get device number
sec
sbc #'0'
- ldy #loc_devnum
- sta (sp),y ; save it
+ and #7
+ sta loc_devnum
+ sta tmp2 ; save it for speed later here also
+ lda #4 ; max. length if only device + number ("Xn:")
+ cmp tmp3
+ bcc do_open_nd ; string is longer -> contains filename
+ bcs check_dev ; handle device only string
+
+; string in "X:xxx" format
+colon1: lda #3 ; max. length if device only ("X:")
+ cmp tmp3
+ bcc do_open_nd ; string is longer -> contains filename
+
+; get device and search it in fd table
+check_dev:
+ ldy #0
+ lda (ptr4),y ; get device id
+ tay
+ ldx #(MAX_FD_VAL*4) - ft_entrylen
+srchdev:lda #$ff
+ cmp fd_table+ft_iocb,x ; is entry valid?
+ beq srch2 ; no, skip this entry
+ tya
+ cmp fd_table+ft_dev,x
+ beq fnddev
+srch2: txa
+ sec
+ sbc #ft_entrylen+1
+ tax
+ bpl srchdev
+
+; not found, open new iocb
+ jmp do_open
+
+; found device in table, check device number (e.g R0 - R3)
+fnddev: lda fd_table+ft_flag,x
+ and #7
+ cmp tmp2 ; contains devnum
+ bne srch2 ; different device numbers
+
+; found existing open iocb with same device
+ txa
+ lsr a
+ lsr a
+ sta tmp2
+ inc fd_table+ft_usa,x ; increment usage counter
+ jsr fdt_to_fdi ; get new index
+ bcs noslot1 ; no one available
+ sta tmp2 ; return index
+
+; clean up and go home
+finish: lda ptr4
+ pha
+ lda ptr4+1
+ pha
+ lda loc_Y
+ pha
+ lda tmp1
+ pha
+ lda loc_tmp1
+ sta tmp1
+ pla
+ lsr a ; set C as needed
+
pla
tay
-colon1:
+ pla
+ tax
+ pla
+ rts
-.endproc
+.endproc ; newfd