您的位置 首页 电子

arm汇编编程(示例)

一、arm的认知及基本概念(一).arm的基本概念1.什么是armarm是一家英国电子公司的名字,全名是AdvancedRISCMachine这家企业设计了大量高性能…

一、arm的认知及根本概念

(一).arm的根本概念

1.什么是arm

arm是一家英国电子公司的姓名,全名是AdvancedRISCMachine

这家企业规划了很多高功用、廉价、耗能低的RISC(精简指令集)处理器,ARM公司只规划芯片而不出产,它将

技能授权给世界上许多公司和厂商。现在选用arm技能知识产权内核的微处理器,即一般所说的arm微处理器

所以arm也是对一类微处理器的通称。

arm指令集体系版别号(软件)为V1~V7现在V1~V3已很少见。从V4版不再与曾经的版别兼容。

arm的CPU系列(硬件)首要有ARM7~ARM11

2.典型的嵌入式处理器

arm占商场79.5%ARM

mips占商场13.9%MIPS

microSPARC占商场3.1%SUN

PowerPc占商场2.8%IBM

其它占商场0.8%

3.arm的运用规模:

工业操控:如机床、主动操控等

无线通信:如手机

网络运用:如

电子产品:如音视频播映噐、机顶盒、游戏机、数码相机、打印机

其它各范畴:如军事、医疗、机器人、智能家居

4.核算机体系结构

见图:冯.诺依曼核算机体系图

冯.诺依曼体系结构

处理器运用同一个存储器,经由同一个总线传输

完结一条指令需求3个进程:即取指令->指令译码->履行指令

指令和数据同享同一总线的结构

哈佛体系结构

将程序指令存储和数据存储分隔

中央处理器首先到程序指令存储器中读取程序指令。解码后到数据地址,再到相应的数据存储器读取数据,然后履行指令

程序指令存储与数据存储分隔,能够使指令和数据有不同的数据宽度。

5.杂乱指令集与精简指令集

CISC杂乱指令集:选用冯.诺依曼体系结构。数据线和指令线分时复用(只能经过一辆车)。

存储器操作指令多汇编程序相对简略指令完毕后呼应间断CPU电路丰厚面积大功耗

RISC精简指令集:选用哈佛体系结构。数据线和指令线别离(一起能经过多辆车)。

对存储器操作有限汇编程序占空间大在恰当当地呼应间断CPU电路较少体积小功耗低

ARM选用RISC精简指令集

Thumb是ARM体系结构中一种16位的指令集。

从ARMv4T之后,的ARM处理器有一种16-bit指令办法,叫做Thumb,较短的指令码供给全体更佳的编码密度,更有用地运用有限的内存带宽。一切ARM9和后来的宗族,包含XScale都纳入了Thumb技能。

即ARM有两种指令集:RISC、Thumb

6.arm的思维

1)arm体系的总思维:

在不献身功用的一起,尽量简化处理器。一起从体系结构上灵敏支撑处理器扩展。选用RISC结构。RISC处理器简化了处理器结构,削减杂乱功用指令的一起,进步了处理器速度。

ARM及MIPS都是典型的RISC处理器

2)arm的流水线结构

arm处理器运用流水线来增加处理器指令流的速度,这样能够使几个操作一起进行。并使处理和存储器体系接连操作。

arm处理器分为三级:取指->译码->履行

取指:指令从存储器中取出

译码:对指令运用的存放器进行译码

履行:从存放器组中读取存放器,履行移位和ALU操作,存放器被写回到存放器组中

3)ARM处理器支撑的类型

字节8位

半字16位

字32位

一切数据操作都以字为单位

ARM指令的长度刚好是一个字,Thumb指令长度刚好是半个字

4)ARM处理器状况

ARM处理器内核运用ARM结构,该结构包含32位的ARM指令集和16位Thumb指令集,因而ARM有两种操作状况

ARM状况:32位

Thumb状况:16位

5)处理器办法

ARM处理器共有7种运转办法:

用户:正常程序作业办法,不能直接切换到其它办法

体系:用于支撑操作体系的特权使命,能够直接切换到其它办法

快间断:支撑高速数据传输及通道处理,FIQ反常呼应时进入此办法

间断:用于通用间断处理,IRQ反常呼应时进入此办法

办理:操作体系维护代码,体系复位和软件间断呼应时进入此办法

间断:用于支撑虚拟内存或存储器维护,用于MMU

未界说:支撑硬件协处理器的软件仿真,未界说指令反常呼应时进入此办法。

(二)、经典渠道硬件组成

见图:arm硬件组成图

开发板一般是由一块组成的,有中心器材和外围器材接口等,可是有的是由两块板子组成,主版和中心板,主版上首要是外围接口,外围器材等,中心板上首要是中心器材,还有一些晶振电路等

1.中心板(天嵌2440)

CPU处理器S3C2440AL,主频400MHz(最高可达533MHz)

SDRAM内存板载64MBSDRAM(规范装备),32bit数据总线SDRAM时钟频率高达100MHz(支撑运转133MHz)

NandFlash板载64MBNandFlash或256MBNandFlash(规范装备)

NorFlash板载2MBNorFlash(最高可升级到8MB)

CorePower专业1.25V中心电压供电

Power中心板选用3.3V供电

Powerled中心板电源指示灯

中心板接口接口型号为DC-2.0双列直插

SDRAM:随机存储器,遍及运用的内存。用作主存。

NORFlash和NANDFlash是现在商场上两种首要的非易失闪存。

NOR的特色是芯片内履行,运用程序能够直接在flash闪存内运转,不用再把代码读到体系RAM中。

NAND结构能供给极高的单元密度,能够到达高存储密度,并且写入和擦除的速度也很快。

2.主板

电源

并口线

复位

RTC电源

RS232电平转化DB9插座

音频IIS,AC97

按键、PS/2与IC接口

数码管

触摸屏

以太网

主USBHUB1转4

3.存放器

见图:ARM模块和内核框图

存放器是中央处理器内的组成部份。

存放器是有限存贮容量的高速存贮部件,用来暂存指令、数据和位址。在中央处理器的操控部件中,包含的存放器有指令存放器(IR)和程序计数器(PC)。在中央处理器的算术及逻辑部件中,包含的存放器有累加器(ACC)。

IR用于存储指令

PC用于存储程序运转的地址(即当时指令在内存中的方位)

存放器是由一个指令的输出或输入能够直接索引到的暂存器群组。一切的核算机指令都是进入存放器后被直接读取

ARM的汇编编程,本质上便是针对CPU存放器的编程。

//*要点需求背讼*

ARM存放器分为2类:一般存放器和状况存放器

(1)通用存放器和计数器:共32个,15个通用存放器

R0-R7未备份存放器

R0(a1)R1(a1)R2(a3)R3(a4)R4(v1)R5(v2)R6(v3)R7(v4)

R8-R12备份存放器

R8(v5)R9(SB,v6)R10(SL,v7)R11(EP,v8)R12(IP)数据存放器

R15(PC)程序计数器它的值是当时正在履行的指令在内存中的方位。

当指令履行完毕后,CPU会主动将PC值加上一个单位,PC值指向下一条行将履行的指令的地址

假如经过汇编指令对PC存放器赋值,就会完结一次程序的跳转(如从子函数跳转回主函数内)

R14(LR)链接存放器存放子程序的回来地址

例如:在主函数内,假如调用子函数,程序会进入到子函数内履行。当子函数履行完毕后,需求回到

主函数内,所以,在子函数调用前需求将这个地址先保存起来,不然无法找到这个地址。

LR用于保存这个地址,这个地址也称为子程序回来地址。当子函数完毕后,再将LR内的地址赋给PC即可。

假如子程序再调用孙程序,LR怎么保存地址呢?

先把当时LR内的值压入内存的栈区,然后LR再保存孙程序的回来地址。当孙程序履行完后经过PC跳转到

子程序内,此刻将栈区内的子程序回来地址取出保存在LR内。当子程序履行完后,再经过PC跳转到主函数内。

R13(SP)栈指针存放器用于存放仓库的栈顶地址。

SP相当于指针变量,保存的是栈顶的地址,出栈时,从SP指向的内存中取出数据,入栈时将新的内存地址

压入栈顶,而SP相当于链表的头指针(head)。

准则上说R0-R12能够保存任何数据。其间R0-R7用来暂时存储数据,R8-R12体系没有用来做任何特别用处,常用于间断

而在汇编与C言语的交互中,定制了ATPCS规范

存放器:R4-R11用来保存部分变量

参数:参数小于等于4,用R0-R3保存参数,参数多于4,剩下的传入仓库

函数回来:成果为32位整数,经过R0回来

成果为64位整数,经过R0,R1回来

关于位数更多的成果,经过内存传递

(2)状况存放器:

状况存放器用于保存程序的当时状况

CPSR当时程序状况存放器

一个存放器为32位,每一位数据代表不同的状况。分为三个部分(条件代码标志位、操控位、保存区位)

31322928….76543210

NZCVIFTM4M3M2M1M0

其间NZCV称为条件标志位(即保存的是条件的运算成果,真和假)

N=1表明运算成果为负数,N=0表明运算成果为正数。

Z=1表明运算成果为0,Z=0表明运算成果为非零。

C=1表明运算成果发生了进位。

V=1运算成果的符号位发生了溢出。

这4个位的组合,代表了各种条件,如下:

0000 EQ Z置位持平/等于0

0001 NE Z清0不等

0010 CS/HS C置位进位/无符号高于或等于

0011 CC/LO C清0无进位/无符号低于

0100 MI N置位负数

0101 PL N清0非负数

0110 VS V置位溢出

0111 VC V清0无溢出

1000 HI C置位且Z清0无符号高于

1001 LS C清0或Z置位无符号低于或等于

1010 GE N等于V有符号大于或等于

1011 LT N不等于V有符号小于

1100 GT Z清0且N等于V有符号大于

1101 LE Z置位或N不等于V有符号小于或等于

1110 AL 任何状况 总是(always)

1111 NV 无 从不(never)

IFT称为操控位

II=1禁用IRO间断

FF=1禁用FIQ间断

T表明CPU当时的状况,1代表正在Thumb指令集状况,0表明正在ARM指令集状况。

M0至M4表明间断类型(操控位内的办法位)

0b10000User用户间断

0b10001FIQ快速间断

0b10010IRQ声卡、调制解调器等外部设备发生的间断

0b10011Supervisor办理程序或监控程序发生的间断

0b10111Abort反常间断

0b11011Undefined未界说间断

0b11111System体系间断

SPSR保存的程序状况存放器,结构与CPSR彻底相同,用来保存CPSR的值。以便出现反常时康复CPSR的值

(3)流水线对pc值的影响

CPU内部的组成部分:指令存放器,指令译码器,指令履行单元(包含ALU和通用存放器组)

CPU履行指令的进程:取指->译码->履行

取指:将指令从内存或指令cache中取入指令存放器

