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