/*
 ******************************************************************************
 *              
 *     動的メモリー管理処理
 *     $Id: Malloc.c,v 1.1 2003/05/30 21:25:28 tong Exp $
 *
 ******************************************************************************
 */
#define  MALLOCp
#include "system_h.h"
#include "utility.h"
#include "Malloc.h"
#include "Malloc_heap.h"
#include "yoshi_spec.h"

#include "string.h"
#if DEBUG
#include "utility.h"
#endif

char *topHeap;
char *bottomHeap;

/*
 ******************************************************************************
 *    動的メモリーの確保状況を記録する
 ******************************************************************************
 */
typedef struct malloc_record {
        void    *allocP;
        size_t  requestSize;
        size_t  totalFree;
        size_t  totalAlloc;
        int     blockCnt;
} MLCREC;
// 動的メモリーの確保状況の記録領域
MLCREC mallocRecord = {0};
#if USE_CHECK_POINT
// 動的メモリーの確保状況のリセット
void resetRecord_malloc(void)
{
    clearArea_s(&mallocRecord, sizeof(MLCREC));
}
// 動的メモリーの確保状況の記録処理
void record_malloc(void *allocP, int size)
{
    mallocRecord.allocP = allocP;
    mallocRecord.requestSize = (size_t)size;
    mallocRecord.totalFree  = (size_t)get_mfreeSize();
    mallocRecord.totalAlloc = (size_t)get_mallocSize();
    mallocRecord.blockCnt   = get_freeBlockCnt();
}
#define record_free()              record_malloc(NULL,0)
#endif
/*
 ******************************************************************************
 *
 *    動的メモリー管理の処理
 *
 ******************************************************************************
 */
/* メモリー境界の調整マクロ(現在１６バイト境界) */
#define MEM_ALIGN               16
#define chk_memszFraction(n)    ((n) & (MEM_ALIGN - 1)) 
#define memoryAlign(n)          (chk_memszFraction(n) \
                                 ? ((n) & ~(MEM_ALIGN - 1)) + MEM_ALIGN : (n))
    
/* メモリーブロックの情報構造体 */
typedef unshort t_mmgn;
typedef struct memory_block_information  MBINF;
struct memory_block_information {
       t_mmgn   mark;		/* マジックナンバー */
       unshort  used;
       MBINF    *before;
       MBINF    *next;
       int      size;
#if DEBUG
       int      mPointMark;
       char     *fileName;
       int      lineNumber;
       int      nop;
#endif
};
#define MAGIC_NUMBER             0x0913                 /* マジックナンバー */
#define HEADER_SIZE             (sizeof(MBINF))
#define SIZE_MINIMUM            memoryAlign(HEADER_SIZE + MEM_ALIGN)

/* Malloc メモリーブロックの先頭ブロック */
static MBINF  membkInfo;
#define getP_topMemBlock()      (&membkInfo)
#if FAST_MALLOC
/* 最新の解放ブロックへのポインター */
static MBINF  *lastFreebk = NULL;
#define saveP_lastFreebk(b)     (lastFreebk = (b))
#define loadP_lastFreebk()      (lastFreebk)
#endif

#if DEBUG
static void displayHeader(void *);
#endif
/*
 ******************************************************************************
 *    メモリー割り振り処理の初期化
 ******************************************************************************
 */