译码:指令译码器对指令存放器中的指令进行译码操作,辨识add,或是sub等操作

履行:指令履行单元依据译码的成果进行运算并保存成果

流水线操作:并发多条流水线(以3条为例)

1取指译码履行

2取指译码履行

3取指译码履行

进步时刻功率

(三)、学习内容

1.汇编(对裸板机的操控,以及驱动程序操控)

2.内核移植(uboot移植、内核编译、文件体系移植、运用程序移植)

3.驱动程序编写

//^^^^^^^^^^^^^^^^^^^^^^^^^^下午^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

(四)、ADS的运用

ADS是汇编或C言语编译调试东西

可生成的文件:.axf含调试信息的可履行ELF文件

.bin可烧写的二进制映像文件

.hex可烧写的十六进制映像文件

ADS装备

在磁盘中新建一个目录D:\arm,用来存储所写的代码

点击目录:File->new,创立一个可履行的ARM映象工程

ARMExecutableImage生成ELF格局映像(bin)

ARMObjectLibrary生成armar格局方针库文件

EmptyProject创立不包含任何库或源文件的工程

MakefileImporterWizard用于Vc

ThumbARMInterworkingImage用于ARM和thumb指令混合代码生成的ELF映像

ThumbExecutableimage用thumb指令生成ELF格局映像

ThumbObjectLibrary用于Thumb指令的代码生成的armar格局文件

选ARMExecutableImage,工程文件名2440ART

加源文件

project->AddFiles

新建

填加已有

生成方针的装备

2440ART.mcp内双击

TargetSettins:post-linker挑选ArMfromELF

LanguageSettins:ArchitectureorProcessor挑选相应的编译器ARM920T

ArmLinker:output内RO0x30000000

options内Imageentrypoint设为0x30000000

layout内Object2440init.oSectionInit

Listings内Imagemap

ArmfromELF:outputformat内Plainbinary

outputfilename内*.bin

编译

make

调试AXD是调试器

设置,debug->翻开AXD调试界面,挑选option->configtarget选项

选ARMUL(模仿调试器),然后挑选确认.进入调试界面.

ARMUL是虚拟调试环境(虚拟开发板)

假如用开发板实在环境调试,则需求运用JTAG连开发板后,在此处选H-JTAG

用file-

execute->runtocousor项.使程序进入用户主程序

能够用F8来一条一条履行句子,也可用F10,能够设置断点.

(五).汇编言语根本结构

例:

AREAInit,CODE,READONLY;AREA界说代码段,段名Init;代码段,只读

ENTRY;伪操作,榜首条指令的进口

Start;标号,一段代码的开端,用于符号,无意义,有必要顶格

MOVr0,#10;将10存入r0存放器,整型常量前面用#号

MOVr1,#3;将3存入r1存放器,r0和r1相当于两个变量,仅仅称号固定,在存放器的存储空间内

ADDr0,r0,r1;将r0内数据与r1内数据相加,相加后数据放在r0内

;Stop;中止标号,下面的代码用于中止运转程序

;MOVr0,#0x18;软件反常间断呼应

;LDRr1,=0x20026;ADP中止运转,运用退出

;SWI0x123456;ARM半主机软件间断

END

1).根本概念

(2)存放器:如R0、R1等

ARM的汇编编程,本质上便是针对CPU存放器的编程。

(3)指令:即操作码,直接操控CPU,如MOV

包含跳转指令、数据处理指令、乘法指令、PSR拜访指令、加载或存储指令、数据交流指令、移位指令等

(4)伪操作:效果于编译器,大多用于界说和操控。如AREA

包含符号界说、数据界说、操控等

(5)标号:仅是一种标识。在跳转句子中,能够指向要跳转到的标识号方位

在ARM汇编中,标号代表一个地址,段内标号的地址在汇编时确认,段外标号的地址值在衔接时确认

(6)符号:即标号(代表地址)、变量名、数字常量名等。符号的命名规矩如下:

a.符号由大小写字母、数字以及下划线组成;

b.除部分标号以数字开端外,其它的符号不能以数字开端;

c.符号差异大小写,且一切字符都是有意义的;

d.符号在其效果域规模你有必要是仅有的;

e.符号不能与体系内部或体系预界说的符号同名;

f.符号不要与指令助记符、伪指令同名。

2).段界说

在汇编言语中,以相对独立的指令或数据序列的程序段组成程序代码

段的区分:数据段、代码段。一个汇编程序至少有一个代码段

(1)代码段

上面的比方为代码段。

AREA界说一个段,并阐明所界说段的相关特色,CODE用以指明为代码段

ENTRY标识程序的进口点。END为程序完毕。

(2)数据段

AREADATAAREA,DATA,BIINIT,ALLGN=2

DISPBUFSPACE200

RCVBUFSPACE200

DATA用以指明为数据段,

SPACE分配200字节的存储单元并初始化为0

指令和伪操作在后边详细描述

3).汇编言语结构

[标号][指令或伪操作]

一切标号有必要在一行的顶格书写,这以后不加冒号

一切指令均不能顶格写

指令助记符大小写灵敏,不能大小写混合,只能悉数大写或悉数小写

;为注释

@代码行注释,同;

#整行注释或直接操作数前缀

\为换行符

ENTRY为程序的进口

END为程序的完毕

//*arm体系结构第二天*

二、ARM的寻址办法

最简略的汇编指令格局是操作码和操作数

如:MOVr0,#10

操作码:即CPU指令如MOVADD

操作数:即表明数据是在存放器中仍是在内存中,是肯定地址仍是相对地址

操作数部分要处理的问题是,到哪里去获取操作数,获取操作数的办法便是寻址办法。

ARM每一条指令都是32位机器码,对应CPU的位数

ARM指令格局:

在32位中分为7个位域,每个位域别离存储不同意义的编码(二进制数

31~2827~2524~212019~1615~1211~0

———————————————————–

|Cond|001|Opcode|S|Rn|Rd|Operand2|

———————————————————–

对应输入的一条指令为:

{}{s},,

Opcode:指令操作码用4个位存储,如MOV,ADD每一个操作码和操作数终究都是以二进制办法存在

Cond:指令的条件码用4个位来储,可省掉

如:ADDr0,r0,#1;核算r0加1后的值,再写入到r0内

ADDEQr0,r0,#1;只要在CPSR存放器条件标志位满意指定条件时,才核算r0加1后的值,再写入到r0内

其间条件助记符如下:

EQ持平

NE不持平

MI负数

VS溢出

PL正数或零

HI无符号大于

LS无符号小于或等于

CS无符号大于或等于

CC无符号小于

GT有符号大于

GE有符号大于或等于

LE有符号小于或等于

LT有符号小于

AL无条件履行

S:决议指令的操作是否影响CPSR的值,用一个位存储,省掉则表明为0值,不然为1值

如SUBSR0,R0,#1;R0减1,成果放入R0,一起响影CPSR的值

SUBR0,R0,#1;R0减1,成果放入R0,不影响CPSR的值

Rd:方针存放器编码用4位存储

Rn:第1个操作数的存放器编码用4位存储

Operand2:第2个操作数用12位存储

寻址办法:是依据指令中给出的地址码字段来完结寻觅实在操作数地址的办法,共8种寻址办法:

存放器寻址、当即寻址、存放器直接寻址、基址寻址、多存放器寻址、仓库寻址、相对寻址、存放器移位寻址

//*寻址办法是要点需求了解背讼*

1.当即寻址

操作数是常量,用#表明常量。例

MOVR0,#0xFF000;指令省掉了第1个操作数存放器。将当即数0xFF000(第2操作数)装入R0存放器

SUBR0,R0,#64;R0减64,成果放入R0

#表明当即数0x或&表明16进制数不然表明十进制数

当即数寻址指令中的地址码便是操作数自身,能够当即运用的操作数。

其间,#0xFF000和#64都是当即数。该当即数坐落32位机器码中,占低位的12位。也便是说在ARM指令中以12位存储一个数据

那么,32位的数据(long或float)怎么存储?

32位的数据以一种特别的办法来处理

其间:高4位表明的无符号整数

低8位补0扩展为32位,然后循环右移x位来代表一个数。x=高4位整数*2

所以,不是每一个32位数都是合法的当即数,只要能经过上述结构得到的才是合法的立好数。如:

合法当即数:0xff,0x104,0xff0

不合法当即数:ox101,0x102,0xff1

2.存放器寻址

操作数的值在存放器中,指令履行时直接取出存放器值来操作

例:MOVR1,R2;将R2的值存入R1在第1个操作数存放器的方位存放R2编码

SUBR0,R1,R2;将R1的值减去R2的值,成果保存到R0在第2操作数方位,存放的是存放器R2的编码

存放器寻址是依据存放器编码获取存放器内存储的操作数

3.存放器直接寻址

操作数从存放器所指向的内存中取出,存放地存储的是内存地址

例:LDRR1,[R2];将R2指向的存储单元的数据读出,保存在R1中R2相当于指针变量

STRR1,[R2];将R1的值写入到R2所指向的内存

SWPR1,R1,[R2];将存放器R1的值和R2指定的存储单元的内容交流

[R2]表明存放器所指向的内存,相当于*p

LDR指令用于读取内存数据

STR指令用于写入内存数据

//—————————————————–

4.存放器基址寻址

操作数从内存址偏移后读取数据。常用于查表、数组操作、功用部件存放器拜访等。

基址:相当于首地址,地址偏移后取值作为操作数

基址存放器:用来存放基址的存放器

变址寻址:基址寻址也称为变址寻址

1)前索引寻址

