569 lines
15 KiB
C
569 lines
15 KiB
C
#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); }
|