ARM基础与简单汇编

汇编

伪操作

GNU汇编中常用的伪操作:1>

1> .text KEIL中Text Start设置项关联,用以说明其下内容属于程序的代码,这些指令在内存中从Text Start设置项指定地t开始存放

2> .end当前源码文件内容结束

3> .global全局用于说明其后标号可以跨源文件使用用法:.global标号

.local局部用于说明其后标号不可以跨源文件使用,只能在当前源文件中使用用法:.local 标号

4>.equ          //宏定义,相当于#defind

5>.text / .data / .bss(静态内存分配)

.text、.data和.bss将汇编系统预定义的段名编译到相应的代码段、数据段和bss段。

KEIL中Data Start设置项关联,用以说明其下内容属于程序的数据段,数据段在内存中从Data Start设置项指定地址开始存放程运行过程中用到的数据

裸机程序的数据段=进程的栈区+堆区+数据区

—些简单的裸机程序,无需对数据段进行细分(分为栈区、堆区、数据区)

复杂的裸机程序,对数据段的细分,由程序员自行实现:

1>栈区:指定栈底地址和栈区大小

2>数据区:采用相应伪操作在其中为相应数据准备空间

3>堆区:对除去栈区、数据区以外剩余空间采用相应的数据结构进行管理,管理代码以及动态分配和释放函数有程序员自行实现

6>用于在代码段(程序运行过程中只读)和数据段为指定数据分配空间的伪操作

.byte

用法1:byte  1个字节的值----分配1个字节并向该字节填上相应的值

例:DATA1: .byte  0xab类似于C语言中语句:char DATA1 = 0xab

用法2:  byte 1个字节的值1,1个字节的值.n…个字节的值n ----分配n个字节,并在相应字节位置填上相应的数值

例:DATA2: .byte 0x12,0x34,0x56(同上)

.word

用法1: .word 4个字节的值---分面可以存放一个字(四个字节)的空间

用法2:.word 4个字节的值1,4个字节的值2.…4个字节的值n ----连续分配n个字的空间

.string

"字符串常量’---分配一块内存空间用于存放指定的字符串内容总计分配: strlen(字符串)+ 1个字节的空间

.space 用法:.space 字节数常量N值------分配N个字节的空间,并将该空间中的所有字节都填上指定的值

-----------也可以用标号对用这些伪操作分配好的空间命名,实际标号就是对应空间的首地址

伪指令 LDR STR

ARM这些RISC-CPJ不是所有指令都能访问内存的,访问内存需要用专门的指令进行,这些指令通称为访存指令:

1.从内存中读数据到寄存器------------ ARM以LD开头Load加载,比如:LDR LDM

2将寄存器中数据存储到指定内存------- ARM以ST开头 Store存储,比如:STR STM

------------涉及不索引,前索引,后索引(详情查阅资料)     

LDR              加载

LDR   R0,[R1]                  ;将存储器地址为R1的字数据读入寄存器R0。

LDR   R0,[R1,R2]          ;将存储器地址为R1+R2的字数据读入寄存器R0。