#if DEBUG
static void init_mallocHeapArea(void);
#endif
void initial_Malloc(void)
{
    MBINF   *topbk= getP_topMemBlock();
    MBINF   *heepbk; 
    extern char _mallocHeapSegmentStart[];

    topHeap = _mallocHeapSegmentStart;
#if PRODUCT_ROM
    bottomHeap = (char *)(0x80000000 + 0x400000); /* 4M */
#else
    bottomHeap = (char *)(0x80000000 + osMemSize);
#endif
#if DEBUG
    init_mallocHeapArea();	  /* ヒープメモリーのチェック処理の初期化 */
#endif
    /* トップブロックの設定 */
    topbk->mark = MAGIC_NUMBER;
    topbk->used = TRUE;
    topbk->next = topbk->before = heepbk = (MBINF *)getP_topHeap();
    topbk->size = (int)sizeof(membkInfo);

    heepbk->size = TOP_BLOCK_SIZE;
    heepbk->mark = MAGIC_NUMBER;
    heepbk->used = FALSE;
    heepbk->next = heepbk->before = topbk;
#if FAST_MALLOC
    /* 最新の解放領域へのポインターをトップブロックに設定する */
    saveP_lastFreebk(topbk->next);
#endif
#if DEBUG
    PRINTF("Malloc処理の初期化の完了\n");
    PRINTF("Mallocヒープ領域のサイズ %d byte  Mallocヒープ領域  %xh 〜 %xh\n",
	   HEAP_SIZE, __TOP_MALLOC_HEAP, __BOTTOM_MALLOC_HEAP);
#endif
#if 0
PRINTF("HEADER_SIZE = %d %xh\n", HEADER_SIZE, HEADER_SIZE);
PRINTF("SIZE_MINIMUM = %d %xh\n", SIZE_MINIMUM, SIZE_MINIMUM);
PRINTF("&heapMemory[] = %xh \n", heapMemory);
PRINTF("HEAP_SIZE = %d %xh\n", HEAP_SIZE, HEAP_SIZE);
#endif
}
/*
 ******************************************************************************
 *    メモリーブロックの切り出し
 *    (指定メモリーブロックをから指定サイズ分のブロックを切り出し, 切り出した
 *   ブロックの先頭ポインターを返す。
 *     メモリーブロックから要求メモリを取った残りのメモリサイズが SIZE_MINIMUM
 *   より小さければ, その残りメモリも要求メモリに加えて領域を確保する)
 ******************************************************************************
 */
static void *cutMemoryBlock(MBINF *currbk, int size)
{
    /* メモリー割り当て後の残りのブロックサイズを見る */
    if((currbk->size - size) > (int)SIZE_MINIMUM) {
	/* 残りのブロックに空きができる場合 */
	MBINF  *newbk = (MBINF *)((char *)currbk + size);

	/* 新ブロックを生成する */
	newbk->mark = MAGIC_NUMBER;
	newbk->used = FALSE;
	newbk->before = currbk;
	newbk->next = currbk->next;
	newbk->size = currbk->size - size;
	/* 後のブロックに新ブロックを登録する */
	newbk->next->before = newbk;
	/* 前のブロックに新ブロックを登録する */
	currbk->next = newbk;
	currbk->size = size;
    }
#if USE_CHECK_POINT
    if(!currbk)
	record_malloc(NULL, size);
#endif
    return (void *)currbk;
}
/*
 ******************************************************************************
 *    ヒープ領域のメモリーブロックの確保処理
 *    (確保した領域のポインターを返す)
 ******************************************************************************
 */
/* ヒープ領域の先頭からのメモリーブロックの確保処理
   (指定ブロックの前方から, 指定サイズの領域を確保した新ブロックを生成する) */
#define allocate(p,s)       fore_allocate(p,s)
static void *fore_allocate(MBINF *currbk, int size)
{
    currbk = cutMemoryBlock(currbk, size);
    currbk->used = TRUE;
    return (char *)currbk + memoryAlign(HEADER_SIZE);
}
#if TWO_SIDE_MALLOC || OPTIMUM_MALLOC
/* ヒープ領域の後方からのメモリーブロックの確保処理
   (指定ブロックの後方から, 指定サイズの領域を確保した新ブロックを生成する) */
static void *rear_allocate(MBINF *currbk, int size)
{
    MBINF  *newbk;
    int    emptySize = currbk->size - (int)to_16ByteAlign((size_t)size
							  + HEADER_SIZE);
    
    if(emptySize >= (int)SIZE_MINIMUM) {
	MBINF  *beforebk = cutMemoryBlock(currbk, (int)emptySize);
	
	if(!beforebk) {
	    return NULL;
	}
	/* 新ブロックを生成する */
	newbk = beforebk->next;
    }
    else
	/* 新ブロックを生成する */
	newbk = currbk;
    newbk->used = TRUE;
    return (char *)newbk + memoryAlign(HEADER_SIZE);
}
#endif
/*
 ******************************************************************************
 *    メモリーを割り振る
 *    FAST_MALLOC     : 最後に解放された領域から領域確保しようとするので, 高速
 *                    ではあるがメモリーが断片かしやすい。
 *    NORMAL_MALLOC   : ヒープ領域の前方から領域を確保する標準的な malloc。
 *    TWO_SIDE_MALLOC : malloc する領域をヒープ領域の前方, 後方いずれからか
 *                    指定して領域を確保できる。
 *    OPTIMUM_MALLOC  : TWO_SIDE_MALLOCの方式でさらに最適に領域を確保する。
 *
 *    (FAST_MALLOCが有効の場合, Malloc()とrMalloc()の機能的な意味がなくなる)
 ******************************************************************************
 */
