Files
player/Project/Src/Drive/Source/mymem.c
2025-09-26 16:57:44 +08:00

569 lines
15 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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); }