例:LDRR2,[R3,#4];读取R3+4地址上的存储单元的内容,放入R2

LDRR2,[R3,#4]!;读取R3+4地址上的存储单元的内容,放入R2,然后R3内的地址变为R3+4,即R3=R3+4

[R3,#4]表明地址偏移后取值,相当于*(p+4)或p[4],R3内保存的地址不变

[R3,#4]!表明地址偏移后取值,相当于*(p+4)或p[4],!表明回写,即R3=R3-4,R3的值发生了改动

2)后索引寻址

例:LDRR2,[R3],#4;先读取R3地址上的存储单元的内容,放入R2,然后R3内的地址变为R3+4,即R3=R3+4

[R3],#4类似于*p++只不过自加的不是1,而是指定的4

[R3,#4]!类似于*++p只不过自加的不是1,而是指定的4

3)存放器的值作索引

例:LDRR2,[R3,R0];R0内存储索引值,R3内存地址,读取R3+R0地址上的存储单元的内容,放入R2

[R3,R0]表明地址偏移后取值,相当于*(p+i)或p[i]

5.多存放器寻址

一次可传送多个存放器的值,也称为块复制寻址

例:LDMIAR1!,{R2-R7,R12};将R1指向的存储单元中的数据读写到R2~R7、R12中,然后R1自加1

STMIAR1!,{R2-R7,R12};将存放器R2~R7、R12的值保存到R1指向的存储单元中,然后R1自加1

其间R1是基址存放器,用来存基址,R2-R7、R12用来存数据赋值编号小的存放器与低地址相对应,与存放器列表次第无关

!为可选后缀,表明改动R1的值,则当数据传送完毕之后,将最终的地址写入基址存放器

基址存放器不允许为R15,存放器列表能够为R0~R15的恣意组合。

这儿R1没有写成[R1]!,是因为这个位不是操作数位,而是存放器位

LDMIA和STMIA是块复制指令,LDMIA是从R1所指向的内存中读数据,STMIA是向R1所指向的内存写入数据

R1指向的是接连地址空间

6.存放器仓库寻址

是按特定次第存取存储区,按后进先出准则,运用专门的存放器SP(仓库指针)指向一块存储区

例:LDMIASP!,{R2-R7,R12};将栈内的数据,读写到R2~R7、R12中,然后下一个地址成为栈顶

STMIASP!,{R2-R7,R12};将存放器R2~R7、R12的值保存到SP指向的栈中

SP指向的是栈顶

7.相对寻址

即读取指令自身在内存中的地址。是相关于PC内指令地址偏移后的地址。

由程序计数器PC供给基准地址,指令中的地址码字段作为偏移量,两者相加后得到的地址即为操作数的有用地址。

例:

BLOOP;B指令用于跳转到标号LOOP指令处履行代码

LOOP

MOVR6#1

其间LOOP仅仅是标号,而不是地址,不是CPU指令,所以在指令的机器码中没有标号的机器码,而是

核算出了从B指令到MOV指令之间内存地址的差值,这个差值相当于PC的偏移量,即相当于:addpc,pc,#偏移量

B指令引起了PC存放器值的改动,PC内永久保存行将运转指令在内存中的地址。

8.存放器移位寻址

操作数在被运用前进行移位运算

例:MOVR0,R2,LSL#3;R2的值左移3位,成果放入R0,;便是R0=R2×8

LSL是移位指令,用于将前面存放器的数据左移

//^^^^^^^^^^^^^^^^^^^^^^^^^^下午^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

ARM汇编言句子子由指令、伪指令、伪操作、宏指令组成

三.ARM指令集

共包含6品种型:数据处理指令、跳转指令、程序状况指令、加载存取储指令、协处理指令、软间断指令

(一)、数据处理指令

数据处理指令,只能对存放器内容进行操作,而不能对内存进行操作,一切数据处理指令均可运用S后缀,并影响状况标志

包含:数据传送指令、算述指令、乘法指令、逻辑运算指令、比较指令、移位指令

1.数据传输指令

1)MOV数据传送指令

格局:MOVRd,

功用:Rd=操作数,操作数能够是存放器、被移位的存放器或当即数。

例:

MOVR0,#0xFF000;当即寻址,将当即数0xFF000(第2操作数)装入R0存放器

MOVR1,R2;存放器寻址,将R2的值存入R1

MOVR0,R2,LSL#3;移位寻址,R2的值左移3位,成果放入R0

2)MVN数据取反传送指令

格局:MVN,;

功用:将操作数传送到意图存放器Rd中,但该值在传送前被按位取反,即Rd=!op1;

例:

MVNR0,#0;R0=-1

mvn意为“取反传输”,它把源存放器的每一位取反,将得到的成果写入成果存放器。

movs和mvns指令对pc存放器赋值时有特别意义,表明要求在赋值的一起从spsr中康复cpsr。

mov和mvn指令,编译器会进行智能的转化。比方指令“movr1,0xffffff00”中的当即数是不合法的。

在编译时,编译器将其转化为“mvnr1,0xff”,这样就不违反当即数的要求。所以关于mov和mvn指令,

能够以为:合法的当即数反码也是合法的当即数。

2.算术指令

1)ADD加法指令

格局:ADD{}{S},,;

功用:Rd=Rn+op2

例:

ADDR0,R1,#5;R0=R1+5

ADDR0,R1,R2;R0=R1+R2

ADDR0,R1,R2,LSL#5;R0=R1+R2左移5位

2)ADC带进位加法指令

格局:ADC{}{S},,;

功用:Rd=Rn+op2+carry,carry为进位标志值。该指令用于完结超越32位的数的加法。

例如:

榜首个64位操作数存放在存放器R2,R3中;

第二个64位操作数存放在存放器R4,R5中;

64位成果存放在R0,R1中。

ADDSR0,R2,R4;低32位相加,S表明成果影响条件标志位的值

ADCR1,R3,R5;高32位相加

3)SUB减法指令

格局:SUB{}{S},,;

功用:Rd=Rn-op2

例:

SUBR0,R1,#5;R0=R1-5

SUBR0,R1,R2;R0=R1-R2

SUBR0,R1,R2,LSL#5;R0=R1-R2左移5位

4)SBC带借位减法指令

格局:SBC{}{S},,;

功用:Rd=Rn-op2-!carry

SUB和SBC生成进位标志的办法不同于惯例,假如需求借位则铲除进位标志,所以指令要对进位标志进行一个非操作。

例:

榜首个64位操作数存放在存放器R2,R3中;

第二个64位操作数存放在存放器R4,R5中;

64位成果存放在R0,R1中。

SUBSR0,R2,R4;低32位相减,S表明成果影响条件标志位的值

SBCR1,R3,R5;高32位相减

5)其它减法指令

RSB反向减法指令,同SUB指令,但倒换了两操作数的前后方位,即Rd=op2-Rn。

RSC带借位的反向减法指令,同SBC指令,但倒换了两操作数的前后方位,即Rd=op2-Rn-!carry。

rsb r0,r1,r2 /*r0=r2–r1*/

rsc r0,r1,r2 /*r0=r2–r1+carry–1*/

adds和adcs在进位时将cpsr的C标志置1;不然置0。

subs和sbcs在发生借位时将cpsr的C标志置0;不然置1。

3.乘法指令

1)MUL32位乘法指令

格局:MUL{}{S},,;

功用:Rd=Rn×op2

该指令依据S标志,决议操作是否影响CPSR的值;其间op2有必要为存放器。Rn和op2的值为32位的有符号数或无符号数。

例:

MULSR0,R1,R2;R0=R1×R2,成果影响存放器CPSR的值

2)MLA32位乘加指令

格局:MLA{}{S},,,;

功用:Rd=Rn×op2+op3op2和op3有必要为存放器。Rn、op2和op3的值为32位的有符号数或无符号数。

例:

MLAR0,R1,R2,R3;R0=R1×R2+R3

3)SMULL64位有符号数乘法指令

格局:SMULL{}{S},,,;

功用:RdhRdl=Rn×op2Rdh、Rdl和op2均为存放器。Rn和op2的值为32位的有符号数。

例:

SMULLR0,R1,R2,R3;R0=R2×R3的低32位R1=R2×R3的高32位

4)SMLAL64位有符号数乘加指令

格局:SMLAL{}{S},,,;

功用:RdhRdl=Rn×op2+RdhRdl;Rdh、Rdl和op2均为存放器。Rn和op2的值为32位的有符号数,RdhRdl的值为64位的加数。

例:

SMLALR0,R1,R2,R3;R0=R2×R3的低32位+R0R1=R2×R3的高32位+R1

5)UMULL64位无符号数乘法指令

格局:UMULL{}{S},,,;

功用:同SMULL指令,但指令中Rn和op2的值为32位的无符号数。

例:

UMULLR0,R1,R2,R3;R0=R2×R3的低32位R1=R2×R3的高32位其间R2,R3的值为无符号数

6)UMLAL64位无符号数乘加指令

格局:UMLAL{}{S},,,;

功用:同SMLAL指令,但指令中Rn,op2的值为32位的无符号数,RdhRdl的值为64位无符号数。

例:

UMLALR0,R1,R2,R3;R0=R2×R3的低32位+R0R1=R2×R3的高32位+R1

;其间R2,R3的值为32位无符号数R1,R0的值为64位无符号数

4.逻辑指令:and、orr、eor和bic

1)AND逻辑与指令

格局:AND{}{S},,;

功用:Rd=RnANDop2一般用于铲除Rn的特定几位。

例:

ANDR0,R0,#5;坚持R0的第0位和第2位,其他位清0

2)ORR逻辑或指令

格局:ORR{}{S},,;

功用:Rd=RnORop2一般用于设置Rn的特定几位。

例:

ORRR0,R0,#5;R0的第0位和第2位设置为1,其他位不变

3)EOR逻辑异或指令

格局:EOR{}{S},,;

功用:Rd=RnEORop2一般用于将Rn的特定几位取反。

例:

EORR0,R0,#5;R0的第0位和第2位取反,其他位不变

4)BIC位铲除指令

格局:BIC{}{S},,;

功用:Rd=RnAND(!op2)用于铲除存放器Rn中的某些位,并把成果存放到意图存放器Rd中

例:

BICR0,R0,#5;R0中第0位和第2位清0,其他位不变

5.比较指令

1)CMP比较指令

格局:CMP{},;

功用:Rn-op1,依据成果更新CPSR中条件标志位的值。

例:

CMPR0,#5;核算R0-5,依据成果设置条件标志位

ADDGTR0,R0,#5;ADD为加法指令,GT为判别条件标志位是否大于5,假如R0>5,则履行ADD指令

2)CMN反值比较指令

格局:CMN{},;

功用:同CMP指令,但存放器Rn的值是和op1取负的值进行比较。

例:

CMNR0,#5;把R0与-5进行比较

3)TST位测验指令

格局:TST{},;

功用:RnANDop1按位与后,更新CPSR中条件标志位,用于检查存放器Rn是否设置了op1中相应的位。

例:

TSTR0,#5;测验R0中第0位和第2位是否为1

4)TEQ持平测验指令

格局:TEQ{},;

功用:RnEORop1按位异或后,更新CPSR中条件标志位,用于检查存放器Rn的值是否和op1所表明的值持平。

例:

TEQR0,#5;判别R0的值是否和5持平

6.移位指令(位运算指令)

1)LSL(或ASL)左移

格局:存放器,LSL(或ASL)操作数

功用:将存放器内的数据左移,操作数是移位的位数在0-31之间

例:

MOVR0,R1,LSL#2;将R1中的内容左移两位后传送到R0中。

2)LSR操作右移

格局:存放器LSR操作数

功用:将存放嚣内的数据右移

例:

MOVR0,R1,LSR#2;将R1中的内容右移两位后传送到R0中,左端用零来填充。

3)其它移位

ASR右移,左端用第31位值来填充

ROR右移,循环右移,左端用右端移出的位来填充

RRX右移,循环右移,左端用进位标志位C来填充

//*arm体系结构第三天*

(二)、跳转指令

1)B跳转指令

格局:B{};

功用:跳转到addr地址。

例:

Bexit;程序跳转到标号exit处

2)BL带回来的跳转指令

格局:BL{};

功用:同B指令,但BL指令履行跳转操作的一起,还将PC(存放器R15)的值保存到LR存放器(存放器R14)中。

