]> git.sur5r.net Git - cc65/blob - libsrc/common/free.s
8caf04d4b05318454d3db158919c6eeead2b5a6a
[cc65] / libsrc / common / free.s
1 ;
2 ; Ullrich von Bassewitz, 19.03.2000
3 ;
4 ; Free a block on the heap.
5 ;
6 ; void __fastcall__ free (void* block);
7 ;
8 ;
9 ; C implementation was:
10 ;
11 ; void free (void* block)
12 ; /* Release an allocated memory block. The function will accept NULL pointers
13 ;  * (and do nothing in this case).
14 ;  */
15 ; {
16 ;     unsigned* b;
17 ;     unsigned size;
18 ;     struct freeblock* f;
19 ;
20 ;
21 ;     /* Allow NULL arguments */
22 ;     if (block == 0) {
23 ;         return;
24 ;     }
25 ;
26 ;     /* Get a pointer to the real memory block, then get the size */
27 ;     b = (unsigned*) block;
28 ;     size = *--b;
29 ;
30 ;     /* Check if the block is at the top of the heap */
31 ;     if (((int) b) + size == (int) _hptr) {
32 ;
33 ;         /* Decrease _hptr to release the block */
34 ;         _hptr = (unsigned*) (((int) _hptr) - size);
35 ;
36 ;         /* Check if the last block in the freelist is now at heap top. If so,
37 ;          * remove this block from the freelist.
38 ;          */
39 ;         if (f = _hlast) {
40 ;             if (((int) f) + f->size == (int) _hptr) {
41 ;                 /* Remove the last block */
42 ;                 _hptr = (unsigned*) (((int) _hptr) - f->size);
43 ;                 if (_hlast = f->prev) {
44 ;                   /* Block before is now last block */
45 ;                     f->prev->next = 0;
46 ;                 } else {
47 ;                     /* The freelist is empty now */
48 ;                     _hfirst = 0;
49 ;                 }
50 ;             }
51 ;         }
52 ;
53 ;     } else {
54 ;
55 ;               /* Not at heap top, enter the block into the free list */
56 ;       _hadd (b, size);
57 ;
58 ;     }
59 ; }
60 ;
61
62         .importzp       ptr1, ptr2
63         .import         __hptr, __hfirst, __hlast
64         .import         pushax, __hadd
65         .export         _free
66
67         .macpack        generic
68
69 ; Offsets into struct freeblock and other constant stuff
70
71 size            = 0
72 next            = 2
73 prev            = 4
74 admin_space     = 2
75 min_size        = 6
76
77
78 ; Code
79
80 _free:  sta     ptr1
81         stx     ptr1+1                  ; Save block
82
83 ; Is the argument NULL?
84
85         ora     ptr1+1                  ; Is the argument NULL?
86         beq     @L9                     ; Jump if yes
87
88 ; Decrement the given pointer by the admin space amount, so it points to the
89 ; real block allocated. The size of the block is stored in the admin space.
90 ; Remember the block size in ptr2.
91
92         lda     ptr1
93         sub     #admin_space
94         sta     ptr1
95         bcs     @L1
96         dec     ptr1+1
97 @L1:    ldy     #size+1
98         lda     (ptr1),y                ; High byte of size
99         sta     ptr2+1                  ; Save it
100         dey
101         lda     (ptr1),y
102         sta     ptr2
103
104 ; Check if the block is on top of the heap
105
106         add     ptr1
107         tay
108         lda     ptr1+1
109         adc     ptr2+1
110         cpy     __hptr
111         bne     @AddToFreeList
112         cmp     __hptr+1
113         bne     @AddToFreeList
114
115 ; The pointer is located at the heap top. Lower the heap top pointer to
116 ; release the block.
117
118 @L3:    lda     ptr1
119         sta     __hptr
120         lda     ptr1+1
121         sta     __hptr+1
122
123 ; Check if the last block in the freelist is now at heap top. If so, remove
124 ; this block from the freelist.
125
126         lda     __hlast
127         sta     ptr2
128         ora     __hlast+1
129         beq     @L9                     ; Jump if free list empty
130         lda     __hlast+1
131         sta     ptr2+1                  ; Pointer to last block now in ptr2
132
133         ldy     #size
134         lda     (ptr2),y                ; Low byte of block size
135         add     ptr2
136         tax
137         iny                             ; High byte of block size
138         lda     (ptr2),y
139         adc     ptr2+1
140
141         cmp     __hptr+1
142         bne     @L9                     ; Jump if last block not on top of heap
143         cpx     __hptr
144         bne     @L9                     ; Jump if last block not on top of heap
145
146 ; Remove the last block
147
148         lda     ptr2
149         sta     __hptr
150         lda     ptr2+1
151         sta     __hptr+1
152
153 ; Correct the next pointer of the now last block
154
155         ldy     #prev+1                 ; Offset of ->prev field
156         lda     (ptr2),y
157         sta     ptr1+1                  ; Remember f->prev in ptr1
158         sta     __hlast+1
159         dey
160         lda     (ptr2),y
161         sta     ptr1                    ; Remember f->prev in ptr1
162         sta     __hlast
163         ora     __hlast+1               ; -> prev == 0?
164         bne     @L8                     ; Jump if free list not empty
165
166 ; Free list is now empty (A = 0)
167
168         sta     __hfirst
169         sta     __hfirst+1
170
171 ; Done
172
173 @L9:    rts
174
175 ; Block before is now last block. ptr1 points to f->prev.
176
177 @L8:    lda     #$00
178         dey                             ; Points to high byte of ->next
179         sta     (ptr1),y
180         dey                             ; Low byte of f->prev->next
181         sta     (ptr1),y
182         rts                             ; Done
183
184 ; The block is not on top of the heap. Add it to the free list.
185
186 @AddToFreeList:
187         lda     ptr1
188         ldx     ptr1+1
189         jsr     pushax                  ; Push b
190         lda     ptr2
191         ldx     ptr2+1
192         jsr     pushax                  ; Push size
193         jmp     __hadd                  ; Add to free list and return
194
195
196
197