*** empty log message ***

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@98 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Alan Korr 2002-04-15 23:19:10 +00:00
parent f5747cf78a
commit 27df7b0b96
12 changed files with 1551 additions and 0 deletions

View File

@ -0,0 +1,27 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id:
*
* Copyright (C) 2002 by Alan Korr
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef __LIBRARY_MEMORY_H__
# error "This header file must be included ONLY from memory.h."
#endif
#ifndef __LIBRARY_MEMORY_CONFIG_H__
# define __LIBRARY_MEMORY_CONFIG_H__
# define PACKAGE_NAME "memory"
# define PACKAGE_VERSION "0.1.0"
# define MEMORY_PAGE_USE_SPLAY_TREE 1
#endif

View File

@ -0,0 +1,39 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id:
*
* Copyright (C) 2002 by Alan Korr
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef __LIBRARY_MEMORY_H__
# error "This header file must be included ONLY from memory.h."
#endif
#ifndef __LIBRARY_MEMORY_DEFINES_H__
# define __LIBRARY_MEMORY_DEFINES_H__
# ifndef MEMORY_PAGE_MINIMAL_ORDER
# define MEMORY_PAGE_MINIMAL_ORDER (9) /* 512 bytes */
# endif
# ifndef MEMORY_PAGE_MAXIMAL_ORDER
# define MEMORY_PAGE_MAXIMAL_ORDER (21) /* 2 Mbytes */
# endif
# ifndef MEMORY_PAGE_MINIMAL_SIZE
# define MEMORY_PAGE_MINIMAL_SIZE (1 << MEMORY_PAGE_MINIMAL_ORDER)
# endif
# ifndef MEMORY_PAGE_MAXIMAL_SIZE
# define MEMORY_PAGE_MAXIMAL_SIZE (1 << MEMORY_PAGE_MAXIMAL_ORDER)
# endif
# define MEMORY_TOTAL_PAGES (MEMORY_PAGE_MAXIMAL_SIZE / MEMORY_PAGE_MINIMAL_SIZE)
# define MEMORY_TOTAL_BYTES (MEMORY_PAGE_MAXIMAL_SIZE)
# define MEMORY_TOTAL_ORDERS (1 + MEMORY_PAGE_MAXIMAL_ORDER - MEMORY_PAGE_MINIMAL_ORDER)
#endif

View File

@ -0,0 +1,34 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Alan Korr
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef __LIBRARY_MEMORY_H__
# error "This header file must be included ONLY from memory.h."
#endif
# ifndef __LIBRARY_MEMORY_FUNCTIONS_H__
# define __LIBRARY_MEMORY_FUNCTIONS_H__
extern void memory_copy (void *target,void const *source,unsigned int count);
extern void memory_set (void *target,int byte,unsigned int count);
extern int memory_release_page (void *);
extern void *memory_allocate_page (int);
extern void memory_setup (void);
# ifdef TEST
void memory_spy_page (void *address);
void memory_dump (int order);
void memory_check (int order);
# endif
#endif

View File

@ -0,0 +1,26 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id:
*
* Copyright (C) 2002 by Alan Korr
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef __LIBRARY_MEMORY_H__
# error "This header file must be included ONLY from memory.h."
#endif
# ifndef __LIBRARY_MEMORY_INLINES_H__
#define __LIBRARY_MEMORY_INLINES_H__
#endif

View File