该指令用于完结子程序调用,程序的回来可经过把LR存放器的值到PC存放器中来完结。

例:

BLfunc;调用子程序func

func

MOVR15,R14;子程序回来

3)其它跳转指令

BLX带回来和状况切换的跳转指令,用于子程序调用和程序Thumb状况的切换。

BX带状况切换的跳转指令,处理器跳转到方针地址处,方针地址处的指令能够是ARM指令,也能够是Thumb指令。

跳转指令用于完结程序的跳转和程序状况的切换。

ARM程序规划中,完结程序跳转有两种办法:跳转指令、直接向程序存放器PC中写入方针地址值。

//—————————————————————————————-

(三)、程序状况指令

用于状况存放器和通用存放器间传送数据。总共有两条指令:MRS和MSR。两者结合可用来修正程序状况存放器的值。

1)MRS程序状况存放器到通用存放器的数据传送指令

格局:MRS{},CPSR/SPSR;

功用:用于将程序状况存放器的内容传送到方针存放器Rd中。

例:

MRSR0,CPSR;状况存放器CPSR的值存入存放器R0中

2)MSR通用存放器到程序状况存放器的数据传送指令

格局:MSR{}CPSR/SPSR_,;

功用:用于将存放器Rd的值传送到程序状况存放器中。

:用来设置状况存放器中需求操作的位。

32位的状况存放器能够分为4个域:

位[31:24]为条件标志位域,用f表明。

位[23:16]为状况位域,用s表明。

位[15:8]为扩展位域,用x表明。

位[7:0]为操控位域,用c表明。

例:

MSRCPSR_f,R0;用R0的值修正CPSR的条件标志域

MSRCPSR_fsxc,#5;CPSR的值修正为5

(四)、加载存储指令

该调集的指令运用频频,当数据存放在内存中时,有必要先把数据从内存装载到存放器,履行完后再把存放器

中的数据存储到内存中

1.单数据访存指令

1)单数据加载指令

格局:LDR(或LDRB、LDRBT、LDRH、LDRSB、LDRSH、LDRT、STR、STRB、STRBT、STRH、STRT),;

功用:内存地址中的数据装载到方针存放器Rd中,一起还能够把组成的有用地址写回到基址存放器。

寻址办法:Rn:基址存放器。Rm:变址存放器。Index:偏移量,12位的无符号数。

LDRRd,[Rn];把内存中地址为Rn的字数据装入存放器Rd中

LDRRd,[Rn,Rm];将内存中地址为Rn+Rm的字数据装入存放器Rd中

LDRRd,[Rn,#index];将内存中地址为Rn+index的字数据装入Rd中

LDRRd,[Rn,Rm,LSL#5];将内存中地址为Rn+Rm×32的字数据装入Rd

LDRRd,[Rn,Rm]!;将内存中地址为Rn+Rm的字数据装入Rd,并将新地址Rn+Rm写入Rn

LDRRd,[Rn,#index]!;将内存中地址为Rn+index的字数据装入Rd,并将新地址Rn+index写入Rn

LDRRd,[Rn,Rm,LSL#5]!;将内存中地址为Rn+Rm×32的字数据装入Rd,并将新地址Rn+Rm×32写入Rn

LDRRd,[Rn],Rm;将内存中地址为Rn的字数据装入存放器Rd,并将新地址Rn+Rm写入Rn

LDRRd,[Rn],#index;将内存中地址为Rn的字数据装入存放器Rd,并将新地址Rn+index写入Rn

LDRRd,[Rn],Rm,LSL#5;将内存中地址为Rn的字数据装入存放器Rd,并将新地址Rn+Rm×32写入Rn

各指令的差异:

(1)LDR字数据加载指令

将内存地址中的字数据装载到方针存放器Rd中

例:LDRR0,[R1,R2,LSL#5]!;将内存中地址为R1+R2×32的字数据装入存放器R0,并将新地址R1+R2×32写入R1

(2)LDRB字节数据加载指令

同LDR,仅仅从内存读取一个8位的字节数据而不是一个32位的字数据,并将Rd的高24位清0。

例:LDRBR0,[R1];将内存中开端地址为R1的一个字节数据装入R0中

(3)LDRBT用户办法的字节数据加载指令

同LDRB指令,但无论处理器处于何种办法,都将该指令当作一般用户办法下的内存操作。

(4)LDRH半字数据加载指令

同LDR指令,但该指令仅仅从内存读取一个16位的半字数据而不是一个32位的字数据,并将Rd的高16位清0。

例:LDRHR0,[R1];将内存中开端地址为R1的一个半字数据装入R0中

(5)LDRSB有符号的字节数据加载指令

同LDRB指令,但该指令将存放器Rd的高24位设置成所装载的字节数据符号位的值。

例:LDRSBR0,[R1];将内存中开端地址为R1的一个字节数据装入R0中,R0的高24位设置成该字节数据的符号位

(6)LDRSH有符号的半字数据加载指令

同LDRH指令,但该指令将存放器Rd的高16位设置成所装载的半字数据符号位的值。

例:LDRSHR0,[R1];将内存中开端地址为R1的一个16位半字数据装入R0中,R0的高16位设置成该半字数据的符号位

(7)LDRT用户办法的字数据加载指令

同LDR指令,但无论处理器处于何种办法,都将该指令当作一般用户办法下的内存操作。有用地址有必要是字对齐的

2)单数据存储指令

格局:STR(或STR、STRB、STRBT、STRH、STRT),;

功用:将存放器数据写入到内存中

寻址办法:Rn:基址存放器。Rm:变址存放器。Index:偏移量,12位的无符号数。

STRRd,[Rn];将存放器Rd中的字数据写入到内存中地址为Rn内存中

STRRd,[Rn,Rm];将存放器Rd中的字数据写入到内存中地址为Rn+Rm的内存中

STRRd,[Rn,#index];将存放器Rd中的字数据写入到内存中地址为Rn+index内存中

STRRd,[Rn,Rm,LSL#5];将存放器Rd中的字数据写入到内存中地址为Rn+Rm×32内存中

STRRd,[Rn,Rm]!;将存放器Rd中的字数据写入到内存中地址为Rn+Rm的内存中

STRRd,[Rn,#index]!;将存放器Rd中的字数据写入到内存中地址为Rn+index的内存中,并将新地址Rn+index写入Rn

STRRd,[Rn,Rm,LSL#5]!;将存放器Rd中的字数据写入到内存中地址为Rn+Rm×32的内存中,并将新地址Rn+Rm×32写入Rn

STRRd,[Rn],Rm;将存放器Rd中的字数据写入到内存中地址为Rn的内存中,并将新地址Rn+Rm写入Rn

STRRd,[Rn],#index;将存放器Rd中的字数据写入到内存中地址为Rn的内存中,并将新地址Rn+index写入Rn

STRRd,[Rn],Rm,LSL#5;将存放器Rd中的字数据写入到内存中地址为Rn的内存中,并将新地址Rn+Rm×32写入Rn

(1)STR字数据存储指令

把存放器Rd中的字数据(32位)保存到addr所表明的内存地址中,一起还能够把组成的有用地址写回到基址存放器。

例:STRR0,[R1,#5]!;把R0中的字数据保存到以R1+5为地址的内存中,然后R1=R1+5

(2)STRB字节数据存储指令

把存放器Rd中的低8位字节数据保存到addr所表明的内存地址中。

例:STRBR0,[R1];将存放器R0中的低8位数据存入R1表明的内存地址中

(3)STRBT用户办法的字节数据存储指令

同STRB指令,但无论处理器处于何种办法,该指令都将被当作一般用户办法下的内存操作。

(4)STRH半字数据存储指令

把存放器Rd中的低16位半字数据保存到addr所表明的内存地址中,并且addr所表明的地址有必要是半字对齐的。

例:STRHR0,[R1];将存放器R0中的低16位数据存入R1表明的内存地址中

(5)STRT用户办法的字数据存储指令

同STR指令,但无论处理器处于何种办法,该指令都将被当作一般用户办法下的内存操作。

2.多数据访存指令

1)批量数据加载指令

格局:LDM{}{}{!},{^};

功用:从一片接连的内存单元读取数据到各个存放器中,内存单元的开端地址为基址存放器Rn的值,各个存放器由存放

器列表regs表明。

该指令一般用于多个存放器数据的出栈。

type字段品种:

IA:每次传送后地址加1。

IB:每次传送前地址加1。

DA:每次传送后地址减1。

DB:每次传送前地址减1。

FD:满递减仓库。

ED:空递减仓库。

FA:满递加仓库。

EA:空递加仓库。

仓库寻址的指令LDMFA/STMFA、LDMEA/STMEA、LDMFD/STMFD、LDMED/STMED。

LDM和STM表明多存放器寻址,即一次能够传送多个存放器值。

LDM:一次装载多个,这儿用来出栈。

STM:一次存储多个,这儿用来入栈。

F/E表明指针指向的方位

F:full满仓库,表明仓库指针指向最终一个入栈的有用数据项。

E:empty空仓库,表明仓库指针指向下一个要放入的空地址。

A/D表明仓库的成长办法

A:仓库向高地址成长,即递加仓库。

D:仓库向低地址成长,即递减仓库。

留意:有一个约好,编号低的存放器在存储数据或许加载数据时对应于存储器的低地址。

FD、ED、FA和EA指定是满栈仍是空栈,是升序栈仍是降序栈,用于仓库寻址。

一个满栈的栈指针指向前次写的最终一个数据单元.

空栈的栈指针指向榜首个闲暇单元。

一个降序栈是在内存中反向增加而升序栈在内存中正向增加。

{!}:若选用了此后缀,则当指令履行完毕后,将最终的地址写入基址存放器。

{^}:当regs中不包含PC时,该后缀用于指示指令所用的存放器为用户办法下的存放器,

不然指示指令履行时,将存放器SPSR的值到CPSR中。

2)批量数据存储指令

格局:STM{}{}{!},{^};

功用:将各个存放器的值存入一片接连的内存单元中,内存单元的开端地址为基址存放器Rn的值

各个存放器由存放器列表regs表明。该指令一般用于多个存放器数据的入栈。

{^}:指示指令所用的存放器为用户办法下的存放器。其他参数用法同LDM指令。

例:STMEAR13!,{R0-R12,PC};将存放器R0~R12以及程序计数器PC的值保存到R13指示的仓库中

3.数据交流指令

1)字数据交流指令

格局:SWP,,[];

功用:Rd=[op2],[op2]=op1

从op2所表明的内存装载一个字并把这个字放置到意图存放器Rd中,然后把存放器op1的内容存储到同一内存地址中。

例:SWPR0,R1,[R2];将R2所表明的内存单元中的字数据装载到R0,然后将R1中的字数据保存到R2所表明的内存单元中

2)字节数据交流指令

格局:SWPB,,[];

功用:从op2所表明的内存装载一个字节并把这个字节放置到意图存放器Rd的低8位中,Rd的高24位设置为0;

然后将存放器op1的低8位数据存储到同一内存地址中。

例:SWPBR0,R1,[R2];将R2所表明的内存单元中的一个字节数据装载到R0的低8位,然后将R1中的低8位字节

数据保存到R2所表明的内存单元中

//^^^^^^^^^^^^^^^^^^^^^^^^^^下午^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

(五)、协处理指令

1)CDP协处理器操作指令

格局:CDP{}

,,,,,;

功用:用于传递指令给协处理器p,要求其在存放器CRn和CRm上,进行操作opcode1,并把成果存放到CRd中,

能够运用opcode2供给与操作有关的弥补信息。指令中的一切存放器均为协处理器的存放器,操作由协处理器完结。

指令中:

P为协处理器编号;

CRd为意图存放器的协处理器存放器;

CRm和CRn为存放操作数的协处理器存放器;

Opcode1和opcode2为协处理器行将履行的操作。

例:CDPp5,5,c0,c1,c2,9;该指令用于告诉协处理器p5,在c1和c2上履行操作5和9,并将成果存放到c0中。

2)LDC协处理器数据读取指令

格局:LDC{}{L}

,,;

功用:将addr表明的内存地址中的接连数据传送到意图存放器CRd中。

L表明指令为长读取操作,比方用于双精度数据的传输;

意图存放器CRd为协处理器的存放器;

addr的寻址办法同LDR指令,其存放器为ARM处理器的存放器。

例:LDCp5,c1,[R1+5]:该指令用于将R1+5所对应的存储单元中的数据,传送到协处理器p5的存放器c1中。

3)STC协处理器数据存储指令

格局:STC{}{L}

,,;

功用:将存放器CRd的值传送到addr表明的内存地址中。指令中各参数用法同LDC。

例如:STCp5,c1,[R1+5];该指令用于将协处理器p5中存放器c1的数据传送到R1+5所对应的存储单元中。

4)MCRARM存放器到协处理器存放器的数据传送指令

格局:MCR{}

,,,,{,op2};

功用:将ARM处理器的存放器Rd中的数据传送到协处理器p的存放器CRn,CRm中;op1,op2为协处理器行将履行的操作。

例:MCRp5,5,R1,C1,C2,9;该指令将R1中的数据传送到协处理器p5的存放器C1,C2中,协处理器履行操作5和9。

MRC协处理器存放器到ARM存放器的数据传送指令

格局:MRC{}

,,,,{,op2};

功用:将协处理器p的存放器CRn,CRm的数据传送到ARM处理器的存放器Rd中;op1,op2为协处理器行将履行的操作。

例:MRCp5,5,R1,C1,C2,9;该指令将存放器C1,C2中的数据传送到R1中,协处理器p5协处理器履行操作5和9。

(六)、反常间断指令

反常间断发生指令:用于体系调用和调试。

1)SWI软件间断指令

