如何为SoC做ARM CPU适配——以裸核使用malloc为例

这篇具有很好参考价值的文章主要介绍了如何为SoC做ARM CPU适配——以裸核使用malloc为例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文任务:为陌生的SoC平台编写基础软件,适配 malloc() 函数

0 如何为SoC做ARM CPU适配

今时不同往日,我们平时开发/娱乐接触到的消费级MCU/MPU基本山都是包含处理核与一系列外设的SoC。如果熟悉裸片开发,一定会在厂家提供的标准库或者SDK包里找到命名类似 startup.s 的汇编文件;如果熟悉 Linux 移植,则不难联想到 arch/arm/kernel 或者 arch/arm/boot 目录下也有类似的文件。

1 Start.s 是什么

startup.s 文件是引导程序的入口点,通常包含引导加载程序需要执行的初始化代码。这些代码负责设置堆栈、加载内核映像到内存中以及跳转到内核入口点。该文件中常见的内容包括:

  • 中断向量和异常处理程序(interrupt handlers):操作系统需要处理各种中断和异常情况,startup.s 文件通常包含中断向量表的定义和异常处理程序的初始化代码。它会设置和配置中断控制器,并将中断向量指向相应的处理函数。

  • 硬件初始化(init):startup.s 文件可能包含对硬件设备的初始化代码,例如启动时钟、初始化串口、启用内存管理单元(MMU)等。这些代码为操作系统提供了基本的硬件支持。

  • 运行环境设置(config):startup.s 文件可能包含设置运行环境所需的代码。例如,它可以设置执行状态,如处理器模式、特权级别等。还可能设置全局变量或数据结构来存储关键的运行时信息。

  • 内核入口点(entry point):最后,startup.s 文件通常将控制权传递给内核的入口函数。这个内核入口点是操作系统初始化的起点,它接收传递的参数和启动信息,并开始执行操作系统的初始化过程。

熟悉意法半导体的 STM32 微控制器的,就知道类似于中断向量表这些最最最最最基本的配置,一般都是放在 startup.s 里面的。宽泛地说,所有围绕 startup.s 文件开展的工作,就是芯片原厂需要做的 SoC 处理器软件适配,具体到ARM Cortex-A,则可以称作是 CPU软件适配。

2 需要考虑哪些问题?

2.1 提供 malloc 函数实现

既然目标在是在裸核上调用 malloc(),那首先得提供一个它的实现吧。

malloc 函数是 C 标准库中的动态内存分配函数。它用于在程序运行时从堆(Heap)中分配指定大小的内存块,并返回该内存块的起始地址。

使用 malloc 函数可以动态地分配内存,避免了在编译时静态地分配内存的限制。这对于需要在运行时根据需要分配或释放内存的情况非常有用。

malloc 函数的原型如下:

void *malloc(size_t size);

参数 size 指定所需内存块的大小,以字节为单位。返回值是一个指向分配的内存块起始地址的指针,类型为 void*。如果分配失败,则返回 NULL。

malloc这种标准函数,处理器厂商都会提供专门优化的实现,比如 ARM 就针对 ARM 处理器提供买了MicroLib库。这是一个精简的 C 标准库,包含常见的标准库函数,例如内存分配和释放(通过 mallocfree)、字符串操作(例如 strcpystrlen)以及输入输出函数(如 printfscanf)。一般在IDE的工程属性设置中勾选包含即可。

如何为SoC做ARM CPU适配——以裸核使用malloc为例,从物理定律到编程语言,arm开发,嵌入式,soc,移植

2.2 提供入口点(entry point)

处理器上电以后从预定位置执行ROM程序,而后跳转到RAM上指定位置执行应用程序,虽然C程序的主流程在main函数中描述,但无论是ROM还是RAM,第一条指令都不是main的入口,那么就需要咱提供跳转到main函数的指令,形如:

	.global main_app
	.balign 0x10
_reset:
	B	main_app

解析每条指令的含义如下:

.global main_app: 这是一个指令宏,用于声明 main_app 是一个全局标识符,该标识符可以在其他文件中引用。

.balign 0x10: 这是对齐指令,将下一个标签或指令地址对齐到 16 字节边界。这种对齐可能对于某些处理器或内存访问要求是必要的,例如某些 ARM 处理器可能需要特定的对齐方式以获得最佳性能。

_reset:: 这是一个标签,用于将 _reset 和下一个指令或数据相关联。标签可以用于跳转、调用或在汇编代码中创建有意义的位置。

B main_app: 这是无条件分支指令(Branch),将程序流转移到名为 main_app 的位置。B 指令将控制权直接跳转到指定的地址。

