(1)ARM Cortex-M3指令集初探

ARM初探–alias


alias是为老函数,取一个新的名字!
attribute关键字来描述函数,变量和数据类型的属性,用于编译器对源代码的优化

#include <stdio.h>  
int __Hard_Fualt()   
{  
  printf("my func = %s\n",__FUNCTION__);  
  return 0;  
}  

int myFun() __attribute__((alias("__Hard_Fualt")));  
int main()  
{  
  myFun();  
  return 0;  
}  

下面是ARM Cortex-M3中应用alias的一段代码能够简化,程序的编写进程!

void NMI_Handler(void)          __attribute((alias("HardFault_Handler")));    //alias指令别名
void MemManage_Handler(void)    __attribute((alias("HardFault_Handler")));
void BusFault_Handler(void)     __attribute((alias("HardFault_Handler")));
void UsageFault_Handler(void)   __attribute((alias("HardFault_Handler")));
void SVC_Handler(void)          __attribute((alias("HardFault_Handler")));
void DebugMon_Handler(void)     __attribute((alias("HardFault_Handler")));
void PendSV_Handler(void)       __attribute((alias("HardFault_Handler")));

经过使用alias修饰之后,只需定义一个NMI_Handler()函数即可,其它的函数调用的时候就会调用NMI_Handler()函数;

void HardFault_Handler(void)
{
    __disable_irq();
    __set_MSP(__Vectors);
    LEDS_SETUP();
    {
        register int count;
        for (count = 0; count < 5; count++)
        {
            LedRunningOn();
            Delay_ms(250);
            LedRunningOff();

            LedConnectedOn();
            Delay_ms(250);
            LedConnectedOff();

            Delay_ms(1000);
        }
    }
    NVIC_SystemReset();
}

ARM 一直支持两种形式相对独立的指令集

32位的ARM指令集。对应的处理状态:ARM状态。
16位的Thumb指令集。对应处理器状态:Thumb状态。
程序执行的过程中,处理器可以动态的在两个指令集之间切换。

名词缩写

AHB 先进高性能总线

AHB‐AP AHB访问端口

AMBA 先进单片机总线架构

APB 先进外设总线

ARM ARM ARM架构参考手册

ASIC 行业领域专用集成电路

ATB 先进跟踪总线

BE8 字节不变式大端模式

CPI 每条指令的周期数

CPU 中央处理单元

DAP 调试访问端口

DSP 数字信号处理器/数字信号处理

DWT 数据观察点及跟踪

ETM 嵌入式跟踪宏单元

FPB 闪存地址重载及断点

FSR Fault状态寄存器

HTM CoreSight AHB跟踪宏单元

ICE 在线仿真器

IDE 集成开发环境

IRQ 中断请求(通常是指外部中断的请求)

ISA 指令系统架构

ISR 中断服务例程

ITM 指令跟踪宏单元

JTAG 连结点测试行动组(一个关于测试和调试接口的标准)

JTAG‐DP JTAG调试端口

LR 连接寄存器

LSB 最低有效位

LSU 加载/存储单元

MCU 微控制器单元(俗称单片机)

MMU 存储器管理单元

MPU 存储器保护单元

MSB 最高有效位

MSP 主堆栈指针

NMI 不可屏蔽中断

NVIC 嵌套向量中断控制器

OS 操作系统

PC 程序计数器

PSP 进程堆栈指针

PPB 私有外设总线

寄存器

这里写图片描述
1. R0-R12:通用寄存器

R0‐R12都是32位通用寄存器,用于数据操作。但是注意:绝大多数16位Thumb指令只能访问R0‐R7,而32位Thumb‐2指令可以访问所有寄存器。

  1. Banked R13: 两个堆栈指针

    Cortex‐M3拥有两个堆栈指针,然而它们是banked,因此任一时刻只能使用其中的一个。