LDR   R0,[R1,#8]         ;将存储器地址为R1+8的字数据读入寄存器R0。

LDR   R0,[R1,R2] !        ;将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1。

LDR   R0,[R1,#8] !      ;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1

LDR   R0,[R1],R2              ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2写入R1。

LDR   R0,[R1,R2,LSL#2]!   ;将存储器地址为R1+R2×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。

LDR   R0,[R1],R2,LSL#2     ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。

LDRB

LDRB R0,[R1]         ;将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零。

LDRB R0,[R1,#8]    ;将存储器地址为R1+8的字节数据读入寄存器R0,并将R0的高24位清零。

LDRH

                                                                  并将R0的高16位清零。 

STR、STRB、STRH     存储

STR   R0,[R1],#8    ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。

STRB R0[R1]         ;将寄存器R0中的字节数据写入以R1为地址的存储器中。//不是R1寄存器里

STRH R0[R1]         ;将寄存器R0中的半字数据写入以R1为地址的存储器中。

例1:LDR R0,=0x11223344

       MOV R1,#0x40000000

       STR R0,[R1]

       LDRB R2,[R1]       

例2:LDR R0,=V1          @取V1的地址

         LDR R1, [R0],#4     @取R0地址了的数据(有点想数组的[])。

数据传输指令:

MOV

MOV 条件码S标记 目标寄存器, 操作数

功能:将操作数写法表示的值传输给目标寄存器目标寄存器=操作数

例:MOV R1,#1          //把1赋值R1寄存器

       MOV R1,R2          //把R2的值赋给R1

MVN:

MVN 条件码S标记 目标寄存器,操作数

功能:将操作数写法表示的值取反后传输给目标寄存器目标寄存器= ~(操作数)

移位码

LSL,LSR,ASR,ROR,RRX

1. LSL:逻辑左移去掉高位低位补零

2.LSR: 逻辑右移去掉低位高位补零

3.ASR: 算术右移去掉低位高位补符号位

4.ROR: 循环石移最低位补到最高位

5.RRX:带扩展的箭环右移连着CPSR的C位一起做循环右移每次只能移1位即用法

:某个寄存器名字,RRX

操作数写法:某个寄存器名字,移位码移位位数

移位位数支持两种写法:某个寄存器名,LSL或LSR或ASR或ROR  #立即数

某个寄存器名,LSL或LSR或ASR或ROR另—个寄存器名

算术运算指令-----加减法

ADD:

ADD+条件码+S标记 目标寄存器,第一个操作数寄存器,第二个操作数

功能:目标寄存器=第一个操作数寄存器的当前值+第二个操作数的值

ADC:------带进位的加法指令 = ADDS

ADC+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数

功能:目标寄存器=第一个操作数寄存器的当前值+第二个操作数的值+ CPSR的C位

SUB:

SUB+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数

功能:目标寄存器=第一个操作数寄存器的当前值-第二个操作数的值

SBC:------带借位的减法指令

SBC+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数

功能:目标寄存器=第一个操作数寄存器的当前值-第二个操作数的值- CPSR的C位的反

RSB: ------逆向减法

RSB+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数

功能:目标寄存器=第二个操作数的值–第一个操作数寄存器的当前值

RSC: ------带借位逆向减法

RSC+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数

功能:目标寄存器=第二个操作数的值–第一个操作数寄存器的当前值- CPSR的C位的反

位运算指令-----又称为逻辑运算指令
注意1:两个操作数的所有位依次做相应的运算注意     2:第一个操作数寄存器中的值并未改变

AND:--------按位与运算

AND+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数

功能:目标寄存器=第一个操作数寄存器的当前值&第二个操作数的值

ORR:--------按位或运算

ORR+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数

功能:目标寄存器=第一个操作数寄存器的当前值│第二个操作数的值

EOR:---------按位异或运算

EOR+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数

功能:目标寄存器=第一个操作数寄存器的当前值^第二个操作数的值

BIC:------位清除指令

BIC+条件码+S标记目标寄存器,第一个操作数寄存器,第二个操作数

功能:第二个操作数的值中哪些位是1,就将第一个操作数寄存器当前值中的对应位置0,结果存放到目标寄存器中

相当于:目标寄存器=第一个操作数寄存器的当前值&(~第二个操作数的值)

数据处理类的比较指令:
特点:1)加S标记与不加S标记都会去修改CPSR的高4位  2)没有目标寄存器

CMP:---加

CMP+条件码第—个操作数寄存器第二操作数

第一个操作数寄存器的当前值-第二操作数的计算结果,不要差,只要记录减后的状态

CMN:---减 *******************************************************

CMN+条件码第一个操作数寄存器,第二操作数

第一个操作数寄存器的当前值+第二操作数的计算结果,不要和,只要记录加后的状态

TST:---按位与

TST+条件码第一个操作数寄存器,第二操作数

第一个操作数寄存器的当前值&第二操作数的计算结果,不要按位与的结果,只要记录按位与后的状态

TEQ:---按位异或

TEQ+条件码第一个操作数寄存器,第二操作数

第一个操作数寄存器的当前值^第二操作数的计算结果,不要按位异或的结构,只要记录按位异或后的状态

跳转指令(Branch分支)

B: --------程序中用于实现选择、码坏、goto

B:B+条件码标号

功能:跳转到标号指示代码位置,不做其它附带动作

BL:--------程序中用于实现函数调用

BL: Branch +Link BL+条件码标号

功能:跳转到标号指示代码位置,还要做一个附带动作:将下一条指令地址读到LR寄存器(R14)中

BX:-------程序中用于实现简单的函数返回

BX: Branch+X带状态转换BX+条件码目标寄存器

功能:跳转到目标寄存器中地址值指示的代码位置,并附带完或状态转换

状态转换的方式:

将目标位置的指令地址赋值给目标寄存器ADD目标寄存器,目标寄存器,1

BX目标寄存器-------ARM转换成Thumb状态

由于ARM指令在内存中按4字节对齐存放、Thumb指令在内存中按2字节对齐存放,因此任何一条指令所占内存的首地址一定是偶数(阅地址值最低位一定是O)O位实际没有什么作用。因此BX指令借助于0位作为状态转换位来用

BLX:旺带状态转换、又带髓接,还要进行跳转

BLX+条件码标号

保存PC到LR,跳转到指定位置,并切换为Thumb状态

BLX+条件码目标寄存器

保存PC到LR,跳转到指定位置,Rm的bits[0]为1切换为Thumb状态、bits[0]为0切换为ARM状态

例:MOV PC,LR 或者BX LR

真假条件跳转命令BNE BEQ MOVHI MOVLS

BNE:---判断是否为零(零标志位“Z”),为假执行

BEQ:---判断是否为零(零标志位“Z”),为真执行

例EBN  loop

CMP R0,R1

SUBGT R0, R0, R1 如果R0大于R1,则执行R0=R0-R1

SUBLT R1,R1,R0  如果R0大于R1,则执行R1=R1-R0

MOVHI R3,R1       真

MOVLS R3,R2       假

汇编数组模板

/*给数组分配空间,并给数组命名以及给数组中的元素初始化*/Array:

.word 0x3,0x5,0x7,0×9,0xb,0x1

/为了方便计算数组中元素的个数,增加了此两行*/Array_end:

.word Ox00

/*分配一个字的空间,专门用于存放数组中元素的个数*/Length:

.word (Array_end -Array)/4

  1. 寄存器-LR-PC-SP-SPSR-PSR-CPSR

SP:堆栈指针R13

LR:连接寄存器R14

PC:程序计数器R15

PSR:程序状态寄存器

SPSR:程序状态保存寄存器

CPSR:程序状态寄存器(current program status register) (当前程序状态寄存器)

栈指令FD,ED,FA,EA,LDMF…,LDME…,STMDA…,STMDB…

栈操作伪指令:

STM+条件码+栈模式SP!,{寄存器列表}------批量入栈

LDM+条件码+栈模式SP!,{寄存器列表}------批量出栈

栈模式:

FD:满递减式顺序栈----出栈时等价于IA,入楼时等价于DB

LDMFD等价于LDMIA,STMFD等价于STMDB

ED:空递减式顺序栈----出栈时等价于IB,入栈时等价于DA

LDMED等价于LDMIB,STMED等价于STMDA

FA:满递增式顺序栈----出栈时等价于DA,入栈时等价于IB

LDMFA等价于LDMDA,STMFA等价于STMIB

EA:空递增式顺序栈-----出栈时等价于DB,入栈时等价于IA

LDMEA等价于LDMDB,STMEA等价于STMIA

例:STMFD(STMDB) SP!,{R4-R12,LR}       //保护现场

       LDMFD(LDMIA) SP!,{R4-R12,PC}       //恢复现场

函数定义过程--- STMFD -- LDMFD

裸机程序调用

第一次函数调用前:指定栈底地址-----LDR SP,=栈底地址

STMFD SP!,{R4-R12,LR} //现场保护---保护调用本函数代码处的现场

LDMFD SP!,{R4-R12,PC} //恢复现场并返回到调用处

              注:在“}”后加“^”,则LDM指令运行在异常模式,并且寄存器列表中含pc寄存器,^标记表示指令会做一个额外动作:将该异常工作模式专用的SPSR中的内容 还原到CPSR

工作模式切换—MRS—MSR

MRS -----将指定的PSR寄存器中内容读到一个通用寄存器中

用法:MRS 通用的目标寄存器,CPSR或SPSR_模式名称

MSR -----将指定的通用寄存器中的内容写到指定的PSR寄存器中

用法1: MSR CPSR或SPSR_模式名称,通用寄存器

用法2:MSR CPSR或SPSR_模式名称_后缀,通用寄存器----只将通用寄存器对应范围的那些位的值写到PSR寄存器中

c:只变更PSR寄存器的0~7位

×:只变更PSR寄存器的8~15位

s:只变更PSR寄存器的16~23位

f:只变更PSR寄存器的24~31位

例:手动切换工作模式的代码:

MRS R0,CPSR

BIC R0,#0x1F

ORR R0, R0    #目标模式对应的5位组合

MSR CPSR,R0或 MSR CPSR_c,R0

软中断指令—SWI

SWI---功能是产生指定编号的软中断异常

用法: SWI+条件码24位一个无符号整数值

操作系统内核实现系统调用时,需借助于SWI指令来完成,一个软中断编号对应这一个系统调用函数

例:SWI 0x11 @调用0x11号功能

       SWI 0x01 @调用0x01号功能    //可参考上面的控制位的6-8位

七种异常模式—运行模式-SVC、UND、ABT、IRQ、FIQ

异常向量地址

异常名称

运行模式

模式位

优先级(6最低)

可使用的寄存器

0x0

复位

SVC

0b10011

1

PCCPSRR12-R0R14_svc-R13_svcSPSR_svc

0x4

未定义指令

UND

0b11011

6

PCCPSRR12-R0R14_und-R13_undSPSR_und

0x8

软中断

SVC

0b10011

6

PCCPSRR12-R0R14_svc-R13_svcSPSR_svc

0xc

指令预取中止

ABT

0b10111

5

PCCPSRR12-R0R14_abt-R13_abtSPSR_abt

0x10

数据访问中止

ABT

0b10111

2

PCCPSRR12-R0R14_abt-R13_abtSPSR_abt

0x14

保留

未使用

未使用

未使用

未使用

0x18

普通中断请求

IRQ

0b10010

4

PCCPSRR12-R0R14_irq-R13_irqSPSR_irq

0x1c

快速中断请求

FIQ

0b10001

3

PCCPSRR7-R0R14_fiq-R8_fiqSPSR_fiq

中断处理过程

SWI地址 0Xxxxxxxx0

LR地址 0Xxxxxxxx4

PC地址0Xxxxxxxx8

LDR R0,[LR,#-4] @获取该SWI指令的地址

由上图可知;LR-4为SWI的地址,以此类推

       STMFD SP!,{R0-R12,LR}     @保存用到的寄存器

       LDR R0,[LR,#-4]                 @获取该SWI指令的地址

       BIC R0,R0,#0xFF000000      @得到SWI指令中的24位正整数

由此得:R0的值被赋值为SWI这行的机器码,如:EF000011

总结----综合代码可参考代码篇的中断部分

一、软中断的处理分为两级:

       第一级完成如下动作:

              1> 现场保护  STMFD  保护对象是SWI指令前的R0~R12,以及R14(LR)、

              2> 获得SWI指令后的软中断编号

              3> 调用第二级软中断处理函数

              4> 第二级软中断处理函数返回后进行现场恢复

       第二级软中断处理函数,可以采用汇编实现,也可以采用C语言实现

          汇编实现:主体思路通过创建软中断向量表(一块连续内存空间,起始地址为SWIJumpTable,该空间连续存放了N个地址值,每个地址对应的空间就是与指定软中断编号对应的分软中断处理程序)

          C语言实现:第一个参数传软中断编号,第二个参数传栈顶地址

二、汇编函数参数、返回值使用R0-R3

    汇编调C函数参数、返回值也是使用R0-R3

    向不同编号的软中断参数、以及获得处理结果也是使用R0-R3

三、其它的异常处理

       IRQ、FIQ的处理也是分两级进行,第一类似于软中断的第一级,只是:

              1> STMFD之前需要做LR-4

              2> 中断号的获取(通过外设寄存器获取)于软中断号的获取方式不一样

       UND、ABT异常处理产品中一般不考虑对它们的处理     

代码

选择语句的实现

简单选择

MOV R0,#2

MOV R1,#1

CMP R0,R1

ADDHI R0,R0,#1  

ADDLS R1,R1,#1

B .

判断奇偶数

MOV R0,#2

TST R0,#1

MOVEQ R1,#0

MOVNE R1,#1

B .

循环语句的实现

求1到100的和

       MOV R0,#100

       MOV R2,#0

loop:

       ADD R2,R2,R0

       SUBS R0,R0,#1    

       BNE loop

      

       B .

函数调用的实现

例1

       MOV R0,#3

       MOV R1,#5

       BL foo

       B .

foo:

       ADD R0,R0,R1

       MOV PC,LR @BX LR

例2

MOV R0,#9

       MOV R1,#15

loop:

       CMP R0,R1

       BEQ stop

       SUBGT R0,R0,R1

       SUBLT R1,R1,R0

       B loop

stop:

       B stop

.end

求最大公约数封装成函数

       MOV R0,#6

       MOV R1,#12

       BL gcd

       B .

      

gcd:

       CMP R0,R1

       BXEQ LR

       SUBGT R0,R0,R1

       SUBLT R1,R1,R0

       B gcd

练习

猴子吃桃问题

有一只猴子摘了一堆桃子,当即吃了一半,又再多吃了一个.以后每天重复,到第10天发现只有1个桃子了,问最开始摘了多少个桃子

/*反推发*/            1+1=2  2*2=4 为上一天的桃数

       MOV R1,#9

       MOV R0,#1

      

loop:

       ADD R0,R0,#1

       MOV R0,R0,LSL #1

       SUBS R1,R1,#1

       BNE loop

      

       B .

求长方形周长

       MOV R0,#3   @length

       MOV R1,#4   @width

       BL RECT_C

       B .

      

RECT_C:

       ADD R2,R0,R1

       MOV R0,R2,LSL #1

       BX LR

数组相加

.text

.global _start

_start:

       LDR R0,=Array

       LDR R2,=Length

       LDR R1,[R2]

       BL Get_Sum

       LDR R2,=Sum

       STR R0,[R2]   

       B .

/*

int Get_Sum(int *pi,int cnt)

{

       int *p = NULL;

       int sum = 0;

       for(p=pi;p < pi+cnt;p++)

       {

              sum+=*p;

       }

       return sum;

}

*/

Get_Sum:

       MOV R2,#0  @R2---->sum

loop:

       LDR R3,[R0],#4

       ADD R2,R2,R3

       SUBS R1,R1,#1

       BHI  loop

       MOV R0,R2

       BX LR    

.data @0x40000000

Array:

       .word 0x3,0x5,0x7,0x9,0xb,0x1

Array_end:

       .word 0x00

Length:

       .word (Array_end - Array)/4

Sum:

       .word 0x00

.end

伪指令练习

判断字节序

LDR R0,=0x11223344

MOV R1,#0x40000000

STR R0,[R1]

LDRB R2,[R1] @将存储器地址为R1的字节数据读入寄存器R2,并将R2的高24位清零。

B .

将内存中的两个数相加并保存到内存

       LDR R0, =Value1 @把Value1的地址写入R0

       LDR R1, [R0]         @就像C语言,把地址交给一个指针变量,在用指针变量赋值

       LDR R0, =Value2 @ADD R0, R0, #0x4

       LDR R2, [R0]

       ADD R1, R1, R2

       LDR R0, =Result

       STR R1, [R0]

       B .

.data

Value1: .word 0x11111111

Value2: .word 0x22222222

Result: .word 0x0

找内存中两个32位数的最大数,并将最大数保存到新的内存块

       LDR R0, =Value1

       LDR R1, [R0],#4

       LDR R2, [R0]

   

       CMP R1,R2

    MOVHI R3,R1

    MOVLS R3,R2

      

       LDR R0, =Result

       STR R3, [R0]

       B .

.data

Value1: .word 0x11111111

Value2: .word 0x22222222

Result: .word 0x0

将内存中的两个64位数相加,并将结果保存到新的内存块

       LDR R6,=Value1

       LDR R0,[R6],#4

       LDR R1,[R6]

      

       LDR R6,=Value2

       LDR R2,[R6],#4

       LDR R3,[R6]

      

       ADDS R4,R0,R2

       ADC  R5,R1,R3

      

       LDR R6,=Result

       STR R4,[R6],#4

       STR R5,[R6]

       B .

      

.data

Value1: .word 0x12345678,0x12345678

.space 12,0x0

Value2: .word 0xF0000000,0x10000000

.space 8,0x0

Result: .word 0x0,0x0

块复制

.equ num,20

.text

.global _start

_start:

       LDR R0,=src

       LDR R1,=dst

       MOV R2,#num

blockcopy: @以8个字为单位复制

       MOVS R3,R2,LSR #3   @除以2的3次方,得到以8个字为单位复制的次数

       BEQ copywords

octcopy:

       LDMIA R0!,{R4-R11}

       STMIA R1!,{R4-R11}

       SUBS R3,R3,#1

       BNE octcopy

copywords:@以单个字为单位复制

       ANDS R2,R2,#7    @总字数对8取余,得到剩余要复制的字数

       BEQ stop

wordcopy:

       LDR R3,[R0],#4

       STR R3,[R1],#4

       SUBS R2,R2,#1

       BNE wordcopy

stop:

       B stop

.data

src:

       .word 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4

dst:

       .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

.end

异常处理

切换工作模式

MRS R0,CPSR

BIC R0,R0,#0x1F

ORR R0,R0,#0x13

MSR CPSR,R0   @MSR CPSR_c,R0

无参单功能版:

.text

.global _start

_start:

Vector_Init_Block:

       B Reset_Handler

       B .

       B SWI_Handler

       B .

       B .

       NOP

       B .

       B .

Reset_Handler:

       LDR SP,=0x40002000

       @切换为用户模式

       MRS R0,CPSR

       BIC R0,R0,#0x1F

       ORR R0,R0,#0x10

       MSR CPSR,R0

       SWI 0x11 @调用0x11号功能

       B .

SWI_Handler:

       STMFD SP!,{R0-R12,LR}  @保存用到的寄存器

       LDR R0,[LR,#-4] @获取该SWI指令的地址             //**

       BIC R0,R0,#0xFF000000 @得到SWI指令中的24位正整数

       CMP R0,#0x11

       BNE SWI_END

       LDR R1,=V1          //**

    LDR R2,[R1],#4     //**

    LDR R3,[R1],#4    

    ADD R0,R2,R3

      

SWI_END:

       STR R0,[R1]

       LDMFD SP!,{R0-R12,PC}^

.data

V1: .word 0x1

V2: .word 0x2

Ret: .word 0

.end

无参多功能版:

.equ MaxSWI,4

.text

.global _start

_start:

Vector_Init_Block:

       B Reset_Handler   @开机执行行

       B .

       B SWI_Handler

       B .

       B .

       NOP

       B .

       B .

Reset_Handler:

       LDR SP,=0x40002000

       @切换为用户模式

       MRS R0,CPSR

       BIC R0,R0,#0x1F

       ORR R0,R0,#0x10

       MSR CPSR,R0

      

       SWI 0x01 @调用0x01号功能

       B .

SWI_Handler:

       STMFD SP!,{R0-R12,LR}  @保存用到的寄存器

       LDR R0,[LR,#-4]  @获取该SWI指令的地址(由SWI切换状态时,LR改变-4是上行)

       BIC R0,R0,#0xFF000000 @得到SWI指令中的24位正整数

      

       BL SWI_Handler2

SWI_END:

       LDMFD SP!,{R0-R12,PC}^

/*第2级处理程序开始*/

SWI_Handler2:

       CMP R0,#MaxSWI

       LDRCC PC,[PC,R0,LSL #2] @跳转到相应位置 R0=01就是在PC的基础上下移1个字节,也就是执行.word SWINum0这句的函数,(类似switch语句)  

       B SWIOutOfRange @错误处理

SWIJumpTable:            @设置多级跳转

       .word SWINum0         

       .word SWINum1

       .word SWINum2

       .Word SWINum3

SWINum0:/*0号功能实现 --- 加*/

       CMP R0,#0x0

       BNE SWIOutOfRange

       LDR R1,=V1

    LDR R2,[R1],#4

    LDR R3,[R1],#4

    ADD R0,R2,R3

       B EndOfSWI2

SWINum1:/*1号功能实现 --- 减*/

       CMP R0,#0x1

       BNE SWIOutOfRange

       LDR R1,=V1

    LDR R2,[R1],#4

    LDR R3,[R1],#4

    SUB R0,R2,R3

       B EndOfSWI2

SWINum2:/*2号功能实现 --- 与*/

       CMP R0,#0x2

       BNE SWIOutOfRange

       LDR R1,=V1

    LDR R2,[R1],#4

    LDR R3,[R1],#4

    AND R0,R2,R3

       B EndOfSWI2

SWINum3:/*3号功能实现 --- 或*/

       CMP R0,#0x3

       BNE SWIOutOfRange

       LDR R1,=V1

    LDR R2,[R1],#4

    LDR R3,[R1],#4

    ORR R0,R2,R3

       B EndOfSWI2

EndOfSWI2:

       STR R0,[R1]

SWIOutOfRange:

       BX LR

/*第2级处理程序结束*/

.data

V1: .word 0x3

V2: .word 0x2

Ret: .word 0

.end

带参多功能C语言版

 

.text

.global _start

_start:

Vector_Init_Block:

       B Reset_Handler

       B .

       B SWI_Handler

       B .

       B .

       NOP

       B .

       B .

Reset_Handler:

       LDR SP,=0x40002000

       @切换为用户模式

       MRS R0,CPSR

       BIC R0,R0,#0x1F

       ORR R0,R0,#0x10

       MSR CPSR,R0

      

       MOV R0,#1

       MOV R1,#2

       SWI 0x11 @调用0x11号功能

       B .

/*SWI第1级处理程序开始*/

SWI_Handler:

       STMFD SP!,{R0-R12,LR}  @保存用到的寄存器

       LDR R0,[LR,#-4] @获取该SWI指令的地址

       BIC R0,R0,#0xFF000000 @得到SWI指令中的24位正整数

      

       MOV R1,SP

    BL C_SWI_Handler

      

SWI_END:

      

       LDMFD SP!,{R0-R12,PC}^

/*SWI第1级处理程序结束*/

.end

void C_SWI_Handler(unsigned number,unsigned *pStack)

{

    //功能额外参数的读取

    value_in_reg_0 = pStack[0];

    value_in_reg_1 = pStack[1];

    value_in_reg_2 = pStack[2];

    value_in_reg_3 = pStack[3];

   

    /*各功能号实现*/

    /*..........*/

   

    /*各功能的返回结果*/

    pStack[0] = updated_value0;

    pStack[1] = updated_value1;

    pStack[2] = updated_value2;

    pStack[3] = updated_value3;

}

利用swi指令实现一个系统功能,该功能要求3个整数返回其中最大数,要求第二级swi处理用C语言实现

/*参考代码--汇编版*/

.text

.global _start

_start:

Vector_Init_Block:

       B Reset_Handler

       B .

       B SWI_Handler

       B .

       B .

       NOP

       B .

       B .

Reset_Handler:

       LDR SP,=0x40002000

       @切换为用户模式

       MRS R0,CPSR

       BIC R0,R0,#0x1F

       ORR R0,R0,#0x10

       MSR CPSR,R0

      

       MOV R0,#11

       MOV R1,#222

       MOV R2,#33

       SWI 0x11 @调用0x11号功能

       B . @结果在R0中

/*SWI第1级处理程序开始*/

SWI_Handler:

       STMFD SP!,{R0-R12,LR}  @保存用到的寄存器

       LDR R0,[LR,#-4] @获取该SWI指令的地址

       BIC R0,R0,#0xFF000000 @得到SWI指令中的24位正整数

      

       CMP R0,#0x11

       BNE SWI_END

       /*1. 从栈区读取系统功能所需参数*/

       LDR R1,[SP]

       LDR R2,[SP,#4]

    LDR R3,[SP,#8]

   

    /*2. 系统功能实现*/

    CMP R1,R2

    MOVLS R1,R2

    CMP R1,R3

    MOVLS R1,R3   

    /*3. 将系统功能产生的结果存放到栈顶位置(即swi指令前的R0入栈位置)*/

    STR R1,[SP]          

SWI_END:

       LDMFD SP!,{R0-R12,PC}^

/*SWI第1级处理程序结束*/

.end

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值