#if OPTIMUM_MALLOC
#define optimumProc(obk, cbk) \
        { \
	    if(!cbk->used && (cbk->size >= size)) \
	        if(!obk) \
		    obk = cbk; \
	        else \
		    if(obk->size > cbk->size) \
		        obk = cbk; \
	}
#endif

/* ヒープ領域の先頭からメモリーを確保する */
#if !DEBUG
void *Malloc(t_mlc Size)
#endif
#if DEBUG
void *__Malloc(t_mlc Size)
#endif
{
    int    size = (int)memoryAlign(Size + HEADER_SIZE);
    MBINF  *topbk  = getP_topMemBlock();
    MBINF  *currbk;

#if FAST_MALLOC
    currbk = loadP_lastFreebk();
    /* 最後に解放されたブロックから適当な空き領域を探し割り当てる */
    for(; currbk != topbk; currbk = currbk->next)
	/* 見つかったブロックのサイズが要求サイズを満たせるか見る */
	if(!currbk->used && (currbk->size >= size))
	    return allocate(currbk, size);
    /* ヒープ領域の前方から空きブロックを探し割り当てる */
    for(currbk = topbk->next;
	currbk != loadP_lastFreebk(); currbk = currbk->next)
	/* 見つかったブロックのサイズが要求サイズを満たせるか見る */
	if(!currbk->used && (currbk->size >= size))
	    return allocate(currbk, size);
    return NULL;
#endif
#if NORMAL_MALLOC || TWO_SIDE_MALLOC
    /* ヒープ領域の前方から空きブロックを探し割り当てる */
    for(currbk = topbk->next; currbk != topbk; currbk = currbk->next)
	/* 見つかったブロックのサイズが要求サイズを満たせるか見る */
	if(!currbk->used && (currbk->size >= size))
	    return fore_allocate(currbk, size);
    return NULL;
#endif
#if OPTIMUM_MALLOC
    MBINF  *optmbk = NULL;

    /* ヒープ領域の前方から空きブロックを探し割り当てる */
    for(currbk = topbk->next; currbk != topbk; currbk = currbk->next)
	/* 見つかったブロックのサイズが最適な要求サイズを満たせるか見る */
	optimumProc(optmbk, currbk);
    if(optmbk)
	return fore_allocate(optmbk, size);
    return NULL;
#endif
}

#if !FAST_MALLOC
/* ヒープ領域の後方からメモリーを確保する */
#if !DEBUG
void *rMalloc(t_mlc Size)
#endif
#if DEBUG
void *__rMalloc(t_mlc Size)
#endif
{
#if NORMAL_MALLOC
    return Malloc(Size);
#endif
#if !NORMAL_MALLOC
    int    size = (int)memoryAlign(Size + HEADER_SIZE);
    MBINF  *topbk = getP_topMemBlock();
    MBINF  *currbk;
#if TWO_SIDE_MALLOC

    /* ヒープ領域の後方から空きブロックを探し割り当てる */
    for(currbk = topbk->before; currbk != topbk; currbk = currbk->before)
	/* 見つかったブロックのサイズが要求サイズを満たせるか見る */
	if(!currbk->used && (currbk->size >= size))
	    return rear_allocate(currbk, size);
    return NULL;
#endif
#if OPTIMUM_MALLOC
    MBINF  *optmbk = NULL;

    /* ヒープ領域の後方から空きブロックを探し割り当てる */
    for(currbk = topbk->before; currbk != topbk; currbk = currbk->before)
	/* 見つかったブロックのサイズが最適な要求サイズを満たせるか見る */
	optimumProc(optmbk, currbk);
    if(optmbk)
	return rear_allocate(optmbk, size);
    return NULL;
#endif
#endif
}
#endif
/*
 ******************************************************************************
 *    メモリーを解放する
 ******************************************************************************
 */
