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