@ -0,0 +1,193 @@
#############################################################################
## __________ __ ___.
## Open \______ \ ____ ____ | | _\_ |__ _______ ___
## Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
## Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
## Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
## \/ \/ \/ \/ \/
## Copyright Alan Korr, 2002. All rights reserved.
##
## Permission to use, copy, modify, and distribute this software for any
## purpose is hereby granted without fee, provided that this copyright and
## permissions notice appear in all copies and derivatives, and that no
## charge may be made for the software and its documentation except to cover
## cost of distribution.
##
## This software is provided "as is" without express or implied warranty.
#############################################################################
ARCH = test
CC = gcc
AS = as
LD = ld
AR = ar
RL = ranlib
OC = objcopy
GZ = gzip -f
PREFIX = ~/rockbox/$(ARCH)
PACKAGE = memory
VERSION = 0.1
DEFINES = -DTEST
#####################################################"
# Compiler flags :
CFLAGS = -g
#CFLAGS += -save-temps
CFLAGS += -Wall \
-W \
-Wshadow \
-Wpointer-arith \
-Waggregate-return \
-Wstrict-prototypes \
-Wredundant-decls \
-Winline \
-Wmissing-prototypes \
-Werror \
-Wsign-compare \
-Wmissing-declarations \
-Wmissing-noreturns \
-Wnested-externs
CFLAGS += -pipe -O3
CFLAGS += -fomit-frame-pointer \
-fschedule-insns
CFLAGS += $(EXTRA_CFLAGS)
CFLAGS += $(DEFINES)
#######################################################################
## PLEASE CONSIDER THERE IS NOTHING TO CHANGE IN THE FOLLOWING LINES
## SINCE THERE ARE COMMON FOR ALL LIBRARY
##
.SUFFIXES : .o .c .s
INCLUDES = -I. \
-I$(PREFIX)/headers
STATIC_LIBRARY_PATH = $(PREFIX)/libraries
LIBRARY = lib$(PACKAGE).a
#######################################################################
## PLEASE CHANGE ONLY THE FOLLOWING LINES
##
LIBS =
HEADERS = $(PACKAGE).h \
config.h \
defines.h \
types.h \
return_values.h \
inlines.h \
functions.h
SOURCES = $(PACKAGE)-page.c \
$(PACKAGE)-slab.c
OBJECTS = $(SOURCES:.c=.o)
DEPENDENCIES = $(SOURCES:.c=.d)
HEADER_PATH = $(PREFIX)/headers/$(PACKAGE)/.
#######################################################################
## PLEASE CONSIDER THERE IS NOTHING TO CHANGE IN THE FOLLOWING LINES
## SINCE THERE ARE COMMON FOR ALL LIBRARY
##
%.o: %.c
@echo "Compiling" $<...
@$(CC) -o $(@) $(CFLAGS) $(INCLUDES) -c $<
@$(CC) -M $< $(CFLAGS) $(INCLUDES) > $(*F).d
%.o: %.s
@echo "Assembling" $<...
@$(CC) -o $(@) $(CFLAGS) $(INCLUDES) -c $<
@$(CC) -M $< $(CFLAGS) $(INCLUDES) > $(*F).d
.PHONY: splash all clean backup restore dist install
all: splash $(LIBRARY) test
splash:
@echo "<<< " $(PACKAGE) "-" $(VERSION) ">>>"
####################################################
# LIBRAY PART :
$(LIBRARY): $(OBJECTS)
@echo "Creating library" $(LIBRARY)...
@$(AR) cru $(@) $(OBJECTS)
@$(RL) $(@)
####################################################
# TEST PART :
test: test.tab.o test.lex.o $(LIBRARY)
@echo "Creating executable" $@...
@$(CC) $(INCLUDES) -g -o $(@) $(+) -lfl -lreadline
test.tab.o: test.tab.c
@echo "Compiling" $<...
@$(CC) -I. -g -o $(@) -O3 -fomit-frame-pointer -c test.tab.c
test.lex.o: test.lex.c
@echo "Compiling" $<...
@$(CC) -I. -g -o $(@) -O3 -fomit-frame-pointer -c test.lex.c
test.tab.h: test.tab.c
test.lex.c: test.l test.tab.h
@echo "Flex:" $<
@flex -otest.lex.c test.l
test.tab.c: test.y
@echo "Bison:" $<
@bison -d test.y
####################################################
# MISCELLANOUS PART :
clean:
@rm -f $(LIBRARY)
@rm -f $(OBJECTS) test.lex.o test.tab.o
@rm -f $(DEPENDENCIES)
@rm -f *~ test test.exe
@rm -f test.tab.h test.tab.c test.lex.c
@rm -f core
backup:
@mkdir -p ./backup
@cp -f makefile ./backup
@cp -f test.l ./backup
@cp -f test.y ./backup
@cp -f $(SOURCES:.c=.txt) ./backup
@for header in $(HEADERS) ; do cp -f $$header ./backup ; done
@for source in $(SOURCES) ; do cp -f $$source ./backup ; done
restore:
@cp -f ./backup/makefile .
@cp -f ./backup/test.l .
@cp -f ./backup/test.y .
@cp -f ./backup/$(SOURCES:.c=.txt)
@for header in $(HEADERS) ; do cp -f ./backup/$$header . ; done
@for source in $(SOURCES) ; do cp -f ./backup/$$source . ; done
dist: backup
@mv backup $(PACKAGE)
@tar czvf $(PACKAGE)-$(VERSION).tar.gz $(PACKAGE)/*
@rm -f $(PACKAGE)/*
@rmdir $(PACKAGE)
install: all
@mkdir -p $(PREFIX)/libraries
@cp $(LIBRARY) $(PREFIX)/libraries
@mkdir -p $(PREFIX)/headers/$(PACKAGE)
@for header in $(HEADERS) ; do cp $$header $(PREFIX)/headers/$(PACKAGE) ; done
-include $(DEPENDENCIES)

View File

@ -0,0 +1,434 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id:
*
* Copyright (C) 2002 by Alan Korr
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <memory.h>
#define LESS -1
#define MORE +1
#ifdef TEST
struct memory_free_page free_page[MEMORY_TOTAL_PAGES];
static inline unsigned int get_offset (int order)
{
return (2 << order);
}
// IA32 has no problem with shift operation
static inline unsigned int get_size (int order)
{
return (MEMORY_PAGE_MINIMAL_SIZE << order);
}
// Arghhhh ! I cannot align 'free_page' on 512-byte boundary (max is 16-byte for Cygwin)
static inline struct memory_free_page *get_neighbour (struct memory_free_page *node,unsigned int size)
{
return ((struct memory_free_page *)((unsigned)free_page + (((unsigned)node - (unsigned)free_page) ^ size)));
}
#else
extern struct memory_free_page free_page[MEMORY_TOTAL_PAGES] asm("dram");
static inline unsigned int get_offset (int order)
{
static unsigned short offset [MEMORY_TOTAL_ORDERS] =
{ 2,4,8,16,32,64,128,256,512,1024,2048,4096,8192 };
return offset[order];
}
// SH1 has very poor shift instructions (only <<1,>>1,<<2,>>2,<<8,>>8,<<16 and >>16).
// so we should use a lookup table to speedup.
static inline unsigned int get_size (int order)
{
return (get_offset (order))<<8;
}
static inline struct memory_free_page *get_neighbour (struct memory_free_page *node,unsigned int size)
{
return ((struct memory_free_page *)((unsigned)node ^ size));
}
#endif
static char free_page_order[MEMORY_TOTAL_PAGES];
static struct memory_free_page *free_page_list[MEMORY_TOTAL_ORDERS];
static inline int get_order (struct memory_free_page *node)
{
return free_page_order[node - free_page];
}
static inline void set_order (struct memory_free_page *node,int order)
{
free_page_order[node - free_page] = order;
}
#if MEMORY_PAGE_USE_SPLAY_TREE
# include <stdio.h>
static struct memory_free_page *splay_page (struct memory_free_page *root,struct memory_free_page *node)
{
struct memory_free_page *down;
struct memory_free_page *less;
struct memory_free_page *more;
struct memory_free_page head;
head.less =
head.more = 0;
less =
more = &head;
while (1)
{
if (node < root)
{
if ((down = root->less))
{
if (node < down)
{
root->less = down->more;
down->more = root;
root = down;
if (!root->less)
break;
}
more->less = root;
more = root;
root = root->less;
continue;
}
break;
}
if (root < node)
{
if ((down = root->more))
{
if (root < node)
{
root->more = down->less;
down->less = root;
root = down;
if (!root->more)
break;
}
less->more = root;
less = root;
root = root->more;
continue;
}
}
break;
}
less->more = root->less;
more->less = root->more;
root->less = head.more;
root->more = head.less;
return root;
}
static inline void insert_page (int order,struct memory_free_page *node)
{
struct memory_free_page *root = free_page_list[order];
if (!root)
{
node->less =
node->more = 0;
}
else if (node < (root = splay_page (root,node)))
{
node->less = root->less;
node->more = root;
root->less = 0;
}
else if (node > root)
{
node->less = root;
node->more = root->more;
node->more = 0;
}
free_page_list[order] = node;
set_order (node,order);
return;
}
static inline struct memory_free_page *pop_page (int order,int want)
{
struct memory_free_page *root = free_page_list[order];
if (root)
{
root = splay_page (root,free_page);
free_page_list[order] = root->more;
set_order (root,~want);
}
return root;
}
static inline void remove_page (int order,struct memory_free_page *node)
{
struct memory_free_page *root = free_page_list[order];
root = splay_page (root,node);
if (root->less)
{
node = splay_page (root->less,node);
node->more = root->more;
}
else
node = root->more;
free_page_list[order] = node;
}
#else
static inline void insert_page (int order,struct memory_free_page *node)
{
struct memory_free_page *head = free_page_list[order];
node->less = 0;
node->more = head;
if (head)
head->less = node;
free_page_list[order] = node;
set_order (node,order);
}
static inline struct memory_free_page *pop_page (int order,int want)
{
struct memory_free_page *node = free_page_list[order];
if (node)
{
free_page_list[order] = node->more;
if (node->more)
node->more->less = 0;
set_order (node,~want);
}
return node;
}
static inline void remove_page (int order,struct memory_free_page *node)
{
if (node->less)
node->less->more = node->more;
else
free_page_list[order] = node->more;
if (node->more)
node->more->less = node->less;
}
#endif
static inline void push_page (int order,struct memory_free_page *node)
{
node->less = 0;
node->more = 0;
free_page_list[order] = node;
set_order (node,order);
}
static struct memory_free_page *allocate_page (unsigned int size,int order)
{
struct memory_free_page *node;
int min = order;
while ((unsigned)order <= (MEMORY_TOTAL_ORDERS - 1))
// order is valid ?
{
if (!(node = pop_page (order,min)))
// no free page of this order ?
{
++order; size <<= 1;
continue;
}
while (order > min)
// split our larger page in smaller pages
{
--order; size >>= 1;
push_page (order,(struct memory_free_page *)((unsigned int)node + size));
}
return node;
}
return MEMORY_RETURN_FAILURE;
}
static inline void release_page (struct memory_free_page *node,unsigned int size,int order)
{
struct memory_free_page *neighbour;
while ((order <= (MEMORY_TOTAL_ORDERS - 1)) &&
((neighbour = get_neighbour (node,size)),
(get_order (neighbour) == order)))
// merge our released page with its contiguous page into a larger page
{
remove_page (order,neighbour);
++order; size <<= 1;
if (neighbour < node)
node = neighbour;
}
insert_page (order,node);
}
/*****************************************************************************/
/* PUBLIC FUNCTIONS */
/*****************************************************************************/
void *memory_allocate_page (int order)
{
if (order < 0)
return MEMORY_RETURN_FAILURE;
return allocate_page (get_size (order),order);
}
// release a page :
// when called, 'address' MUST be a valid address pointing
// to &dram[i], where i ranges from 0 to MEMORY_TOTAL_PAGES - 1.
// FAILURE if block is already freed.
int memory_release_page (void *address)
{
struct memory_free_page *node = (struct memory_free_page *)address;
int order = ~get_order (node);
if (order < 0)
return MEMORY_RETURN_FAILURE;
release_page (node,get_size (order),order);
return MEMORY_RETURN_SUCCESS;
}
/* NOT VERY OPTIMIZED AT ALL BUT WE WILL DO IT WHEN PRIORITY COMES */
void memory_copy (void *target,void const *source,unsigned int count)
{
while (count--)
*((char *)target)++ = *((char const *)source)++;
}
/* NOT VERY OPTIMIZED AT ALL BUT WE WILL DO IT WHEN PRIORITY COMES */
void memory_set (void *target,int byte,unsigned int count)
{
while (count--)
*((char *)target)++ = (char)byte;
}
void memory_setup (void)
{
#if 0
memory_set (free_page,0,MEMORY_TOTAL_BYTES);
memory_set (free_page_list,0,MEMORY_TOTAL_ORDERS *sizeof (struct memory_free_page *));
#endif
memory_set (free_page_order + 1,(MEMORY_TOTAL_ORDERS - 1),MEMORY_TOTAL_PAGES);
free_page_order[0] = MEMORY_TOTAL_ORDERS - 1;
free_page_list[MEMORY_TOTAL_ORDERS - 1] = free_page;
}
#ifdef TEST
# include <stdio.h>
# include <stdlib.h>
# if MEMORY_PAGE_USE_SPLAY_TREE
static void dump_splay_node (struct memory_free_page *node,int level)
{
if (!node)
return;
dump_splay_node (node->less,level+1);
printf ("\n%*s[%d-%d]",level,"",(node - free_page),(node - free_page) + (1 << get_order (node)) - 1);
dump_splay_node (node->more,level+1);
}
static void dump_splay_tree (struct memory_free_page *root)
{
dump_splay_node (root,2); fflush (stdout);
}
# endif
void memory_spy_page (void *address)
{
struct memory_free_page *node = (struct memory_free_page *)address;
int order,used;
if (node)
{
order = get_order (node);
used = order < 0;
if (used)
order = ~order;
printf("\n(%s,%2d,%7d)",(used ? "used" : "free"),order,get_size (order));
}
}
void memory_dump (int order)
{
struct memory_free_page *node = free_page_list[order];
printf("\n(%s,%2d,%7d)",node ? "free" : "none",order,get_size (order));
# if MEMORY_PAGE_USE_SPLAY_TREE
dump_splay_tree (node);
# else
while (node)
{
printf("[%d-%d]",(node - free_page),(node - free_page) + (1<<order) - 1);
node = node->more;
}
# endif
}
void memory_check (int order)
{
struct memory_free_page *node[4096],*swap;
unsigned int i = 0,j = 0;
while (i <= 12)
memory_dump (i++);
i = 0;
printf ("\nallocating...\n");
while (order >= 0)
{
j = order;
while ((swap = memory_allocate_page (j)))
{
node[i++] = swap;
printf("[%d-%d]",(swap - free_page),(swap - free_page) + ((1 << j)-1));
for (j += (rand () & 15); j > (unsigned int)order; j -= order);
}
--order;
}
node[i] = 0;
while (j <= 12)
memory_dump (j++);
j = 0;
printf ("\nreleasing...");
--i;
while (i > 0)
{
unsigned int k = 0;
printf ("\n");
swap = node[k++];
#if 0
while (swap)
{
printf("[%d-%d]",(swap - free_page),(swap - free_page) + ((1 << ~get_order (swap))-1));
swap = node[k++];
}
#endif
for (j += 1 + (rand () & 15); j >= i; j -= i);
swap = node[j];
node[j] = node[i];
memory_release_page (swap);
node[i] = 0;
--i;
}
memory_release_page (node[0]);
i = 0;
while (i <= 12)
memory_dump (i++);
printf("\n\n%s !",(get_order (free_page) == 12) ? "SUCCESS" : "FAILURE");
}
#endif