格局:SWI{}24位的当即数;

功用:用于发生软件间断,以运用户程序调用操作体系的体系例程。

指令中24位的当即数指定用户程序调用体系例程的类型,其参数经过通用存放器传递。当24位的当即数

被疏忽时,体系例程类型由存放器R0指定,其参数经过其他通用存放器传递。

例:SWI0X05;调用编号为05的体系例程。

2)BKPT断点间断指令

格局:BKPT16位的当即数;

功用:用于发生软件断点间断,以便软件调试时运用。16位的当即数用于保存软件调试中额定的断点信息。

指令操作的伪代码:

(七)、信号量操作指令

信号量操作指令:用于进程间的同步互斥,供给对信号量的原子操作。

(八)、ARM程序常见结构

1.子函数和主函数

运用BL指令进行调用,该指令会把回来的PC值保存在LR

AREAExample,CODE,READONLY;声明代码段Example

ENTRY;程序进口

Start

MOVR0,#0;设置实参,将传递给子程骗子的实参存放在r0和r1内

MOVR1,#10

BLADD_SUM;调用子程序ADD_SUM

BOVER;跳转到OVER标号处,进入完毕

ADD_SUM

ADDR0,R0,R1;完结两数相加

MOVPC,LR;子程序回来,R0内为回来的成果

OVER

END

运转进程

(1)程序从ENTRY后边指令处开端运转(即主函数)

R0和R1先准备好数据令子函数运算时运用

(2)BL为跳转指令,用于调用子函数后边为函数标号。

在调用函数的进程中,主动将PC内的值保存到LR(R14)内备份,PC内当时的值为下一条要履行的指令地址

(即BOVER指令地址),在子函数完毕前将该地址康复到PC内

(3)B为跳转指令,用于跳转到指定的标号后,此处跳转到程序完毕

(4)MOVPC,LR是子函数内的最终一条句子,用于将LR内保存的地址康复到PC内

PC(R15)程序计数器存储要履行的指令在内存中的地址

PC的值=当时正在履行指令在内存中的地址+8

2.条件跳转句子

AREAExample,CODE,READONLY;声明代码段Example

ENTRY;程序进口

Start

MOVR0,#2;将R0赋初值2

MOVR1,#5;将R1赋初值5

ADDR5,R0,R1;将R0和R1内的值相加并存入R5

CMPR5,#10

BEQDOEQUAL;若R5为10,则跳转到DOEQUAL标签处

WAIT

CMPR0,R1

ADDHIR2,R0,#10;若R0>R1则R2=R0+10

ADDLSR2,R1,#5;若R1<=R2则R2=R1+5

DOEQUAL

ANDSR1,R1,#0x80;R1=R1&0x80,并设置相应标志位

BNEWAIT;若R1的d7位为1则跳转到WAIT标签

OVER

END

运转进程

(1)程序从ENTRY后边指令处开端运转(即主函数)

R0和R1赋初值2和5

将R0与R1相加后存入R5内

(2)CMP用于比较两个数据,指令格局如下:

CMP操作数1,操作数2

CMP用于把一个存放器的内容和另一个存放器或当即数进行比较,一起

更新CPSR中条件标志位的值。标志位表明操作数1和操作数2的联系。然后履行后边的句子

(3)条件助记符

BEQB为跳转指令,EQ为条件持平,读取CPSR内的条件标志位,如持平则跳转到所指定的标号处

BNEB为跳转指令,NE为不持平(0),如不持平则跳转到所指定的标号处

ADDHIADD为相加指令,HI为无符号大于,如大于则履行相加

ADDLSADD为相加指令,LS为无符号小于或等于,如小于或等于则相加

(4)位运算

ANDSAND按位与,0x80取出第7位,S为将该位与的值写入标志位

3.循环句子

AREAExample,CODE,READONLY;声明代码段Example

ENTRY;程序进口

Start

MOVR1,#0;将R1赋初值0

LOOP

ADDR1,R1,#1

CMPR1,#10

BCCLOOP;R1小于10则履行跳转到LOOP处履行循环,即R1从0到10后退出循环

END

例:编写一具有完好汇编格局的程序,完结冒泡法排序功用。

设无符号字数据存放在从0x400004开端的区域,字数据的数目字存放在0x400000中。

AREASORT,CODE,READONLY

ENTRY

START

MOV R1,#0x400000

LP

SUBS R1,R1,#1

BEQ EXIT

MOV R7,R1

LDR R0,=0x400004

LP1

LDR R2,[R0],#4

LDR R3,[R0]

CMP R2,R3

STRLOR3,[R0,#-4]

STRLOR2,[R0]

SUBSR7,R7,#1

BNE LP1

B LP

EXIT

END

操练:

1.编写1+2+3+…+100的汇编程序。

2.完结子函数,该函数回来两个参数中的最大值,在主函数内调用。

//*arm体系结构第四天*

四.伪操作和宏指令

伪指令——是汇编言语程序里的特别指令助记符,在汇编时被适宜的机器指令代替。

伪操作——为汇编程序所用,在源程序进行汇编时由汇编程序处理,只在汇编进程起效果,不参加程序运转。

宏指令——经过伪操作界说的一段独立的代码。在调用它时将宏体刺进到源程序中。也便是常说的宏。

阐明:一切的伪指令、伪操作和宏指令,均与详细的开发东西中的编译器有关

1.宏界说(MACRO、MEND)

格局:MACRO

{$标号名}宏名{$参数1,$参数2,……}

指令序列

MEND

MACRO、MEND伪指令能够将一段代码界说为一个全体,称为宏指令,在程序中经过宏指令屡次调用该段代码。

{}为可选项

$标号在宏指令被翻开时,标号会被替换为用户界说的符号

在宏界说体的榜首行应声明宏的原型(包含宏名、所需的参数),然后就能够在汇编程序中经过宏名来调用该指令序列

写在代码段或数据段前面

MEXIT跳出宏

例:没有参数的宏(完结子函数回来)

MACRO

MOV_PC_LR;宏名

MOVPC,LR;子程序回来,R0内为回来的成果

MEND

AREAExample,CODE,READONLY;声明代码段Example

ENTRY;程序进口

Start

MOVR0,#0;设置实参,将传递给子程骗子的实参存放在r0和r1内

MOVR1,#10

BLADD_NUM;调用子程序ADD_NUM

BLSUB_NUM;调用子程序SUB_NUM

BOVER;跳转到OVER标号处,进入完毕

EXPORTADD_NUM

ADD_NUM

ADDR0,R0,R1;完结两数相加

MOV_PC_LR;调用宏,代表子函数完毕

EXPORTSUB_NUM

SUB_NUM

SUBR0,R1,R0;完结两数相减

MOV_PC_LR;调用宏,代表子函数完毕

OVER

END

例:有参数宏

宏界说从MACRO伪指令开端,到MEND完毕,并能够运用参数。类似于C的#define

MACRO;宏界说

CALL$Function,$dat1,$dat2;宏称号为CALL,带3个参数

IMPORT$Function;声明外部子程序宏开端

MOVR0,$dat1;设置子程序参数,R0=$dat1

MOVR1,$dat2

BL$Function;调用子程序宏最终一句

MEND;宏界说完毕

CALLFADD1,#3,#2;宏调用,后边是三个参数

汇编预处理后,宏调用将被翻开,程序清单如下:

IMPORTFADD1

MOVR0,#3

MOVR1,#3

BLFADD1

2.符号界说伪操作

1)界说常量(EQU)

格局:标号称号EQU表达式{,类型}

用于为程序中的常量、标号等界说一个等效的字符称号,类似于C言语中的#define。

其间EQU可用*代替。

标号称号:为常量名。

表达式:存放器的地址值、程序中的标号、32位地址常量、32位常量

当表达式为32位的常量时,能够指定表达式的数据类型,能够有以下三品种型:

CODE16、CODE32和DATA

示例:EQU的运用

XEQU45;即#defineX45,有必要顶格

YEQU64

stack_topEQU0x30200000,CODE32

AREAExample,CODE,READONLY

CODE32

ENTRY

Start

LDRSP,=stack_top;stack_top内的值0x30200000是地址,=stack_top是取stack_top常量地址(即指针的指针)