#if !DEBUG
void Free(void *block)
#endif
#if DEBUG
static void __Free(void *block)
#endif
{
    MBINF *freebk;

#if !DEBUG
    if(!block || !is_codesegment(block))
	return;
#endif
    
    freebk = (MBINF *)((char *)block - HEADER_SIZE);

#if !DEBUG
    /* メモリー解放ポインターのチェック */
    if(!freebk || !freebk->used || (freebk->mark != MAGIC_NUMBER))
	return;
#endif

    /* 直前のブロックは空き領域か */
    if(!freebk->before->used) {
	freebk->next->before = freebk->before;
	freebk->before->next = freebk->next;
	freebk->before->size += freebk->size;
	freebk = freebk->before;
    }
    /* 直後のブロックは空き領域か */
    if(!freebk->next->used) {
	freebk->next->next->before = freebk;
	freebk->size += freebk->next->size;
	freebk->next = freebk->next->next;
    }
    freebk->used = FALSE;
#if FAST_MALLOC
    /* 最新の解放ブロックをセーブする */
    saveP_lastFreebk(freebk);
#endif
}
/*
 ******************************************************************************
 *    メモリーを再割当てする
 ******************************************************************************
 */
#if !DEBUG
void *Realloc(void *mem, t_mlc Size)
{
    t_mlc omSize = (t_mlc)((MBINF *)((char *)mem - HEADER_SIZE))->size;
    t_mlc cpSize = omSize;
    void  *newMem;
    
    if(Size < omSize)
	cpSize = Size;
    newMem = Malloc(Size);
    cpymem_i(newMem, mem, cpSize);
    Free(mem);
    return  newMem;
}
#endif
/*
 ******************************************************************************
 *    Malloc 領域のチェック
 *    (指定ポインターが Malloc() によって確保した領域か否か判定する。
 *     Malloc() によって確保した領域ならTRUEを返す。)
 ******************************************************************************
 */
int is_mallocArea(void *mem)
{
    if(mem)
	if(is_codesegment(mem))
	    if(is_heapMemory(mem)) {
		MBINF *currbk = (MBINF *)((char *)mem - HEADER_SIZE);
		
		return (currbk->mark == MAGIC_NUMBER);
	    }
    return FALSE;
}
#if DEBUG
/*
 ******************************************************************************
 *    メモリーの状態情報の表示のための設定エリア
 ******************************************************************************
 */
static  int   mMsgSW = FALSE;
static  int   mCnt   = 1;
static  int   mSize  = 0;

#define get_messageSW()       mMsgSW   
#define set_messageSW(m)      (mMsgSW = (m))
#define is_emptyMemory()      (!mSize)
/*
 ******************************************************************************
 *    メモリー内容のダンプ出力
 ******************************************************************************
 */
void dump_memory(void *topmem, int size)
{
    int     i, c;
    unshort *mem = (unshort *)topmem;
    
    i = 0;
    size /= (int)sizeof(unshort);
    while(i < size) {
	PRINTF("%x : ",mem);
	for(c=0; (c<8) && (i<size); c++,i++)
	    PRINTF("%04x ",*mem++);
	PRINTF("\n");
    }
}
#endif
/*
 ******************************************************************************
 *    メモリーの状態情報の表示
 ******************************************************************************
 */
#if DEBUG
void mallocInfor(int mode)
{
    set_messageSW(mode);
}
#endif
#if USE_CHECK_POINT
/* メモリーの確保領域のサイズを返す */
int get_mallocSize(void)
{
    MBINF   *topbk = getP_topMemBlock();
    MBINF   *currbk;
    int     size = 0;

    for(currbk = topbk->next; currbk != topbk; currbk = currbk->next)
	if(currbk->used)
	    size += currbk->size;
     return size;
}
/* メモリーの空き領域のサイズを返す */
int get_mfreeSize(void)
{
    return HEAP_SIZE - get_mallocSize();
}
/* メモリーの空きブロックの件数を返す */
int get_freeBlockCnt(void)
{
    MBINF   *topbk = getP_topMemBlock();
    MBINF   *currbk;
    int     blockCnt = 0;

    for(currbk = topbk->next; currbk != topbk; currbk = currbk->next)
	if(!currbk->used)
	    blockCnt++;
    return blockCnt;
}
#if DEBUG
/* メモリーの空きブロックの各サイズを表示する */
void get_freeBlockSize(void)
{
    MBINF   *topbk = getP_topMemBlock();
    MBINF   *currbk;

    for(currbk = topbk->next; currbk != topbk; currbk = currbk->next)
	if(!currbk->used)
	    PRINTF("%d, ",currbk->size);
}
/* メモリー状態の表示 */
void print_mallocMsg(void)
{
    int  mSize = get_mallocSize();
    
    PRINTF("/ 使用ﾒﾓﾘｰ %d byte / 空きﾒﾓﾘｰ %d byte (空きﾒﾓﾘｰﾌﾞﾛｯｸ数 %d)\n",
	   mSize, HEAP_SIZE - mSize, get_freeBlockCnt());
}
/* メモリーの割り当て件数の計算と表示 */
enum malloc_counter_mode {MALLOC, FREE};
static void displayMessage(int mode, void *Mem, int size, char *file, int line)
{
    char *mem = (char *)Mem - HEADER_SIZE;

    if(!get_messageSW())
	return;
    mode ? PRINTF("○領域解放  %s:%d / ｱﾄﾞﾚｽ %xh / ｻｲｽﾞ %d byte ",
		  file, line, mem, size)
	 : PRINTF("●領域確保  %s:%d / ｱﾄﾞﾚｽ %xh / ｻｲｽﾞ %d byte"
		  "(ﾍｯﾀﾞｰ含む) / 件数 %d ",
		  file, line, mem, size, get_freeBlockCnt());
    PRINT_MALLOCMSG;
}
/* メモリー割り当て個所のヘッダー情報 */
static void displayHeader(void *mem)
{
    if(get_messageSW() && mem) {
	PRINTF("  ヘッダー情報 = ");
	dump_memory((char *)mem - HEADER_SIZE, HEADER_SIZE);
    }
}
#endif // DEBUG
#endif // USE_CHECK_POINT

