我刚刚开始使用LPC2148 ARM处理器。
我正在尝试理解有关创建中断向量的汇编代码。
这是代码:
// Runtime Interrupt Vectors
// -------------------------
Vectors:
b _start // reset - _start
ldr pc,_undf // undefined - _undf
ldr pc,_swi // SWI - _swi
ldr pc,_pabt // program abort - _pabt
ldr pc,_dabt // data abort - _dabt
nop // reserved
ldr pc,[pc,#-0xFF0] // IRQ - read the VIC
ldr pc,_fiq // FIQ - _fiq
#if 0
// Use this group for production
_undf: .word _reset // undefined - _reset
_swi: .word _reset // SWI - _reset
_pabt: .word _reset // program abort - _reset
_dabt: .word _reset // data abort - _reset
_irq: .word _reset // IRQ - _reset
_fiq: .word _reset // FIQ - _reset
#else
// Use this group for development
_undf: .word __undf // undefined
_swi: .word __swi // SWI
_pabt: .word __pabt // program abort
_dabt: .word __dabt // data abort
_irq: .word __irq // IRQ
_fiq: .word __fiq // FIQ
__undf: b . // undefined
__swi: b . // SWI
__pabt: b . // program abort
__dabt: b . // data abort
__irq: b . // IRQ
__fiq: b . // FIQ
#endif
.size _boot, . - _boot
.endfunc
我根本不明白这里发生了什么。 如果有人能向我解释这个过程,特别是如何在这里使用ldr指令,我将不胜感激。
塔尔
答案 0 :(得分:9)
我要删除条件代码,因为它只会让事情变得复杂:
// Runtime Interrupt Vectors
// -------------------------
Vectors:
b _start // reset - _start
ldr pc,_undf // undefined - _undf
ldr pc,_swi // SWI - _swi
ldr pc,_pabt // program abort - _pabt
ldr pc,_dabt // data abort - _dabt
nop // reserved
ldr pc,[pc,#-0xFF0] // IRQ - read the VIC
ldr pc,_fiq // FIQ - _fiq
_undf: .word __undf // undefined
_swi: .word __swi // SWI
_pabt: .word __pabt // program abort
_dabt: .word __dabt // data abort
_irq: .word __irq // IRQ
_fiq: .word __fiq // FIQ
__undf: b . // undefined
__swi: b . // SWI
__pabt: b . // program abort
__dabt: b . // data abort
__irq: b . // IRQ
__fiq: b . // FIQ
.size _boot, . - _boot
.endfunc
让我们先看看重置/开始向量:
b _start
该指令是标记为“_start”的代码的无条件分支(跳转),我在您的代码片段中没有看到。基本上它是初始化堆栈和处理器寄存器的程序集,也许某些内存区域可能会跳转到执行大量初始化的C例程。
接下来是执行无效指令时ARM将执行的“未定义”向量(如果我的内存是正确的):
ldr pc, _undf
该指令加载pc
寄存器('程序计数器'或指令指针),地址为“_undf”符号。如果我们查看_undf
变量,它会包含符号__undf
表示的地址。因此,ldr pc, _undf
指令会将pc
加载__undf
的地址 - 跳至__undf:
。
我们在__undf
看到:
__undf: b .
这只是同一地址的分支 - 无限循环(.
符号表示'此处'或'此位置')。
因此,对于大多数这些向量(遵循与未定义向量相同的技术),它们只会跳转到无限循环。您可以使用适合于所讨论的向量的代码替换这些标签上的无限循环,但许多项目不会,因为这些向量触发将代表某种严重错误。
最后,最有趣的向量槽是IRQ向量:
ldr pc,[pc,#-0xFF0] // IRQ - read the VIC
这看起来像是恩智浦设备的处理程序。
它将pc
寄存器加载从相对于pc
寄存器的内存位置读取的值。因为在ARM体系结构中,IRQ向量总是在地址0x00000018(我将忽略可以将向量映射到其他地方的实现或者像使用不同向量模型的Cortex-M3那样的ARM)并且因为当指令管道对使用PC
寄存器值进行寻址的影响时,该指令将读取的存储器位置为0xFFFFF030
,这是存储器映射的VICVectAddr
的地址。在“向量中断控制器”(VIC)中注册:
'apparent' Pipeline offset in effective
PC value effect the opcode address
------------- ------------ ----------- ----------
0x00000018 + 0x00000008 - 0x0000ff0 == 0xfffff030
该设备寄存器将包含刚刚发生的中断的中断处理程序的地址(当然,VIC需要正确初始化,因此它知道该地址)。
因此,当ldr pc,[pc,#-0xFF0]
指令执行时,它将为pc
寄存器加载适当设备的中断处理程序例程的地址(基本上,跳转到正确的中断处理程序)。
答案 1 :(得分:2)
中断向量表的许多/大多数处理器实现是具有中断处理程序的地址列表。复位向量包含存储器中复位处理程序的第一条指令所在的地址。中断向量是中断处理程序代码的第一条指令所在的地址,等等。
传统上ARM并不是这样做的。大多数ARM内核实际上在该地址执行,因此该表包含可执行指令。因为该表中每4个字节有一个入口点,所以你基本上想要有一些分支指令。您可以使用多条指令,但正如您所看到的那样,第二条或第三条指令成为其他异常的入口点。如果你确定你永远不会有其他的例外,你可以侥幸逃脱,但这通常是不明智的。如果您将自己限制为一条指令,则您的选择是pc相对分支或带有附近地址的负载pc。所以ldr pc,有些东西正在将一些代码的第一条指令的地址加载到程序计数器中,以便它实际上分支到该代码。 b。是一个汇编程序(仅限gnu?)语法快捷方式意味着分支到自身,或在无限循环中分支。如果目的地足够接近异常表,则可以简单地b __irq。有各种解决方案和各种原因,您可以选择我不会选择的方式。
相对较新的Cortex-M3和其他仅限thumb2的ARM处理器(thumb是ARM指令集的简化形式,thumb2是thumb指令集的扩展)。您可以在Cortex-M3上运行thumb only或thumb2,但是您无法运行任何ARM指令,因此指令表的传统(ARM)模型必须更改为16位,2字节指令的表,或者它具有改变一切。他们所做的是寻找与大多数其他处理器非常相似的模型,他们使用地址表。例外情况是在地址0处,表中有一个32位值,它被加载到堆栈指针中,这是嵌入式的一个很好的特性。复位后,内核将在地址0处读取32位,将该值放入堆栈指针,在地址0x4读取32位并将该值放入程序计数器,实际上是分支到该地址。请注意,cortex-m3中的异常列表与传统ARM内核中的列表不同。例如,cortex-m3表中有许多中断处理程序向量。
答案 2 :(得分:0)
试着猜测:
ldr pc,_undf // undefined - _undf
ldr pc,_swi // SWI - _swi
ldr pc,_pabt // program abort - _pabt
ldr pc,_dabt // data abort - _dabt
nop // reserved
ldr pc,[pc,#-0xFF0] // IRQ - read the VIC
ldr pc,_fiq
ldr似乎 l oa d r egister pc上有指向ISR的指针,因此它是一种跳转到这些例程。< / p>
#if 0
#else
这些气味就像条件编译指令一样,就像C的预处理器一样。不久,这个
ldr pc,_swi // SWI - _swi
调用存储在_swi的例程,该例程定义为
_swi: .word __swi // SWI
(因为#if 0
永远不会成立,所以只有#else
部分很重要),而__swi定义如下:
__swi: b . // SWI
继续猜测点可能意味着你可以指定你的中断例程的地址,因此使用那个。