#include "mymem.h" #include "sdram.h" // 定义是否使用ccm内存,1,使用,0,不使用 #define USE_CCM 0 #ifndef BOOTLOADER #define OS_RTT #ifdef OS_RTT #include "rthw.h" #define IRQ_DISABLE() rt_enter_critical() #define IRQ_ENABLE() rt_exit_critical() #else #include "os.h" #define IRQ_DISABLE() \ { \ CPU_SR_ALLOC(); \ CPU_CRITICAL_ENTER(); \ } #define IRQ_ENABLE() CPU_CRITICAL_EXIT() #endif #else #define IRQ_DISABLE() \ {} #define IRQ_ENABLE() \ {} #endif static void exmem_init(void); // 内存管理初始化函数 static u32 exmem_malloc(u32 size); // 内存分配 static u8 exmem_free(u32 offset); // 内存释放 static void mem_init(void); // 内存管理初始化函数 static u32 mem_malloc(u32 size); // 内存分配 static u8 mem_free(u32 offset); // 内存释放 static void ccm_init(void); void mymem_init(void) { mem_init(); exmem_init(); // ccm_init(); } #define EXMEM_BLOCK_SIZE (256) // 内存块大小为64字节 #define EXMEM_MAX_SIZE \ ((uint64_t)((SDRAM_USER_SIZE)) * EXMEM_BLOCK_SIZE / (EXMEM_BLOCK_SIZE + 2)) #define EXMEM_ALLOC_TABLE_SIZE \ ((u32)(EXMEM_MAX_SIZE / EXMEM_BLOCK_SIZE) & \ (~3)) // 内存表大小,必须为偶数,双字对齐 // 分配的内存都是双字对齐的 #define EXMEM_BASE ((u8 *)(SDRAM_USER_ADDR + EXMEM_ALLOC_TABLE_SIZE * 2)) #define EXMEMMAP_BASE ((u16 *)(SDRAM_USER_ADDR)) // 内存管理参数 u32 exmemtblsize; // 内存表大小 u32 exmemblksize; // 内存分块大小 uint64_t exmemsize; // 内存总大小 // 内存管理控制器 struct _m_mallco_dev exmallco_dev; // 复制内存 //*des:目的地址 //*src:源地址 // n:需要复制的内存长度(字节为单位) void mymemcpy(void *des, void *src, u32 n) { u8 *xdes = des; u8 *xsrc = src; while (n--) *xdes++ = *xsrc++; } // 设置内存 //*s:内存首地址 // c :要设置的值 // count:需要设置的内存大小(字节为单位) void mymemset(void *s, u8 c, u32 count) { u8 *xs = s; while (count--) *xs++ = c; } // 内存管理初始化 // memx:所属内存块 static void exmem_init(void) { exmemtblsize = EXMEM_ALLOC_TABLE_SIZE; // 内存表大小 exmemblksize = EXMEM_BLOCK_SIZE; // 内存分块大小 exmemsize = EXMEM_MAX_SIZE; // 内存总大小 exmallco_dev.membase = EXMEM_BASE; // 内存池 exmallco_dev.memmap = EXMEMMAP_BASE; // 内存管理状态表 exmallco_dev.memrdy = 0; // 内存管理未就绪 mymemset(exmallco_dev.memmap, 0, exmemtblsize * 2); // 内存状态表数据清零 mymemset(exmallco_dev.membase, 0, exmemsize); // 内存池所有数据清零 exmallco_dev.memrdy = 1; // 内存管理初始化OK } // 获取内存使用率 // memx:所属内存块 // 返回值:使用率(0~100) int exmem_perused(void) { u32 used = 0; u32 i; for (i = 0; i < exmemtblsize; i++) { if (exmallco_dev.memmap[i]) used++; } return (used * 10000) / (exmemtblsize); } // 内存分配(内部调用) // memx:所属内存块 // size:要分配的内存大小(字节) // 返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址 static u32 exmem_malloc(u32 size) { signed long offset = 0; u32 nmemb; // 需要的内存块数 u32 cmemb = 0; // 连续空内存块数 u32 i; // if(!mallco_dev.memrdy)mallco_dev.init();//未初始化,先执行初始化 if (size == 0) return 0XFFFFFFFF; // 不需要分配 nmemb = size / exmemblksize; // 获取需要分配的连续内存块数 if (size % exmemblksize) nmemb++; for (offset = exmemtblsize - 1; offset >= 0; offset--) // 搜索整个内存控制区 { if (!exmallco_dev.memmap[offset]) cmemb++; // 连续空内存块数增加 else cmemb = 0; // 连续内存块清零 if (cmemb == nmemb) // 找到了连续nmemb个空内存块 { for (i = 0; i < nmemb; i++) // 标注内存块非空 { exmallco_dev.memmap[offset + i] = nmemb; } return (offset * exmemblksize); // 返回偏移地址 } } return 0XFFFFFFFF; // 未找到符合分配条件的内存块 } // 释放内存(内部调用) // memx:所属内存块 // offset:内存地址偏移 // 返回值:0,释放成功;1,释放失败; static u8 exmem_free(u32 offset) { u32 i; if (!exmallco_dev.memrdy) // 未初始化,先执行初始化 { // mallco_dev.init(); return 1; // 未初始化 } if (offset < exmemsize) // 偏移在内存池内. { u32 index = offset / exmemblksize; // 偏移所在内存块号码 u32 nmemb = exmallco_dev.memmap[index]; // 内存块数量 for (i = 0; i < nmemb; i++) // 内存块清零 { exmallco_dev.memmap[index + i] = 0; } return 0; } else return 2; // 偏移超区了. } //------------------------------------内部SRAM--------------------------------------- #define SRAM_USER_SIZE (110 * 1024) u8 g_sram_mem[SRAM_USER_SIZE]; #define MEM_BLOCK_SIZE (32) // 内存块大小为64字节 #define MEM_MAX_SIZE \ (((SRAM_USER_SIZE)) * MEM_BLOCK_SIZE / (MEM_BLOCK_SIZE + 2)) #define MEM_ALLOC_TABLE_SIZE \ ((MEM_MAX_SIZE / MEM_BLOCK_SIZE) & (~3)) // 内存表大小,必须为偶数,双字对齐 #define SRAM_USER_ADDR ((u32)g_sram_mem) // 分配的内存都是双字对齐的 #define MEM_BASE ((u8 *)(SRAM_USER_ADDR + MEM_ALLOC_TABLE_SIZE * 2)) #define MEMMAP_BASE ((u16 *)(SRAM_USER_ADDR)) // 内存管理参数 u32 memtblsize; // 内存表大小 u32 memblksize; // 内存分块大小 u32 memsize; // 内存总大小 // 内存管理控制器 struct _m_mallco_dev mallco_dev; // 内存管理初始化 // memx:所属内存块 static void mem_init(void) { memtblsize = MEM_ALLOC_TABLE_SIZE; // 内存表大小 memblksize = MEM_BLOCK_SIZE; // 内存分块大小 memsize = MEM_MAX_SIZE; // 内存总大小 // mallco_dev.init=mem_init; //内存初始化 // mallco_dev.perused=mem_perused; //内存使用率 mallco_dev.membase = MEM_BASE; // 内存池 mallco_dev.memmap = MEMMAP_BASE; // 内存管理状态表 mallco_dev.memrdy = 0; // 内存管理未就绪 mymemset(mallco_dev.memmap, 0, memtblsize * 2); // 内存状态表数据清零 mymemset(mallco_dev.membase, 0, memsize); // 内存池所有数据清零 mallco_dev.memrdy = 1; // 内存管理初始化OK } // 获取内存使用率 // memx:所属内存块 // 返回值:使用率(0~100) int mem_perused(void) { u32 used = 0; u32 i; for (i = 0; i < memtblsize; i++) { if (mallco_dev.memmap[i]) used++; } return (used * 10000) / (memtblsize); } // 内存分配(内部调用) // memx:所属内存块 // size:要分配的内存大小(字节) // 返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址 static u32 mem_malloc(u32 size) { signed long offset = 0; u16 nmemb; // 需要的内存块数 u16 cmemb = 0; // 连续空内存块数 u32 i; // if(!mallco_dev.memrdy)mallco_dev.init();//未初始化,先执行初始化 if (size == 0) return 0XFFFFFFFF; // 不需要分配 nmemb = size / memblksize; // 获取需要分配的连续内存块数 if (size % memblksize) nmemb++; for (offset = memtblsize - 1; offset >= 0; offset--) // 搜索整个内存控制区 { if (!mallco_dev.memmap[offset]) cmemb++; // 连续空内存块数增加 else cmemb = 0; // 连续内存块清零 if (cmemb == nmemb) // 找到了连续nmemb个空内存块 { for (i = 0; i < nmemb; i++) // 标注内存块非空 { mallco_dev.memmap[offset + i] = nmemb; } return (offset * memblksize); // 返回偏移地址 } } return 0XFFFFFFFF; // 未找到符合分配条件的内存块 } // 释放内存(内部调用) // memx:所属内存块 // offset:内存地址偏移 // 返回值:0,释放成功;1,释放失败; static u8 mem_free(u32 offset) { int i; if (!mallco_dev.memrdy) // 未初始化,先执行初始化 { // mallco_dev.init(); return 1; // 未初始化 } if (offset < exmemsize) // 偏移在内存池内. { int index = offset / memblksize; // 偏移所在内存块号码 int nmemb = mallco_dev.memmap[index]; // 内存块数量 for (i = 0; i < nmemb; i++) // 内存块清零 { mallco_dev.memmap[index + i] = 0; } return 0; } else return 2; // 偏移超区了. } //------------------------------------内部CCM--------------------------------------- #if USE_CCM == 1 #define CCM_USER_SIZE 64 * 1024 u8 g_ccm_mem[CCM_USER_SIZE] __attribute__((at(0x10000000))); #define CCM_BLOCK_SIZE (32) // 内存块大小为64字节 #define CCM_MAX_SIZE (((CCM_USER_SIZE)) * CCM_BLOCK_SIZE / (CCM_BLOCK_SIZE + 2)) #define CCM_ALLOC_TABLE_SIZE \ ((CCM_MAX_SIZE / CCM_BLOCK_SIZE) & (~3)) // 内存表大小,必须为偶数,双字对齐 #define CCM_USER_ADDR ((u32)g_ccm_mem) // 分配的内存都是双字对齐的 #define CCM_BASE ((u8 *)(CCM_USER_ADDR + CCM_ALLOC_TABLE_SIZE * 2)) #define CCMMAP_BASE ((u16 *)(CCM_USER_ADDR)) // 内存管理参数 u32 ccm_memtblsize; // 内存表大小 u32 ccm_memblksize; // 内存分块大小 u32 ccm_memsize; // 内存总大小 // 内存管理控制器 struct _m_mallco_dev ccm_mallco_dev; // 内存管理初始化 // memx:所属内存块 static void ccm_init(void) { ccm_memtblsize = CCM_ALLOC_TABLE_SIZE; // 内存表大小 ccm_memblksize = CCM_BLOCK_SIZE; // 内存分块大小 ccm_memsize = CCM_MAX_SIZE; // 内存总大小 ccm_mallco_dev.membase = CCM_BASE; // 内存池 ccm_mallco_dev.memmap = CCMMAP_BASE; // 内存管理状态表 ccm_mallco_dev.memrdy = 0; // 内存管理未就绪 mymemset(ccm_mallco_dev.memmap, 0, ccm_memtblsize * 2); // 内存状态表数据清零 mymemset(ccm_mallco_dev.membase, 0, ccm_memsize); // 内存池所有数据清零 ccm_mallco_dev.memrdy = 1; // 内存管理初始化OK } // 获取内存使用率 // memx:所属内存块 // 返回值:使用率(0~100) int ccm_perused(void) { u32 used = 0; u32 i; for (i = 0; i < ccm_memtblsize; i++) { if (ccm_mallco_dev.memmap[i]) used++; } return (used * 10000) / (ccm_memtblsize); } // 内存分配(内部调用) // memx:所属内存块 // size:要分配的内存大小(字节) // 返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址 static u32 ccm_malloc(u32 size) { signed long offset = 0; u16 nmemb; // 需要的内存块数 u16 cmemb = 0; // 连续空内存块数 u32 i; // if(!mallco_dev.memrdy)mallco_dev.init();//未初始化,先执行初始化 if (size == 0) return 0XFFFFFFFF; // 不需要分配 nmemb = size / ccm_memblksize; // 获取需要分配的连续内存块数 if (size % ccm_memblksize) nmemb++; for (offset = ccm_memtblsize - 1; offset >= 0; offset--) // 搜索整个内存控制区 { if (!ccm_mallco_dev.memmap[offset]) cmemb++; // 连续空内存块数增加 else cmemb = 0; // 连续内存块清零 if (cmemb == nmemb) // 找到了连续nmemb个空内存块 { for (i = 0; i < nmemb; i++) // 标注内存块非空 { ccm_mallco_dev.memmap[offset + i] = nmemb; } return (offset * ccm_memblksize); // 返回偏移地址 } } return 0XFFFFFFFF; // 未找到符合分配条件的内存块 } // 释放内存(内部调用) // memx:所属内存块 // offset:内存地址偏移 // 返回值:0,释放成功;1,释放失败; static u8 ccm_free(u32 offset) { int i; if (!ccm_mallco_dev.memrdy) // 未初始化,先执行初始化 { // mallco_dev.init(); return 1; // 未初始化 } if (offset < exmemsize) // 偏移在内存池内. { int index = offset / ccm_memblksize; // 偏移所在内存块号码 int nmemb = ccm_mallco_dev.memmap[index]; // 内存块数量 for (i = 0; i < nmemb; i++) // 内存块清零 { ccm_mallco_dev.memmap[index + i] = 0; } return 0; } else return 2; // 偏移超区了. } #endif // 释放内存(外部调用) // memx:所属内存块 // ptr:内存首地址 void myfree(void *ptr) { IRQ_DISABLE(); u32 free_addr = (u32)ptr; u32 offset; if (ptr == NULL) { IRQ_ENABLE(); return; // 地址为0. } else if ((free_addr & 0xf0000000) == 0x20000000) // sram { offset = (u32)ptr - (u32)mallco_dev.membase; mem_free(offset); // 释放内存 } else { offset = (u32)ptr - (u32)exmallco_dev.membase; exmem_free(offset); // 释放内存 } // printf ("free:%#X\r\n",free_addr); IRQ_ENABLE(); } // 分配内存(外部调用) // 首先尝试在内部分配,失败后再外部分配 // size:内存大小(字节) // 返回值:分配到的内存首地址. void *mymalloc(size_t size) { IRQ_DISABLE(); u32 offset; void *ret_addr = NULL; if (size > 5 * 1024) offset = 0XFFFFFFFF; else offset = mem_malloc(size); if (offset != 0XFFFFFFFF) { ret_addr = (void *)((u32)mallco_dev.membase + offset); } else { offset = exmem_malloc(size); if (offset != 0XFFFFFFFF) { ret_addr = (void *)((u32)exmallco_dev.membase + offset); } } // printf ("malloc:%#X,%d\r\n",(u32)ret_addr,size); IRQ_ENABLE(); return ret_addr; } // 分配内存(外部调用) // 首先尝试在内部分配,失败后再外部分配 // size:内存大小(字节) // 返回值:分配到的内存首地址. void *mymalloc_fast(u32 size) { IRQ_DISABLE(); u32 offset; void *ret_addr = NULL; offset = mem_malloc(size); if (offset != 0XFFFFFFFF) { ret_addr = (void *)((u32)mallco_dev.membase + offset); } else { offset = exmem_malloc(size); if (offset != 0XFFFFFFFF) { ret_addr = (void *)((u32)exmallco_dev.membase + offset); } } // printf ("malloc:%#X,%d\r\n",(u32)ret_addr,size); IRQ_ENABLE(); return ret_addr; } // 分配外部内存(外部调用) // 首先尝试在内部分配,失败后再外部分配 // size:内存大小(字节) // 返回值:分配到的内存首地址. void *mymalloc_exm(u32 size) { IRQ_DISABLE(); u32 offset; void *ret_addr = NULL; offset = exmem_malloc(size); if (offset != 0XFFFFFFFF) { ret_addr = (void *)((u32)exmallco_dev.membase + offset); } IRQ_ENABLE(); return ret_addr; } #if USE_CCM == 1 // 释放CCM内存 void myfree_ccm(void *ptr) { IRQ_DISABLE(); u32 free_addr = (u32)ptr; u32 offset; if (ptr == NULL) { IRQ_ENABLE(); return; // 地址为0. } else if ((free_addr & 0xf0000000) == 0x10000000) // sram { offset = (u32)ptr - (u32)ccm_mallco_dev.membase; ccm_free(offset); // 释放内存 } else { offset = (u32)ptr - (u32)exmallco_dev.membase; exmem_free(offset); // 释放内存 } // printf ("free:%#X\r\n",free_addr); IRQ_ENABLE(); } // 分配CCM内存 void *mymalloc_ccm(u32 size) { IRQ_DISABLE(); u32 offset; void *ret_addr = NULL; offset = ccm_malloc(size); if (offset != 0XFFFFFFFF) { ret_addr = (void *)((u32)ccm_mallco_dev.membase + offset); } else { offset = exmem_malloc(size); if (offset != 0XFFFFFFFF) { ret_addr = (void *)((u32)exmallco_dev.membase + offset); } } IRQ_ENABLE(); return ret_addr; } #endif // 重新分配内存(外部调用) // memx:所属内存块 //*ptr:旧内存首地址 // size:要分配的内存大小(字节) // 返回值:新分配到的内存首地址. void *myrealloc(void *ptr, u32 size) { IRQ_DISABLE(); void *ret_addr; ret_addr = mymalloc_exm(size); if (ret_addr != NULL) { if (ptr != NULL) { mymemcpy(ret_addr, ptr, size); myfree(ptr); } } IRQ_ENABLE(); return ret_addr; } // 分配内存并清零 void *mycalloc(u32 size) { void *ptr = mymalloc(size); if (ptr) mymemset(ptr, 0, size); return ptr; } //////////////////////////////////////////////////////////////////////////////// // 基本调用接口 void *malloc(size_t size) { return mymalloc(size); } void free(void *ptr) { myfree(ptr); } void *realloc(void *ptr, size_t size) { return myrealloc(ptr, size); } void *calloc(size_t nmemb, size_t size) { return mycalloc(nmemb * size); }