韦东山FreeRTOS ARM架构简明教程

【3-2-1/2】ARM架构简明教程


前言

本节简单讲解一下ARM架构

一、ARM架构

1.1 RISC

ARM芯片属于精简指令集计算机(RISC:Reduced Instruction Set Computing),它所用的指令比较简单,有如下特点:

     1、对内存只有读写指令

     2、对数据的运算是在CPU内部实现

     3、使用RISC指令的CPU复杂度小一点,易于设计

首先,我们看一下上一节我们是怎么编写的程序,我们去创建一个任务的时候,为什么要指定栈?

在这里的128会去指定栈的大小,这里的xTaskCreate函数会去分配栈,理解栈之后,才能深入理解RTOS的本质,要想去理解栈,又得对处理器的架构有所了解。

如果你组装过电脑的话,会组装一个主板,然后去买CPU,把CPU插到主板上去,然后还会去买内存条,把内存条也插到主板上去。然后还会去买硬盘,通过各种接线接上去。对于我们的一台电脑,这些主板,CPU,内存条,硬盘等,它们是离散的,他们通过主板来组装到一起,

那么对于我们的单片机来说,它被称为SOC,System On Chip,在一个芯片上具有一个比较完整的或者称为相对完整的系统。

就比如说这是我们的一款ARM芯片,里面就已经集成了CPU,内存,类比于电脑上的硬盘,在单片机中这是Flash,Flash上面用来保存我们的程序,CPU用来运行程序,程序运行的过程中会用到内存,这个内存有什么功能呢?

注意了,内存没有计算功能。我们访问内存的时候,要么把数据写进去,要么把数据读出来,所有的计算都是在CPU内部执行的。就比如说

上图所示,CPU对内存只有读和写两条指令,对于数据的运算是在CPU内部执行的,使用精简指令集,这个CPU的复杂度小一点,易于设计。上图所示为a =  a*b  在内存和CPU之间的操作步骤,共有4步

1.2 提出问题

那么你要把a的值从内存中读入CPU,那CPU里面就有保存这个值的位置呀,CPU里面用什么来保存变量a的值呢?另外CPU里面用什么来保存b的值?CPU里面用什么来保存a*b这个计算之后的新值呢?咱们又得深入看看CPU的内部结构

1.3 CPU内部寄存器

无论是cortex-M3/M4,还是M7

CPU内部都有R0,R1,......,R15寄存器;它们可以用来“暂存”数据

对于R13、R14、R15,还另有用途

R13:别名SP(Stack Pointer),栈指针

R14:别名LR(Link Register),用来保存返回地址

R15:别名PC(Program Counter),程序计数器,表示当前指令地址,写入新值即可跳转

当我们要计算a = a +1 b 时,会涉及到4条汇编指令,汇编指令就是我们所谓的程序嘛,这些程序存在Flash上(上图右下角的代码)     a 和 b 的具体数值保存在内存里(上图右上角的数据)。CPU(上图左边)从Flash得到指令然后执行。

就比如说CPU得到了第一条汇编指令 LDR  R0,[a]  这条指令要求CPU去读取变量a ,把内存上变量a的值读入CPU 保存在哪里?这条指令是将变量a的值保存到R0里面,在下一条指令里,把变量b的值保存进R1  ,然后计算的时候把新值继续保存进R0  ,最后一条指令,把R0的值写入内存中去

我们现在知道了CPU内部有计算单元ALU,这个计算呢需要用到寄存器,这些寄存器的值哪来的?你可以去执行读内存的指令,把内存里面的值读进寄存器里面来。咱们现在重点说的是,在CPU内部有寄存器,寄存器可以起一些保存的作用。

这些寄存器除了起到保存的作用之外,有一些寄存器它还有特殊的功能,

R13一般来说用来保存栈的地址,R14一般来说用来保存返回地址(就比如说函数A()里面有函数B(),调用B函数,B函数执行完之后,返回到这里再执行C函数,这里的返回地址一般就用R14进行保存)。R15是程序计数器,你写这个寄存器的时候,你要把某一个函数的地址写进去,他就跳过去执行这个函数

1.4 汇编指令

对于初学者你可能用不到汇编指令,但是随着你工作的深入,你必须掌握汇编指令,才可以理解程序的一些本质,才可以理解RTOS的一些本质

先来讲讲读内存和写内存,我们进行数据传输的时候需要指定三个参数,就比如说,我们经常使用memcpy对吧,数据传输memcpy(目的,源,长度)  ;数据传输的三大要素就是   源 目的  长度

