This repository has been archived on 2025-02-28. You can view files and clone it, but cannot push or open issues or pull requests.
controller-hd/User/hart/lib/src/malloc.c

339 lines
13 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.

/*
* @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); // 返回新内存首地址
}
}