MOVR0,#X;将X替换为45

STRR0,[SP];将R0内的45存入到SP所指向的内存中(SP此刻是指针的指针)

MOVR0,#Y

LDRR1,[SP];从内存中读取数据到R1内

ADDR0,R0,R1

STRR0,[SP]

END

注:X,Y,stack_top为标号,有必要顶格写,大多写在代码段外面

2)界说变量

常量:数字常量,有三种表明办法:十进制数、十六进制数、字符串常量、布尔常量(如testnoSETS{FALSE})

变量:数字变量、逻辑变量、字符串变量

(1)*GBLA、GBLL、GBLS界说大局变量

格局:GBLA(GBLL、GBLS)大局变量名

GBLA伪指令用于界说一个大局的数字变量,并初始化为0;

GBLL伪指令用于界说一个大局的逻辑变量,并初始化为F(假);

GBLS伪指令用于界说一个大局的字符串变量,并初始化为空;

因为以上三条伪指令用于界说大局变量,因而在整个程序规模内变量名有必要仅有。

示例:大局变量的界说与赋值

GBLAcount;界说大局变量

countSETA2;给大局变量赋值为2,有必要顶格

AREAExample,CODE,READONLY

CODE32

ENTRY

Start

MOVR0,#count;将count内的值写入R0内

ADDR0,R0,#2

BStart

END

注:在赋值进程中,大局变量名有必要顶格写,大局变量常在代码段外界说和赋值

示例:变量与内存地址

GBLAglobv

globvSETA23

AREAExample,CODE,READONLY;声明代码段Example

ENTRY;程序进口

Start

LDRR0,=globv;golbv是大局变量,将内存地址读入到R0内

LDRR1,[R0];将内存数据值读入到R1内

ADDR1,R1,#2

STRR1,[R0];将修正后数据再赋给变量

MOVR0,#0

OVER

END

注:#取变量值=取变量地址[R0]读取R0内地址所指向的数据值

(2)*LCLA、LCLL、LCLS界说部分变量

格局:LCLA(LCLL或LCLS)部分变量名

LCLA伪指令用于界说一个部分的数字变量,并初始化为0;

LCLL伪指令用于界说一个部分的逻辑变量,并初始化为F(假);

LCLS伪指令用于界说一个部分的字符串变量,并初始化为空;

以上三条伪指令有必要写在宏界说内,用于声明部分变量,宏完毕,部分变量不再起效果

示例:

LCLAnum;声明一个部分的数字变量,变量名为num

numSETA0xaa;将该变量赋值为0xaa

LCLLisOk;声明一个部分的逻辑变量,变量名为isOk

isOkSETL;将该变量赋值为真

LCLSstr1;界说一个部分的字符串变量,变量名为str1

str1SETS”Testing”;将该变量赋值为”Testing”

示例:部分变量的界说与赋值

MACRO

MOV_START;宏名

LCLAx;界说部分变量

LCLAy

xSETA12;有必要顶格写

ySETA24

MOVR0,#2

MOVR1,#3

ADDR0,R0,R1

MEND

AREAExample,CODE,READONLY;声明代码段Example

ENTRY;程序进口

Start

MOV_START

MOVR0,#0

OVER

END

注:在赋值进程中,部分变量名有必要顶格写,部分变量有必要在宏界说内运用

(3)*SETA、SETL和SETS用于给一个现已界说的大局变量或部分变量赋值。

SETA伪指令用于给一个数学变量赋值;

SETL伪指令用于给一个逻辑变量赋值;

SETS伪指令用于给一个字符串变量赋值;

其间,变量名为现已界说过的大局变量或部分变量,表达式为行将赋给变量的值。

(4)变量代换$

$在数字变量前,将变值转化为十六进制字符串

$在逻辑变量前,将变量转化为真或假

$在字符串变量前,替换后边变量的字符串

如:

LCLSY1;界说部分字符串变量Y1和Y2

LCLSY2

Y1SETS”WORLD!”

Y2SETS”LELLO,$Y1″;将字符串Y2的值替换$Y1,构成新的字符串

3)、界说一个存放器(RN)

格局:称号RN表达式

RN伪指令用于给一个存放器界说一个别号。

示例:

TempRNR0;将R0界说一个别号Temp

4)界说存放器列表(RLIST)

格局:称号RLIST{存放器列表}

用于对一个通用存放器列表界说称号,运用该伪指令界说的称号可在ARM指令LDM/STM中运用。

在LDM/STM指令中,存放器列表中的存放器拜访次第总是先拜访编号较低的存放器,再拜访编号较高的存放器,而不论存放器列表中各存放器的摆放次第。

示例:RegListRLIST{R0-R5,R8,R10};将存放器列表称号界说为RegList,用于多存放器寻址(后边详解)

5)界说协处理器存放器(CN)

格局:称号CN协处理器的存放器编号

示例:PowerCN6;将协处理器的存放器6称号界说为Power

6)界说协处理器(CP)

格局:称号CP协处理器名

示例:DmuCP6;将协处理器6称号界说为Dmu

7)界说浮点或精度存放器(DN,SN,FN)

格局:称号DN双精度存放器编号;DN为双精度VFP存放器界说称号

格局:称号SN单精度存放器编号;SN为单精度VFP存放器界说称号

格局:称号FN浮点存放器编号;FN为浮点存放器界说称号

示例:

heightDN6;将VFP双精度存放器6称号界说为height

widthSN16;将VFP单精度存放器16称号界说为width

heightFN6;将浮点存放器6称号界说为height

//^^^^^^^^^^^^^^^^^^^^^^^^^^下午^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

3.数据界说伪操作(请求内存)

数据界说伪指令用于为特定的数据分配存储单元,一起可完结已分配存储单元的初始化。

1)按类型分配内存

格局:标号伪指令表达式

标号

表达式:初始化的值,表达式能够为程序标号或字符、数字表达式

伪指令:如下

(1)DCB用于分配一片接连的字节存储单元(字符数组),可用=号代替

StrDCB”Thisisatest!”;分配一片接连的字节存储单元并初始化。

(2)DCW(或DCWU)用于分配一片接连的半字存储单元(16位短整型数组),DCW半字对齐,DCWU不严厉半字对齐。

DataTestDCW1,2,3

(3)DCD(或DCDU)用于分配一片接连的字存储单元(32位,整型数组),DCD可用&代替,DCD字对齐的

DataTestDCD4,5,6

(4)DCFD(或DCFDU)为双精度的浮点数分配一片接连的字存储单元,每个双精度的浮点数占有两个字单元。

FDataTestDCFD2E115,-5E7

(5)DCFS(或DCFSU)为单精度的浮点数分配一片接连的字存储单元,每个单精度的浮点数占有一个字单元。

FDataTestDCFS2E5,-5E-7

(6)DCQ(或DCQU)用于分配一片以8个字节为单位的接连存储区域(每8字节为一个数据的数组)

DataTestDCQ100;分配一片接连的存储单元并初始化为指定的值100。

2)请求接连内存

(1)请求一个接连内存(SPACE)

用于分配一片接连的存储区域并初始化为0,可用%代替

格局:标号SPACE表达式

表达式为要分配的字节数

例:DataSpaceSPACE100;分配接连100字节的存储单元并初始化为0。

(2)声明一个数据缓冲池的开端(LTORG)

一般,把数据缓冲池放在代码段的最终面,下一个代码段之前,或END之前

示例:

AREAExample,CODE,READONLY;声明代码段Example

ENTRY;程序进口

Start

BLfuncl

funcl

LDRR0,=0x12345678

ADDR1,R1,R0

MOVPC,LR

LTORG;界说缓冲池0x12345678LTORG依据LDR确认内存地址

dataSPACE4200;从当时方位开端分配4200字节内存

END

(3)界说一个结构化的内存表首地址(MAP)

格局:MAP表达式{,基址存放器}

用于界说一个结构化的内存表的首地址。可用^代替。

表达式能够为程序中的标号或数学表达式,基址存放器为可选项.

当基址存放器选项不存在时,表达式的值即为内存表的首地址,

当该选项存在时,内存表的首地址为表达式的值与基址存放器的和。

例:

DatastrucSPACE280;分配280个字节单元

MAPDatastruc;内存表的首地址为Datastruc内存块

(4)界说一个结构化内存表的数据域(FILED

用于界说一个结构化内存表中的数据域。可用#代替

格局:标号FILED表达式

FIELD伪指令常与MAP伪指令合作运用来界说结构化的内存表。表达式的值为当时数据域所占的字节数。

标号为数据域(字段、成员变量)名

MAP伪指令界说内存表的首地址,

FIELD伪指令界说内存表中的各个数据域,并能够为每个数据域指定一个标号供其他的指令引证。(3)内存首地址(MAP)

MAP伪指令一般与FIELD伪指令合作运用来界说结构化的内存表。

示例:

DatastrucSPACE280;分配280个字节单元

MAPDatastruc;内存表的首地址为Datastruc内存块

constaFIELD4;字段consta长度4字节,相对地址0

constabFIELD4;字段constab长度4字节,相对地址4

xFIELD8;字段x长度8字节,相对地址8

yFIELD8;字段y长度8字节,相对地址16

stringFIELD256;字段string长度256字节,相对地址24

LDRR6,[R9,consta];引证内存表中的数据域

留意:MAP伪操作和FIELD伪操作仅仅是界说数据结构,他们并不实践分配内存单元,而SPACE用于分配内存

4.汇编操控伪操作

用于操控汇编程序的履行流程,常用的汇编操控伪指令包含以下几条:

(1)IF逻辑表达式…ELSE…ENDIF条件操控

(2)WHILE逻辑表达式…WEND循环操控

例:条件编译

AREAExample,CODE,READONLY

CODE32

Data_in*100;界说标号Data_in的值为100在ENTRY进口之前

GBLAcount;界说大局变量

countSETA20

ENTRY

Start

IFcount

MOVR0,#3

ELSE

MOVR1,#24

ENDIF

MOVR1,#12

ADDR0,R0,R1

END

例:循环编译

GBLACounter;声明一个大局的数学变量,变量名为Counter

CounterSETA3;由变量Counter操控循环次数

……

WHILECounter<10

指令序列

IFcontinue

MEXIT;退出宏

ENDIF

WEND

5.其他常用的伪指令

1)、AREA

格局:AREA段名特色1,特色2,……

AREA伪指令用于界说一个代码段或数据段。其间,段名若以数字开端,则该段名需用”|”括起来,如|1_test|。

特色字段表明该代码段(或数据段)的相关特色,多个特色用逗号?

—CODE特色:用于界说代码段,默以为READONLY。

—DATA特色:用于界说数据段,默以为READWRITE。

—READONLY特色:指定本段为只读,代码段默以为READONLY。

—READWRITE特色:指定本段为可读可写,数据段的默许特色为READWRITE。

—ALIGN特色:运用办法为ALIGN表达式。在默许时,ELF(可履行衔接文件)的代码段和数据段是按字对齐的

