339 lines
13 KiB
C
339 lines
13 KiB
C
/*
|
||
* @Author:
|
||
* @Date: 2023-04-11 08:50:25
|
||
* @LastEditors: xxx
|
||
* @LastEditTime: 2023-06-15 10:23:12
|
||
* @Description:
|
||
* email:
|
||
* Copyright (c) 2023 by xxx, All Rights Reserved.
|
||
*/
|
||
#include "../inc/data_type_def.h"
|
||
#include "../inc/malloc.h"
|
||
|
||
/*****************************************************************************
|
||
* 科普C语言 *
|
||
******************************************************************************
|
||
*__align 作用 :对齐跟数据在内存中的位置有关,也就是内存字节对齐。有点
|
||
* 难理解,需要通过以下举例来理解
|
||
*__attribute__作用:可以设置函数属性、变量属性和类型属性。在这里我们用来绝
|
||
* 对定位地址,即专门指点内存地址
|
||
*
|
||
*实例一:
|
||
* __align(32) uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000)));
|
||
* 意思:定义一个数组,数组大小为MEM2_MAX_SIZE,数组所占的空间能被32整除,其数组
|
||
* 的起始内存地址为0X68000000。
|
||
* 如果MEM2_MAX_SIZE为2,则数组内存空间大小为32字节;如果MEM2_MAX_SIZE为33,则数
|
||
* 组内存空间大小为64字节。
|
||
*
|
||
*实例二:
|
||
struct A{
|
||
char a;
|
||
unsigned int b;
|
||
unsigned char c;
|
||
char d;
|
||
};
|
||
|
||
另一个结构体是:
|
||
structB{
|
||
char a;
|
||
unsigned int b;
|
||
unsigned char c;
|
||
char d;
|
||
}__attribute__((align(8)));
|
||
|
||
sizeof(A) = 12(内存空间大小12个字节)
|
||
sizeof(B) = 8(内存空间大小8个字节)
|
||
********************************************************************************/
|
||
// 内存池(32字节对齐)
|
||
// 可控制的内存大小
|
||
__attribute__((aligned(32))) uint8_t mem1base[MEM1_MAX_SIZE]; // 内部SRAM内存池
|
||
__attribute__((aligned(32))) uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((section(".sram2")));
|
||
// __attribute__((aligned(32))) uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000))); // 外部SRAM内存池
|
||
// 内存管理表
|
||
// 可控制的内存控制块个数(每个内存块大小为32字节)
|
||
uint16_t mem1mapbase[MEM1_ALLOC_TABLE_SIZE]; // 内部SRAM内存池MAP
|
||
uint16_t mem2mapbase[MEM2_ALLOC_TABLE_SIZE];
|
||
// uint16_t mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000 + MEM2_MAX_SIZE))); // 外部SRAM内存池MAP
|
||
|
||
// 内存管理参数
|
||
// const 定义的变量的值是不允许改变的
|
||
// 因为有内部SRAM和外部SRAM,所以用数组
|
||
const uint32_t memtblsize[SRAMBANK] = {MEM1_ALLOC_TABLE_SIZE, MEM2_ALLOC_TABLE_SIZE}; // 内存表大小(即控制多少内存块)
|
||
const uint32_t memblksize[SRAMBANK] = {MEM1_BLOCK_SIZE, MEM2_BLOCK_SIZE}; // 内存分块大小(一块内存块占多少字节内存空间)
|
||
const uint32_t memsize[SRAMBANK] = {MEM1_MAX_SIZE, MEM2_MAX_SIZE}; // 内存池大小(即可以分配的内存空间大小)
|
||
|
||
// 内存管理控制器
|
||
struct _m_mallco_dev mallco_dev =
|
||
{
|
||
my_mem_init, // 内存初始化
|
||
my_mem_perused, // 内存使用率
|
||
mem1base, mem2base, // 内存池
|
||
mem1mapbase, mem2mapbase, // 内存管理状态表
|
||
0, 0, // 内存管理未就绪
|
||
};
|
||
|
||
/*******************************************
|
||
*函数功能 :复制内存里面的数据(从一个内存空间里拷贝数据到另一内存空间里)
|
||
*函数名 :mymemcpy
|
||
*函数参数 :void *des void *src uint32_t n
|
||
*函数返回值:void
|
||
*描述 :
|
||
* *des :目标地址
|
||
* *src :源地址
|
||
* n :要复制的长度(字节为单位)
|
||
*********************************************/
|
||
void mymemcpy(void *des, void *src, uint32_t n)
|
||
{
|
||
// 一般我们不会对要操作的参数指针进行操作
|
||
// 而是通过一个变量指针作为中介,这样是为了出于安全保证
|
||
uint8_t *xdes = des;
|
||
uint8_t *xsrc = src;
|
||
// 变量在++之前,则先用,后++
|
||
// 变量在++之后,先++,后使用
|
||
while (n--)
|
||
*xdes++ = *xsrc++;
|
||
}
|
||
|
||
/*****************************************************
|
||
*函数功能 :设置内存(设置内存空间的值,一般用来对空间清0)
|
||
*函数名 :mymemset
|
||
*函数参数 :void *s uint8_t c uint32_t count
|
||
*函数返回值:void
|
||
*描述 :
|
||
* *s :内存首地址
|
||
* c :要设置的值
|
||
* count :需要设置的内存大小(字节为单位)
|
||
******************************************************/
|
||
void mymemset(void *s, uint8_t c, uint32_t count)
|
||
{
|
||
// 一般我们不会对要操作的参数指针进行操作
|
||
// 而是通过一个变量指针作为中介,这样是为了出于安全保证
|
||
uint8_t *xs = s;
|
||
// 变量在++之前,则先用,后++
|
||
// 变量在++之后,先++,后使用
|
||
while (count--)
|
||
*xs++ = c;
|
||
}
|
||
|
||
/*****************************************************************
|
||
*函数功能 :内存管理初始化
|
||
*函数名 :my_mem_init
|
||
*函数参数 :uint8_t memx
|
||
*函数返回值:void
|
||
*描述 :
|
||
* memx:所属内存块,即是内部SRAM还是外部SRAM的内存块
|
||
*
|
||
* 其实所谓的初始化就是把内存池和内存表(他们的本质就是数组)清0
|
||
******************************************************************/
|
||
void my_mem_init(uint8_t memx)
|
||
{
|
||
mymemset(mallco_dev.memmap[memx], 0, memtblsize[memx] * 2); // 内存状态表数据清零
|
||
mymemset(mallco_dev.membase[memx], 0, memsize[memx]); // 内存池所有数据清零
|
||
mallco_dev.memrdy[memx] = 1; // 内存管理初始化OK,即内存池和内存表都清0了
|
||
}
|
||
|
||
/*****************************************************************
|
||
*函数功能 :获取内存使用率
|
||
*函数名 :my_mem_perused
|
||
*函数参数 :uint8_t memx
|
||
*函数返回值:void
|
||
*描述 :
|
||
* memx:所属内存块,即是内部SRAM还是外部SRAM的内存块
|
||
*
|
||
* 是否占用是通过判断mem1mapbase或mem2mapbase的数组成员是否非0,如果
|
||
* 非0则被占用,之中数组成员值有一定意义,代表占了多少块,如值为10,则表示
|
||
* 该申请了连续10个内存块
|
||
******************************************************************/
|
||
uint8_t my_mem_perused(uint8_t memx)
|
||
{
|
||
uint32_t used = 0;
|
||
uint32_t i;
|
||
// memtblsize:内存表大小(一共内存块数)
|
||
// 遍历内存表数组
|
||
for (i = 0; i < memtblsize[memx]; i++)
|
||
{
|
||
// mallco_dev.memmap[memx]:内存表数组
|
||
// 取出每个成员判断是否非0
|
||
// 非0则是用了
|
||
if (mallco_dev.memmap[memx][i])
|
||
used++;
|
||
}
|
||
|
||
// 使用数量/数量总数*100 = 使用率
|
||
return (used * 100) / (memtblsize[memx]);
|
||
}
|
||
|
||
/*****************************************************************
|
||
*函数功能 :内存分配(内部调用)------确定在内存池的偏移量
|
||
*函数名 :my_mem_malloc
|
||
*函数参数 :uint8_t memx,uint32_t size
|
||
*函数返回值:uint32_t
|
||
*描述 :
|
||
* memx:所属内存块,即是内部SRAM还是外部SRAM的内存块
|
||
* size:要分配的内存大小(字节)
|
||
* 返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
|
||
*
|
||
* 注意:内存表的遍历是从后往前的
|
||
******************************************************************/
|
||
uint32_t my_mem_malloc(uint8_t memx, uint32_t size)
|
||
{
|
||
signed long offset = 0; // 偏移量变量
|
||
uint32_t nmemb; // 需要的内存块数
|
||
uint32_t cmemb = 0; // 连续空内存块数,保证我们申请的内存块是连续的
|
||
uint32_t i;
|
||
// 判断是否已执行了初始化
|
||
if (!mallco_dev.memrdy[memx])
|
||
mallco_dev.init(memx); // 未初始化,先执行初始化
|
||
if (size == 0)
|
||
return 0XFFFFFFFF; // 不需要分配
|
||
// 内存块数 = 申请空间大小(字节单位) / t一个内存块大小(字节单位)
|
||
nmemb = size / memblksize[memx]; // 获取需要分配的连续内存块数
|
||
// 申请空间大小(字节单位) / t一个内存块大小(字节单位) != 0
|
||
// 如果非0则要多申请一块内存块
|
||
if (size % memblksize[memx])
|
||
nmemb++;
|
||
// 内存表的遍历是从后往前的
|
||
for (offset = memtblsize[memx] - 1; offset >= 0; offset--) // 搜索整个内存控制区
|
||
{
|
||
// 判断该内存块是否被占用了
|
||
if (!mallco_dev.memmap[memx][offset])
|
||
cmemb++; // 连续空内存块数增加
|
||
// 保证内存块的连续性
|
||
else
|
||
cmemb = 0; // 连续内存块清零
|
||
// 确定好所有内存块位置后
|
||
if (cmemb == nmemb) // 找到了连续nmemb个空内存块
|
||
{
|
||
for (i = 0; i < nmemb; i++) // 标注内存块非空
|
||
{
|
||
// 开始往内存块在内存表数组的位置标记该内存块被占用
|
||
mallco_dev.memmap[memx][offset + i] = nmemb;
|
||
}
|
||
|
||
// 确定申请空间在内存池数组位置 在内存表数组位置*一个内存块大小(32字节)
|
||
return (offset * memblksize[memx]); // 返回偏移地址
|
||
}
|
||
}
|
||
return 0XFFFFFFFF; // 未找到符合分配条件的内存块
|
||
}
|
||
|
||
/*****************************************************************
|
||
*函数功能 :释放内存(内部调用)------内存池偏移量清除申请空间在内存表的占用标志
|
||
*函数名 :my_mem_free
|
||
*函数参数 :uint8_t memx,uint32_t offset
|
||
*函数返回值:uint32_t
|
||
*描述 :
|
||
* memx:所属内存块,即是内部SRAM还是外部SRAM的内存块
|
||
* size:内存地址偏移(字节)--------也就是在内存池数组的位置
|
||
* 返回值:0,释放成功;1,释放失败;
|
||
*
|
||
******************************************************************/
|
||
uint8_t my_mem_free(uint8_t memx, uint32_t offset)
|
||
{
|
||
int i;
|
||
int index;
|
||
int nmemb;
|
||
|
||
// 判断是否初始化
|
||
if (!mallco_dev.memrdy[memx]) // 未初始化,先执行初始化
|
||
{
|
||
mallco_dev.init(memx);
|
||
return 1; // 未初始化
|
||
}
|
||
|
||
// 判断这个偏移量是否超出了内存池的大小
|
||
if (offset < memsize[memx]) // 偏移在内存池内.
|
||
{
|
||
// 内存表偏移量 = 内存池偏移量/一块内存块大小
|
||
index = offset / memblksize[memx]; // 偏移所在内存块号码
|
||
// 内存表数组成员的值就是申请的块数
|
||
nmemb = mallco_dev.memmap[memx][index]; // 内存块数量
|
||
|
||
for (i = 0; i < nmemb; i++) // 内存块清零
|
||
{
|
||
// 清除申请空间在内存表的标记
|
||
mallco_dev.memmap[memx][index + i] = 0;
|
||
}
|
||
return 0;
|
||
}
|
||
else
|
||
return 1; // 偏移超区了.
|
||
}
|
||
|
||
/*****************************************************************
|
||
*函数功能 :分配内存(外部调用)
|
||
*函数名 :mymalloc
|
||
*函数参数 :uint8_t memx,uint32_t size
|
||
*函数返回值:void *
|
||
*描述 :
|
||
* memx:所属内存块,即是内部SRAM还是外部SRAM的内存块
|
||
* size:内存大小(字节)
|
||
* 返回值:分配到的内存首地址
|
||
******************************************************************/
|
||
void *mymalloc(uint8_t memx, uint32_t size)
|
||
{
|
||
uint32_t offset; // 在内存池数组的偏移量变量
|
||
// 获取在内存池数组的偏移量
|
||
offset = my_mem_malloc(memx, size);
|
||
// 如果申请错误,则返回空地址
|
||
if (offset == 0XFFFFFFFF)
|
||
return NULL;
|
||
// 如果申请成功,则返回申请空间首地址
|
||
else
|
||
return (void *)((uint32_t)mallco_dev.membase[memx] + offset);
|
||
}
|
||
|
||
/*****************************************************************
|
||
*函数功能 :释放内存(外部调用)
|
||
*函数名 :myfree
|
||
*函数参数 :uint8_t memx,void *ptr
|
||
*函数返回值:uint32_t
|
||
*描述 :
|
||
* memx:所属内存块,即是内部SRAM还是外部SRAM的内存块
|
||
* ptr :要释放的内存空间首地址
|
||
******************************************************************/
|
||
void myfree(uint8_t memx, void *ptr)
|
||
{
|
||
uint32_t offset;
|
||
uint32_t n; // 该要释放的空间的空间大小
|
||
if (ptr == NULL)
|
||
return; // 地址为0.
|
||
// 确定申请空间的内存池偏移量
|
||
offset = (uint32_t)ptr - (uint32_t)mallco_dev.membase[memx];
|
||
// 空间占内存池空间的大小
|
||
n = mallco_dev.memmap[memx][offset / memblksize[memx]] * memblksize[memx];
|
||
// 释放内存池对应空间的数据
|
||
mymemset(ptr, 0, n);
|
||
// 释放内存表
|
||
my_mem_free(memx, offset); // 释放内存
|
||
}
|
||
|
||
/*****************************************************************
|
||
*函数功能 :重新分配内存(外部调用)
|
||
*函数名 :myfree
|
||
*函数参数 :uint8_t memx,void *ptr
|
||
*函数返回值:uint32_t
|
||
*描述 :
|
||
* memx:所属内存块,即是内部SRAM还是外部SRAM的内存块
|
||
* ptr :旧内存空间地址首地址
|
||
* size:要重新分配的内存大小(字节)
|
||
******************************************************************/
|
||
void *myrealloc(uint8_t memx, void *ptr, uint32_t size)
|
||
{
|
||
uint32_t offset;
|
||
|
||
// 申请一个新的空间
|
||
offset = my_mem_malloc(memx, size);
|
||
if (offset == 0XFFFFFFFF)
|
||
return NULL;
|
||
else
|
||
{
|
||
// 把旧空间的数据复制到新空间里
|
||
mymemcpy((void *)((uint32_t)mallco_dev.membase[memx] + offset), ptr, size); // 拷贝旧内存内容到新内存
|
||
// 删掉旧空间
|
||
myfree(memx, ptr); // 释放旧内存
|
||
// 返回新空间地址
|
||
return (void *)((uint32_t)mallco_dev.membase[memx] + offset); // 返回新内存首地址
|
||
}
|
||
}
|