]> git.sur5r.net Git - cc65/blob - libsrc/atari/fdtable.s
lseek: Implement additional feedback from PR #723.
[cc65] / libsrc / atari / fdtable.s
1 ;
2 ; Christian Groessler, May-2000
3 ;
4 ; fd indirection table & helper functions
5 ;
6
7         .include "atari.inc"
8         .include "fd.inc"
9         .importzp tmp1,tmp2,tmp3,ptr4,sp
10         .import fd_table,fd_index
11         .import fdt_to_fdi
12         .export clriocb
13         .export fdtoiocb_down
14         .export fddecusage
15         .export newfd
16
17         .code
18
19 ; gets fd in ax, decrements usage counter
20 ; return iocb index in X
21 ; return N bit set for invalid fd
22 ; return Z bit set if last user
23 ; all registers destroyed
24 .proc   fdtoiocb_down
25
26         cpx     #0
27         bne     inval
28         cmp     #MAX_FD_INDEX
29         bcs     inval
30         tax
31         lda     fd_index,x              ; get index
32         tay
33         lda     #$ff
34         sta     fd_index,x              ; clear entry
35         tya
36         asl     a                       ; create index into fd table
37         asl     a
38         tax
39         lda     #$ff
40         cmp     fd_table+ft_iocb,x      ; entry in use?
41         beq     inval                   ; no, return error
42         lda     fd_table+ft_usa,x       ; get usage counter
43         beq     ok_notlast              ; 0? (shouldn't happen)
44         sec
45         sbc     #1                      ; decr usage counter
46         sta     fd_table+ft_usa,x
47 retiocb:php
48         txa
49         tay
50         lda     fd_table+ft_iocb,x      ; get iocb
51         tax
52         plp
53         bne     cont
54         lda     #$ff
55         sta     fd_table+ft_iocb,y      ; clear table entry
56         lda     fd_table+ft_flag,y
57         and     #16                     ; opened by app?
58         eor     #16                     ; return set Z if yes
59 cont:   rts
60
61 ok_notlast:
62         lda     #1                      ; clears Z
63         jmp     retiocb
64
65 .endproc        ; fdtoiocb_down
66
67 inval:  ldx     #$ff                    ; sets N
68         rts
69
70
71 ; clear iocb except for ICHID field
72 ; expects X to be index to IOCB (0,$10,$20,etc.)
73 ; all registers destroyed
74
75 .proc   clriocb
76
77         inx                     ; don't clear ICHID
78         ldy     #15
79         lda     #0
80 loop:   sta     ICHID,x
81         inx
82         dey
83         bne     loop
84         rts
85
86 .endproc
87
88
89 ; decrements usage counter for fd
90 ; if 0 reached, it's marked as unused
91 ; get fd index in tmp2
92 ; Y register preserved
93 .proc   fddecusage
94
95         lda     tmp2                    ; get fd
96         cmp     #MAX_FD_INDEX
97         bcs     ret                     ; invalid index, do nothing
98         tax
99         lda     fd_index,x
100         pha
101         lda     #$ff
102         sta     fd_index,x
103         pla
104         asl     a                       ; create index into fd table
105         asl     a
106         tax
107         lda     #$ff
108         cmp     fd_table+ft_iocb,x      ; entry in use?
109         beq     ret                     ; no, do nothing
110         lda     fd_table+ft_usa,x       ; get usage counter
111         beq     ret                     ; 0? should not happen
112         sec
113         sbc     #1                      ; decrement by one
114         sta     fd_table+ft_usa,x
115         bne     ret                     ; not 0
116         lda     #$ff                    ; 0, table entry unused now
117         sta     fd_table+ft_iocb,x      ; clear table entry
118 ret:    rts
119
120 .endproc        ; fddecusage
121
122
123 ; newfd
124 ;
125 ; called from open() function
126 ; finds a fd to use for an open request
127 ; checks whether it's a device or file (file: characters follow the ':')
128 ; files always get an exclusive slot
129 ; for devices it is checked whether the device is already open, and if yes,
130 ; a link to this open device is returned
131 ;
132 ; Calling parameters:
133 ;       tmp3 - length of filename + 1
134 ;       AX   - points to filename
135 ;       Y    - iocb to use (if we need a new open)
136 ; Return parameters:
137 ;       tmp2 - fd num ($ff and C=0 in case of error - no free slot)
138 ;       C    - 0/1 for no open needed/open should be performed
139 ; all registers preserved!
140
141         .bss
142
143 ; local variables:
144 loc_Y:          .res    1
145 loc_ptr4_l:     .res    1
146 loc_ptr4_h:     .res    1
147 loc_tmp1:       .res    1
148 loc_devnum:     .res    1
149 loc_size:       .res    1
150
151         .code
152
153 .proc   newfd
154
155         pha
156         txa
157         pha
158         tya
159         pha
160
161         ldx     #0
162         stx     loc_devnum
163         lda     tmp1
164         sta     loc_tmp1
165         stx     tmp1            ; init tmp1
166         stx     tmp2            ; init tmp2
167         lda     ptr4+1
168         sta     loc_ptr4_h
169         lda     ptr4
170         sta     loc_ptr4_l
171         pla
172         sta     loc_Y
173         pla
174         sta     ptr4+1
175         pla
176         sta     ptr4
177
178         ; ptr4 points to filename
179
180         ldy     #1
181         lda     #':'
182         cmp     (ptr4),y        ; "X:"
183         beq     colon1
184         iny
185         cmp     (ptr4),y        ; "Xn:"
186         beq     colon2
187
188         ; no colon there!? OK, then we use a fresh iocb....
189         ; return error here? no, the subsequent open call should fail
190
191 do_open_nd:     ; do open and don't remember device
192         lda     #2
193         sta     tmp1
194 do_open:lda     tmp1
195         ora     #1
196         sta     tmp1            ; set flag to return 'open needed' : C = 1
197         ldx     #ft_iocb
198         ldy     #$ff
199 srchfree:
200         tya
201         cmp     fd_table,x      ; check ft_iocb field for $ff
202         beq     freefnd         ; found a free slot
203         txa
204         clc
205         adc     #ft_entrylen
206         tax
207         cmp     #(MAX_FD_VAL*4)+ft_iocb ; end of table reached?
208         bcc     srchfree
209
210 ; error: no free slot found
211 noslot: ldx     #0
212         stx     tmp1            ; return with C = 0
213         dex
214         stx     tmp2            ; iocb: $ff marks error
215         jmp     finish
216
217 ; found a free slot
218 freefnd:txa
219         sec
220         sbc     #ft_iocb        ; normalize
221         tax
222         lsr     a
223         lsr     a
224         sta     tmp2            ; return fd
225         lda     #2
226         bit     tmp1            ; remember device?
227         beq     l1              ; yes
228         lda     #0              ; no, put 0 in field
229         beq     l2
230
231 l1:     ldy     #0
232         lda     (sp),y                  ; get device
233 l2:     sta     fd_table+ft_dev,x       ; set device
234         lda     #1
235         sta     fd_table+ft_usa,x       ; set usage counter
236         lda     loc_Y
237         sta     fd_table+ft_iocb,x      ; set iocb index
238         lda     loc_devnum
239         and     #7                      ; device number is 3 bits
240         ora     #16                     ; indicated a fd actively opened by the app
241         sta     fd_table+ft_flag,x
242         lda     tmp2
243         jsr     fdt_to_fdi              ; get new index
244 noslot1:bcs     noslot                  ; no one available (noslot1: helper label for branch out of range)
245         ;cmp    #$ff                    ; no one available
246         ;beq    noslot  ;@@@ cleanup needed
247         sta     tmp2                    ; return index
248         jmp     finish
249
250 ; string in "Xn:xxx" format
251 colon2: dey
252         lda     (ptr4),y        ; get device number
253         sec
254         sbc     #'0'
255         and     #7
256         sta     loc_devnum
257         sta     tmp2            ; save it for speed later here also
258         lda     #4              ; max. length if only  device + number ("Xn:")
259         cmp     tmp3
260         bcc     do_open_nd      ; string is longer -> contains filename
261         bcs     check_dev       ; handle device only string
262
263 ; string in "X:xxx" format
264 colon1: lda     #3              ; max. length if device only ("X:")
265         cmp     tmp3
266         bcc     do_open_nd      ; string is longer -> contains filename
267
268 ; get device and search it in fd table
269 check_dev:
270         ldy     #0
271         lda     (ptr4),y        ; get device id
272         tay
273         ldx     #(MAX_FD_VAL*4) - ft_entrylen
274 srchdev:lda     #$ff
275         cmp     fd_table+ft_iocb,x      ; is entry valid?
276         beq     srch2                   ; no, skip this entry
277         tya
278         cmp     fd_table+ft_dev,x
279         beq     fnddev
280 srch2:  txa
281         sec
282         sbc     #ft_entrylen+1
283         tax
284         bpl     srchdev
285
286 ; not found, open new iocb
287         jmp     do_open
288
289 ; found device in table, check device number (e.g R0 - R3)
290 fnddev: lda     fd_table+ft_flag,x
291         and     #7
292         cmp     tmp2                    ; contains devnum
293         bne     srch2                   ; different device numbers
294
295 ; found existing open iocb with same device
296         txa
297         lsr     a
298         lsr     a
299         sta     tmp2
300         inc     fd_table+ft_usa,x       ; increment usage counter
301         jsr     fdt_to_fdi              ; get new index
302         bcs     noslot1                 ; no one available
303         sta     tmp2                    ; return index
304
305 ; clean up and go home
306 finish: lda     ptr4
307         pha
308         lda     ptr4+1
309         pha
310         lda     loc_Y
311         pha
312         lda     tmp1
313         pha
314         lda     loc_tmp1
315         sta     tmp1
316         pla
317         lsr     a                       ; set C as needed
318
319         pla
320         tay
321         pla
322         tax
323         pla
324         rts
325
326 .endproc        ; newfd
327