Chapter fourteen ARM概述(1)

来源:互联网 发布:考勤系统数据读不出 编辑:程序博客网 时间:2024/06/06 00:02

本章主要介绍ARM处理器的工作状态、工作模式、以及寄存器的简单使用。为了帮助大家理解Soc与外设之间的通信,我们还涉及到了ARM汇编语言和C语言的综合应用,具体使用的开发板为Smart210。具体要学习的章节包括ARM概述、汇编指令集和MDK安装、GCC开发环境搭建、异常处理机制、中断处理实现、时钟系统、ARM GPIO编程、ARM串口编程、ARM nand flash编程、从0编写Bootloader从0编写Bootloader。

14.1 ARM概述


14.1.1 ARM处理器的特点


1)单周期操作:每条指令在一个机器周期内完成。
2)指令长度固定:指令固定的长度为32位(16位代码的Thumb工作状态除外),这使得指令译码结构简单。
3)只用加载或存储指令访问内存:因为访问存储器指令的时间过长,所以通过提前加载到寄存器中提高了效率。


14.1.2 ARM指令集

1)ARM指令集由数据处理指令、跳转指令、Load/Store指令、程序状态寄存器指令、协处理器指令和软件中断指令六大类构成。下面我们列出一些常用的指令。


2)指令一般格式:<opcode>{<cond>}{S}  <Rd>,<Rn>{,<opcode2>}

指令格式说明项目含义备注 <opcode>指令操作码即助记符,例如MOV、ADD、B等 {<cond>}条件域,满足条件才执行可不加条即可省略条件,例如EQ(相等)、EN(不相等)等 {S}指令执行时是否更新CPSR可省略 Rd目的寄存器任意通用寄存器(R1--R12) Rn第一个源操作数任意通用寄存器(R1--R12) op2第二个源操作数可为#imm8m,寄存器Rm和任意位移寄存器 

3)ARM处理器的工作模式




4)ARM状态下的寄存器组织
ARM处理器共有37个寄存器,包括31个通用寄存器(包括PC)和6个状态寄存器。值得注意的是,R15是PC指针,R14是程序连接寄存器LR,R13是堆栈指针SP。CPSR是作为另外的状态寄存器。R0——R7无论什么模式,都是通用寄存器。





14.1.3 ARM汇编

1)汇编语言的定义:用助记符(Memoni)代替操作码,用地址符号(Symbol)或标号(Label)代替地址码,用符号代替机器语言的二进制码就是汇编语言。

2)优点:可以直接操作硬件目标,执行速度快。缺点:阅读性差,可移植性差。

3)  小符号
a."#"为立即数的标识符号
b."!"表示更新基地址,一般用于保存现场时,放在stmfd和ldmfd后,表示将完成最后操作后的地址保存到基址寄存器中.
c."^"表示将SPSR复制到CPSR中.
d."-"表示寄存器列表的范围.

4)立即数的判定

    1:首先把这个数用二进制表示出来,然后看这个数中“1”的最大间隔是多少。要看两次,一次是顺序看,一次是循环看,循环看就是把16位或32位寄存器的首尾连起来,越过首尾来看,两次中如果最大间隔都大于8(包含首尾的两个1),那这个数肯定是非法的。如果有一次小于或等于8则有可能是合法的,可以进行下一步的判断。

    2:此时又分为两种可能
       a:如果顺序看时“1”的最大间隔小于或等于8,此时可以看看,这个数的最高位1的前面或者最低位1的后面是否有偶数个0,只要有一种情况下有,这个数是合法的的立即数。
       b:如果循环看时1的最大间隔小于或等于8,此时可以看看,循环看时,两端得到的间隔个数是否有一个为偶数,如果有一个为偶数,这个数就是合法的。

   3:举例

      以下都是合法的

      0xff=0000 0000 0000 0000 0000 0000 1111 1111B,首尾的两个1不大于8,符合2(a),是立即数


      0x104=0000 0000 0000 0000 0000 0001 0000 0100B,首尾的两个1不大于8,符合2(a),是立即数


      0xff0=0000 0000 0000 0000 0000 1111 1111 0000B,首尾的两个1不大于8,符合2(a),是立即数



5)   MDK的安装
1.软件下载及安装
2.配置:新建工程-->new project-->选择设备samsung2440--->新建文件-->保存-->添加文件到工程
3.代码练习:


area mycode, code, readonly

code32
entry@固定格式

start
mov r0,#1

end


4.运行后进入Debug模式


5.开机就是supervisor模式(管理模式)

6) 汇编的保存现场和函数跳转
a.要保存现场就要用到内存连续操作指令ldmfd和stmfd.跳转前,保存现场数据到寄存器,结束后,从寄存器中恢复现场.使用场景是当
ldmfd:把数据从内存地址上加载到寄存器
例子:ldmfd:r0,{r5,r8}

stmfd:把数据从寄存器存储到内存地址中去
例子:stmfd:r0,{r1,r4}

实际工作中的使用案例:
.global _start
_start:

@这里开始地址为0x41000000

b reset
b undef
b swi
b abt_pre
b abt_dat
b reserved
b irq
b fiq

reset:
undef:
@初始化栈指针
ldr sp,=0x42000000
@规定r13(sp)指向保存现场的内存地址,并且sp必须始终保持不变。因为上述操作是先减去4再存储,因此要把0x40000000改为0x4000 0100.

stmfd sp!, {r1-r12, lr}
@注意:加上!是因为指针会随着r1--r4的赋值而移动。加!是为了让R0恢复到初始位置

ldr r0,=undef_str
mrs r1,cpsr      @取cpsr到r1
mov lr,pc
and r1 ,r1 , #0x1f  @取cpsr的后5位


ldr pc,=0x3ff13e54

@ldmfd sp!, {r1-r12, pc}^,和下面两条语句效果一样

ldmfd sp! ,{ r1-r12, lr}
movs pc,lr
swi:
abt_pre:
abt_dat:
reserved:
irq:
fiq:

undef_str:
.asciz " hello define mode cpsr = 0x%x\n"
loop:
b loop

b.汇编函数标签跳转后,要用mov pc, lr进行结尾.只有这样,下个函数才能正常运行.

7)我的小总结:
a.keil里的汇编是分号为注释,Ubuntu里的汇编是用@注释;C是用//注释;shell或makefile使用#注释.
b.mov:有效的立即数;mvn:需要按位取反的数; ldr:任何数(一般是大的地址或者非立即数)
c.C语言后八位清零操作:a&=~0xff;后八位置1操作:a &=~0xff,a |=0xff.
d.汇编后八位清零操作:bic r0, r0,#0xff;后八位置1操作:bic r0, r0,#0xff, orr r0, r0,#0xff



原创粉丝点击