View File

@ -0,0 +1,463 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id:
*
* Copyright (C) 2002 by Alan Korr
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#if 0
#include <memory.h>
static struct memory_cache *free_block_cache[MEMORY_PAGE_MINIMAL_SIZE - ];
static struct memory_cache *cache_list;
static inline int get_order (unsigned size)
{
int order = 0;
size = (size + sizeof(struct memory_free_block) - 1) & - sizeof(struct memory_free_block);
while (size > 0)
{
++order; size <<= 1;
}
return order;
}
static inline struct memory_slab *get_slab (struct memory_cache *cache,void *address)
{
#ifdef TEST
return (struct memory_slab *)((((unsigned)address + cache->page_size) & -cache->page_size) - sizeof (struct memory_slab));
#else
return (struct memory_slab *)((free_page + (((unsigned)address - free_page + cache->page_size) & -cache->page_size) - sizeof (struct memory_slab)));
#endif
}
static struct memory_cache *splay_cache (struct memory_cache *root,unsigned int left)
{
struct memory_cache *down;
struct memory_cache *less;
struct memory_cache *more;
struct memory_cache head;
head.less =
head.more = 0;
less =
more = &head;
while (1)
{
if (left < root->left)
{
if ((down = root->less))
{
if (left < down->left)
{
root->less = down->more;
down->more = root;
root = down;
if (!root->less)
break;
}
more->less = root;
more = root;
root = root->less;
continue;
}
break;
}
if (root->left < left)
{
if ((down = root->more))
{
if (root->left < left)
{
root->more = down->less;
down->less = root;
root = down;
if (!root->more)
break;
}
less->more = root;
less = root;
root = root->more;
continue;
}
}
break;
}
less->more = root->less;
more->less = root->more;
root->less = head.more;
root->more = head.less;
return root;
}
static inline struct memory_cache *insert_cache (struct memory_cache *root,struct memory_cache *node)
{
node->less =
node->more =
node->same = 0;
if (root)
{
if (node->left == ((root = splay_cache (root,node))->left))
{
node->less = root.less;
node->more = root.more;
node->same = root;
root->less = node;
}
else if (node < root)
{
node->less = root->less;
node->more = root;
root->less = 0;
}
else
{
node->less = root;
node->more = root->more;
node->more = 0;
}
}
return node;
}
static inline struct memory_cache *remove_cache (struct memory_cache *root,struct memory_cache *node)
{
if (root)
{
root = splay_cache (root,node);
if (root != node)
{
node->less->same = node->same;
if (node->same)
node->same->less = node->less;
return root;
}
if (root->less)
{
node = splay_page (root->less,node);
node->more = root->more;
}
else
node = root->more;
}
return root;
}
static inline struct memory_cache *move_cache (struct memory_cache *root,struct memory_cache *node,int delta)
{
if ((root = remove_cache (root,node)))
{
node->left += delta;
root = insert_cache (root,node);
}
return root;
}
static inline struct memory_slab *push_slab (struct memory_cache *head,struct memory_cache *node)
{
node->less = head;
if (head)
{
node->more = head->more;
head->more = node;
}
else
node->more = 0;
return node;
}
static inline struct memory_slab *pop_slab (struct memory_cache *head,struct memory_cache *node)
{
if (head)
head->more = node->more;
return node->more;
}
static inline struct memory_slab *move_slab (struct memory_slab **from,struct memory_slab **to)
{
struct memory_slab *head = *from;
*from = (*from)->more;
if (*from)
(*from)->less = head->less;
head->less = 0;
head->more = (*to);
if (*to)
(*to)->prev = head;
*to = head;
return head;
}
/*****************************************************************************/
/* PUBLIC FUNCTIONS */
/*****************************************************************************/
///////////////////////////////////////////////////////////////////////////////
// MEMORY CACHE :
/////////////////
//
// - memory_grow_cache : allocate a new slab for a cache
// - memory_shrink_cache : release free slabs from a cache
// - memory_create_cache : create a new cache of size-fixed blocks
// - memory_destroy_cache : destroy the cache and release all the slabs
// - memory_cache_allocate : allocate a block from the cache
// - memory_cache_release : release a block in the cache
//
struct memory_slab *memory_grow_cache (struct memory_cache *cache)
{
struct memory_slab *slab;
unsigned int page;
if (cache)
{
page = (unsigned int)memory_allocate_page (cache->page_order);
if (page)
{
struct memory_free_block *block,**link;
slab = (struct memory_slab *)(page + cache->page_size - sizeof (struct memory_slab));
slab->free = 0;
slab->left = 0;
link = &slab->free;
for ((unsigned int)block = page;
(unsigned int)block + cache->size < (unsigned int)slab;
(unsigned int)block += cache->size)
{
*link = block;
link = &block->link;
++slab->free;
}
*link = 0;
cache->blocks_per_slab = slab->free;
cache->reap = push_slab (cache->reap,slab);
cache_list = move_cache (cache_list,cache,+1);
return slab;
}
}
return MEMORY_RETURN_FAILURE;
}
static int memory_shrink_cache (struct memory_cache *cache,int all,int move)
{
struct memory_slab *slab;
unsigned int slabs = 0;
if (cache)
{
while ((slab = cache->reap))
{
++slabs;
cache->reap = pop_slab (cache->reap,slab);
memory_release_page ((void *)slab);
if (all)
continue;
if (move)
cache_list = move_cache (cache_list,cache,-slabs);
return MEMORY_RETURN_SUCCESS;
}
}
return MEMORY_RETURN_FAILURE;
}
int memory_shrink_cache (struct memory_cache *cache,int all)
{
return shrink_cache (cache,all,1 /* move cache in cache_list */);
}
struct memory_cache *memory_create_cache (unsigned int size,int align,int flags)
{
struct memory_cache *cache;
unsigned int waste = 0,blocks_per_page;
int page_order;
unsigned int page_size;
unsigned int original_size = size;
// Align size on 'align' bytes ('align' should equal 1<<n)
// if 'align' is inferior to 4, 32-bit word alignment is done by default.
size = (align > 4) ? ((size + align - 1) & -align) : ((size + sizeof (int) - 1) & -sizeof (int));
if (!(cache = memory_cache_allocate (&cache_cache))
return MEMORY_RETURN_FAILURE;
cache->flags =
cache->left = 0;
cache->used =
cache->free =
cache->reap = 0;
cache->original_size = original_size;
cache->size = size;
page_size = 0;
page_order = MEMORY_PAGE_MINIMAL_SIZE;;
// Trying to determine what is the best number of pages per slab
for (;; ++order,(page_size <<= 1))
{
if (page_order >= MEMORY_MAXIMUM_PAGE_ORDER_PER_SLAB)
{
memory_cache_release (&cache_cache,cache);
return MEMORY_RETURN_FAILURE;
}
waste = page_size;
waste -= sizeof (struct memory_slab);
blocks_per_slab = waste / size;
waste -= block_per_slab * size;
if (blocks_per_slab < MEMORY_MINIMUM_BLOCKS_PER_SLAB)
{
++page_order; page_size <<= 1;
continue;
}
// below 3% of lost space is correct
if ((waste << 16) / page_size) < 1967)
break;
++page_order; page_size <<= 1;
}
cache->page_size = page_size;
cache->page_order = page_order;
cache_list = insert_cache (cache_list,cache);
return cache;
}
int memory_destroy_cache (struct memory_cache *cache)
{
if (cache)
{
cache_list = remove_cache (cache_list,cache);
if (shrink_cache (cache,1 /* release all free slabs */,0 /* don't move in cache_list */))
return memory_cache_release (&cache_cache,cache);
}
return MEMORY_RETURN_FAILURE;
}
void *memory_cache_allocate (struct memory_cache *cache)
{
if (cache)
{
do
{
struct memory_slab *slab;
if ((slab = cache->free))
{
if (slab->left > 0)
{
ok: struct memory_free_block *block = slab->free;
slab->free = block->link;
if (--slab->left == 0)
move_slab (&cache->free,&cache->used);
return block;
}
}
if (cache->reap)
{
slab = move_slab (&cache->reap,&cache->free);
cache_list = move_cache (cache_list,cache,-1);
goto ok;
}
}
while (grow_cache (cache));
}
return MEMORY_RETURN_FAILURE;
}
int memory_cache_release (struct memory_cache *cache,void *address)
{
struct memory_slab *slab = get_slab (cache,address);
slab->free = (struct memory_free_block *)address;
if (slab->left++ == 0)
move_slab (&cache->used,&cache->free);
else if (slab->left == cache->elements_per_slab)
{
move_slab (&cache->free,&cache->reap);
cache_list = move_cache (cache_list,cache,+1);
}
return MEMORY_RETURN_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
// MEMORY BLOCK :
/////////////////
//
// - memory_allocate_small_block : allocate a small block (no page)
// - memory_release_small_block : release a small block (no page)
// - memory_allocate_block : allocate a block (or a page)
// - memory_release_block : release a block (or a page)
//
static inline void *allocate_small_block (int order)
{
struct memory_cache *cache = free_block_cache[order];
do
{
if (cache)
return memory_cache_allocate (cache);
}
while ((free_block_cache[order] = cache = memory_create_cache (size,0,0)));
return MEMORY_RETURN_FAILURE;
}
void *memory_allocate_small_block (int order)
{
if (order < MEMORY_PAGE_MINIMAL_ORDER)
return allocate_small_block (order)
return MEMORY_RETURN_FAILURE;
}
static inline int release_small_block (int order,void *address)
{
struct memory_cache *cache = free_block_cache[order];
if (cache)
return memory_cache_release (cache,address);
return MEMORY_RETURN_FAILURE;
}
int memory_release_small_block (int order,void *address)
{
if (order < MEMORY_PAGE_MINIMAL_ORDER)
return memory_release_small_block (order,address);
return memory_release_page (address);
}
void *memory_allocate_block (unsigned int size)
{
size += sizeof (int *);
int order = get_order (size);
if (size < MEMORY_PAGE_MINIMAL_SIZE)
{
int *block = (int *)allocate_block (order);
*block = order;
return block;
}
if (size < MEMORY_PAGE_MAXIMAL_SIZE)
return memory_allocate_page (order);
return MEMORY_RETURN_FAILURE;
}
int memory_release_block (void *address)
{
int order = *((int *)address);
if (order < MEMORY_PAGE_MINIMAL_ORDER)
return release_block (order);
if (order < MEMORY_PAGE_MAXIMAL_ORDER)
return memory_release_page (address);
return MEMORY_RETURN_FAILURE;
}
#endif

View File

@ -0,0 +1,27 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Alan Korr
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef __LIBRARY_MEMORY_H__
# define __LIBRARY_MEMORY_H__
# include <config.h>
# include <defines.h>
# include <types.h>
# include <return_values.h>
# include <inlines.h>
# include <functions.h>
#endif

View File

@ -0,0 +1,31 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id:
*
* Copyright (C) 2002 by Alan Korr
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef __LIBRARY_MEMORY_H__
# error "This header file must be included ONLY from memory.h."
#endif
# ifndef __LIBRARY_MEMORY_RETURN_VALUES_H__
#define __LIBRARY_MEMORY_RETURN_VALUES_H__
enum
{
MEMORY_RETURN_SUCCESS = 1,
MEMORY_RETURN_FAILURE = 0
};
#endif

View File

@ -0,0 +1,23 @@
%{
#include "test.tab.h"
#define YY_INPUT(buf,result,max_size) \
result = read_input (buf,max_size);
%}
%s GETNUMBER
%%
<GETNUMBER>[0-9]+ { yylval = atoi(yytext); return NUMBER;}
<INITIAL>"a"|"allocate" { BEGIN GETNUMBER; return ALLOCATE; }
<INITIAL>"r"|"release" { BEGIN GETNUMBER; return RELEASE; }
<INITIAL>"s"|"spy" { BEGIN GETNUMBER; return SPY; }
<INITIAL>"c"|"check" { BEGIN GETNUMBER; return CHECK; }
<INITIAL>"i"|"init" { return INIT; }
<INITIAL>"d"|"dump" { return DUMP; }
<INITIAL>"q"|"quit" { return QUIT; }
[ \t] ;
\n|. { BEGIN 0; return yytext[0]; }
%%

182
firmware/test/memory/test.y Normal file
View File

@ -0,0 +1,182 @@
%{
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void allocate (int);
void release (int);
void spy (int);
void dump (void);
void prompt (void);
%}
%token NUMBER
%token ALLOCATE
%token RELEASE
%token DUMP
%token SPY
%token CHECK
%token INIT
%token QUIT
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS
%%
commands
: command ';'
{ }
| commands command ';'
{ }
| error ';'
{ yyerrok; }
;
command
: allocate
| release
| spy
| check
| INIT
{ memory_setup (); }
| DUMP
{ dump (); }
| QUIT
{ return 0; }
;
allocate
: ALLOCATE expression
{ allocate (yylval); }
;
release
: RELEASE expression
{ release (yylval); }
;
spy
: SPY expression
{ spy (yylval); }
;
check
: CHECK expression
{ memory_check (yylval); }
;
expression
: expression '+' expression
{ $$ = $1 + $3; }
| expression '-' expression
{ $$ = $1 - $3; }
| expression '*' expression
{ $$ = $1 * $3; }
| expression '/' expression
{
if($3 == 0)
yyerror("divide by zero");
else
$$ = $1 / $3;
}
| '-' expression %prec UMINUS
{
$$ = -$2;
}
| '(' expression ')'
{
$$ = $2;
}
| NUMBER
{
$$ = $1;
}
;
%%
#include <readline/readline.h>
#include <readline/history.h>
int yyerror(char *s)
{
fprintf(stderr,"\nBad command");
return 1;
}
void prompt (void)
{
printf("\n>"); fflush (stdout);
}
void allocate (int order)
{
extern char free_page[0];
void *address;
printf("\nallocating a page of %d bytes...",512<<order);
if ((unsigned)order > 21)
printf (" bad order !");
else if ((address = memory_allocate_page (order)))
printf (" page #%d allocated !",((char *)address - free_page) >> 9);
else
printf (" cannot allocate a page !");
}
void release (int page)
{
extern char free_page[0];
void *address = (void *)(free_page + (page << 9));
printf("\nreleasing page #%d...",page);
if ((unsigned)page >= (2*1024*1024/512))
printf (" bad page number !");
else if (memory_release_page (address))
printf (" page #%d released !",page);
else
printf (" cannot release this page !");
}
void spy (int page)
{
extern char free_page[0];
void *address = (void *)(free_page + (page << 9));
printf("\nspying page #%d...",page);
if ((unsigned)page >= (2*1024*1024/512))
printf (" bad page number !");
else
memory_spy_page (address);
}
void dump (void)
{
int order;
printf("\ndumping free pages list...");
for (order = 0; order < 13; ++order)
memory_dump (order);
}
int main ()
{
yyparse();
return 0;
}
int read_input (char *buffer,int max)
{
char *line = 0;
while (1)
{
line = readline ("\n>");
if (!line)
break;
if (*line)
add_history(line);
strncpy (buffer,line,max);
strcat (buffer,";");
free (line);
return strlen (buffer);
}
buffer[0] = ';';
return 1;
}

View File

@ -0,0 +1,72 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id:
*
* Copyright (C) 2002 by Alan Korr
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef __LIBRARY_MEMORY_H__
#error "This header file must be included ONLY from memory.h."
#endif
#ifndef __LIBRARY_MEMORY_TYPES_H__
#define __LIBRARY_MEMORY_TYPES_H__
struct memory_free_page
{
struct memory_free_page
*less,*more;
char
reserved[MEMORY_PAGE_MINIMAL_SIZE - 2*sizeof (struct memory_free_page *)];
};
struct memory_free_block
{
struct memory_free_block
*link;
};
struct memory_cache
{
struct memory_cache
*less,*more,*same;
unsigned int
left; // number of free slabs
struct memory_slab
*used;
struct memory_slab
*free;
struct memory_slab
*reap;
unsigned int
size,original_size;
unsigned int
page_size;
unsigned int
blocks_per_slab;
int
page_order;
unsigned int
flags;
};
struct memory_slab
{
struct memory_slab
*less,*more;
unsigned int // left == number of free blocks left
left;
struct memory_free_block
*free;
};
#endif