#if USE_CHECK_POINT
#if DEBUG
/*
 ******************************************************************************
 *    "メモリー確保個所情報"の登録と表示
 ******************************************************************************
 */
static  int  mPointMarkSW = FALSE;
#define get_mallocMark()      mPointMarkSW   
/* メモリーマークのスイッチの設定 */
void set_mallocMark(int mode)
{
    mPointMarkSW = mode;
}
/* "メモリー確保個所情報"の登録 */
static void set_mallocPoint(void *Mem, char *file, int line)
{
    MBINF *currbk = (MBINF *)((char *)Mem - HEADER_SIZE);

    currbk->fileName = file;
    currbk->lineNumber = line;
    currbk->mPointMark = get_mallocMark();
}
/* "メモリー確保個所情報"の表示
   (ヘッダーを除く割り当てメモリーの先頭ポインターを与える。
    ヘッダーを除く割り当てメモリーのサイズを返す。)*/
int print_mallocPoint(void *Mem)
{
    MBINF *currbk = (MBINF *)((char *)Mem - HEADER_SIZE);

    if(!is_mallocArea(Mem)) {
	PRINTF("Malloc()されたポインターではない!!\n");
	return 0;
    }
    PRINTF("●未解放領域 ｱﾄﾞﾚｽ %xh / ｻｲｽﾞ %d byte (%s:%d)\n",
	   Mem, currbk->size,
	   currbk->fileName,  currbk->lineNumber);
    return currbk->size;
}
/*
 ******************************************************************************
 *    未解放メモリーの情報を表示する
 ******************************************************************************
 */
/* すべての未解放メモリー情報を表示 */
void print_UnfreeInfo(void)
{
    MBINF   *topbk = getP_topMemBlock();
    MBINF   *currbk;
    int     size = 0;
 
    for(currbk = topbk->next; currbk != topbk; currbk = currbk->next)
	if(currbk->used)
	    size += print_mallocPoint((char *)currbk + HEADER_SIZE);
    if(size)
	PRINTF("未解放領域のトータルサイズ %d \n", size);
    else
	PRINTF("未解放領域は無い\n");
}
/* マークのついている未解放メモリー情報を表示 */
void print_MarkUnfreeInfo(void)
{
    MBINF   *topbk = getP_topMemBlock();
    MBINF   *currbk;
    int     size = 0;
 
    for(currbk = topbk->next; currbk != topbk; currbk = currbk->next)
	if(currbk->used && currbk->mPointMark)
	    size += print_mallocPoint((char *)currbk + HEADER_SIZE);
    if(size)
	PRINTF("マーク範囲内の未解放領域のトータルサイズ %d \n", size);
    else
	PRINTF("マーク範囲内の未解放領域は無い\n");
}
/*
 ******************************************************************************
 *    領域確保/解放後の"メモリー埋め"の許可設定
 ******************************************************************************
 */
static int  fillAreaFg = TRUE;
/* "メモリー埋め"をするか確認 */
int is_fillArea(void)
{
    return fillAreaFg;
}
/* "メモリー埋め"の許可設定 */
void fillArea_OnOff(int fg)
{
    fillAreaFg = fg;
}
/*
 ******************************************************************************
 *    メモリーチェインを表示する
 ******************************************************************************
 */
