嵌入式与Linux那些事

电子技术应用专栏作家——嵌入式与Linux那些事。关注嵌入式与Linux的校招社招,本人整理了《嵌入式软件工程师笔试面试指南》PDF,平时发布嵌入式与Linux相关的实用技术文章

这些关于代码如何运行的知识,要懂!

0
阅读(1395)
问题1:FLASH中的代码是如何得到运行的呢?比如PC指针是在哪里由谁设置的?

以ARM为例:

ARM-cortex-M3/4的单片机(比如STM32 等):该类单片机的代码在nor flash中,cortex内核可以直接运行,不需要将代码加载到ram中运行。

ARM-cortex-A系列的SOC(比如Exynos4412):该类SOC更加复杂,通常有内存管理单元(MMU),代码存储在nand flash中,程序运行时,需要先将代码加载到ram中运行,该类SOC的启动环节包含了加载程序。就像Windows操作系统存储在硬盘中,开机的时候,操作系统的代码会加载到内存条(RAM)中。

PC指针:无论什么单片机或者SOC,都有一个PC寄存器,这个寄存器保存了下一条待取指令的地址。正常情况下自动加“4”,遇到分支跳转的时候,由跳转指令设置值。那么指针是什么?指针是一个变量的地址,在含有操作系统(比如Linux、Windows)即硬件层面含有内存管理单元(MMU)的情况下,指针是虚拟地址,不含操作系统的情况下,是物理地址,虚拟地址和物理地址经过MMU转换。

问题2:这些代码需要搬到RAM中才能运行吗?不这样做会有什么不妥吗?

上文讲了,大部分单片机的代码直接在nor flash中运行,少部分需要加载到ram中。nor flash可以直接寻址一个字节,可以找到一个指令的具体地址,因此可以直接运行。nand flash 的存储单元是块,不能对指令直接寻址,因此不能直接运行其中的代码。因此保存在nand flash中的程序不加载到ram中运行不了。即你的硬盘中的Windows不加载到内存条中,运行不起来。

问题3:如果需要搬到RAM,那是片内还是片外有什么区别吗?

片内片外都可以,具体看是那款SOC或CPU了。

问题4:如果用户存在FLASH的实际代码大小(比如1MB),超过了RAM的可用空间(比如512KB),那这个搬移过程是啥样的?

现在实际情况很少遇到这种情况,当然可能会有RAM很小的系统,可以分时分段的使用,即程序运行一段,加载一段,运行完,加载下一段。很不建议这样玩,现在的RAM很大了,你的实际代码达到1MB的时候,你的内存可能都有1G,2G了。比如Linux操作系统编译完后,实际上只有几MB,实际的Linux系统会有几个G 的内存可用。

问题5:片外扩展的FLASH和SRAM与片内的想比,除了空间大小有差别,性能速度上会有怎样的差异呢?

具体要看SOC的总线设计。一般来说片外的性能弱一点。

能不能在Flash中直接运行程序代码,取决于Flash的访问特性。

Flash存储器是按块组织的,在使用时也倾向于按块访问才更加高效。Flash类似于ROM一类的存储器,但它其实是可读可写的,不同于同样可读可写的RAM,它在写入数据时需要先将你所写位置所属的块擦除,不管你是不是只写几个字节,所以如果要改写Flash中的数据,总是会先将数据所属的块缓存到内存中,然后再在内存中改写好数据后又重新将块写回,这样就不会丢失数据,但是花销太大。读的时候,往往也是先定位块的位置,然后在块中顺序读取,在不同块中间断读取数据是非常低效的,所以按块读按块写是Flash的一大特点,它不能够随意的对存储区域寻址,典型的如NAND Flash。

不过有一类Flash存储器在读取数据时可以做到任意的寻址而不会有太大的花销,它的读操作是接近于RAM的,而写操作依然延续了按块擦除然后再按块写的特点,典型的如NOR Flash。

所以正因为这样的特性,Flash通常用于存储不需要频繁改动的掉电不能丢失的数据。

介绍完背景知识,回到问题:

首先要清楚的是,CPU需要在存储器中读取指令,指令地址由PC寄存器给出,每执行完一条指令PC会自动的指向下一条指令,如果指令的长度不等会使得给出的地址不总是有一致的对齐,其次程序运行总会伴随跳转,这使得指令的寻址更具有随意性,所以说要直接在某种存储器中执行程序,至少读取数据时要能够任意寻址,而NOR Flash是刚好能满足要求的,市面上常见的MCU内置的Flash就是这种类型,所以能够直接在上面运行存储的程序,而不需要加载到RAM中。其他不具备这种访问特性的存储器是不能直接在上面执行程序的,必须转移到满足这种特性的存储器当中执行,比如加载到RAM。