主堆栈指针(MSP):复位后缺省使用的堆栈指针,用于操作系统内核以及异常处理例程(包括中断服务例程)
进程堆栈指针(PSP):由用户的应用程序代码使用。
堆栈指针的最低两位永远是0,这意味着堆栈总是4字节对齐的。
在ARM编程领域中,凡是打断程序顺序执行的事件,都被称为异常(exception)。除了外部中断外,当有指令执行了“非法操作”,或者访问被禁的内存区间,因各种错误产生的fault,以及不可屏蔽中断发生时,都会打断程序的执行,这些情况统称为异常。在不严格的上下文中,异常与中断也可以混用。另外,程序代码也可以主动请求进入异常状态的(常用于系统调用)。

  1. R14:连接寄存器

    当呼叫一个子程序时,由R14存储返回地址 不像大多数其它处理器,ARM为了减少访问内存的次数(访问内存的操作往往要3个以上指令周期,带MMU和cache的就更加不确定了),把返回地址直接存储在寄存器中。这样足以使很多只有1级子程序调用的代码无需访问内存(堆栈内存),从而提高了子程序调用的效率。如果多于1级,则需要把前一级的R14值压到堆栈里。在ARM上编程时,应尽量只使用寄存器保存中间结果,迫不得以时才访问内存。
    在RISC处理器中,为了强调访内操作越过了处理器的界线,并且带来了对性能的不利影响,给它取了一个专业的术语:溅出。

  2. R15:程序计数寄存器

    指向当前的程序地址。如果修改它的值,就能改变程序的执行流(很多高级技巧就在这里面——译注)。

  3. 特殊功能寄存器

Cortex‐M3还在内核水平上搭载了若干特殊功能寄存器,包括

程序状态字寄存器组(PSRs)

中断屏蔽寄存器组(PRIMASK,FAULTMASK, BASEPRI)

控制寄存器(CONTROL)

来自于ARM Cortex-M3 权威指南


为了使代码更加的清爽,Cortex-M3在进入异常服务例程时,自动压栈了R0-R3、R12、LR、PSR和PC,并且返回时自动的弹出它们,即加速了中断的响应,也不在需要汇编语言代码了;

在内核水平上支持节能模式(SLEEPING和SLEEPDEEP位),通过使用等待中断指令(“WFI”)和等待事件指令(“WFE”),内核可以进入睡眠模式,并以不听的方式唤醒。

R15程序计数器,在汇编代码中一般都叫它的外号“PC”。因为CM3内部采用指令流水线,读取PC时返回的值是当前指令的地址+4。
如果向PC中写数据,就会引起一次程序的分支(但是不更新LR寄存器)。CM3中的指令至少是半字节对其的,所以PC得LSB总是读回0。然而在分支时无论是直接写PC值还是使用分支指令都必须保证加载到PC的值是奇数(LSB ==1),用以表明这是在Thumb状态下执行。倘若写成了0,则视为企图装入ARM状态模式,CM3将会产生一个fault异常。


在Thumb-2指令集中,有些操作既可以由16位指令完成,也可以由32位指令完成,如:R0 = R0 +1,在UAL下,汇编器能够决定使用哪个,也可以自己指定使用暗种 汇编指令;

使用.W和.N表示32位指令还是16位指令,如:

ADDS    R0,    #1;    汇编器为了节省空间使用16位指令
ADDS.N  R0,    #1;    指定使用16位指令(N == Narrow)
ADDS.W  R0,    #1;    指定使用32位指令(W == Wide)

ARM 指令集中的跳转指令可以完成从当前指令向前或向后的 32MB 的地址空间的跳转,包括以下 4 条指令:

(1) B 跳转指令

(2) BL 带返回的跳转指令

(3) BLX 带返回和状态切换的跳转指令

(4) BX 带状态切换的跳转指令

1、 B 指令

B 指令的格式为:

B{条件} 目标地址

B 指令是最简单的跳转指令。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继
续执行。注意存储在跳转指令中的实际值是相对当前PC 值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(前后32MB 的地址空间)。以下指令:

B Label ;程序无条件跳转到标号 Label 处执行

CMP R1 ,# 0 ;当 CPSR 寄存器中的 Z 条件码置位时,程序跳转到标号 Label 处执行

BEQ Label

2、 BL 指令

BL 指令的格式为:

BL{条件} 目标地址

BL 是另一个跳转指令,但跳转之前,会在寄存器R14 中保存PC 的当前内容,因此,可以通过将R14 的内容重新加载到PC 中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。以下指令:

BL Label ;当程序无条件跳转到标号 Label 处执行时,同时将当前的 PC 值保存到 R14 中

3、 BLX 指令

BLX 指令的格式为:

BLX 目标地址

