回顾:
--------------------------------------------------------------------------------------
指令集
(1)跳转指令:B BL BX 修改PC寄存器
(2)数据处理指令:
1.数据传送
2.算术运算
3.位运算
4.比较测试
操作码{条件}S 目标寄存器,第一源操作数,第二源操作数
(3)加载存储指令
单寄存器
LDR Rd,<地址模式>
LDRB Rd,<地址模式>
基址+偏移量(立即数,寄存器,寄存器移位)
LDRH Rd,<地址模式>
LDRSH Rd,<地址模式>
LDRSB Rd,<地址模式>
基址+偏移量(立即数,寄存器)
STR Rd,<地址模式>
STRH Rd,<地址模式>
STRB Rd,<地址模式>
(4)多寄存器
LDM Rb! ,{R0, R1,R2}
STM
IA
IB
DA
DB都是指的如何操作地址的
(5)栈
满减栈
Push STMDB STMFD
Pop LDMIA LDMFD
MRS 读CPSR,SPSR
MSR 写CPSR,SPSR
(6)伪指令:
ADR
ADRL
LDR
LDR PC,label
label:
.word 0x12345678
LDR R0,=label
LDR PC , [R0]
label:
.word 0x12345678
NOP
--------------------------------------------------------------------------------------
Day11
伪操作
main: mov r1, r0 @主程序入口
test.s示例
.text @指定代码放到.text段
.global do_sub @声明全局标号
do_sub:
sub r0, r0, r1 @两个数相减
mov pc, lr @子程序返回
.end
伪操作(derective)
汇编语言程序里的一些特殊助记符为编程方便,完成一些辅助功能的操作。
在对汇编源程序进行汇编过程中由汇编程序处理,而不是在程序运行期间由机器执行.
也就是说,这些伪操作只在汇编过程中起作用,汇编结束,伪操作作用消失。
(1)常量定义伪操作.equ
语法格式:
.equ symbol, expr
其中:
symbol 为要指定的名称,它可以是以前定义过的符号;
expr 表示数字常量或程序中的标号。
示例
.equ TEST_NUM, #0x20
(2)声明全局常量伪操作.global或.globl
语法格式:
.global symbol
.globl symbol
其中:
symbol 为要声明的全局变量名称
示例
.global start
.globl start
(3)声明外部常量伪操作.extern
语法格式:
.extern symbol
其中
symbol 为要声明的外部变量名称
示例
.extern main
字节定义.byte
语法格式:
.byte expr {, expr }…
其中:
expr 数字表达式或程序中的标号。
示例
.byte 20
半字定义.hword或.short
语法格式:
.hword expr {, expr }….
.short expr {, expr }…
其中:
expr 数字表达式或程序中的标号
字定义.word或.int或.long
语法格式:
.word expr {, expr }….
.int expr {,expr }…
.long expr {, expr }…
其中:
expr 数字表达式或程序中的标号。
字符串定义.ascii和.asciz或.string
语法格式:
.ascii expr{, expr }…
.asciz expr {, expr }…
.string expr{, expr }…
其中:
expr 表示字符串。
str:
.ascii “test\0”
str1:
.asciz “tarena”
.ascii定义字符串,需要人为添加结束符
.asciz和.string定义字符串,自动添加结束符
固定填充字节内存单元定义.space或.skip
语法格式:
.space size {, value}
.skip size {, value}
其中:
size 所分配的字节数
yy:
.space 1024
从yy开始,分配了1024个字节,以0填充
如何使用汇编代码实现两个字符串的比较
汇编语言与C语言混合调用
1.C语言中如何调用汇编语言实现的函数
2.C语言中如何使用汇编语言定义的变量
3.汇编语言中调用C的函数
4.汇编语言中如何调用C中的变量
1.C语言中如何调用汇编语言实现的函数
.text
.code 32
.global my_strcmp
my_strcmp:
ldrb r2,[r1],#1
ldrb r3,[r0],#1
cmp r2, #0
beq cmd_end
….
cmd_end:
….
bx lr
extern void my_strcmp(char *d, constchar *s);
r0 r1
main.c
int main(void)
{
char buf[256];
uart0_gets(buf);
my_strcmp(buf, “ledon”);
//此时调用的my_strcmp函数就是汇编实现的字符串比较函数
}
1.汇编函数名字声明为全局标号.global my_strcmp
2.C程序若要调用这个函数,需要声明该函数原型
extern void my_strcmp(char *d, constchar *s);
r0 r1
3.按照C语言的方式调用该函数
2.C语言中如何使用汇编语言定义的变量
.data
.global yy
yy:
.word 0x100
1.汇编中将该变量声明为全局变量
2.在C语言中声明为外部标号
extern int yy;
3.按照C的方式使用该变量
3.汇编语言中调用C的函数
int add(int a, int b, int c, int d)
{
return(a+b+c+d);
}
1.C程序中该函数定义为全局,不能加static
2.汇编程序中声明为外部标号
.extern add
3.按照汇编的方式调用
mov r0, #1 ->a
mov r1, #2 ->b
mov r2, #3 ->c
mov r3, #4 ->d
bl add @CPU将bl指令下一条指令地址给lr,PC
cmp r0 #0 @r0保存返回值r0+r1+r2+r3
4.汇编语言中如何调用C中的变量
int a;
1.C中变量声明为全局;
2.汇编程序中声明该变量为外部变量
.extern a
3.按照汇编的方式使用
ldr r0, =a
ldr r1, [r0]
被调用方:
将被调用函数或变量都要定义为全局的
调用方:
声明函数原型和变量为外部标号
C程序调用汇编函数
将用汇编实现的字符串比较函数替换掉用C实现的字符串比较函数
1.汇编函数(字符串比较函数)定义为全局标号
2.在C程序中将该汇编函数的函数原型声明为extern
3.替换C函数,用汇编函数
汇编语言C语言
r0 r1 r2 r3
a_strcmp.s源文件
a_strcmp(name,cmd_tbl[i].name)
r0 r1
C
1.清BSS段
2.调用main函数
arm-linux-ld -nostartfiles
*******************************************************************************
异常处理:
异常模式:
SVC管理模式:复位,执行SWI指令
FIQ快速中断模式:发生高优先级的中断
IRQ中断模式:发生低优先级的中断
中止模式:
未定义模式:
异常:
1.复位异常,进入管理SVC模式
2.未定义指令异常,进入未定义模式
3.软中断异常,执行SWI指令,进入管理SVC模式
4.预取指令异常,没有取到指定的指令,进入中止模式
5.数据中止异常,没有取到指定的数据,进入中止模式
6.中断,进入中断模式
7.快速中断,进入快速中断模式
如何处理异常
异常发生,处理异常,CPU做:
1.拷贝CPSR到相应异常模式的SPSR,SPSR_mode=CPSR
2.设置适当的CPSR位:
1.将处理器的状态改为ARM状态,CPSR的bit[5]=0
2.改变处理器的工作模式,进入到相对应的异常模式,改CPSR的bit[4:0]到对应异常模式
3.设置中断禁止位,禁止相应的中断
3.保存返回地址到lr_mode=PC-4
4.设置PC为相应的异常向量的地址
5.处理异常
6.异常处理完毕,返回
软中断SWI
…….
sub r1, r1, #0x5
swi 1 @发生软中断异常
add r0, r0, #0x1
bic r0, r0, #0xF0
……..
取指,解码,执行,在swi指令的第三个阶段,执行阶段,发生异常
1.SPSR_SVC= CPSR
2.改CPSR的T位,0
3.改CPSR的mode位[4:0],改到SVC管理模式
4.禁止中断位
5.lr=PC-4(PC=bic)
=add
6.PC=0x8
7.处理异常
8.异常处理完毕,异常返回,movs pc, lr CPSR=SPSR
未定义指令异常
…….
sub r1, r1, #0x5
abc #3 @未定义指令
add r0, r0, #0x1
bic r0, r0, #0xF0
……..
取指,解码,执行,当abc指令进入执行阶段,发生异常
1.SPSR_未定义 =CPSR
2.改CPSR的T位,0
3.改CPSR的mode位[4:0],改到未定义模式
4.禁止中断位
5.lr=PC-4(PC=bic)
=add
6.PC=处理未定义异常的地址
7.处理未定义异常
8.异常处理完毕,异常返回,movs pc, lr CPSR=SPSR
FIQ IRQ
…….
sub r1, r1, #0x5
add r0, r0, #0x1
bic r0,r0, #0xF0
cmp r0,r1
……..
当执行到sub指令时,来了中断,虽然中断来了,sub指令执行完毕,发生中断异常
pc=cmp
lr =pc-4=bic
异常返回时,执行add指令,subs pc, lr, #4 CPSR=SPSR
预取指令异常
…….
sub r1, r1, #0x5
add r0, r0, #0x1
bic r0, r0, #0xF0
cmp r0,r1
……..
1.当sub取指,根本没有取到,直到执行阶段,发生异常
2.lr=pc-4 pc=bic
=add
3.异常返回:
再次取指sub指令,subs pc , lr , #4 CPSR=SPSR
数据异常返回
…….
ldr r0, [r2] //取指,解码,执行,访存,回写
sub r1, r1, #0x5
add r0, r0, #0x1
bic r0, r0, #0xF0
cmp r0,r1
……..
1.在ldr指令的访存阶段发生异常,pc=bic
2.lr=pc-4=add
3.异常返回:subs pc, lr, #8 cpsr=spsr
异常的返回
swi软中断异常
未定义指令异常
中断
快速中断
预取指令
数据异常
1.什么时候发生异常
执行阶段 8(SWI,未定义,预取指令)
执行完毕阶段 12(中断,快速中断)
访存阶段 12(数据异常)
确定当前的PC值
2.CPU:自动的,lr=pc-4
3.异常处理完毕,返回时,执行的指令是哪条
1.重新执行发生异常的指令(预取指令,数据异常)
2.执行发生异常的下一条指令
系统执行代码,执行SWI 0x01指令,在该指令的执行阶段,发生软中断异常
CPU:
1.备份CPSR, SPSR_SVC=CPSR
2.修改CPSR
1.改状态,ARM状态,CPSR的bit[5]=0
2.改模式,SVC管理模式,CPSR的bit[4:0]=10011
3.改中断位
3.保存返回地址lr_svc=PC-4
4.修改PC为异常向量表中对应的地址 PC=0x8,对应指令:
ldr pc, swi_hdl
5.swi_hdl就是SWI指令的异常处理程序,在此程序中,可以调用C语言编写的较为复杂的处理过程。(汇编调用C函数)
6.当C函数处理完毕之后,返回汇编swi_hdl,再做最后的异常返回
7.movs pc,lr cpsr=spsr
8.接下去继续执行swi指令后的下一条指令
shell#s1
shell#s2
将irq_uboot.rar拷贝到共享目录中,在windows解压
cp bss swi -rf
cd swi
cp /mnt/hgfs/1405/irq_uboot/irq_uboot/* ./