]> git.sur5r.net Git - cc65/blob - libsrc/common/free.s
faa40c672a3b450f69509b2e7b24d2ef9a930703
[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 ; Offsets into struct freeblock
68
69         size    = 0
70         next    = 2
71         prev    = 4
72
73 ; Code
74
75 _free:  sta     ptr1
76         stx     ptr1+1                  ; Save block
77
78 ; Is the argument NULL?
79
80         ora     ptr1+1                  ; Is the argument NULL?
81         beq     @L9                     ; Jump if yes
82
83 ; Decrement the given pointer by 2. The size of the block is stored there.
84 ; Remember the block size in ptr2.
85
86         sec
87         lda     ptr1
88         sbc     #2
89         sta     ptr1
90         bcs     @L1
91         dec     ptr1+1
92 @L1:    ldy     #size+1
93         lda     (ptr1),y                ; High byte of size
94         sta     ptr2+1                  ; Save it
95         dey
96         lda     (ptr1),y
97         sta     ptr2
98
99 ; Check if the block is on top of the heap
100
101         clc
102         adc     ptr1
103         tay
104         lda     ptr1+1
105         adc     ptr2+1
106         cpy     __hptr
107         bne     @AddToFreeList
108         cmp     __hptr+1
109         bne     @AddToFreeList
110
111 ; The pointer is located at the heap top. Lower the heap top pointer to
112 ; release the block.
113
114 @L3:    lda     ptr1
115         sta     __hptr
116         lda     ptr1+1
117         sta     __hptr+1
118
119 ; Check if the last block in the freelist is now at heap top. If so, remove
120 ; this block from the freelist.
121
122         lda     __hlast
123         sta     ptr2
124         ora     __hlast+1
125         beq     @L9                     ; Jump if free list empty
126         lda     __hlast+1
127         sta     ptr2+1                  ; Pointer to last block now in ptr2
128
129         clc
130         ldy     #size
131         lda     (ptr2),y                ; Low byte of block size
132         adc     ptr2
133         tax
134         iny                             ; High byte of block size
135         lda     (ptr2),y
136         adc     ptr2+1
137
138         cmp     __hptr+1
139         bne     @L9                     ; Jump if last block not on top of heap
140         cpx     __hptr
141         bne     @L9                     ; Jump if last block not on top of heap
142
143 ; Remove the last block
144
145         lda     ptr2
146         sta     __hptr
147         lda     ptr2+1
148         sta     __hptr+1
149
150 ; Correct the next pointer of the now last block
151
152         ldy     #prev+1                 ; Offset of ->prev field
153         lda     (ptr2),y
154         sta     ptr1+1                  ; Remember f->prev in ptr1
155         sta     __hlast+1
156         dey
157         lda     (ptr2),y
158         sta     ptr1                    ; Remember f->prev in ptr1
159         sta     __hlast
160         ora     __hlast+1               ; -> prev == 0?
161         bne     @L8                     ; Jump if free list not empty
162
163 ; Free list is now empty (A = 0)
164
165         sta     __hfirst
166         sta     __hfirst+1
167
168 ; Done
169
170 @L9:    rts
171
172 ; Block before is now last block. ptr1 points to f->prev.
173
174 @L8:    lda     #$00
175         dey                             ; Points to high byte of ->next
176         sta     (ptr1),y
177         dey                             ; Low byte of f->prev->next
178         sta     (ptr1),y
179         rts                             ; Done
180
181 ; The block is not on top of the heap. Add it to the free list.
182
183 @AddToFreeList:
184         lda     ptr1
185         ldx     ptr1+1
186         jsr     pushax                  ; Push b
187         lda     ptr2
188         ldx     ptr2+1
189         jsr     pushax                  ; Push size
190         jmp     __hadd                  ; Add to free list and return
191
192
193