—COMMON特色:界说一个通用的段,不包含任何的用户代码和数据。各源文件中同名的COMMON段同享同一段存储单元

一个汇编言语程序至少要包含一个段,当程序太长时,也能够将程序分为多个代码段和数据段。

运用示例:

AREAInit,CODE,READONLY

该伪指令界说了一个代码段,段名为Init,特色为只读

2)、ENTRY

格局:ENTRY

用于指定汇编程序的进口点。一个源文件里最多只能有一个ENTRY(能够没有)。

3)、END

格局:END

用于告诉编译器现已到了源程序的完毕。

4)、CODE16、CODE32

格局:CODE16(或CODE32)

CODE16伪指令告诉编译器,这以后的指令序列为16位的Thumb指令。

CODE32伪指令告诉编译器,这以后的指令序列为32位的ARM指令。

在运用ARM指令和Thumb指令混合编程的代码里,可用这两条伪指令进行切换

示例:

AREAInit,CODE,READONLY

CODE32;告诉编译器这以后的指令为32位的ARM指令

LDRR0,=NEXT+1;将跳转地址放入存放器R0

BXR0;程序跳转到新的方位履行,并将处理器切换到Thumb作业状况

……

CODE16;告诉编译器这以后的指令为16位的Thumb指令

NEXTLDRR3,=0x3FF

……

END;程序完毕

5)、EXPORT(或GLOBAL)

格局:EXPORT标号

export伪指令用于在程序中声明一个大局的标号,该标号可在其他的文件中引证。

6)、IMPORT

格局:IMPORT标号

IMPORT伪指令用于告诉编译器要运用的标号在其他的源文件中界说,但要在当时源文件中引证

假如当时源文件实践并未引证该标号,该标号也会被加入到当时源文件的符号表中。

7)、EXTERN

格局:EXTERN标号

EXTERN伪指令用于告诉编译器要运用的标号在其他的源文件中界说,但要在当时源文件中引证

假如当时源文件实践并未引证该标号,该标号就不会被加入到当时源文件的符号表中。

8)、GET(或INCLUDE)

格局:GET文件名

GET伪指令用于将一个源文件包含到当时的源文件中,并将被包含的源文件在当时方位进行汇编处理。

汇编程序中常用的办法是在某源文件中界说一些宏指令,用EQU界说常量的符号称号,用MAP和FIELD界说结构化的数据类型,然后用GET伪指令将这个源文件包含到其他的源文件中。运用办法与C言语中的”include”类似。

GET伪指令只能用于包含源文件,包含方针文件需求运用INCBIN伪指令

示例:

AREAInit,CODE,READONLY

GETa1.s;告诉编译器当时源文件包含源文件a1.s

GETC:\a2.s;告诉编译器当时源文件包含源文件C:\a2.s……

END

9)、INCBIN

格局:INCBIN文件名

INCBIN伪指令用于将一个方针文件或数据文件包含到当时的源文件中

示例:

AREAInit,CODE,READONLY

INCBINa1.dat;告诉编译器当时源文件包含文件a1.dat

INCBINC:\a2.txt;告诉编译器当时源文件包含文件C:\a2.txt……

END

10)、ROUT

格局:{称号}ROUT

ROUT伪指令用于给一个部分变量界说效果规模。

在程序中未运用该伪指令时,部分变量的效果规模为地点的AREA,

而运用ROUT后,部分变量的作为规模为当时ROUT和下一个ROUT之间。

11)、ALIGN

格局:ALIGN{表达式{,偏移量}}

ALIGN伪指令可经过增加填充字节的办法,使当时方位满意必定的对其办法

表达式的值用于指定对齐办法,或许的取值为2的幂,如1、2、4、8、16等。

偏移量也为一个数字表达式,若运用该字段,则当时方位的对齐办法为:2的表达式次幂+偏移量。

示例:

AREAInit,CODE,READONLY,ALIEN=3;指定后边的指令为8字节对齐。

五.ARM汇编伪指令(读取内存地址)

1)ADR及ADRL

将PC相对偏移的地址或根据存放器相对偏移的地址值读取到存放器中

格局:ADR(ADRL)存放器,地址表达式

ADR小规模的地址读取伪指令,

ADRL中等规模的地址读取伪指令

例:

查表

ADRR0,D_TAB;加载转化表地址

LDRBR1,[R0,R2];运用R2作为参数,进行查表

……

D_TAB

DCB0xC0,0xF9,0xA4,0xB0,0x99,0x92

2)LDR

用于加载32位当即数或一个地址值到指定的存放器,大规模的地址读取伪指令.

LDR一般都是作加载指令,可是它也能够作伪指令。效果是装载一个32bit常数和一个地址到存放器。

格局:LDR存放器,=地址表达式

COUNTEQU0x56000054;COUNT是一个变量,地址为0x56000054。

LDRR1,=COUNT;将COUNT这个变量的值(地址),也便是0x56000054放到R1中。

MOVR0,#0

STRR0,[R1];是一个典型的存储指令,将R0中的值放到以R1中的值为地址的存储单元去

;这三条指令是为了完结对变量COUNT赋值。

3)NOP

空操作伪指令,可用于延时操作

例:延时子程序

Delay

NOP;空操作

NOP

NOP

SUBSR1,R1,#1;循环次数减1

BNEDelay

MOVPC,LR

六、Thumb指令集

有爱好的自学

//*arm体系结构第五天*

七、C言语与汇编混合编程

彻底运用汇编言语来编写程序会十分的繁琐

一般,仅仅运用汇编程序来完结少数有必要由汇编程序才干完结的作业,而其它作业则由C言语程序来完结。

(一)、ATPCS规矩

混合编程中,两边都须恪守ATPCS规矩。这些根本规矩包含:

子程序调用进程中存放器的运用规矩、数据栈的运用规矩和参数的传递规矩。

1.存放器运用规矩

存放器:R4-R11用来保存部分变量

R0-R3(a1-a4)用于保存参数/回来成果/scratch(暂时存放器)

R4-R11(v1-v8)用于保存ARM状况部分变量

R12(IP)子程序内部调用的scratch

R13(SP)数据栈指针

R14(LR)衔接存放器

R15(PC)程序计数器

R7又可称为wr用于Thumb状况作业存放器

R9又可称为sb在支撑RWPI的ATPCS中为静态基址存放器

R10又可称为sl在支撑PWPI的ATPCS中为数据栈约束指针

R11又可称为fp用于帧指针

2.数据栈运用规矩

ATPCS规范规矩,数据栈为FD(满递减类型),并且对数据栈的操作是8字节对齐。在进行出栈和入栈操作,则

有必要运用ldmfd和strnfd指令(或ldmia和stmdb)

3.参数的传递规矩

参数:参数小于等于4,用R0-R3保存参数,参数多于4,剩下的传入仓库

函数回来:成果为32位整数,经过R0回来

成果为64位整数,经过R0,R1回来

关于位数更多的成果,经过内存传递

例:参数传递及成果回来(r0-r3做参数,r0做回来值)

AREAExample,CODE,READONLY;声明代码段Example

ENTRY;程序进口

Start

MOVR3,#4;设置实参,将参数写入R0-R3

MOVR2,#3

MOVR1,#2

MOVR0,#1

BLfunc1;调用子程序ADD_SUM

BOVER;跳转到OVER标号处,进入完毕

func1

ADDR0,R0,R1;完结两数相加

ADDR0,R0,R2

ADDR0,R0,R3

MOVPC,LR;子程序回来,R0内为回来的成果

OVER

END

相当于如下C言语

intfunc1(inta,intb,intc,intd){

returna+b+c+d;

}

intmain(){

func1(1,2,3,4);

}

例:多于4个参数,前4个经过存放器R0-R3传递,其它参数经过数据栈传递

AREAExample,CODE,READONLY;声明代码段Example

ENTRY;程序进口

Start

STMFDSP!,{R1-R4,LR};先将R1-R4,及LR内原有数据压入栈,需求运用这五个存放器

MOVR0,#1;准备好7个存放嚣存入7个数据LR,IP,R4作暂时存放器运用

MOVIP,#2

MOVLR,#3

MOVR4,#4

MOVR1,#5

MOVR2,#6

MOVR3,#7

STMFDSP!,{R1-R3};先将R1-R3数据早年向后入栈,然后将IP,LR,R4内的数据装入R1-R3

MOVR3,R4;其间IP,LR,R4是暂时运用的存放器

MOVR2,LR

MOVR1,IP

BLfunc1;调用子程序funclR0是回来成果

LDMFDSP!,{R1-R4,PC};从栈中取出开端的数据,康复原始值

BOVER;跳转到OVER标号处,进入完毕

func1

STMFDSP!,{R4,LR};当调用函数时,LR和R4都已发生了改动,其间LR是指令地址所以也压入栈

