]> git.sur5r.net Git - cc65/blobdiff - libsrc/atari/fdtable.s
The spans do now contain the size of a span, no longer the end offset.
[cc65] / libsrc / atari / fdtable.s
index 547681e12384976786a495f1bd79ef65e5086015..111f340d0e064e6011ef4f21ee92fae92345eea0 100644 (file)
@@ -5,32 +5,15 @@
 ;
 
        .include "atari.inc"
-       .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
-
-       .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
+       .export findfreeiocb
+       .export fddecusage
+       .export newfd
 
        .code
 
@@ -43,8 +26,14 @@ ft_flag = 3  ; flags
 
        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
@@ -52,7 +41,7 @@ ft_flag = 3   ; flags
        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
@@ -63,41 +52,302 @@ retiocb:php
        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
+.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
+; Y register preserved
+.proc  fddecusage
+
+       lda     tmp2                    ; get fd
+       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
        lda     #$ff
        cmp     fd_table+ft_iocb,x      ; entry in use?
-       beq     inval                   ; no, return error
+       beq     ret                     ; no, do nothing
        lda     fd_table+ft_usa,x       ; get usage counter
-       beq     inval                   ; 0? should not happen
-       lda     fd_table+ft_iocb,x      ; get iocb
+       beq     ret                     ; 0? should not happen
+       sec
+       sbc     #1                      ; decrement by one
+       sta     fd_table+ft_usa,x
+       bne     ret                     ; not 0
+       lda     #$ff                    ; 0, table entry unused now
+       sta     fd_table+ft_iocb,x      ; clear table entry
+ret:   rts
+
+.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 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 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 ($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:
+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
+
+       pha
+       txa
+       pha
+       tya
+       pha
+
+       ldx     #0
+       stx     loc_devnum
+       lda     tmp1
+       sta     loc_tmp1
+       stx     tmp1            ; init tmp1
+       stx     tmp2            ; init tmp2
+       lda     ptr4+1
+       sta     loc_ptr4_h
+       lda     ptr4
+       sta     loc_ptr4_l
+       pla
+       sta     loc_Y
+       pla
+       sta     ptr4+1
+       pla
+       sta     ptr4
+
+       ; ptr4 points to filename
+
+       ldy     #1
+       lda     #':'
+       cmp     (ptr4),y        ; "X:"
+       beq     colon1
+       iny
+       cmp     (ptr4),y        ; "Xn:"
+       beq     colon2
+
+       ; no colon there!? OK, then we use a fresh iocb....
+       ; return error here? no, the subsequent open call should fail
+
+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
+       lda     (ptr4),y        ; get device number
+       sec
+       sbc     #'0'
+       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
+       pla
+       tax
+       pla
        rts
 
-.endproc
+.endproc       ; newfd
+