这段汇编代码的意图是:通过 _reset 标签将程序引导到 main_app 代码的入口点。在 _reset 处,执行一个无条件的分支指令 B,将控制权转移到 main_app 标签/符号(涉及编译原理)处的代码。

2.3 初始化堆栈指针

跳转到main函数的最终目的,是调用malloc函数,而arm处理器上执行函数调用势必发生压栈、出栈等堆栈操作,故而需要提前设置好堆栈,于是我们修改 startup.s 为:

	.set stack_top, 0x2E009000
	.global main_app
.balign 0x10
_reset:
	ldr r3, =stack_top
	mov sp, r3
	B	main_app

.set stack_top, 0x2E009000: 这是一个宏定义,表示将标识符 stack_top 的值设置为 0x2E009000。在这里,stack_top 被用来表示栈顶的地址,即堆栈将会从这个地址开始增长。

ldr r3, =stack_top: 这条指令将 stack_top 的值加载到寄存器 r3 中。

mov sp, r3: 这条指令将 r3 中的值移动到堆栈指针寄存器 sp 中。

2.4 整个程序应该放在什么地方运行?

自然是RAM中啦,软件设计人员应该找系统设计人员要一张系统架构图/地址分配表,据之明确片上存储器的位置和存储容量,然后才能确定如何编写链接文件。

啥是链接文件啊?链接文件(Linker file),也称为链接脚本(Linker script)或连接器脚本,是用于指导链接器(Linker)如何将多个目标文件(Object file)组合在一起以生成可执行文件的文本文件。

我们目前的地址分配表是这样的:
如何为SoC做ARM CPU适配——以裸核使用malloc为例,从物理定律到编程语言,arm开发,嵌入式,soc,移植
可以看到 System RAM 的起始地址是0x2E000000,存储容量是64KB,这就是我们的程序在运行时所处的位置(不考虑更上层的Cache和寄存器)。大概划分一下用途,前面 0x9000 的空间用来放指令,从 0x200E9000 开始的空间则用作堆(heap),即 mallocfree 函数管理的空间。
如何为SoC做ARM CPU适配——以裸核使用malloc为例,从物理定律到编程语言,arm开发,嵌入式,soc,移植
对应的链接脚本可以写成:

LOAD_REGION 0x2E000000 0x10000
{
	P0 +0
    {
       start_up.o
    }
    P1 +0
    {
        *(+ro)
        *(+rw, +zi)
    }
    
    ARM_LIB_STACK	+0 ALIGN 8 EMPTY 0x1000 {}

    ARM_LIB_HEAP 0x2E009000 EMPTY 0x7000 ; Heap region growing up
    { }
}

可视化的效果为:
如何为SoC做ARM CPU适配——以裸核使用malloc为例,从物理定律到编程语言,arm开发,嵌入式,soc,移植

2.5 堆栈指针的初始值是怎么确定的?

原则就一句话——只要保证栈不会和堆或者代码段发生交叠(overlap)就行。这里我把栈放在代码段后面(0x200E9000之前),故而初始值设为:

.set stack_top, 0x2E009000

3 怎么验证适配效果?

答案是不外乎仿真、实测、反汇编三板斧。

3.1 实测验证

前两个很明白,写个测试程序看看适配的函数行为是否符合预期就行,例如用下面这个程序测试 mallocfree

/*
 * author water cutter
 * */
#include <stdlib.h>

unsigned int* ptrs[32] = {0};
unsigned int allocByteNum = 1;

void main_app(){
	ptrs[0] = (unsigned int*)malloc(allocByteNum);
	ptrs[1] = (unsigned int*)malloc(allocByteNum);
	ptrs[2] = (unsigned int*)malloc(allocByteNum);
	free(ptrs);
	ptrs[3] = (unsigned int*)malloc(allocByteNum);
	while(1){ asm("nop"); }
}

比较ptrs[2]和ptrs[3]的值,一致则说明malloc和free功能正确(保证所有分配的地址都在堆空间范围内的前提下):

如何为SoC做ARM CPU适配——以裸核使用malloc为例,从物理定律到编程语言,arm开发,嵌入式,soc,移植

3.2 通过反汇编检验

.axf 或者 .out 文件反汇编,在反汇编文件中找到对应的实现,分析确认其功能正确即可。

free() 的反汇编:
如何为SoC做ARM CPU适配——以裸核使用malloc为例,从物理定律到编程语言,arm开发,嵌入式,soc,移植
malloc() 的反汇编:
如何为SoC做ARM CPU适配——以裸核使用malloc为例,从物理定律到编程语言,arm开发,嵌入式,soc,移植

源码

源码仓库:soc_port_method文章来源地址https://www.toymoban.com/news/detail-584411.html