void dump_memoryChain(void)
{
    MBINF   *topbk = getP_topMemBlock();
    MBINF   *currbk;

#if 0
    PRINTF("トップブロック\n");
    PRINTF("before=%x next=%x \n", topbk->before, topbk->next);
    PRINTF("ヘッダー\n");
    dump_memory(topbk, HEADER_SIZE);
#endif
    for(currbk = topbk->next; currbk != topbk; currbk = currbk->next) {
	if(currbk->used)
	    PRINTF("●確保領域  %xh - %d byte (%s:%d)\n",
		   currbk,
		   currbk->size,
		   currbk->fileName,
		   currbk->lineNumber);
	else
	    PRINTF("○空き領域  %d byte\n", currbk->size);
    }
#if 0
    PRINTF("ブロック\n");
    PRINTF("before=%x next=%x \n", currbk->before, currbk->next);
    PRINTF("ヘッダー\n");
    dump_memory(currbk, HEADER_SIZE);
#endif
}
/*
 ******************************************************************************
 *    デバッグ支援コードを含む メモリーを割り振り処理
 ******************************************************************************
 */
#include "entryManager.h"
void *dbg_Malloc(t_mlc size, MALLOCPRC malloc, char *file, int line)
{
    void  *mem;
    
    C_CHECK_MALLOC();
    if(size <= 0) {
	PRINTF(__ERROR"Malloc() : Malloc()サイズの指定がおかしい。"
	       "%d byte!!(%s : %d)\n",
	       size,
	       file, line);
	return NULL;
    }
    if(!(mem = (*malloc)(size))) {
	PRINTF(__WARNING"Malloc() : 割り当てる領域が無い!! "
	       "(%s:%d 要求サイズ %d byte) \n", file, line, size);
	PRINT_MALLOCMSG;
#if 0
	print_entryCount();
	dump_memoryChain();
#endif
	return mem;
    }
    set_mallocPoint(mem, file, line);
    displayMessage(MALLOC,
		   mem, (int)memoryAlign(size + HEADER_SIZE), file, line);
    displayHeader(mem);
#if 0
    if(is_fillArea())
	fillArea_s(mem, size, MALLOC_FILLCODE);
#endif
#if 0
    dump_memoryChain();
    dump_memory((char *)0x801f4240 - 0x250, 0x4A0);
#endif
    return mem;
}
void  *debugMalloc(t_mlc size, char *file, int line)
{
    return dbg_Malloc(size, __Malloc, file, line);
}
/*
 ******************************************************************************
 *    デバッグ支援コードを含む メモリーを解放処理
 *    (メモリー解放に失敗すれば FALSE を返す)
 ******************************************************************************
 */
/* コードセグメントかチェックする */
int dbg_Free(void *mem, char *file, int line)
{
    MBINF *freebk;
    int   freeSize;

    if(!mem)
	return TRUE;
    if(!is_codesegment(mem)) {
	PRINTF(__ERROR"Free() : 解放しようとしたメモリーは"
	       "コードセグメントではない!!(%s : %d mem=%x)\n",
	       file, line, mem);

	return FALSE;
    }

    freebk = (MBINF *)((char *)mem - HEADER_SIZE);

    if(!freebk) {
	PRINTF(__ERROR"Free() : Malloc()されたメモリーポイントではない!!"
	       "(%s : %d mem=%x)\n", file, line, mem);
	return FALSE;
    }
    if(!freebk->used) {
	PRINTF("Free()の警告 : "
	       "NULL設定されていないすでに解放済みのメモリーを"
	       "解放しようとした!!(%s : %d mem=%x) \n", file, line, mem);
	dump_memory((char *)freebk, 32);
	return FALSE;
    }
    freeSize = freebk->size;
    if(freebk->mark != MAGIC_NUMBER) {
	PRINTF(__ERROR"Free() : 解放しようとしたメモリーは"
	       "侵食されているか, Malloc()されたポインターではない!!"
	       " %s : %d mem=%x mark=%x\n", file, line, mem, freebk->mark);
	return FALSE;
    }
    displayMessage(FREE, mem, freeSize, file, line);
#if 0
    if(is_fillArea())
	fillArea_s(mem, (t_mlc)freeSize - HEADER_SIZE, FREE_FILLCODE);
#endif
    __Free(mem);
    displayHeader(mem);
#if 0
    dump_memory((char *)0x801f4240 - 0x250, 0x4A0);
#endif
}
int debugFree(void *mem, char *file, int line)
{
    return dbg_Free(mem, file, line);
}
/*
 ******************************************************************************
 *    デバッグ支援コードを含む メモリーを再割当て処理
 ******************************************************************************
 */