LDRR4,[SP,#0x10];现在共压入5个数据,每一个数据占两个字节,当时栈顶偏移10为前5个数据7

ADDLR,SP,#8;将前第4个数据的地址(栈项+偏移)赋给LR

LDMIALR,{IP,LR};接连将LR地址处的两个数据取出写入IP和LR内,从右向左写,LDMIA即出栈指令

ADDR0,R0,R1;从此行开端相当于returna+b+c+d+e+f+g;

ADDR0,R0,R2

ADDR0,R0,R3

ADDR0,R0,IP

ADDR0,R0,LR

ADDR0,R0,R4

LDMFDSP!,{R4,PC};从栈内取数据加载入R4和PC,PC跳转回主函数

OVER

END

下面是栈顶

相当于如下C言语

intfunc1(inta,intb,intc,intd,inte,intf,intg){

returna+b+c+d+e+f+g;

}

intmain(){

inta=1,b=2,c=3,d=4,e=5,f=6,g=7;

func1(a,b,c,d,e,f,g);

}

(二)、C和ARM汇编程序间的彼此调用

1.汇编程序调用C子程序

为确保程序调用时参数正确传递,有必要恪守ATPCS。

在C程序中函数不能界说为static函数。在汇编程序中需求在汇编言语中运用IMPORT伪操作来声明C子函数

//C代码

intsum5(inta,intb,intc,intd)

{

return(a+b+c+d);

}

//汇编代码

AREAExample,CODE,READONLY;声明代码段Example

IMPORTsum5;

ENTRY;程序进口

Start

MOVR3,#4;设置实参,将参数写入R0-R3

MOVR2,#3

MOVR1,#2

MOVR0,#1

BLsum5;调用子程序sum5

BOVER;跳转到OVER标号处,进入完毕

OVER

END

2.汇编程序拜访大局C变量

汇编程序中能够经过C大局变量的地址来直接拜访C言语中界说的大局变量

在编编程序顶用IMPORT引进C大局变量,该C大局变量的称号在汇编程序中被以为是一个标号。经过ldr和str指令拜访该编号所代表的地址

//C代码

inti=3;

intsum5(inta,intb,intc,intd)

{

return(a+b+c+d+i);

}

//汇编代码

AREAExample,CODE,READONLY;声明代码段Example

IMPORTsum5

IMPORTi

ENTRY;程序进口

Start

LDRR1,i;将i读入R1内

MOVR0,#2

ADDR0,R0,R1

STRR0,i;将存放器值写入i内

MOVR3,#4;设置实参,将参数写入R0-R3

MOVR2,#3

MOVR1,#2

MOVR0,#1

BLsum5;调用子程序ADD_SUM

BOVER;跳转到OVER标号处,进入完毕

OVER

END

3.在C言语中调用汇编子程序

为确保程序调用时参数的正确传递,在汇编程序中需求运用EXPORT伪操作来声明汇编子程序,一起在C言语中运用extern扩展声明汇编子程序。

//汇编代码

EXPORTfunc1;func1为子函数名

AREAExample,CODE,READONLY;声明代码段Example

func1

ADDR0,R0,R1;完结两数相加

ADDR0,R0,R2

ADDR0,R0,R3

MOVPC,LR;子程序回来,R0内为回来的成果

END

//C代码

externintfunc1(inta,intb,intc,intd);

intmain(intargc,charargv){

inta=1,b=2,c=3,d=4;

intz=func1(a,b,c,d);

printf(“%d”,z);

return0;

}

4.在C言语中调用汇编大局变量

汇编顶用DCD为大局变量分配空间并赋值,并界说一个标号代表该存储方位。

在汇编顶用EXPORT导出标号(这个标号便是大局变量),在C程序顶用extern扩展声明名该变量

//汇编代码

EXPORTfunc1

EXPORTtmp

AREAExample,CODE,READONLY;声明代码段Example

tmp;大局变量名

DCD0x0005;大局变量创立内存空间及赋初值

func1;子函数名

ADDR0,R0,R1;完结两数相加

ADDR0,R0,R2

ADDR0,R0,R3

MOVPC,LR;子程序回来,R0内为回来的成果

END

//C代码

externintfunc1(inta,intb,intc,intd);

externinttmp;

intmain(intargc,charargv){

inta=1,b=2,c=3,d=4;

intz=func1(a,b,c,tmp);

printf(“%d”,z);

return0;

}

5.在C言语中内嵌汇编

有些操作C言语程序无法完结,如改动CPSP存放器值,初始化仓库指针存放器SP等,这些只能由汇编来完结。

但出于编程简练等一些要素,有时需求在C源代码中完结上述操作,此刻就需求在C中嵌入少数汇编代码。

内嵌的汇编不能直接引证C的变量界说,有必要经过ATPCS进行,语法格局如下:

__asm{

//内嵌汇编

}

例:在C言语中嵌入汇编

intf(){//C函数

__asm{//内嵌汇编,禁用间断比方

MRSR0,CPSR

ORRR0,R0,#0x80

MSRCPSR_c,R0

}

}

intmain(intargc,charargv){

inta;

intz=f(a);

printf(“%d”,z);

return0;

}

出地完好性考虑,内嵌汇编相关于一般汇编的不同特色如下:

1)操作数能够是存放器、常量或C表达式。能够是char、short、或int类型,并且是无符号数进行操作

2)常量前的#号能够省掉

3)只要指令B能够运用C程序中的标号,指令BL不能够运用

4)不支撑汇编言语顶用于内存分配的伪操作

5)内嵌汇编不支撑经过“.”指示符或PC获取当时指令地址

6)不支撑LDRRn,=expression伪指令,而运用MOVRn,expression指令向存放器赋值

7)不支撑标号表达式

8)不支撑ADR和ADRL伪指令

9)不支撑BX和BLX指令

10)不能够向PC赋值

11)运用0x前缀代替&表明十六进制数

12)不运用存放寻址变量

13)ldm和stm指令的存放器列表只允许物理存放器

14)有必要当心运用物理存放器,如R0-R3,LR和PC

//——————————————

(三)、裸机硬件的操控办法

1.裸板开发环境建立

1)J-Link

(1)装置Setup_JLinkARM_V408i.exe

(2)衔接开发板

1翻开桌面方便J-FlashARMV4.08i

2衔接好开发板开发板->jlink->pc(usb)

3将开发板置为NorFlash发动

4翻开菜单file->openproject->挑选TQ2440.jflash

5填加装备选项

将Flash.csv到装置目录的\ETC\JFlash内

翻开菜单options->projectsettings

在弹出对话框内选flash后,点击按钮selectflashdevice

在弹出对话框内挑选EN29LV160AB

6.衔接开发板

重启开发板,然后点击菜单target->connect检查联接信息

(3)烧写办法

将j-link衔接好后,在菜单file->open内挑选要烧写的程序。

如:烧写u-boot.bin,

然后在烧写地址对话框内输入烧写地址,u-boot的地址设为0

再点击菜单target->program进行烧写

(4)调试办法

衔接JLINK和开发板。

翻开程序J-LINKARMV4.08i->J-linkGDBServer

设置信息JTAGspeed为500KH

一切选项勾选

设置AXD调试环境options->configuretarget填加JlinkARM目录下的JLinkRDI.dll

然后在AXD内选则JLinkRDI.dll选项,一起点击右侧configure按钮

在弹出对话框内General标签:JTAGspeed设为4000Khz

flash标签:去掉Enableflashprogramming选项

Breakpoints:去掉Usesoftwarebreakpoints选项

CPU标签:勾选Allowinstructionsetsimulation

Littleendian

Resetstrategy内选

Hardware,haltafterreset(normal)和1000ms

在AXD内,经过File->LoadImage载入要调试的axf文件

(四)、软件操控硬件的编程原理

每一种硬件,在其操控器芯片上都有物理存放器(不是CPU存放器,是硬件上的存放器)

这些存放器分为三类:指令存放器、状况存放器、数据存放器

程序操控硬件的办法是,经过汇编str指令向指令存放器写入指令即可完结对硬件的装备操作或履行物理操作。

经过汇编ldr指令从数据存放器中获取数据,或从状况存放器获取状况。

程序操控硬件,其实质便是对硬件的存放器进行读写操作。

程序中需求处理的问题:

1)硬件存放器的内存地址是多少?

2)向哪一个存放器写入什么值?

如想处理上述两个问题,需求娴熟检查硬件的手册,阅览硬件连线原理图。

数电的根本知识:

1).电路符号

2).根本原理

以LED灯为例解说怎么运用硬件手册,和原理图

在开发板上有4个LED灯,假如想点亮,有必要先看硬件连线图

1.检查开发板LED管脚连线

TQ2400开发板有两块电路板:中心板、主板

LED灯在主板上,所以检查《TQ2440底板原理图.pdf》,找到LED模块(LED测验)

从电路图可看到假如让LED1灯点亮,有必要在nLED_1连线上输出低电屏(即通电)

怎么让LED1上输出低电屏,需检查CPU相关引脚连线

2.检查TQ2440中心板原理图

CPU在中心板上,所以检查《TQ2440_V2中心板原理图.pdf》

找到nLED1连线,如下

nLED1在CUP的GPB5引脚上

nLED2GPB6

nLED3GPB7

nLED4GPB8

怎么让CPU的GPB5为低电屏,需检查CPU引脚办法

3.检查CPU用户手册

TQ2440的微处理器芯片为S3C2440,所以检查《S3C2440.pdf》芯片手册,找到GPB5的管脚办法

1)操控存放器

GPB5[11:10]00=Input01=Output

10=nXBACK11=Reserved

GPBCON操控存放器

GPBDAT数据存放器

GPBUP上拉使能存放器

[11:10]是地点位,每个管脚都是占两个位

其间Input是输入值

Output输出值

reserved保存值

nXBACKnXBACK/GPB5

即,假如将GPB5设为低电屏,则需求将操控存放器设置为输出办法。

即需求CPU存放器GPBCON的11和10位设置为01即11位为010位为1

2)数据存放器

GPB[10:0][10:0]当端口装备为输入端口时,相应位为引脚状况。

当端口装备为输出端口时,相应位为引脚状况。

当端口装备为功用引脚时,将读取到未界说值

所以,当GPBCON为输入状况时,GPBDAT的相应位5则应为0才会输出低电屏

3)检查存放器地址

GPBCON0x56000010R/W端口装备存放器复位值0x0

GPBDAT0x56000014R/W端口数据存放器复位值-

所以,需求将地址位0x56000010的存放器作为GPBCON存放器

地址位0x56000014的存放器作为GPBDAT存放器

4.代码编写

//ledtest.c

#defineGPBCON(*(volatileunsignedlong*)0x56000010)

#defineGPBDAT(*(volatileunsignedlong*)0x56000014)

//volatile影响编译器编译的成果,表明变量是随时或许发生改动的

//0x56000010是地址,强行转化为unsignedlong*类型,

//然后前面加*代表这个地址所指向的存放器变量

#defineLEDS(1<<5|1<<6|1<<7|1<<8)//即11110000

#defineDELAYVAL(0xFFFF)

externintdelay(inttime);//声明汇编函数

intmain(){

intval;

inti=0;

GPBCON=(1<<16|1<<14|1<<12|1<<10);//即010101010000000000即B5B6B7B8的状况存放器

val=val+1;

for(i=0;i<4;i++){

GPBDAT=(GPBDAT&(~LEDS))|(1<<6|1<<7|1<<8);

delay(DELAYVAL);

GPBDAT=(GPBDAT&(~LEDS))|(1<<5|1<<7|1<<8);

delay(DELAYVAL);

GPBDAT=(GPBDAT&(~LEDS))|(1<<5|1<<6|1<<8);

delay(DELAYVAL);

GPBDAT=(GPBDAT&(~LEDS))|(1<<5|1<<6|1<<7);

delay(DELAYVAL);

}

return0;

}

//delay.s

;汇编指令延时程序

EXPORTdelay

AREADELAY,CODE,READONLY

;下面是延时子程序

delay

subR0,R0,#1;r0=r0-1

cmpR0,#0x0;将r0与0比较

bnedelay;比较的成果不为0,则持续调用delay

movPC,LR;回来

END

5.调试代码

2440ART.mcp内双击

TargetSettins:post-linker挑选ArMfromELF

LanguageSettins:ArchitectureorProcessor挑选相应的编译器ARM920T

ArmLinker:output内RO0x30000000

options内Imageentrypoint设为0x30000000

layout内Object2440init.oSectionInit

Listings内Imagemap

ArmfromELF:outputformat内Plainbinary

outputfilename内*.bin

编译

make

调试AXD是调试器

设置,debug->翻开AXD调试界面,挑选option->configtarget选项

选ARMUL(模仿调试器),然后挑选确认.进入调试界面.

ARMUL是虚拟调试环境(虚拟开发板)

假如用开发板实在环境调试,则需求运用JTAG连开发板后,在此处选H-JTAG

用file-

execute->runtocousor项.使程序进入用户主程序

能够用F8来一条一条履行句子,也可用F10,能够设置断点.

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qiche/dianzi/277098.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部