;
.include "atari.inc"
- .importzp tmp2,ptr4,sp
+ .importzp tmp1,tmp2,tmp3,ptr4,sp
.import subysp,addysp
.export fdtoiocb
.export fdtoiocb_down
.export fd_table
.export fddecusage
.export newfd
+ .export getfd
+
+ .export _fd_table,_fd_index
.data
+MAX_FD_INDEX = 12
+_fd_index:
+fd_index: ; fd number is index into this table, entry's value specifies the fd_table entry
+ .res MAX_FD_INDEX,$ff
-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
+_fd_table:
+fd_table: ; each entry represents an open iocb
+ .byte 0,0,'E',0 ; system console, app starts with opened iocb #0 for E:
.byte 0,$ff,0,0
.byte 0,$ff,0,0
.byte 0,$ff,0,0
MAX_FD_VAL = (* - fd_table) / 4
+ft_entrylen = 4 ; length of table entry (it's not sufficient to change here!
+ ; the code sometimes does two bit shifts to multiply/divide by
+ ; this length)
+
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_dev = 2 ; device of open iocb (0 - device not remembered, eg. filename specified)
ft_flag = 3 ; flags
; lower 3 bits: device number (for R: and D:)
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
cpx #0
bne inval
- cmp #MAX_FD_VAL
+ cmp #MAX_FD_INDEX
bcs inval
+ tax
+ lda fd_index,x
asl a ; create index into fd table
asl a
tax
.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
;
; 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!
; 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_A = 0
+;loc_X = 1
+loc_Y = 0
+loc_ptr4_l = 1
+loc_ptr4_h = 2
+loc_tmp1 = 3
+loc_devnum = 4
+loc_size = 5
.proc newfd
lda #0
sta (sp),y ; loc_devnum
dey
+ lda tmp1
+ sta (sp),y ; loc_tmp1
+ lda #0
+ sta tmp1 ; init tmp1
+ sta tmp2 ; init tmp2
+ dey
lda ptr4+1
sta (sp),y ; loc_ptr4_h
dey
dey
pla
sta (sp),y ; loc_Y
- dey
+; dey
pla
- sta (sp),y ; loc_X
+; sta (sp),y ; loc_X
sta ptr4+1
- dey
+; dey
pla
- sta (sp),y ; loc_A
+; 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
+ 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
+ ldy #loc_Y
+ lda (sp),y
+ sta fd_table+ft_iocb,x ; set iocb index
+ ldy #loc_devnum
+ lda (sp),y ; get (optional) device number
+ and #7 ; only 3 bits
+ sta fd_table+ft_flag,x
+ lda tmp2
+ jsr fdt_to_fdi ; get new index
+ bcs noslot ; no one available
+ ;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'
+ and #7
ldy #loc_devnum
sta (sp),y ; save it
+ 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
+
+; helper for branch out of range
+noslot1:jmp noslot
+
+; 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
+ ldy #loc_Y
+ lda (sp),y
+ pha
+ lda tmp1
+ pha
+ ldy #loc_tmp1
+ lda (sp),y
+ sta tmp1
+ ldy #loc_size
+ jsr addysp
+ pla
+ lsr a ; set C as needed
+
pla
tay
-colon1:
+ pla
+ tax
+ pla
+ rts
.endproc
+; ftp_to_fdi
+; returns a fd_index entry pointing to the given ft_table entry
+; get fd_table entry in A
+; return C = 0/1 for OK/error
+; return fd_index entry in A if OK
+; registers destroyed
+.proc fdt_to_fdi
+
+ tay
+ lda #$ff
+ tax
+ inx
+loop: cmp fd_index,x
+ beq found
+ inx
+ cpx #MAX_FD_INDEX
+ bcc loop
+ rts
+
+found: tya
+ sta fd_index,x
+ txa
+ clc
+ rts
+
+.endproc
+
+; getfd
+; get a new fd pointing to a ft_table entry
+; usage counter of ft_table entry incremented
+; A - fd_table entry
+; return C = 0/1 for OK/error
+; returns fd in A if OK
+; registers destroyed, tmp1 destroyed
+.proc getfd
+
+ sta tmp1 ; save fd_table entry
+ jsr fdt_to_fdi
+ bcs error
+
+ pha
+ lda tmp1
+ asl a
+ asl a ; also clears C
+ tax
+ inc fd_table+ft_usa,x ; increment usage counter
+ pla
+error: rts
+
+.endproc