1、FLASH中的代码是如何得到运行的呢?比如PC指针是在哪里由谁设置的?

采用cortex- m内核的MCU会根据外部启动配置引脚的电平,将启动存储器映射到0x00000000地址,如果是在Flash启动,在内部Flash的起始位置会存储一张异常中断向量表,表中的第一项和第二项存储了初始的栈地址和复位向量,这张表的位置是可配置的,而复位后的位置正是在0x00000000地址。硬件上电复位后,SP,PC寄存器会自动依次设置为表中的前两项,然后根据PC设置的初始值开始执行代码,所以说PC的值是在复位时是自动设置的。

2、这些代码需要搬到RAM中才能运行吗?不这样做会有什么不妥吗?

正如前面叙述的,并不必要。在RAM中执行可能会得到更好的执行性能,但是对于MCU内部的Nor Flash来说是没有必要的。有一点要提及的是,程序一般会由代码段txt,只读数据段rodata,初始化数据段data和未初始化数据段bss(并无数据)组成,只读数据段因为和代码段一样不需要改动,所以可以留在Flash当中 ,但是需要将也存储在Flash中的data段加载到RAM中以及空出空间给bss。这是运行环境的初始化,是有搬运的,只是搬运的不是代码,这发生在进入main函数之前。

3、如果需要搬到RAM,那是片内还是片外有什么区别吗?

在片内的RAM性能会更好,但是容量一般不能做的太大。

4、如果用户存在FLASH的实际代码大小(比如1MB),超过了RAM的可用空间(比如512KB),那这个搬移过程是啥样的?

是可以分阶段加载执行的,但是对程序的组织会变得复杂,运行变得低效,如果出现了这种情况应该考虑更换硬件配置或者对程序优化裁剪。

5、片外扩展的FLASH和SRAM与片内的想比,除了空间大小有差别,性能速度上会有怎样的差异呢?

这取决于存储器的时钟速率和访问延迟,集成在内部的存储器性能一般是能比片外的更好的,所以要使程序有更高的运行性能应该优先使用内部存储器。低端MCU由于运行速率低,内部和外部不会有太大的区别。

可以从以下三个方面可以回答这个问题:

1、计算机组成原理

image.png

冯诺依曼模型

计算机专业的同学对这张图一定不陌生,这是最经典的计算机模型,现在所有的计算机设备(当然也包括嵌入式)都没有跳出这个模型。里面的五项可以分为三部分:(1)CU和ALU是CPU(2)Memory是内存设备(理想的内存设备)(3)Input和Output是各种外设设备(键盘、鼠标、显示器······)。

图片

我们这里关注的点是内存设备。冯诺依曼模型中将Memory想象成理想内存设备。所谓理想内存设备就是可读可写、非易失、随机读写。对于理论模型来说,简介易懂是关键。但是在现实中却没有这么理想,受限于成本,不同的存储器只能满足部分指标,这就是接下来要说的主流存储器。

2、主流存储器的特点

现在的存储器可以大致分为两类:RAM和ROM。关于这两类存储器的具体定义和发展历程已经有很多总结,这里就不再赘述,只从我个人的角度谈一下对这两类存储器的理解。

(1)RAM,具体可以分为SRAM和DRAM

共同特点(RAM的根本特点):可读可写、随机读写

区别:SRAM上电即可用,DRAM需要初始化后才能使用,并且SRAM单位成本高于DRAM。

(2)ROM,具体可分为硬盘、Flash(NOR Flash和NAND Flash)

共同特点:非易失

区别:硬盘和NAND Flash都是整块读写、NOR Flash可以随机读,但是需要整块写。

NOR Flash非易失、随机读的特性让它可以作为系统的启动介质。

3、CPU与存储器之间的速度差异是现在制约计算机性能的主要原因。

4、具体到上面5个问题

(1)具体要看是什么Flash,如果是NOR Flash,那么系统可以直接访问执行。如果是NAND Flash,则需要将代码加载到RAM中再运行。PC寄存器在CPU中,在CPU上电时由硬件设置一个特定的值(例如:ARM Cortex-M3的PC寄存器上电默认是0x4)。

(2)和第一问一样,需不需要搬移代码要看Flash类型。

(3)如果是相同类型的RAM,片内和片外没有区别。如果RAM类型不同,就需要具体情况具体分析。

(4)这里假设Flash是1MB,RAM是512KB,猜测应该是NOR Flash和SRAM(例如STM32),则代码不需要搬移。如果是NAND Flash,一般会和DRAM搭配,容量会大很多,应该假设不成立。

原文链接:https://mp.weixin.qq.com/s/G5usGermg0tHp5GjtEz7yA

微信图片_20220708145705.jpg

电子技术应用专栏作家 嵌入式与Linux那些事