[mw_shl_code=c,true]
[mw_shl_code=c,true]声明:纯自学的,基础不实,高手勿笑,请指点,谢谢![/mw_shl_code]
[mw_shl_code=c,true]最近移植了下综合测试的nes模拟器,增加内存管理代码后,用keil4编译时,外部内部内存会视为64K,看了例程的keil5工程也没见有设置扩展ram范围设置,也能编译通过,不知道为什么。。呵呵。。代码没认真研究,所在自己又写了一个内存管理函数,但nes模拟器的nes_ram申请为内部ram时会运行不了,只能选择外部的,不知为什么。。:[/mw_shl_code]
[mw_shl_code=c,true]自学了一段时间,代码有什么看法?大家发表下意见吧:[/mw_shl_code]
[mw_shl_code=c,true]头文件可以配置内存大小信息。[/mw_shl_code]
[mw_shl_code=c,true]介绍:[/mw_shl_code]
[mw_shl_code=c,true]向上生长方式查找,不适合多任务。。没有内存整理功能,中间被释放的太多空段会申请失败。当内申请部内存不够用时会重定向外部申请,所以有时候选择内部时也会申请到外部的内存位置,不要的这个自己注释掉那个重申请的调用。。。[/mw_shl_code]
[mw_shl_code=c,true]外部RAM直接用指针指向外部RAM地址,而不使用数组了![/mw_shl_code]
[mw_shl_code=c,true]使用表用1个bit代表一个块使用状态,申请时会自动多加1个块记录大小信息,释放内存参数自动根据指针地址取出信息,释放时不用增加RAMIN或RAMEX,会自动判断为外部还是内部的,因为我看到nes模拟器有很多释放函数。。。有时会忘记哪个没释放()。。。。而且移植过来时是强行修改外部ram的。。。多打开两次就内存申请失败了。。。不知道为什么[/mw_shl_code]
#ifndef _MEMORY_MALLOC_H
#define _MEMORY_MALLOC_H
#include "typedef.h"
#define RAMIN 0//内
#define RAMEX 1//外
#define MRAM_SIZE (10*1024)//内部ram大小Byte
#define MEXRAM_SIZE (1024*1024)//外部RAM大小Byte
#define MBLOCK_SIZE 16//每个块大小Byte[最小16Byte]
#define M_DEF_DAT 0x00//ram内存初始化值
#define RAM_BLOCK_MAX (MRAM_SIZE/MBLOCK_SIZE)//RAM块数量
#define EXRAM_BLOCK_MAX (MEXRAM_SIZE/MBLOCK_SIZE)//SRAM块数量
#define BP_SIZE 16//每个字节记录的位数[与PDATA_TYPE对应]
typedef unsigned short PDATA_TYPE;//指针与其它数据类型,方便对齐[与表的类型对齐]
#define MCRC_FLAG 0x5555AAAA//使用块效验标志
#define M_ERROR 0xFFFFFFFF//错误
//定义参数使用偏移量[方便改变位置]
#define MP_crc_flag 0//效验标志
#define MP_st_block 1//块起始地址[即信息块起始地直,下一块为用户地址]
#define MP_bl_siz 2//块占用数量[包括1块信息块]
#define MP_class 3//指向RAM类型
//*****************************************************************************
void M_Init(void);//初始化
U8 GetTableUser(U8 n,U32 bl);//获取块使用标志
void SetTableUser(U8 n,U32 bl,U8 b);//设置块使用标志
U32 SeekVoidBlock(U8 n,U32 stbl);//从指定位置查找空位,错误返回 M_ERROR
//用户函数
void *MyMalloc(U8 n,U32 size);//申请指定size(Byte)大小的空间 ,成功返回指针地址,失败返回0
U8 MyFree(void *p);//释放指针内存,成功返回0,失败返回错误ID
void *MyReMalloc(U8 n,void *m);//重定向申请内存
U32 CountVoidBlock(U8 n);//统计空块数量
void SetPointDat(void *p,U8 dat,U32 len);//设置指针指向地址数据
U8 GetMemoryType(void *p);//获取指针所在RAM
U32 GetMemorySize(void *p);//获取指针占用内存大小(Byte)[不包括信息块]
#endif
#include "memory_malloc.h"
#include "system.h"
#ifdef SYS_DEBUG
#include "windows.h"
#endif
U8 Mram[MRAM_SIZE];//虚拟一个ram
VU8 *MRAM_P;//指向内部ram指针
VU8 *MEXRAM_P=((VU8*)(Bank1_SRAM3_ADDR+MALLOC_ADDR_BASIC));//指向外部ram指针
PDATA_TYPE MRAM_TABLE[RAM_BLOCK_MAX/BP_SIZE];//表大小计算[1个U32可记录32块内存块]
PDATA_TYPE MEXRAM_TABLE[EXRAM_BLOCK_MAX/BP_SIZE];//表大小计算[1个U32可记录32块内存块]
PDATA_TYPE *M_TABLE_P[2];//表指针
//********************
void M_Init(void)
{//初始化
U32 i;
M_TABLE_P[RAMIN]=&MRAM_TABLE[0];//RAM表位置
M_TABLE_P[RAMEX]=&MEXRAM_TABLE[0];//SRAM表位置
MRAM_P=&Mram[0];
for(i=0;i<(RAM_BLOCK_MAX/BP_SIZE);i++){MRAM_TABLE=0;}//初始化RAM表
for(i=0;i<(EXRAM_BLOCK_MAX/BP_SIZE);i++){MEXRAM_TABLE=0;}//初始化EXRAM表
for(i=0;i<MRAM_SIZE;i++){*(MRAM_P+i)=M_DEF_DAT;}//初始化内部RAM块
for(i=0;i<MEXRAM_SIZE;i++){*(MEXRAM_P+i)=M_DEF_DAT;}//初始化外部RAM块
}
//***********************
//n为RAM类型
//bl为块
U8 GetTableUser(U8 n,U32 bl)
{//获取块使用标志
return ((*(M_TABLE_P[n]+(bl/BP_SIZE))>>(bl%BP_SIZE))&0x00000001);
}
//*********************************************
void SetTableUser(U8 n,U32 bl,U8 b)
{//设置块使用标志
if(b)
{*(M_TABLE_P[n]+(bl/BP_SIZE))|=(1<<(bl%BP_SIZE));}//置1
else
{*(M_TABLE_P[n]+(bl/BP_SIZE))&=~(1<<(bl%BP_SIZE));}//清0
}
//************************************************
U32 SeekVoidBlock(U8 n,U32 stbl)
{//查找空块,返回空块位,错误返回MERROR
//stbl:起始位置
U32 i,temp;
if(n==RAMIN){temp=RAM_BLOCK_MAX;}else{temp=EXRAM_BLOCK_MAX;}
for(i=stbl;i<temp;i++)
{//查找空位
if(!GetTableUser(n,i)){return i;}//返回空块编号
}
return M_ERROR;//无空位错误
}
//*********************************************************
U32 CountVoidBlock(U8 n)
{//统计空块数量
U32 i,temp,c=0;
if(n==RAMIN){temp=RAM_BLOCK_MAX;}else{temp=EXRAM_BLOCK_MAX;}
for(i=0;i<temp;i++)
{//查找空位
if(!GetTableUser(n,i)){c++;}//空块加1
}
return c;
}
//************************************************************************
void *MyMalloc(U8 n,U32 size)
{//申请指定size(Byte)大小的空间 ,成功返回指针地址,失败返回0
U32 bl_siz;//申请块数量
U32 i=0,temp;
U32 st_block;//首块地址
U32 r_zia;//空块计数
U32 *p;
bl_siz=size/MBLOCK_SIZE;//计算需要占用整块数量
if(size%MBLOCK_SIZE){bl_siz+=1;}//不足整块算整块计算
bl_siz+=1;//多申请1块记录指针信息[首地址用作信息记录]
RE_SEEK:
if(n==RAMIN){temp=RAM_BLOCK_MAX;}else{temp=EXRAM_BLOCK_MAX;}//范围
st_block=SeekVoidBlock(n,i);//从指位置搜索空位
if(st_block==M_ERROR)
{//首内存超出错误
#ifdef SYS_DEBUG
WinAlertScrollbar(0,0,size,n,"MyMalloc_Err:0");
CheckKey();
#endif
if(n==RAMIN)
{//若为内部,则在外部重申请
return MyMalloc(RAMEX,size);//返回
}
return 0;
}//失败返回0
r_zia=0;//清0计数
for(i=st_block;i<temp;i++)
{
if(!GetTableUser(n,i))
{//如果是空块
r_zia+=1;//可用块加1
if(r_zia>=bl_siz){break;}//满足连续块大小退出查找
}
else
{//如果中间有占用,则重新查找下一个空闲起始地址
goto RE_SEEK;
}
}
if(i==temp)//检查是否查找到结尾块
{//如果达到结尾
if(r_zia<bl_siz)//判断查找的可用块是否满足需要大小
{//如果小于需求块
//return 0;
//不使用自动向外申请将下面注释掉
if(n==RAMIN)
{n=RAMEX;i=0;goto RE_SEEK;}//如果是从内部申请内存,则从外部重新查找
else
{return 0;}//申请失败
}
}
for(i=0;i<bl_siz;i++){SetTableUser(n,st_block+i,1);}//设置使用标志
if(n==RAMIN)//基地址加偏移地址
{p=(U32 *)(MRAM_P+(st_block*MBLOCK_SIZE));}
else
{p=(U32 *)(MEXRAM_P+(st_block*MBLOCK_SIZE));}
//记录信息
p[MP_crc_flag]=MCRC_FLAG;//效验标志[释放时用于检测内存有效性]
p[MP_st_block]=st_block;//记录块起始块
p[MP_bl_siz]=bl_siz;//记录块数量包括信息块[用户块应少一块]
p[MP_class]=n;//RAM类型
if(n==RAMIN)
{return (void *)((U32)MRAM_P+((st_block+1)*MBLOCK_SIZE));}//内部RAM
else
{return (void *)((U32)MEXRAM_P+((st_block+1)*MBLOCK_SIZE));}//外部RAM
}
//*********************************************************************
U8 MyFree(void *p)
{//释放内存,成功返回0,失败返回错误ID
U32 i;
U32 *d;
if(!p){return 1;}//如果为空则返回
d=(U32 *)((U32)p-MBLOCK_SIZE);//计算信息基地址
if(d[MP_crc_flag]!=MCRC_FLAG)
{//内存未申请或不存在
#ifdef SYS_DEBUG
WinAlertScrollbar(0,0,(U32)p,d[MP_crc_flag],"MyFree_Err:2");
CheckKey();
#endif
return 2;
}
if(d[MP_class]==RAMIN&&d[MP_bl_siz]>RAM_BLOCK_MAX)
{//超出总块范围错误
#ifdef SYS_DEBUG
WinAlertScrollbar(0,0,(U32)p,d[MP_bl_siz],"MyFree_Err:3");
CheckKey();
#endif
return 3;
}
if(d[MP_class]==RAMEX&&d[MP_bl_siz]>EXRAM_BLOCK_MAX)
{//超出总块范围错误
#ifdef SYS_DEBUG
WinAlertScrollbar(0,0,(U32)p,d[MP_bl_siz],"MyFree_Err:4");
CheckKey();
#endif
return 4;
}
if(((int)d[MP_bl_siz]-1)<1){return 5;}//大小错误
for(i=0;i<d[MP_bl_siz];i++){SetTableUser(d[MP_class],d[MP_st_block]+i,0);}//清空标志位
SetPointDat(d,0,d[MP_bl_siz]*MBLOCK_SIZE);//清0内存值,放在最后,否则ram位置信息会被清除
return 0;
}
//******************************
//重申请
//n:新的内存类型
//m:原地址指针
//成功返回0
void *MyReMalloc(U8 n,void *m)
{
U32 *d;
U32 bl_size;//需要暂存,否则释放后信息丢失
if(!m){return 0;}//如果为空则返回 0
d=(U32 *)((U32)m-MBLOCK_SIZE);//计算信息基地址
bl_size=(d[MP_bl_siz]-1);//记录需要的块数量[不包括信息块]
if(MyFree(m)){return 0;}//释放失败
return MyMalloc(n,bl_size*MBLOCK_SIZE);//重新申请
}
//********************************
//设置指针指向地址数据
//p:指针首地址
//dat:数据
//len:长度
void SetPointDat(void *p,U8 dat,U32 len)
{
u8 *p1 = p;
while(len--)*p1++=dat;
}
//获取指针所在RAM
U8 GetMemoryType(void *p)
{
U32 *d;
if(!p){return 0xFF;}//如果为空则返回错误
d=(U32 *)((U32)p-MBLOCK_SIZE);//计算信息基地址
return d[MP_class];//返回记录的类型
//或通过地址判断
//if((U32)p>=(Bank1_SRAM3_ADDR+MALLOC_ADDR_BASIC)){return RAMEX;}elxe{return RAMIN;}
}
U32 GetMemorySize(void *p)
{//获取指针占用内存大小(Byte)[不包括信息块]
U32 *d;
if(!p){return 0;}//如果为空则返回错误
d=(U32 *)((U32)p-MBLOCK_SIZE);//计算信息基地址
if(((int)d[MP_bl_siz]-1)<1){return 0;}//大小错误
return ((MBLOCK_SIZE*d[MP_bl_siz-1]));
}
[mw_shl_code=c,true]
[/mw_shl_code]
[/mw_shl_code]
[mw_shl_code=c,true][/mw_shl_code]
[mw_shl_code=c,true]
[/mw_shl_code] |