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