2 ; Christian Groessler, May-2000
4 ; fd indirection table & helper functions
8 .importzp tmp1,tmp2,tmp3,ptr4,sp
17 .export _fd_table,_fd_index ; for test purposes
22 fd_index: ; fd number is index into this table, entry's value specifies the fd_table entry
26 fd_table: ; each entry represents an open iocb
27 .byte 0,0,'E',0 ; system console, app starts with opened iocb #0 for E:
36 MAX_FD_VAL = (* - fd_table) / 4
38 ft_entrylen = 4 ; length of table entry (it's not sufficient to change here!
39 ; the code sometimes does two bit shifts to multiply/divide by
42 ft_usa = 0 ; usage counter
43 ft_iocb = 1 ; iocb index (0,$10,$20,etc.), $ff for empty entry
44 ft_dev = 2 ; device of open iocb (0 - device not remembered, eg. filename specified)
46 ; lower 3 bits: device number (for R: and D:)
50 ; gets fd in ax, decrements usage counter
51 ; return iocb index in X
52 ; return N bit set for invalid fd
53 ; return Z bit set if last user
54 ; all registers destroyed
62 lda fd_index,x ; get index
65 sta fd_index,x ; clear entry
67 asl a ; create index into fd table
71 cmp fd_table+ft_iocb,x ; entry in use?
72 beq inval ; no, return error
73 lda fd_table+ft_usa,x ; get usage counter
76 sbc #1 ; decr usage counter
81 lda fd_table+ft_iocb,x ; get iocb
87 sta fd_table+ft_iocb,y ; clear table entry
97 inval: ldx #$ff ; sets N
102 ; return iocb index in X
103 ; return N bit set for invalid fd
104 ; all registers destroyed
113 asl a ; create index into fd table
117 cmp fd_table+ft_iocb,x ; entry in use?
118 beq inval ; no, return error
119 lda fd_table+ft_usa,x ; get usage counter
120 beq inval ; 0? should not happen
121 lda fd_table+ft_iocb,x ; get iocb
126 ; decrements usage counter for fd
127 ; if 0 reached, it's marked as unused
128 ; get fd index in tmp2
129 ; Y register preserved
134 bcs ret ; invalid index, do nothing
141 asl a ; create index into fd table
145 cmp fd_table+ft_iocb,x ; entry in use?
146 beq ret ; no, do nothing
147 lda fd_table+ft_usa,x ; get usage counter
148 beq ret ; 0? should not happen
150 sbc #1 ; decrement by one
151 sta fd_table+ft_usa,x
153 lda #$ff ; 0, table entry unused now
154 sta fd_table+ft_iocb,x ; clear table entry
161 ; called from open() function
162 ; finds a fd to use for an open request
163 ; checks whether it's a device or file (file: characters follow the ':')
164 ; files always get an exclusive slot
165 ; for devices it is checked whether the device is already open, and if yes,
166 ; a link to this open device is returned
168 ; Calling parameters:
169 ; tmp3 - length of filename + 1
170 ; AX - points to filename
171 ; Y - iocb to use (if we need a new open)
173 ; tmp2 - fd num ($ff and C=0 in case of error - no free slot)
174 ; C - 0/1 for no open needed/open should be performed
175 ; all registers preserved!
180 ; ptr4 - 3,4 (backup)
218 ; ptr4 points to filename
228 ; no colon there!? OK, then we use a fresh iocb....
229 ; return error here? no, the subsequent open call should fail
231 do_open_nd: ; do open and don't remember device
236 sta tmp1 ; set flag to return 'open needed' : C = 1
242 beq freefnd ; found a free slot
247 cmp #(MAX_FD_VAL*4)+ft_iocb ; end of table reached?
250 ; error: no free slot found
252 stx tmp1 ; return with C = 0
254 stx tmp2 ; iocb: $ff marks error
260 sbc #ft_iocb ; normalize
266 bit tmp1 ; remember device?
268 lda #0 ; no, put 0 in field
272 lda (sp),y ; get device
273 l2: sta fd_table+ft_dev,x ; set device
275 sta fd_table+ft_usa,x ; set usage counter
277 sta fd_table+ft_iocb,x ; set iocb index
280 sta fd_table+ft_flag,x
282 jsr fdt_to_fdi ; get new index
283 bcs noslot ; no one available
284 ;cmp #$ff ; no one available
285 ;beq noslot ;@@@ cleanup needed
286 sta tmp2 ; return index
289 ; string in "Xn:xxx" format
291 lda (ptr4),y ; get device number
296 sta tmp2 ; save it for speed later here also
297 lda #4 ; max. length if only device + number ("Xn:")
299 bcc do_open_nd ; string is longer -> contains filename
300 bcs check_dev ; handle device only string
302 ; string in "X:xxx" format
303 colon1: lda #3 ; max. length if device only ("X:")
305 bcc do_open_nd ; string is longer -> contains filename
307 ; get device and search it in fd table
310 lda (ptr4),y ; get device id
312 ldx #(MAX_FD_VAL*4) - ft_entrylen
314 cmp fd_table+ft_iocb,x ; is entry valid?
315 beq srch2 ; no, skip this entry
317 cmp fd_table+ft_dev,x
325 ; not found, open new iocb
328 ; helper for branch out of range
331 ; found device in table, check device number (e.g R0 - R3)
332 fnddev: lda fd_table+ft_flag,x
334 cmp tmp2 ; contains devnum
335 bne srch2 ; different device numbers
337 ; found existing open iocb with same device
342 inc fd_table+ft_usa,x ; increment usage counter
343 jsr fdt_to_fdi ; get new index
344 bcs noslot1 ; no one available
345 sta tmp2 ; return index
347 ; clean up and go home
359 lsr a ; set C as needed
371 ; returns a fd_index entry pointing to the given ft_table entry
372 ; get fd_table entry in A
373 ; return C = 0/1 for OK/error
374 ; return fd_index entry in A if OK
375 ; registers destroyed
398 ; get a new fd pointing to a ft_table entry
399 ; usage counter of ft_table entry incremented
401 ; return C = 0/1 for OK/error
402 ; returns fd in A if OK
403 ; registers destroyed, tmp1 destroyed
406 sta tmp1 ; save fd_table entry
413 asl a ; also clears C
415 inc fd_table+ft_usa,x ; increment usage counter