void *Realloc(void *mem, t_mlc Size)
{
    t_mlc omSize = (t_mlc)((MBINF *)((char *)mem - HEADER_SIZE))->size;
    t_mlc cpSize = omSize;
    void  *newMem;
    
    if(omSize < Size)
	cpSize = Size;
    newMem = __Malloc(Size);
    if(!newMem) {
	PRINTF("%d byte のメモリーを再割当てできませんでした!!\n", Size);
	return NULL;
    }
    cpymem_c(newMem, mem, cpSize);
    __Free(mem);
    return  newMem;
}
/*
 ******************************************************************************
 *    Malloc()テスター
 ******************************************************************************
 */
int Tester_of_malloc(void)
{
    void  *mem1, *mem2, *mem3;

    mem1 = Malloc(100);
    mem2 = Malloc(160);
    mem3 = Malloc(256);

    Free(mem1);
    Free(mem2);
    Free(mem3);

    if(is_emptyMemory()) {
	PRINTF("Malloc() Free()テスト 正常 終了\n");
	return TRUE;
    }
    PRINT_MALLOCMSG;
    PRINTF(__ERROR"Malloc() Free()テスト 異常 終了!!\n");
    return FALSE;
}   
/*
 ******************************************************************************
 *
 *    mallocヒープ領域の状態をチェックする
 *
 ******************************************************************************
 */
/*
 ******************************************************************************
 *    mallocヒープ領域の状態を見る
 *    (メモリー侵食があれば, 侵食ブロックのポインターを返し, 戻り値に
 *   エラーの種別コードを返す)
 ******************************************************************************
 */
/* ヒープ領域の先頭/後方のマジック領域にマジックナンバーを入れる */
static void init_mallocHeapArea(void)
{
    t_mmgn  *heapHeaderP = (t_mmgn *)getP_heapHeader();
    t_mmgn  *heapFooterP = (t_mmgn *)getP_heapFooter();
    int     i;
    
    for(i=0; i<(int)(MAGIC_SIZE / sizeof(t_mmgn)); i++) {
	*heapHeaderP++ = MAGIC_NUMBER;
	*heapFooterP++ = MAGIC_NUMBER;
    }
}
enum {
    NORMAL_HEAP,		/* 正常 */
    ERR_MALLOC_BLOCK,		/* mallocブロックの異常 */ 
    ERR_HEAP_HEADER,            /* ヒープ領域の先頭の異常 */
    ERR_HEAP_FOOTER,            /* ヒープ領域の後方の異常 */
    ERR_MALLOC_BLOCK_P		/* mallocトップブロックの異常 */ 
};
/*   mallocヒープ領域の状態を見る  */
static int chk_mallocHeapArea(MBINF **beforebk, MBINF **currbk)
{
    int     i;

    /* Malloc ヒープ領域の前後のメモリー侵食をチェックする */
    {
	t_mmgn  *heapHeaderP = (t_mmgn *)getP_heapHeader();
	t_mmgn  *heapFooterP = (t_mmgn *)getP_heapFooter();
	
	for(i=0; i<(int)(MAGIC_SIZE / sizeof(t_mmgn)); i++) {
	    if(*heapHeaderP++ != MAGIC_NUMBER)
		return ERR_HEAP_HEADER;
	    if(*heapFooterP++ != MAGIC_NUMBER)
		return ERR_HEAP_FOOTER;
	}
    }
    /* メモリーブロックのチェーンを追跡し, 侵食の有無をチェックする */
    {
	MBINF   *topbk = getP_topMemBlock();
	
	if(!is_heapMemory(topbk->before) || !is_heapMemory(topbk->next))
	    return ERR_MALLOC_BLOCK_P;
	*beforebk = *currbk = NULL;
	for(*currbk = topbk->next;
	    *currbk != topbk;
	    *beforebk = *currbk, *currbk = (*currbk)->next) {
	    if(!is_heapMemory((char *)*currbk)
	       || !is_heapMemory((char *)*currbk + HEADER_SIZE)) {
		return ERR_MALLOC_BLOCK;
	    }
	    if((*currbk)->mark != MAGIC_NUMBER)
		return ERR_MALLOC_BLOCK;
	}
    }
    return NORMAL_HEAP;
}
/*
 ******************************************************************************
 *    Malloc()のメモリーを調査する
 *    (メモリー侵食があれば, 侵食情報を表示し戻り値に TRUE を返す)
 ******************************************************************************
 */
