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