ppc64: Don't set Kp bit on SLB
[openbios.git] / forth / bootstrap / memory.fs
blob6fa4a2cc7c461a8c203a6df3f959546b9d609e8f
1 \ tag: forth memory allocation
2 \
3 \ Copyright (C) 2002-2003 Stefan Reinauer
4 \
5 \ See the file "COPYING" for further information about
6 \ the copyright and warranty status of this work.
7 \
9 \ 7.3.3.2 memory allocation
11 \ these need to be initialized by the forth kernel by now.
12 variable start-mem 0 start-mem ! \ start of memory
13 variable end-mem 0 end-mem ! \ end of memory
14 variable free-list 0 free-list ! \ free list head
16 \ initialize necessary variables and write a valid
17 \ free-list entry containing all of the memory.
18 \ start-mem: pointer to start of memory.
19 \ end-mem: pointer to end of memory.
20 \ free-list: head of linked free list
22 : init-mem ( start-addr size )
23 over dup
24 start-mem ! \ write start-mem
25 free-list ! \ write first freelist entry
26 2dup /n - swap ! \ write 'len' entry
27 over cell+ 0 swap ! \ write 'next' entry
28 + end-mem ! \ write end-mem
31 \ --------------------------------------------------------------------
33 \ return pointer to smallest free block that contains
34 \ at least nb bytes and the block previous the the
35 \ actual block. On failure the pointer to the smallest
36 \ free block is 0.
38 : smallest-free-block ( nb -- prev ptr | 0 0 )
39 0 free-list @
40 fffffff 0 0 >r >r >r
41 begin
42 dup
43 while
44 ( nb prev pp R: best_nb best_pp )
45 dup @ 3 pick r@ within if
46 ( nb prev pp )
47 r> r> r> 3drop \ drop old smallest
48 2dup >r >r dup @ >r \ new smallest
49 then
50 nip dup \ prev = pp
51 cell + @ \ pp = pp->next
52 repeat
53 3drop r> drop r> r>
57 \ --------------------------------------------------------------------
59 \ allocate size bytes of memory
60 \ return pointer to memory (or throws an exception on failure).
62 : alloc-mem ( size -- addr )
64 \ make it legal (and fast) to allocate 0 bytes
65 dup 0= if exit then
67 aligned \ keep memory aligned.
68 dup smallest-free-block \ look up smallest free block.
70 dup 0= if
71 \ 2drop
72 -15 throw \ out of memory
73 then
75 ( al-size prev addr )
77 \ If the smallest fitting block found is bigger than
78 \ the size of the requested block plus 2*cellsize we
79 \ can split the block in 2 parts. otherwise return a
80 \ slightly bigger block than requested.
82 dup @ ( d->len ) 3 pick cell+ cell+ > if
84 \ splitting the block in 2 pieces.
85 \ new block = old block + len field + size of requested mem
86 dup 3 pick cell+ + ( al-size prev addr nd )
88 \ new block len = old block len - req. mem size - 1 cell
89 over @ ( al-size prev addr nd addr->len )
90 4 pick ( ... al-size )
91 cell+ - ( al-size prev addr nd nd nd->len )
92 over ! ( al-size prev addr nd )
94 over cell+ @ ( al-size prev addr nd addr->next )
95 \ write addr->next to nd->next
96 over cell+ ! ( al-size prev addr nd )
97 over 4 pick swap !
98 else
99 \ don't split the block, it's too small.
100 dup cell+ @
101 then
103 ( al-size prev addr nd )
105 \ If the free block we got is the first one rewrite free-list
106 \ pointer instead of the previous entry's next field.
107 rot dup 0= if drop free-list else cell+ then
108 ( al-size addr nd prev->next|fl )
110 nip cell+ \ remove al-size and skip len field of returned pointer
115 \ --------------------------------------------------------------------
117 \ free block given by addr. The length of the
118 \ given block is stored at addr - cellsize.
120 \ merge with blocks to the left and right
121 \ immediately, if they are free.
123 : free-mem ( addr len -- )
125 \ we define that it is legal to free 0-byte areas
126 0= if drop exit then
127 ( addr )
129 \ check if the address to free is somewhere within
130 \ our available memory. This fails badly on discontigmem
131 \ architectures. If we need more RAM than fits on one
132 \ contiguous memory area we are too bloated anyways. ;)
134 dup start-mem @ end-mem @ within 0= if
135 \ ." free-mem: no such memory: 0x" u. cr
136 exit
137 then
139 /n - \ get real block address
140 0 free-list @ ( addr prev l )
142 begin \ now scan the free list
143 dup 0<> if \ only check len, if block ptr != 0
144 dup dup @ cell+ + 3 pick <
145 else
146 false
147 then
148 while
149 nip dup \ prev=l
150 cell+ @ \ l=l->next
151 repeat
153 ( addr prev l )
155 dup 0<> if \ do we have free memory to merge with?
157 dup dup @ cell+ + 3 pick = if \ hole hit. adding bytes.
158 \ freeaddr = end of current block -> merge
159 ( addr prev l )
160 rot @ cell+ ( prev l f->len+cellsize )
161 over @ + \ add l->len
162 over ! ( prev l )
163 swap over cell+ @ \ f = l; l = l->next;
165 \ The free list is sorted by addresses. When merging at the
166 \ start of our block we might also want to merge at the end
167 \ of it. Therefore we fall through to the next border check
168 \ instead of returning.
169 true \ fallthrough value
170 else
171 false \ no fallthrough
172 then
173 >r \ store fallthrough on ret stack
175 ( addr prev l )
177 dup 3 pick dup @ cell+ + = if \ hole hit. real merging.
178 \ current block starts where block to free ends.
179 \ end of free block addr = current block -> merge and exit
180 ( addr prev l )
181 2 pick dup @ ( f f->len )
182 2 pick @ cell+ + ( f newlen )
183 swap ! ( addr prev l )
184 3dup drop
185 0= if
186 free-list
187 else
188 2 pick cell+
189 then ( value prev->next|free-list )
190 ! ( addr prev l )
191 cell+ @ rot ( prev l->next addr )
192 cell+ ! drop
193 r> drop exit \ clean up return stack
194 then
196 r> if 3drop exit then \ fallthrough? -> exit
197 then
199 \ loose block - hang it before current.
201 ( addr prev l )
203 \ hang block to free in front of the current entry.
204 dup 3 pick cell+ ! \ f->next = l;
205 free-list @ = if \ is block to free new list head?
206 over free-list !
207 then
209 ( addr prev )
210 dup 0<> if \ if (prev) prev->next=f
211 cell+ !
212 else
213 2drop \ no fixup needed. clean up.
214 then