/* mallocブロックの侵食エラーメッセージの表示 */
static disp_mallocBlockError(MBINF *beforebk, MBINF *currbk)
{
    if(beforebk) 
	PRINTF("▼ 侵食している領域  ｱﾄﾞﾚｽ %xh / ｻｲｽﾞ %d byte (%s : %d)\n",
	       (char *)beforebk + HEADER_SIZE,
	       beforebk->size,
	       beforebk->fileName,
	       beforebk->lineNumber);
    PRINTF("× 侵食されている領域 ｱﾄﾞﾚｽ %xh \n", (char *)currbk + HEADER_SIZE);
    PRINTF("*** 侵食場所 ***\n");
    dump_memory(currbk, HEADER_SIZE);
    PRINTF("*** ダンプ出力結果 *** \n");
    dump_memory((char *)currbk - 100, 200);
#if 0
    PRINTF("*** メモリーチェインの表示 ***\n");
    dump_memoryChain();
#endif
    PRINTF("\n");
}
/* mallocヒープ領域の先頭の侵食エラーメッセージの表示 */
static 	disp_heapHeaderError(void)
{
    PRINTF("mallocヒープ領域の先頭が侵食されている!!\n");
    PRINTF("× 侵食されている領域 \n");
    dump_memory(getP_heapHeader(), MAGIC_SIZE);
}
/* mallocヒープ領域の後方への侵食エラーメッセージの表示 */
static 	disp_heapFooterError(void)
{
    MBINF *beforebk = getP_topMemBlock()->before;
    
    PRINTF("mallocヒープ領域の最後のブロックから, "
	   "ヒープ領域外へ侵食している!!\n");
    PRINTF("▼ 侵食している領域  ｱﾄﾞﾚｽ %xh / ｻｲｽﾞ %d byte (%s : %d)\n",
	   (char *)beforebk + HEADER_SIZE,
	   beforebk->size,
	   beforebk->fileName,
	   beforebk->lineNumber);
    PRINTF("× 侵食されている領域 \n");
    dump_memory(getP_heapFooter(), MAGIC_SIZE + 16);
}
/*  Malloc()のメモリーを調査する */
int check_mallocHeap(char *files, int line)
{
    MBINF  *currbk, *beforebk;
    int    errNum = chk_mallocHeapArea(&beforebk, &currbk);

    if(errNum == NORMAL_HEAP)
	return FALSE;
    PRINTF("\nメモリー侵食の観察個所 %s : %d\n", files, line);
    switch(errNum) {
    case ERR_MALLOC_BLOCK :
	disp_mallocBlockError(beforebk, currbk);
	return TRUE;
    case ERR_HEAP_HEADER :
	disp_heapHeaderError();
	return TRUE;
    case ERR_HEAP_FOOTER :
	disp_heapFooterError();
	return TRUE;
    case ERR_MALLOC_BLOCK_P :
	PRINTF("mallocのトップブロックが異常!! \n");
	dumpMem(getP_topMemBlock(), 128);
  	return TRUE;
    default :
	break;
    }
    return FALSE;
}
/*
 ******************************************************************************
 *    Malloc()のメモリーの状態をチェックする。
 *    (コントローラ入力によってメモリーチェックの起動/停止をコントロール
 *   できる。
 *     メモリー侵食があれば TRUE を返す)
 ******************************************************************************
 */
static memChk = FALSE;
// メモリーチェック処理のコントロール
void memChkControl(void)
{
    if(chkButtonC2(Z_BTN) && chkTriggerC2(A_BTN)) {
	memChk ^= TRUE;
	if(memChk)
	    PRINTF("** メモリーチェックの起動 !! \n");
	else
	    PRINTF("** メモリーチェックの停止 !! \n");
    }
}
// メモリー侵食チェック
int c_check_mallocHeap(char *files, int line)
{
    if(memChk)
	return check_mallocHeap(files, line);
    return FALSE;
}
#endif   // DEBUG


#endif   // USE_CHECK_POINT