BLX 指令从ARM 指令集跳转到指令中所指定的目标地址,并将处理器的工作状态有ARM 状态切换到Thumb 状态,该指令同时将PC 的当前内容保存到寄存器R14 中。因此,当子程序使用Thumb 指令集,而调用者使用ARM 指令集时,可以通过BLX 指令实现子程序的调用和处理器工作状态的切换。

同时,子程序的返回可以通过将寄存器R14 值复制到PC 中来完成。

4、 BX 指令
BX 指令的格式为:

BX{条件} 目标地址

BX 指令跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM 指令,也可以是Thumb指令。

LDMIA指令 与之对应的指令是STMIA指令
LDM是多寄存器存取的意思,IA表示数据传输后地址增加(increase after);(IB:increase before, DA: decrease after, DB: decrease before)
后面参数以“,”分隔,第一个参数是首地址;第二个参数是寄存器列表,并以“{}”括起来。
具体的例子:
LDMIA R0!, {R1-R4}
R0表示要操作的存储空间首地址,要操作的数据个数由寄存器列表决定,现在是R1到R4,共4个数据(每个数据是32bits的)
具体:地址为R0的存储空间中的数据赋值给R1
地址为R0+4的存储空间中的数据赋值给R2
地址为R0+8的存储空间中的数据赋值给R3
地址为R0+12的存储空间中的数据赋值给R4

MRS,状态寄存器传送至通用寄存器类指令
功能:将状态寄存器的内容传送至通用寄存器。

格式:

MRS{<条件码>}Rd,CPSR}SPSR
其中:
Rd  目标寄存器,Rd不允许R15。
R=0  将CPSR中的内容传送目的寄存器。
R=1SPSR中的内容传送至目的寄存器。

注释:
MRS与MSR配合使用,作为更新PSR的读-修改-写序列的一部分。例如:改变处理器或清除标志Q。注意:当处理器在用户模式或系统模式下,一定不能试图访问SPSR
这条指令不影响条件码标志。
例:
MRS  R0,CRSR  ;将CPSR中的内容传送至R0
MRS  R3SPSR  ;将SPSR中的内容传送至R3



MSR,通用寄存器传送至状态寄存器传送指令
功能:将通用寄存器的内容传送至状态寄存器。

格式:
MSR{<条件码>CPSR_f|SPSR_f,<#immed_8r>
MSR{<条件码>CPSR_<field>|SPSR_<field>,Rm
其中:
<field>字段可以是以下之一或多种:(位从右到左)
C:控制域屏蔽字段(PSR中的第0位到第7位);
X:扩展域屏蔽字段(PSR中的第8位到第15位);
S:状态域屏蔽字段(PSR中的第16位到第32位);
F:标志域屏蔽字段(PSR中的第24位到第31位)。
immed_8r 值数字常量的表达式。常量必须对应8位位图。该位图在32位字中循环移位偶数数位。
Rm  源寄存器。

CM3中隔离指令的来历
举例来说,如果可以在运行时更改存储器的映射关系或者内存保护区的设置,(通过写 MPU 的寄存 器),就必须在更改之后立即补上一条 DSB 指令(数据同步指令)。因为对 MPU 的写操作很可能会被放 到一个写缓冲中。写缓冲是为了提高存储器的总体访问效率而设的,但它也有副作用,其中之一,就是 会导致写内存的指令被延迟几个周期执行,因此对存储器的设置不能即刻生效,这会导致紧临着的下一 条指令仍然使用旧的存储器设置——但程序员的本意显然是使用新的存储器设置。这种紊乱危象是后患 无穷的,常会破坏未知地址的数据,有时也会产生非法地址访问 fault。紊乱危象还有其它的表现形式, 后续章节会一一介绍。CM3 提供隔离指令族,就是要消灭这些紊乱危象(在有些讲解计算机体系体系结 构的书中,这类紊乱危象也被称为“存储器相关”——译注)
指令名
DMB

数据存储器隔离。DMB 指令保证: 仅当所有在它前面的存储器访问操作

都执行完毕后,才提交(commit)在它后面的存储器访问操作。

DSB

数据同步隔离。比 DMB 严格: 仅当所有在它前面的存储器访问操作

都执行完毕后,才执行在它后面的指令(亦即任何指令都要等待存储器访 问操作——译者注)

ISB

指令同步隔离。最严格:它会清洗流水线,以保证所有它前面的指令都执

行完毕之后,才执行它后面的指令。


猜你喜欢

转载自blog.csdn.net/andrewgithub/article/details/80351983