summaryrefslogtreecommitdiff
path: root/firmware/test/memory/memory-page.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/test/memory/memory-page.c')
-rw-r--r--firmware/test/memory/memory-page.c425
1 files changed, 425 insertions, 0 deletions
diff --git a/firmware/test/memory/memory-page.c b/firmware/test/memory/memory-page.c
new file mode 100644
index 0000000000..438fd63669
--- /dev/null
+++ b/firmware/test/memory/memory-page.c
@@ -0,0 +1,425 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id:
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#ifndef __LIBRARY_MEMORY_C__
20# error "This header file must be included ONLY from memory.c."
21#endif
22#ifndef __LIBRARY_MEMORY_PAGE_H__
23# define __LIBRARY_MEMORY_PAGE_H__
24
25struct memory_free_page
26 {
27 struct memory_free_page
28 *less,*more;
29 char
30 reserved[MEMORY_PAGE_MINIMAL_SIZE - 2*sizeof (struct memory_free_page *)];
31 };
32
33#define LESS -1
34#define MORE +1
35
36#ifdef TEST
37
38struct memory_free_page free_page[MEMORY_TOTAL_PAGES];
39
40static inline unsigned int get_offset (int order)
41 {
42 return (2 << order);
43 }
44
45// IA32 has no problem with shift operation
46static inline unsigned int get_size (int order)
47 {
48 return (MEMORY_PAGE_MINIMAL_SIZE << order);
49 }
50
51// Arghhhh ! I cannot align 'free_page' on 512-byte boundary (max is 16-byte for Cygwin)
52static inline struct memory_free_page *get_neighbour (struct memory_free_page *node,unsigned int size)
53 {
54 return ((struct memory_free_page *)((unsigned)free_page + (((unsigned)node - (unsigned)free_page) ^ size)));
55 }
56
57#else
58
59extern struct memory_free_page free_page[MEMORY_TOTAL_PAGES] asm("dram");
60
61static inline unsigned int get_offset (int order)
62 {
63 static unsigned short offset [MEMORY_TOTAL_ORDERS] =
64 { 2,4,8,16,32,64,128,256,512,1024,2048,4096,8192 };
65 return offset[order];
66 }
67
68// SH1 has very poor shift instructions (only <<1,>>1,<<2,>>2,<<8,>>8,<<16 and >>16).
69// so we should use a lookup table to speedup.
70static inline unsigned int get_size (int order)
71 {
72 return (get_offset (order))<<8;
73 }
74
75static inline struct memory_free_page *get_neighbour (struct memory_free_page *node,unsigned int size)
76 {
77 return ((struct memory_free_page *)((unsigned)node ^ size));
78 }
79
80#endif
81
82static char free_page_order[MEMORY_TOTAL_PAGES];
83static struct memory_free_page *free_page_bin[MEMORY_TOTAL_ORDERS];
84
85static inline int get_order (struct memory_free_page *node)
86 {
87 return free_page_order[node - free_page];
88 }
89static inline void set_order (struct memory_free_page *node,int order)
90 {
91 free_page_order[node - free_page] = order;
92 }
93
94#if MEMORY_PAGE_USE_SPLAY_TREE
95
96# include <stdio.h>
97
98static struct memory_free_page *splay_page (struct memory_free_page *root,struct memory_free_page *node)
99 {
100 struct memory_free_page *down;
101 struct memory_free_page *less;
102 struct memory_free_page *more;
103 struct memory_free_page head;
104 head.less =
105 head.more = 0;
106 less =
107 more = &head;
108 while (1)
109 {
110 if (node < root)
111 {
112 if ((down = root->less))
113 {
114 if (node < down)
115 {
116 root->less = down->more;
117 down->more = root;
118 root = down;
119 if (!root->less)
120 break;
121 }
122 more->less = root;
123 more = root;
124 root = root->less;
125 continue;
126 }
127 break;
128 }
129 if (root < node)
130 {
131 if ((down = root->more))
132 {
133 if (root < node)
134 {
135 root->more = down->less;
136 down->less = root;
137 root = down;
138 if (!root->more)
139 break;
140 }
141 less->more = root;
142 less = root;
143 root = root->more;
144 continue;
145 }
146 }
147 break;
148 }
149 less->more = root->less;
150 more->less = root->more;
151 root->less = head.more;
152 root->more = head.less;
153 return root;
154 }
155
156static inline void insert_page (int order,struct memory_free_page *node)
157 {
158 struct memory_free_page *root = free_page_bin[order];
159 if (!root)
160 {
161 node->less =
162 node->more = 0;
163 }
164 else if (node < (root = splay_page (root,node)))
165 {
166 node->less = root->less;
167 node->more = root;
168 root->less = 0;
169 }
170 else if (node > root)
171 {
172 node->less = root;
173 node->more = root->more;
174 node->more = 0;
175 }
176 free_page_bin[order] = node;
177 set_order (node,order);
178 return;
179 }
180
181static inline struct memory_free_page *pop_page (int order,int want)
182 {
183 struct memory_free_page *root = free_page_bin[order];
184 if (root)
185 {
186 root = splay_page (root,free_page);
187 free_page_bin[order] = root->more;
188 set_order (root,~want);
189 }
190 return root;
191 }
192
193static inline void remove_page (int order,struct memory_free_page *node)
194 {
195 struct memory_free_page *root = free_page_bin[order];
196 root = splay_page (root,node);
197 if (root->less)
198 {
199 node = splay_page (root->less,node);
200 node->more = root->more;
201 }
202 else
203 node = root->more;
204 free_page_bin[order] = node;
205 }
206
207#else
208
209static inline void insert_page (int order,struct memory_free_page *node)
210 {
211 struct memory_free_page *head = free_page_bin[order];
212 node->less = 0;
213 node->more = head;
214 if (head)
215 head->less = node;
216 free_page_bin[order] = node;
217 set_order (node,order);
218 }
219
220static inline struct memory_free_page *pop_page (int order,int want)
221 {
222 struct memory_free_page *node = free_page_bin[order];
223 if (node)
224 {
225 free_page_bin[order] = node->more;
226 if (node->more)
227 node->more->less = 0;
228 set_order (node,~want);
229 }
230 return node;
231 }
232
233static inline void remove_page (int order,struct memory_free_page *node)
234 {
235 if (node->less)
236 node->less->more = node->more;
237 else
238 free_page_bin[order] = node->more;
239 if (node->more)
240 node->more->less = node->less;
241 }
242
243#endif
244
245static inline void push_page (int order,struct memory_free_page *node)
246 {
247 node->less = 0;
248 node->more = 0;
249 free_page_bin[order] = node;
250 set_order (node,order);
251 }
252
253static struct memory_free_page *allocate_page (unsigned int size,int order)
254 {
255 struct memory_free_page *node;
256 int min = order;
257 while ((unsigned)order <= (MEMORY_TOTAL_ORDERS - 1))
258 // order is valid ?
259 {
260 if (!(node = pop_page (order,min)))
261 // no free page of this order ?
262 {
263 ++order; size <<= 1;
264 continue;
265 }
266 while (order > min)
267 // split our larger page in smaller pages
268 {
269 --order; size >>= 1;
270 push_page (order,(struct memory_free_page *)((unsigned int)node + size));
271 }
272 return node;
273 }
274 return MEMORY_RETURN_FAILURE;
275 }
276
277static inline void release_page (struct memory_free_page *node,unsigned int size,int order)
278 {
279 struct memory_free_page *neighbour;
280 while ((order <= (MEMORY_TOTAL_ORDERS - 1)) &&
281 ((neighbour = get_neighbour (node,size)),
282 (get_order (neighbour) == order)))
283 // merge our released page with its contiguous page into a larger page
284 {
285 remove_page (order,neighbour);
286 ++order; size <<= 1;
287 if (neighbour < node)
288 node = neighbour;
289 }
290 insert_page (order,node);
291 }
292
293
294/*****************************************************************************/
295/* PUBLIC FUNCTIONS */
296/*****************************************************************************/
297
298void *memory_allocate_page (int order)
299 {
300 if (order < 0)
301 return MEMORY_RETURN_FAILURE;
302 return allocate_page (get_size (order),order);
303 }
304
305// release a page :
306// when called, 'address' MUST be a valid address pointing
307// to &dram[i], where i ranges from 0 to MEMORY_TOTAL_PAGES - 1.
308// FAILURE if block is already freed.
309int memory_release_page (void *address)
310 {
311 struct memory_free_page *node = (struct memory_free_page *)address;
312 int order = ~get_order (node);
313 if (order < 0)
314 return MEMORY_RETURN_FAILURE;
315 release_page (node,get_size (order),order);
316 return MEMORY_RETURN_SUCCESS;
317 }
318
319
320#ifdef TEST
321# include <stdio.h>
322# include <stdlib.h>
323# if MEMORY_PAGE_USE_SPLAY_TREE
324
325static void dump_splay_node (struct memory_free_page *node,int level)
326 {
327 if (!node)
328 return;
329 dump_splay_node (node->less,level+1);
330 printf ("\n%*s[%d-%d]",level,"",(node - free_page),(node - free_page) + (1 << get_order (node)) - 1);
331 dump_splay_node (node->more,level+1);
332 }
333
334static void dump_splay_tree (struct memory_free_page *root)
335 {
336 dump_splay_node (root,2); fflush (stdout);
337 }
338
339# endif
340
341void memory_spy_page (void *address)
342 {
343 struct memory_free_page *node = (struct memory_free_page *)address;
344 int order,used;
345 if (node)
346 {
347 order = get_order (node);
348 used = order < 0;
349 if (used)
350 order = ~order;
351 printf("\n(%s,%2d,%7d)",(used ? "used" : "free"),order,get_size (order));
352 }
353 }
354
355void memory_dump (int order)
356 {
357 struct memory_free_page *node = free_page_bin[order];
358 printf("\n(%s,%2d,%7d)",node ? "free" : "none",order,get_size (order));
359# if MEMORY_PAGE_USE_SPLAY_TREE
360 dump_splay_tree (node);
361# else
362 while (node)
363 {
364 printf("[%d-%d]",(node - free_page),(node - free_page) + (1<<order) - 1);
365 node = node->more;
366 }
367# endif
368
369 }
370
371void memory_check (int order)
372 {
373 struct memory_free_page *node[4096],*swap;
374 unsigned int i = 0,j = 0;
375 while (i <= 12)
376 memory_dump (i++);
377 i = 0;
378 printf ("\nallocating...\n");
379 while (order >= 0)
380 {
381 j = order;
382 while ((swap = memory_allocate_page (j)))
383 {
384 node[i++] = swap;
385 printf("[%d-%d]",(swap - free_page),(swap - free_page) + ((1 << j)-1));
386 for (j += (rand () & 15); j > (unsigned int)order; j -= order);
387 }
388 --order;
389 }
390 node[i] = 0;
391 while (j <= 12)
392 memory_dump (j++);
393 j = 0;
394 printf ("\nreleasing...");
395 --i;
396 while (i > 0)
397 {
398 unsigned int k = 0;
399#if 0
400 printf ("\n");
401#endif
402 swap = node[k++];
403#if 0
404 while (swap)
405 {
406 printf("[%d-%d]",(swap - free_page),(swap - free_page) + ((1 << ~get_order (swap))-1));
407 swap = node[k++];
408 }
409#endif
410 for (j += 1 + (rand () & 15); j >= i; j -= i);
411 swap = node[j];
412 node[j] = node[i];
413 memory_release_page (swap);
414 node[i] = 0;
415 --i;
416 }
417 memory_release_page (node[0]);
418 i = 0;
419 while (i <= 12)
420 memory_dump (i++);
421 printf("\n\n%s !",(get_order (free_page) == 12) ? "SUCCESS" : "FAILURE");
422 }
423
424#endif
425#endif \ No newline at end of file