Assembly code for creating interrupts vector on LPC2148 ARM processor

arm, assembly, embedded

Solution

I'm going to remove the conditional code, since it just complicates things:

// 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

Lets look first at the reset/start vector:

b   _start

That instruction is an unconditional branch (a jump) to the the code labeled "_start" which I don't see in your snippet. Basically it'll be the assembly that initializes the stack and processor registers, maybe some memory areas then probably jumps to a C routine that performs the bulk of the initialization.

Next is the "undefined" vector that the ARM will go to when an invalid instruction is executed (if my memory is right):

ldr pc, _undf

That instruction loads the `pc` register (the 'program counter' or instruction pointer) with the address at the "_undf" symbol. If we look at the `_undf` variable, it contains the address represented by symbol `__undf`. So the `ldr pc, _undf` instruction loads `pc` with `__undf`'s address - jumping to `__undf:`.

And at `__undf` we see:

__undf: b     .  

That's just a branch to the same address - an infinite loop (the `.` symbol means 'here' or 'this location').

So for most of these vectors (which follow the same technique as the undefined vector), they'll just jump to little infinite loops. You could replace the infinite loops at those labels with code that's appropriate for the vector in question, though many projects don't because those vectors firing would represent some sort of serious error.

Finally, the vector slot that's most interesting is the IRQ vector:

ldr   pc,[pc,#-0xFF0]           // IRQ - read the VIC

This looks like the handler for an NXP device.

It loads the `pc` register with the value read from a memory location that's relative to the `pc` register. Since on the ARM architecture the IRQ vector is always at address 0x00000018 (I'm going to ignore implementations that can map the vectors elsewhere or ARMs like the Cortex-M3 that use a different vector model) and because of the instruction pipeline's effect on using the `PC` register value for addressing, the memory location that will be read by this instruction will be `0xFFFFF030`, which is the address of the memory-mapped `VICVectAddr` register in the 'Vectored Interrupt Controller` (VIC):

 'apparent'      Pipeline      offset in      effective
  PC value        effect       the opcode      address
-------------   ------------   -----------    ----------
  0x00000018  +  0x00000008  -  0x0000ff0  == 0xfffff030

This device register will contain the address of the interrupt handler for the interrupt that just occurred (of course the VIC needs to be properly initialized so it knows that address).

So when the `ldr pc,[pc,#-0xFF0]` instruction executes, it'll load the `pc` register with the address of the interrupt handler routine for the appropriate device (basically, jumping to the right interrupt handler).

Problem

I have just recently started to work with LPC2148 ARM processor. I am trying to understand some assembly code regarding the creation of the interrupts vector. here is the code: ``` // 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 ``` I dont understand what is going on here at all. If someone could explain to me the process, especially how the ldr instruction is used here, i would appreciate it. Tal

Original source