那么回到我们的芯片,在这个芯片里面有CPU,内存,Flash。我无论是想访问内存还是Flash,我都必须指定它的地址。比如说我CPU这边要读内存和读Flash的时候,读到的数据放到某一个寄存器Register,你看数据传输的双方是某个CPU内部寄存器和某个地址,那长度呢?长度用汇编指令来分辨

下面我们来看几个汇编的例子

二、C函数的反汇编

C函数:

我们先把这段代码放到driver_oled.c文件的第683行这里

故意用volatile,就是让编译器去优化我们的程序

将上次所做的累加操作进行更换

将OLED_PrintSignedVal(0, 4, cnt++) ;   

改为 

OLED_PrintSignedVal(0, 4, cnt);

cnt = add(cnt ,1) ;

我们现在编译程序,它肯定没有问题,但是我们想看的是反汇编,参考我们的文档

fromelf --text -a -c --output=test.dis xxx.axf

将上面的复制,粘贴替换掉 fromelf --text -a -c --output=test.dis xxx.axf  之中的xxx.axf

点击OK,再点击运行,你看就生成了test.dis

我们打开这个文件,寻找add函数

我们来看一下这个add函数是怎么被调用的:

因为这个add函数是在OLED_Test函数中被调用的,所以我们在反汇编文件中再搜索一下OLED_Test

在C函数里面他是怎么传递参数的,这个我们没有讲,但是现在可以给大家讲一下,对于cnt = add(cnt,1)   这个函数来说第一个参数使用R0来传输,R0 = cnt  第二个参数使用R1来传输   R1 = 1

第一步,它会先设置R0和R1  

第二步,就会去调用add函数

在OLED_Test里面它是这样做的:

然后我们去看一下add函数,在add函数里面,我们添加了3个volatile 就是不想让编译器去做某些优化,我们想更加容易地去看懂这些代码

这里面的a,b和sum都是局部变量,我们说局部变量都保存在栈里,等会我们来看看能都体现出这一点

最左边的是地址,中间的是机器码,给机器看的,最右边是给人看的汇编码,我们烧录的机器中的只有中间的机器码

由上方的指令BL add  跳转到add函数中,

左边的地址为Flash的地址,我们的CPU根据地址去Flash中获取这些机器码(读地址得到机器码),然后去执行机器码,那么这条机器码对应的是什么操作呢?

假设我们的栈指针指向一块内存,你看假设一开始的时候,SP寄存器等于A,指向内存的某一个位置,

现在呢,执行这条PUSH指令,PUSH实际上就是写内存,也就是STR指令的变种,它会写三个寄存器,把这三个寄存器的值写到栈里面去,并且调整栈的位置

比如地址上方是高地址,下方是低地址,它会先写入lr然后让SP往下挪一个位置,然后再写入r1,再将SP往下挪一个位置,再写入r0,SP往下挪一个位置,最后SP就等于SP减去12就等于A-12

这三个寄存器占据12个字节(一个寄存器占4个字节),在栈里面保存的是这些寄存器的值

当前 r1 等于 1 ,r0 等于 cnt   lr为返回地址

返回到哪里?对于C函数来说返回到while循环后面,对于汇编代码来说,返回到上方的BL代码的下方

这些寄存器的值都被保存在栈里,然后我们继续往下看,下面是个减法操作

SP等于SP减4,好现在栈里又空出了一块空间,SP向下挪了4个字节

然后继续往下走,LDRD ,road读4个字节,这个D代表double  读8个字节,从哪里读呢?

从SP加4的位置读8个字节(就是读取r0和r1)

这条指定就会执行这样的操作:

r0等于SP加4的位置等于cnt   r1等于SP加8的位置,等于1  读内存得到1

然后下面这条指定ADD  r0 等于 r0 加 r1 等于  cnt  加 1 

STR将这个新值保存到SP加0的位置去

最后是POP  ,POP的时候低地址对应低标号的寄存器  ,POP的时候会做这样的事情(弹出):

你看PC等于上面的0x09002a36程序就会返回到BL的下方来继续执行了,返回到add函数之后,add函数被调用之后,下一条指令

汇编代码本质上就是读内存,写内存,加加减减这些操作

看起来比较高大上的C函数,实际上它的本质都是这些读内存写内存加加减减跳转


总结

本节课主要讲了一些基础的汇编代码和程序执行的过程,为下面的堆和栈做铺垫

目录

【3-2-1/2】ARM架构简明教程

文章目录

前言

一、ARM架构

1.1 RISC

1.2 提出问题

1.3 CPU内部寄存器

1.4 汇编指令

二、C函数的反汇编

总结


  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值