]> git.sur5r.net Git - cc65/blob - libsrc/atari/fdtable.s
ecc7c451fa307d0b247eec43262750860dd803be
[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         .bss
192
193 ; local variables:
194 loc_Y:          .res    1
195 loc_ptr4_l:     .res    1
196 loc_ptr4_h:     .res    1
197 loc_tmp1:       .res    1
198 loc_devnum:     .res    1
199 loc_size:       .res    1
200
201         .code
202
203 .proc   newfd
204
205         pha
206         txa
207         pha
208         tya
209         pha
210
211         ldx     #0
212         stx     loc_devnum
213         lda     tmp1
214         sta     loc_tmp1
215         stx     tmp1            ; init tmp1
216         stx     tmp2            ; init tmp2
217         lda     ptr4+1
218         sta     loc_ptr4_h
219         lda     ptr4
220         sta     loc_ptr4_l
221         pla
222         sta     loc_Y
223         pla
224         sta     ptr4+1
225         pla
226         sta     ptr4
227
228         ; ptr4 points to filename
229
230         ldy     #1
231         lda     #':'
232         cmp     (ptr4),y        ; "X:"
233         beq     colon1
234         iny
235         cmp     (ptr4),y        ; "Xn:"
236         beq     colon2
237
238         ; no colon there!? OK, then we use a fresh iocb....
239         ; return error here? no, the subsequent open call should fail
240
241 do_open_nd:     ; do open and don't remember device
242         lda     #2
243         sta     tmp1
244 do_open:lda     tmp1
245         ora     #1
246         sta     tmp1            ; set flag to return 'open needed' : C = 1
247         ldx     #ft_iocb
248         ldy     #$ff
249 srchfree:
250         tya
251         cmp     fd_table,x      ; check ft_iocb field for $ff
252         beq     freefnd         ; found a free slot
253         txa
254         clc
255         adc     #ft_entrylen
256         tax
257         cmp     #(MAX_FD_VAL*4)+ft_iocb ; end of table reached?
258         bcc     srchfree
259
260 ; error: no free slot found
261 noslot: ldx     #0
262         stx     tmp1            ; return with C = 0
263         dex
264         stx     tmp2            ; iocb: $ff marks error
265         jmp     finish
266
267 ; found a free slot
268 freefnd:txa
269         sec
270         sbc     #ft_iocb        ; normalize
271         tax
272         lsr     a
273         lsr     a
274         sta     tmp2            ; return fd
275         lda     #2
276         bit     tmp1            ; remember device?
277         beq     l1              ; yes
278         lda     #0              ; no, put 0 in field
279         beq     l2
280
281 l1:     ldy     #0
282         lda     (sp),y                  ; get device
283 l2:     sta     fd_table+ft_dev,x       ; set device
284         lda     #1
285         sta     fd_table+ft_usa,x       ; set usage counter
286         lda     loc_Y
287         sta     fd_table+ft_iocb,x      ; set iocb index
288         lda     loc_devnum
289         and     #7                      ; device number is 3 bits
290         ora     #16                     ; indicated a fd actively opened by the app
291         sta     fd_table+ft_flag,x
292         lda     tmp2
293         jsr     fdt_to_fdi              ; get new index
294 noslot1:bcs     noslot                  ; no one available (noslot1: helper label for branch out of range)
295         ;cmp    #$ff                    ; no one available
296         ;beq    noslot  ;@@@ cleanup needed
297         sta     tmp2                    ; return index
298         jmp     finish
299
300 ; string in "Xn:xxx" format
301 colon2: dey
302         lda     (ptr4),y        ; get device number
303         sec
304         sbc     #'0'
305         and     #7
306         sta     loc_devnum
307         sta     tmp2            ; save it for speed later here also
308         lda     #4              ; max. length if only  device + number ("Xn:")
309         cmp     tmp3
310         bcc     do_open_nd      ; string is longer -> contains filename
311         bcs     check_dev       ; handle device only string
312
313 ; string in "X:xxx" format
314 colon1: lda     #3              ; max. length if device only ("X:")
315         cmp     tmp3
316         bcc     do_open_nd      ; string is longer -> contains filename
317
318 ; get device and search it in fd table
319 check_dev:
320         ldy     #0
321         lda     (ptr4),y        ; get device id
322         tay
323         ldx     #(MAX_FD_VAL*4) - ft_entrylen
324 srchdev:lda     #$ff
325         cmp     fd_table+ft_iocb,x      ; is entry valid?
326         beq     srch2                   ; no, skip this entry
327         tya
328         cmp     fd_table+ft_dev,x
329         beq     fnddev
330 srch2:  txa
331         sec
332         sbc     #ft_entrylen+1
333         tax
334         bpl     srchdev
335
336 ; not found, open new iocb
337         jmp     do_open
338
339 ; found device in table, check device number (e.g R0 - R3)
340 fnddev: lda     fd_table+ft_flag,x
341         and     #7
342         cmp     tmp2                    ; contains devnum
343         bne     srch2                   ; different device numbers
344
345 ; found existing open iocb with same device
346         txa
347         lsr     a
348         lsr     a
349         sta     tmp2
350         inc     fd_table+ft_usa,x       ; increment usage counter
351         jsr     fdt_to_fdi              ; get new index
352         bcs     noslot1                 ; no one available
353         sta     tmp2                    ; return index
354
355 ; clean up and go home
356 finish: lda     ptr4
357         pha
358         lda     ptr4+1
359         pha
360         lda     loc_Y
361         pha
362         lda     tmp1
363         pha
364         lda     loc_tmp1
365         sta     tmp1
366         pla
367         lsr     a                       ; set C as needed
368
369         pla
370         tay
371         pla
372         tax
373         pla
374         rts
375
376 .endproc        ; newfd
377