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