我这里讲的快速是指能够快速的上手工作,但任何一门学问都包含着比较具体的知识在里面,这些知识是需要长年累月的积累才可以逐渐从未知到已知,从笨拙到熟练.快速只是一种学知识的步骤,能够在短的时间里把那些不常用的知识排到后面来学习.
一些书中介绍,不需要了解汇编语言就可以进行Arm的编程,我想对于一般的开发者来讲C语言大概是够用了,但不了解汇编,很多原理性和底层的工作就会做起来困难了.即要快速,又要保证一定的汇编知识,那么学的时候可以走马观花的看一下,至少有个印象,再以后如果碰到的时候,逐渐学习和加深就可以了.
记忆是比较苦涩的事情,我觉得使用例子最好的方法,例子再加查找,以后用起来比较方便.前面讲过,Arm中有两种指令集,一种叫Arm指令集,一种叫Thumb指令集.资料中使用了一大堆理由说Thumb的16位指令集比Arm 32位指令集要性能好,这是因为它不完全等同于PC的32 80386指令集与8086/8088的16位指令集的区别,再具体的原因对于初学者可以不去理会.
我们讲一下Arm 32位指令集的寻址方式:
1. 寄存器寻址:
MOV R1,R2 ;读取R2的值到R1中
SUB R0,R1,R2 ;将R1的值减去R2的值,结果保存到R0中
2.立即寻址:
SUBS R0,R0,#1 ;R0减1,结果保存到R0中,并影响标志位
MOV R0,#0xFF000 ;将0xFF000存储到R0中
3. 寄存器移位寻址:
MOV R0,R2,LSL #3 ;R2的值左移3位,结果存入R0
ANDS R1,R1,R2,LSL R3 ;R2的值左移R3位,然后与R1相与,结果存入R1.
移位操作有这样几种: LSL,LSR,ASR,ROR,RRX,具体含义可以查相关手册
4.寄存器间接寻址:
LDR R1,[R2] ;将R2指向的存储单元的数据读出,保存到R1中
SWP R1,R1,R[2] ;将R1的值与R2指定的存储单元的值进行交换.
5.基址寻址:
LDR R2,[R3,,0x0C] ;读取R3+0x0C地址上的存储单元的内容,存入R2中
STR R1,[R0,#-4]! ;先R0=R0-4,然后把R1的值保存到R0指定的存储单元
LDR R1,[R0,R3,LSL #1] ;将R0+R3*2地址上的存储单元中的内容读出,保存到R1中.
6.多寄存器寻址:
LDMA R1! {R1-R7,R12} ;将R1指向单元的数据读出,放到R1~R7,R12中,R1自动加1
STMIA R0!,{R2-R7,R12} ;与上面方向相反,R0自动加1
我总感觉书中写的方向不对
7.堆栈寻址:
STMFD SP!,{R1-R7,LR}
LDMFD SP!,{R1-R7,LR}
可以参考前面的例子,只不过是堆栈SP寄存器而已
8.块拷贝寻址:
STMIA R0,{R1-R7}
STMIB R0,{R1-R7}
STMDA R0! {R1-R7}
STMDB R0! {R1-R7}
9.相对寻址:
BL SUBR1 ;调用到SUBR1子程序
BEQ LOOP ;条件跳转到LOOP标号处
所谓寻址方式,就是指令的表达方式,这种表达方式大概明白了,也就比较容易理解各种指令的含义了.汇编是种学起来比较讨厌的东西,不同CPU系列的计算机汇编语言都不统一,不像高级语言那样,语法比较一致,而且指令会很多,寻址方式也不同,对于常时间只是有同一种CPU的汇编编程的人来讲,汇编也不是什么难事,但对于工作范围比较广的开发者来讲,记忆指令的确是个麻烦的事情.幸好现在大多单片机都可以使用C语言来编程,但对汇编的了解还是有好处的,它能够帮助你理解更底层的问题.