ARM汇编程序设计学习笔记(一)
为了学习android系统,发现需要学习linux驱动,发现学习linux驱动,需要先知道处理器的各种架构,为了学习此种知识,发现网上有很多mini2440相关的知识,因此,将其作为蓝本,认真学习。直到linux驱动的学习完成。
这是linux驱动学习的第一部分,arm的汇编程序。
本文档的大部分资料翻译于《S3C2440A 32-BIT CMOS MICROCONTROLLER USER’S MANUAL》
一.编程模型
处理器工作状态
从程序员的角度来看,ARM920T(s3c2440的内核)有如下两种状态:
- ARM状态,执行32位,字对齐的指令
- THUMB状态,执行16位,半字对齐的THUMB指令。
注意:这两种状态的切换,不会影响处理器的模式和寄存器状态
1.1 切换状态
进入THUMB状态
将操作数寄存器的第0位,设为1,然后执行BX指令,就可以切换为THUMB状态。
例如:
BX Rm;如果Rm的第0位,是1,则跳转到Rm所在的地址,并且设置处理器在thumb模式下
如果在THUMB状态下,进入了异常,从异常中退出,依然是THUMB状态
进入ARM状态
可以通过下面的方法,进入arm状态:
- 将操作数寄存器的第0位,清零,然后执行BX指令
BX Rm;如果Rm的第0位,是0,则跳转到Rm所在的地址,并且设置处理器为arm模式下
- 处理器发生异常时,PC被放置在异常模式下的连接寄存器中,然后从异常向量地址开始执行
1.2 内存格式
ARM920T 将内存视为一个线性的字节序列。字节地址从0开始。0到3字节保存第一个字。4到7字节保存第二个字,依次类推。这些字支持小端和大端格式。
1.3 指令长度
指令长度为32位长(arm模式)和16位长(thumb模式)
1.4 数据类型
ARM920T 支持字节(8位)、半字(16位)、字(32位)数据类型。字必须4字节对齐。半字必须两字节对齐。
1.5 运行模式
ARM920T 支持7种运行模式:
- User(usr):最普通的arm执行状态
- FIQ(fiq):被用来进行数据传输,和信道处理
- IRQ(irq):通用的中断处理
- Supervisor(svc):为操作系统设计的保护模式
- Abort mode(abt):数据和指令预取发生问题时,进入
- System(sys):为操作系统设计的特权用户模式
- Undefined(und):当一个未定义的指令执行时,进入此模式
模式的改变可以通过软件控制,也可以通过外部的中断,或者异常。大多数的应用程序将运行在用户模式下。
特殊模式(非用户模式)仅仅在服务中断或者异常,或者访问受保护的资源时才会进入。
1.6 寄存器
ARM920T 总共有37个寄存器。其中,31个通用的32位寄存器和6个状态寄存器。这37个寄存器,对于程序来说,不能同时可见。
处理器状态和运行模式,决定了那些寄存器对于程序员来说可见。
1.7 arm状态下的寄存器集
在arm状态下,程序员只能看到16个通用寄存器和1个或者2个状态寄存器。在特殊模式(非用户模式),相应的寄存器组被切换。图2-3展示了在每种模式下那些寄存器可见。这些寄存器组使用一个阴影三角形标记:
arm状态下的寄存器组包含16个可直接访问的寄存器:R0-R15.除了R15寄存器以外,其他的寄存器都是通用寄存器。可以用来存储数据或者地址。
除此之外,还有第十七个寄存器用来存储状态信息。
寄存器 | 描述 |
---|---|
寄存器14 | 该寄存器作为子程序的链接寄存器。当分支指令(Branch)和连接指令(BL)执行时,这个寄存器保存R15的值.其他时候,可以被作为通用寄存器来使用。对应的寄存器有:R14_svc,R14_irq,R14_fiq,R14_abt,R14_und,他们都在对应的模式下保存R15的值 |
寄存器15 | 这个寄存器为程序计数器(PC)。在arm模式下,bits[1:0]是0,bits[31-2]保存PC。在thumb模式下,bit[0]为0,bits[31:1]保存PC |
寄存器16 | 这个寄存器是CPSR(当前程序状态寄存器)。它保存代码的各种flag和一些模式位 |
FIQ模式有7个寄存器,被映射为R8-R14(R8_fiq-R14_fiq).在arm模式下有许多FIQ处理程序不需要保存的寄存器。
而USer,IRQ,SuperVisor,Abort和Undefined模式,都有R13和R14,并且允许他们有自己的堆栈指针和链接寄存器
ARM和THUMB之间的寄存器关系
如下:
- THUMB模式下R0-R7 ,ARM模式下R0-R7 完全相同
- THUMB模式下CPSR和SPSRs,ARM模式下CPSR和SPSRs是完全相同的
- THUMB模式下SP映射为ARM的R13
- THUMB模式下LR映射为ARM下的R14
- THUMB模式下PC映射为ARM的R15
在thumb模式下访问高寄存器组(Hi-registers)
在THUMB模式下,寄存器组R8-R15(被称为Hi-registers)不是标准寄存器组中的一部分。因此,汇编程序对他的访问是受限制的。但是他们可以用来作为临时的存放地。
可以使用mov指令,将R0-R7里面的值放置到高寄存器中。也可以将高寄存器中的值放到低寄存器中(R0-R7)
也可以使用CMP指令,将高寄存器和低寄存器进行比较
也可以使用ADD指令,将高寄存器中的值加到低寄存器中
1.8 程序状态寄存器
ARM920T 包含一个当前程序状态寄存器(CPSR),以及5个已经保存了的程序状态寄存器(SPSR)。这些寄存器的功能有:
- 保存执行单元(ALU)最近的信息
- 打开或者关闭中断
- 处理器运行模式
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
N | Z | C | V | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | I | F | T | M4 | M3 | M2 | M1 | M0 |
条件码标识
N,Z,C,V是条件码的标志位。这些将会被算术和逻辑运算改变,然后再根据这些位来决定指令是否执行。
在arm状态下,所有的指令可以被条件的执行。
在thumb状态下,只有分支指令才可以按照条件执行
控制位
最低下的8位被称为控制位。当一个异常发生时,他们会被改变。如果处理器在特权模式下,那么他们也可以被软件手动改变。
位 | 描述 |
---|---|
T | 当为1时,处理器运行在THUMB模式下,否则运行在ARM模式下。他将影响TBIT外部信号 |
中断禁止位 | I和F是中断禁止位。为1,则相应的禁止IRQ和FIQ |
模式位 | M4,M3,M2,M1,M0是模式位,如下表,只有下表出现的模式才是正确的模式,一旦程序设置了错误的模式,则会产生复位异常 |
保留位 | 剩下的位为保留位。 |
M[4:0] | 模式 | thumb模式下的寄存器 | arm模式下的寄存器 |
---|---|---|---|
10000 | User | R7…R0,LR,SP,PC,CPSR | R14…R0,PC,CPSR |
10001 | FIQ | R7…R0,LR_fiq,SP_fiq,PC,CPSR,SPSR_fiq | R7…R0,R14_fiq…R8_fiq,PC,CPSR,SPSR_fiq |
10010 | IRQ | R7…R0,LR_irq,SP_irq,PC,CPSR,SPSR_irq | R12…R0,R14_irq,R13_irq,PC,CPSR,SPSR_iraq |
10011 | Supervisor | R7…R0,LR_svc,SP_svc,PC,CPSR,SPSR_svc | R12…R0,R14_svc,R13_svc,PC,CPSR,SPSR_svc |
10111 | Abort | R7…R0,LR_abt,SP_abt,PC,CPSR,SPSR_abt | R12…R0,R14_abt,R13_abt,PC,CPSR,SPSR_abt |
11011 | Undefined | R7…R0,LR_und,SP_und,PC,CPSR,SPSR_und | P12…R0,R14_und,R13_und,PC,CPSR |
11111 | System | R7…R0,LR,SP,PC,CPSR | R14…R0,PC,CPSR |
1.9 异常
例如响应外设电路的中断,此时反生异常。在异常处理前,当前处理器的状态必须保存下来,目的是,当异常处理完成之后,可以继续执行
在同一时间,可能同时出现多个异常,此时他们以固定的顺序进行处理,详见下面的异常优先级。
进入异常时的操作
当处理异常时,ARM920T会做如下的操作:
- 在链接寄存器中保存下一个指令的地址。如果异常从arm状态进入,则下一个指令的地址被复制到链接寄存器中(即PC+4,或者PC+8,具体依赖于不同的异常,后面有详细说明)如果异常从THUMB状态进入,链接寄存器则保存当前PC的偏移量。这就意味着,异常处理程序,不用管,到底是从哪个状态进入的异常。
- 赋值CPSR到对应的SPSR
- 修改CPSR对应的模式位
- 修改PC为对应的异常向量地址
还可以设置异常禁止位,防止异常嵌套的发生
如果处理器在THUMB状态下,此时发生了异常,当PC指向异常向量的地址时,自动切为ARM状态
离开异常时的操作
异常处理程序完成后:
- 将链接寄存器的值,复制到PC中
- 复制SPSR到CPSR
- 如果允许中断,则清除中断禁止位,
异常入口/出口摘要
下表列出了异常发生时,保存在链接寄存器中的PC的值,以及退出异常处理程序的推荐的指令
返回的指令 | arm R14_x | thumb R14_x |
---|---|---|
BL;MOV PC,R14 | PC+4 | PC+2 |
SWI;MOVS PC,R14_svc | PC+4 | PC+2 |
UDEF;MOVS PC,R14_und | PC+4 | PC+2 |
FIQ;SUBS PC,R14_fiq,#4 | PC+4 | PC+4 |
IRQ;SUBS PC,R14_irq,#4 | PC+4 | PC+4 |
PABT;SUBS PC,R14_abt,#4 | PC+4 | PC+4 |
DABT;SUBS PC,R14_abt,#8 | PC+8 | PC+8 |
RESET;NA | - | - |
FIQ
FIQ(快速中断异常)被设计来处理数据传输和信道处理。在arm模式下,保证有最小,且足够的寄存器可用,以达到最优的上下文切换
外部的nFIQ输入为低时,产生FIQ异常。根据ISYNC输入信号的状态,nFIQ的输入可以被处理为同步或异步。当ISYNC为低时,nFIQ和nIRQ被当做异步。同步的周期延迟发生在中断影响处理器流之前。
无论异常是从ARM状态还是thumb状态进入的,FIQ异常可以通过下面的指令退出异常处理流程:
SUBS PC,R14_fiq,#4
FIQ可以通过CPSR的F位来禁止(用户模式下无法操作)。如果F位为0,ARM920T在每条指令结束时检查FIQ同步器输出的低电平。
IRQ
IRQ就是常见的中断,它由nIRQ输入触发。IRQ的优先级比FIQ的优先级低并且当FIQ进入时,IRQ将被禁止。通过设置CPSR寄存器的I位,可以在任何时候在特殊模式下(非用户模式)禁止这个异常
可以执行下面的代码,返回异常:
SUBS PC,R14_irq,#4
Abort
当前内存访问无法完成时,产生一个Abort异常。它也可以由外部的ABORT输入产生。ARM920T在内存访问周期中,检查abort异常
两种abort异常:
- 预取址Abort:在指令预取址的时候发生
- 数据Abort:数据访问时发生
如果预取址Abort发生,则取到的指令被标记为非法指令,并且直到指令到达管道的头部才发生异常。
如果指令没有被执行,abort也不会产生,比如分支指令
如果数据abort发生,接下来会发生什么,则依赖于指令的类型:
- 但数据传输指令(LDR,STR)写会被修改的寄存器。abort异常处理程序必须清楚这一点
- 交换指令(swap)中止,就好像它没有被执行一样
- 块数据传输指令继续完成(LDM,STM)。如果回写位被置位,则基址寄存器被更新。如果指令要覆盖基址寄存器,则覆盖会被中止,以保证不会覆盖。一旦发生abort异常,所有的寄存器覆盖都会被中止。因此R15就会被保留
abort机制可以实现按需分页的虚拟内存系统。在这个系统中,处理器可以产生任意的地址。当数据地址无效时,内存管理单元(MMU)产生一个abort异常。然后abort异常处理程序找出abort的原因,让请求的数据可用,然后重新执行产生abort异常的指令。
应用程序不需要知道他可用的内存量,他的状态也不会受abort异常的任何影响
退出abort异常的指令为:
SUBS PC,R14_abt,#4;for a prefetch abort
SUBS PC,R14_abt,#8;for a data abort
然后恢复PC和CPSR,并且再次执行产生abort异常的指令
软件中断
软件中断(SWI)被用来进入Supervisor模式。软件中断通过下面的指令返回:
MOV PC,R14_svc
他们恢复PC和CPSR,然后继续执行SWI后面的指令
未定义指令
当arm920T无法处理一个指令时,产生一个未定义指令异常。这种机制可以被用来扩展THUMB和ARM指令的软件仿真。
可以执行下面的指令,退出异常:
MOVS PC,R14_und
恢复CPSR,然后执行产生未定义指令异常的下一条指令
异常向量表
下表展示了异常向量地址:
地址 | 异常 | 进入的模式 |
---|---|---|
0x00000000 | Rest | Supervisor |
0x00000004 | Undefined instruction | Undefined |
0x00000008 | Software Interrupt | Supervisor |
0x0000000C | Abort(prefetch) | Abort |
0x00000010 | Abort(data) | Abort |
0x00000014 | Reserved | Reserved |
0x00000018 | IRQ | IRQ |
0x0000001C | FIQ | FIQ |
异常优先级
当同时产生异常时,系统以固定的顺序处理。
高优先级:
- Rest
- Data abort
- FIQ
- IRQ
- Prefetch abort
低优先级:
- Undefined instruction,Software Interrupt
注意:并不是所有的异常都能同时发生
未定义指令和软件中断异常他们是互斥的
如果数据abort异常和FIQ异常同时发生,并且FIQ异常被允许,ARM920T进入数据abort异常处理程序,然后立刻去处理FIQ的异常。FIQ异常退出之后,继续在abort异常处理程序中执行。
数据abort的优先级高于FIQ是有道理的,他能够保证第一时间捕获到传输错误。进入这个异常的时间,应该加上FIQ的延迟。
中断延迟
如果FIQ打开,则最长的延时包括:传递给同步器(Tsyncmax)的最长请求时间,加上,最长的指令时间(Tldm),加上,数据abort进入的时间(Texc),加上FIQ进入的时间(Tfiq)。然后才是ARM920T在0x1c处执行。
Tsyncmax三个处理器周期,Tldm20个处理器周期,Texc3个处理器周期,Tfiq2个处理器周期。总共需要28个处理器周期。在一个连续的20Mhz的处理器上大约消耗1.4微秒。
最大的IRQ延迟计算方式跟上面类似。但是必须考虑到FIQ有更高的优先级,可以延迟任意时间进入IRQ异常处理程序。
FIQ和IRQ的最小时间则由Tsyncmin加上Tfiq组成,为4个处理器周期。
复位异常
当nREST输入为低时,ARM920T放弃执行指令,然后继续从递增的字地址中取指令。
当nRest再次变高,ARM920T:
- 将当前的PC和CPSR,写入到R14_svc和SPSR_svc。
- 将M[4:0]改为1011(supervisor模式),CPSR的I,F位置位,清楚CPSR的T位
- 将PC为0x00
- 在arm模式下,继续执行