到了这里,关于如何为SoC做ARM CPU适配——以裸核使用malloc为例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 如何根据需求理解CPU、SoC和MCU的区别

    在当今数字化的世界中,我们经常听到关于CPU、SoC和MCU的名词,它们都是计算机科学和电子工程领域中的重要组成部分。然而,这三者之间存在着明显的区别。本文将深入探讨CPU(中央处理器)、SoC(系统芯片)和MCU(微控制器)的定义、功能和应用领域,以帮助读者更好地

    2024年02月19日
    浏览(43)
  • 利用AHB-Lite总线实现ARM Cortex-M0基础的SoC系统;如何设计一个SoC系统;AHB-Lite;ARM Cortex-M0;SoC;

      本文讨论了SoC系统的架构设计,包括处理器核心、内存以及其他外设的互连,并详细描述了如何通过AHB-Lite总线实现高效的数据传输。AHB-Lite总线是一种简化版本的AHB总线。同时,阐述了利用寄存器映射以及其他硬件资源与软件接口的设计方法,以满足SoC系统的功能需求。

    2024年02月06日
    浏览(64)
  • RISCV SOC项目(基于蜂鸟E203开源RISCV CPU)

    快年底了,会有一些空余时间,准备抽出一些时间实现一个基于RISCV的SOC芯片,完成之前给自己设定的目标。 1)ZYNQ 7010开发板 之前读研的时候购买的领航者ZYNQ 7010开发板(工作忙,放置3年了。。。) 2)E203 RISCV 开源CPU CORE 链接:https://github.com/riscv-mcu/e203_hbirdv2 第二版蜂鸟

    2024年02月15日
    浏览(38)
  • 【ARM Coresight SOC-600 -- ETF 介绍】

    请阅读 【ARM Coresight SoC-400/SoC-600 专栏导读】

    2024年04月28日
    浏览(38)
  • CPU,GPU,MCU,SOC,NPU,DPU,内核,架构简略区分

    1.架构 架构由不同的指令集构成,不同的侧重方向的指令集构成不同的软件架构,如ARM架构和X86架构等。 2.内核 内核可以看做是不同的软件架构,铺设上一些外设之后构成,相当于软件架构的载体实现,架构是一堆软件代码,内核放置架构指令代码,并进行基础实现 3.cpu C

    2024年02月16日
    浏览(46)
  • ARM 多核 SoC 面临缓存一致性困境

    快速链接: . 👉👉👉 个人博客笔记导读目录(全部) 👈👈👈 付费专栏-付费课程 【购买须知】: 【精选】ARMv8/ARMv9架构入门到精通-[目录] 👈👈👈 联系方式-加入交流群 ---- 联系方式-加入交流群 在此探索 Cadence IP ARM 正在通过多核处理器将其固有的低功耗架构提升到更高的性

    2024年02月03日
    浏览(70)
  • 【ARM CoreLink 系列 1 -- SoC 片上互联介绍】

    下篇文章:【ARM CoreLink 系列 1.1 – CoreLink 系列 产品介绍】 在摩尔定律的推动下,集成电路工艺取得了高速发展,单位面积上的晶体管数量不断增加。片上系统(System-on-Chip,SoC)具有集成度高、功耗低、成本低等优势,已经成为大规模集成电路系统设计的主流方向,解决了

    2024年02月07日
    浏览(46)
  • ARM DIY(一)电源、SD卡座、SOC 调试

    之前打样的几块 ARM 板,一直放着没去焊接。今天再次看到,决定把它焊起来。 为了提高焊接效率,先使用加热台焊接。不过板子为双面贴片,使用加热台只能焊接一面,那就优先焊主芯片那面,并把 Type C、SD 卡座还有一些关键电阻电容一并焊接。 (不过后来发现这个决定

    2024年02月10日
    浏览(39)
  • 基于 ARM SoC 的视频传输系统设计(10-01-01)引言

    新芯设计:专注,积累,探索,挑战   对于 《基于 SoC 的卷积神经网络车牌识别系统设计》 这个极具竞争的项目而言,其主要是 通过 CPU 软核 IP 在纯 FPGA 平台上构建一个 AI SoC 卷积神经网络车牌识别系统,其中,缩放、填充层、卷积层、ReLU、池化层、全连接层 IP 都是 V

    2024年01月25日
    浏览(38)
  • 【ARM Trace32(劳特巴赫) 使用介绍 15 -- 通过 nRESE从CPU第一条指令开始Debug】

    请阅读 【嵌入式开发学习必备专栏 】 在 TRACE32 系统中, nRESET 是一个非常重要的概念,它直接关联到目标系统(通常是一个微处理器或微控制器)的硬件复位信号。 nRESET 通常表示为负逻辑(即 “n” 前缀通常表示负逻辑,“RESET” 表示复位信号),意味着当信号为低电平时

    2024年04月28日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包