EmbeddedRelated.com
Forums

confusion on startup code of LPC2129

Started by skiddybird March 8, 2012
hi,fellows,
For the demo port of FreeRTOS V7.1.0 for LPC2129 using IAR toolchain, I have many questions regarding the startup code to consult you.
The relevant code is as below.

SECTION .intvec:CODE:NOROOT(2)

PUBLIC __vector
PUBLIC __vector_0x14
PUBLIC __iar_program_start
EXTERN vPortYieldProcessor

ARM
__vector:
;;
ldr pc,[pc,#+24] ;; Reset
ldr pc,[pc,#+24] ;; Undefined instructions
;; ldr pc,[pc,#+24] ;; Software interrupt (SWI/SVC)
b vPortYieldProcessor
ldr pc,[pc,#+24] ;; Prefetch abort
ldr pc,[pc,#+24] ;; Data abort
__vector_0x14
DC32 0 ;; RESERVED
ldr pc, [PC, #-0xFF0] ;; IRQ
ldr pc,[pc,#+24] ;; FIQ

DC32 __iar_program_start ;; Reset
DC32 undef_handler ;; Undefined instructions
DC32 0 ;; Software interrupt (SWI/SVC)
DC32 prefetch_handler ;; Prefetch abort
DC32 data_handler ;; Data abort
DC32 0 ;; RESERVED
DC32 0 ;; IRQ
DC32 fiq_handler ;; FIQ

undef_handler
b undef_handler

prefetch_handler
b prefetch_handler

data_handler
b data_handler

fiq_handler
b fiq_handler
the disassembly code shown by IAR is as below.

0x0: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x20] ?cstartup
0x4: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x24] undef_handler
0x8: 0xea000310 B vPortYieldProcessor ; 0xc50
0xc: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x2c] prefetch_handler
FIQ_MODE:
USR_MODE:
0x10: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x30] data_handler
__vector_0x14:
0x14: 0xb4c04c88 STRBLT R4, [R0], #0xc88
0x18: 0xe51ffff0 LDR PC, VICVectAddr ; 0x0 (0)
0x1c: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x3c] fiq_handler
0x20: 0x00002450 ANDEQ R2, R0, R0, ASR R4
0x24: 0x00000040 ANDEQ R0, R0, R0, ASR #32
0x28: 0x00000000 ANDEQ R0, R0, R0
0x2c: 0x00000044 ANDEQ R0, R0, R4, ASR #32
0x30: 0x00000048 ANDEQ R0, R0, R8, ASR #32
0x34: 0x00000000 ANDEQ R0, R0, R0
0x38: 0x00000000 ANDEQ R0, R0, R0
0x3c: 0x0000004c ANDEQ R0, R0, R12, ASR #32
undef_handler:
0x40: 0xeafffffe B undef_handler ; 0x40
prefetch_handler:
0x44: 0xeafffffe B prefetch_handler ; 0x44
data_handler:
0x48: 0xeafffffe B data_handler ; 0x48
fiq_handler:
0x4c: 0xeafffffe B fiq_handler ; 0x4c
0x50: 0x00000000 ANDEQ R0, R0, R0
0x54: 0x00000000 ANDEQ R0, R0, R0
The first question. At address 0x0 in disassembly part, the instruction sums the value in PC with 0x18, and since the instruction address is 0x0, is the current PC value 0x0 also? if true, 0x0 + 0x18 = 0x18, not 0x20, as the comment says. What is wrong?
The second question. At address 0x14 and 0x28 in disassembly part, the instructions are different, but they are both produced from one assembly statement(DC32 0). Why does one cause result in two distinct effects?
The third question. At address 0x20 in disassembly part, what does it stand for when Z bit in CPSR is high? And what are the roles of R2, R0 and R4 for the moment?

An Engineer's Guide to the LPC2100 Series

When summing with the PC, the PC points to the next instruction, not the
current instruction.

Not sure about the 0x14, but it might be that the tools have inserted a CRC
here for the boot loader, which would be why that location is reserved.

Can't remember the ARM instructions that well, but it looks like the
disassembler is showing the equivalent ARM instruction, though in fact that
is not an actual instruction, it's a table entry.

The disassemble often shown what appears to be garbage since it doesn't know
whether the contents of a location are instructions or data, in this case
they are data.

The actual instruction it thinks it sees seems to be something like

If (Zero){

R2 = R0 & (R0 >> R4)

}

If you follow my pseudo code

ARM allows operands to be immediate or register values, and one operand can
be shifted by a third operand, so you can load large constants with a
smaller operand field, the range of constants being determined by the
highest and lowest bits that are set, so for example you could not load
0xf000000f as an immediate value, but you could load 0xf0000000, as it only
requires 4 contiguous bits, it can be loaded as 0xF << 28.

Regards

Phil.

From: l... [mailto:l...] On Behalf Of
skiddybird
Sent: 08 March 2012 18:19
To: l...
Subject: [lpc2000] confusion on startup code of LPC2129

hi,fellows,
For the demo port of FreeRTOS V7.1.0 for LPC2129 using IAR toolchain, I have
many questions regarding the startup code to consult you.
The relevant code is as below.

SECTION .intvec:CODE:NOROOT(2)

PUBLIC __vector
PUBLIC __vector_0x14
PUBLIC __iar_program_start
EXTERN vPortYieldProcessor

ARM
__vector:
;;
ldr pc,[pc,#+24] ;; Reset
ldr pc,[pc,#+24] ;; Undefined instructions
;; ldr pc,[pc,#+24] ;; Software interrupt (SWI/SVC)
b vPortYieldProcessor
ldr pc,[pc,#+24] ;; Prefetch abort
ldr pc,[pc,#+24] ;; Data abort
__vector_0x14
DC32 0 ;; RESERVED
ldr pc, [PC, #-0xFF0] ;; IRQ
ldr pc,[pc,#+24] ;; FIQ

DC32 __iar_program_start ;; Reset
DC32 undef_handler ;; Undefined instructions
DC32 0 ;; Software interrupt (SWI/SVC)
DC32 prefetch_handler ;; Prefetch abort
DC32 data_handler ;; Data abort
DC32 0 ;; RESERVED
DC32 0 ;; IRQ
DC32 fiq_handler ;; FIQ

undef_handler
b undef_handler

prefetch_handler
b prefetch_handler

data_handler
b data_handler

fiq_handler
b fiq_handler

the disassembly code shown by IAR is as below.

0x0: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x20] ?cstartup
0x4: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x24] undef_handler
0x8: 0xea000310 B vPortYieldProcessor ; 0xc50
0xc: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x2c] prefetch_handler
FIQ_MODE:
USR_MODE:
0x10: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x30] data_handler
__vector_0x14:
0x14: 0xb4c04c88 STRBLT R4, [R0], #0xc88
0x18: 0xe51ffff0 LDR PC, VICVectAddr ; 0x0 (0)
0x1c: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x3c] fiq_handler
0x20: 0x00002450 ANDEQ R2, R0, R0, ASR R4
0x24: 0x00000040 ANDEQ R0, R0, R0, ASR #32
0x28: 0x00000000 ANDEQ R0, R0, R0
0x2c: 0x00000044 ANDEQ R0, R0, R4, ASR #32
0x30: 0x00000048 ANDEQ R0, R0, R8, ASR #32
0x34: 0x00000000 ANDEQ R0, R0, R0
0x38: 0x00000000 ANDEQ R0, R0, R0
0x3c: 0x0000004c ANDEQ R0, R0, R12, ASR #32
undef_handler:
0x40: 0xeafffffe B undef_handler ; 0x40
prefetch_handler:
0x44: 0xeafffffe B prefetch_handler ; 0x44
data_handler:
0x48: 0xeafffffe B data_handler ; 0x48
fiq_handler:
0x4c: 0xeafffffe B fiq_handler ; 0x4c
0x50: 0x00000000 ANDEQ R0, R0, R0
0x54: 0x00000000 ANDEQ R0, R0, R0

The first question. At address 0x0 in disassembly part, the instruction sums
the value in PC with 0x18, and since the instruction address is 0x0, is the
current PC value 0x0 also? if true, 0x0 + 0x18 = 0x18, not 0x20, as the
comment says. What is wrong?
The second question. At address 0x14 and 0x28 in disassembly part, the
instructions are different, but they are both produced from one assembly
statement(DC32 0). Why does one cause result in two distinct effects?
The third question. At address 0x20 in disassembly part, what does it stand
for when Z bit in CPSR is high? And what are the roles of R2, R0 and R4 for
the moment?



Thank you. But still puzzled, because since PC points to the next instruction, its value should be 0x4, then 0x4 + 0x18 = 0x1c, not 0x20 yet. A difference of 0x4 exists. When has it taken a further increment? The timing is tricky. For a new round of discussion, this is question 1.

Question 2 is, which part of code take the act of initilization of global variables and when? It seems that during a whole debug process, no a single line of code perform this kind of task, if I am free of mistakes.

Actually, I start this topic because I need to accomplish the functionality of online update using the built-in IAP routine on one LPC2119 target board. Though two kinds of MCUs, they are of same family, with identical instruction set and similar architecture, therefore software compatibility is not an issue.

The flash is divided into two parts, one for updater, another for application code. The updater occupies the ROM from 0x44 to 0xbfff (sector 0 - 5), the application region starts from 0xe000 to 0x1ffff (sector 7 -15). The updater resides in memory permanently, and when active, wait for request to burn the application zone with new firmware, and jump to the entry point of that zone at last. The whole course of firmware update is prohibited of direct manual contact to the target board. Under this precondition, one problem arises. The two parts of code share one area of vector table at the anterior 64 bytes of flash. My idea to solve this contradiction is to instruct the updater to store the first 80 bytes of the application code to sector 6 which is from 0xc000 to 0xdfff, then the rest to sector 7 - 15. On completion of update, I use one inline assembly code like asm ("B 0xc000") for part switching. The application code has one global array declared as this,
__no_init unsigned char vecfixed[80]@0x40000000;
where 0x40000000 is the starting address of RAM. After the application code run to main function in plain C code, it copy its first 80 bytes in sector 6 to this array, and then set MEMMAP to 2, meaning interrupt vectors are re-mapped to Static RAM, before enabling global interrupt.

So far question 3 comes into being. Is it feasible to remap interrupt vectors to boot block instead of RAM? I tried and failed. Need I copy the content of interrupt vectors to boot block starting at 0x7FFFE000? But isn't it readonly? And if mandatory to remap to RAM, do you have any scientific substitutions for my silly method?

It is time to show the entire content of the startup code. Pristine source file from the FreeRTOS demo port without any essential changes.

MODULE ?cstartup

;; Forward declaration of sections.
SECTION IRQ_STACK:DATA:NOROOT(3)
SECTION ABT_STACK:DATA:NOROOT(3)
SECTION SVC_STACK:DATA:NOROOT(3)
SECTION UND_STACK:DATA:NOROOT(3)
SECTION FIQ_STACK:DATA:NOROOT(3)
SECTION CSTACK:DATA:NOROOT(3)

SECTION .intvec:CODE:NOROOT(2)

PUBLIC __vector
PUBLIC __vector_0x14
PUBLIC __iar_program_start
EXTERN vPortYieldProcessor

ARM
__vector:
;;
ldr pc,[pc,#+24] ;; Reset
ldr pc,[pc,#+24] ;; Undefined instructions
b vPortYieldProcessor
ldr pc,[pc,#+24] ;; Prefetch abort
ldr pc,[pc,#+24] ;; Data abort
__vector_0x14
DC32 0 ;; RESERVED
ldr pc, [PC, #-0xFF0] ;; IRQ
ldr pc,[pc,#+24] ;; FIQ

DC32 __iar_program_start ;; Reset
DC32 undef_handler ;; Undefined instructions
DC32 0 ;; Software interrupt (SWI/SVC)
DC32 prefetch_handler ;; Prefetch abort
DC32 data_handler ;; Data abort
DC32 0 ;; RESERVED
DC32 0 ;; IRQ
DC32 fiq_handler ;; FIQ

undef_handler
b undef_handler

prefetch_handler
b prefetch_handler

data_handler
b data_handler

fiq_handler
b fiq_handler
SECTION .text:CODE:NOROOT(2)

; PUBLIC ?cstartup
EXTERN ?main
REQUIRE __vector

ARM

__iar_program_start:
?cstartup:

MAMCR DEFINE 0xE01FC000 ; MAM Control Register
MAMTIM DEFINE 0xE01FC004 ; MAM Timing register

ldr r0,=MAMCR
ldr r1,=MAMTIM
ldr r2,=0
str r2,[r0]
ldr r2,=3 ; 1 < 20 MHz; 20 MHz < 2 < 40 MHz; 40MHz > 3
str r2,[r1]
ldr r2,=2
str r2,[r0]

; Mode, correspords to bits 0-5 in CPSR
MODE_BITS DEFINE 0x1F ; Bit mask for mode bits in CPSR
USR_MODE DEFINE 0x10 ; User mode
FIQ_MODE DEFINE 0x11 ; Fast Interrupt Request mode
IRQ_MODE DEFINE 0x12 ; Interrupt Request mode
SVC_MODE DEFINE 0x13 ; Supervisor mode
ABT_MODE DEFINE 0x17 ; Abort mode
UND_MODE DEFINE 0x1B ; Undefined Instruction mode
SYS_MODE DEFINE 0x1F ; System mode

MRS r0, cpsr ; Original PSR value

BIC r0, r0, #MODE_BITS ; Clear the mode bits
ORR r0, r0, #ABT_MODE ; Set ABT mode bits
MSR cpsr_c, r0 ; Change the mode
LDR sp, =SFE(ABT_STACK) ; End of ABT_STACK

BIC r0, r0, #MODE_BITS ; Clear the mode bits
ORR r0, r0, #SVC_MODE ; Set SVC mode bits
MSR cpsr_c, r0 ; Change the mode
LDR sp, =SFE(SVC_STACK) ; End of SVC_STACK

BIC r0, r0, #MODE_BITS ; Clear the mode bits
ORR r0, r0, #UND_MODE ; Set UND mode bits
MSR cpsr_c, r0 ; Change the mode
LDR sp, =SFE(UND_STACK) ; End of UND_STACK

BIC r0, r0, #MODE_BITS ; Clear the mode bits
ORR r0, r0, #FIQ_MODE ; Set FIQ mode bits
MSR cpsr_c, r0 ; Change the mode
LDR sp, =SFE(FIQ_STACK) ; End of FIQ_STACK

BIC r0, r0, #MODE_BITS ; Clear the mode bits
ORR r0, r0, #IRQ_MODE ; Set IRQ mode bits
MSR cpsr_c, r0 ; Change the mode
LDR sp, =SFE(IRQ_STACK) ; End of IRQ_STACK

BIC r0 ,r0, #MODE_BITS ; Clear the mode bits
ORR r0 ,r0, #SYS_MODE ; Set System mode bits
MSR cpsr_c, r0 ; Change the mode
LDR sp, =SFE(CSTACK) ; End of CSTACK

; Add more initialization here
BIC r0, r0, #MODE_BITS ; Clear the mode bits
ORR r0, r0, #SVC_MODE ; Set SVC mode bits
MSR cpsr_c, r0 ; Change the mode

; Continue to ?main for C-level initialization.

LDR r0, =?main
BX r0

END

Previously I mentioned the copy operation of the first 80 bytes of application code to a seperate flash sector. Apart from the first 64 bytes for interrupt vectors, the remaining 16 bytes are the 4 exception handlers respectively for undef_handler, prefetch_handler, data_handler and fiq_handler. The source program accesses them by absolute addressing. In my opinion, for the robustness of the software under current circumstances, it is quite necessary to move them to another place than the shared area. Then how? Is it OK to simply move them to the very front of "END"? I experimented and found it works, their addresses being out of the shared area, but with uncertainty of lack of errors. This is question 4.
--- In l..., "Phil Young" wrote:
>
> When summing with the PC, the PC points to the next instruction, not the
> current instruction.
>
>
>
> Not sure about the 0x14, but it might be that the tools have inserted a CRC
> here for the boot loader, which would be why that location is reserved.
>
>
>
> Can't remember the ARM instructions that well, but it looks like the
> disassembler is showing the equivalent ARM instruction, though in fact that
> is not an actual instruction, it's a table entry.
>
>
>
> The disassemble often shown what appears to be garbage since it doesn't know
> whether the contents of a location are instructions or data, in this case
> they are data.
>
>
>
>
>
> The actual instruction it thinks it sees seems to be something like
>
>
>
> If (Zero){
>
> R2 = R0 & (R0 >> R4)
>
> }
>
>
>
> If you follow my pseudo code
>
>
>
> ARM allows operands to be immediate or register values, and one operand can
> be shifted by a third operand, so you can load large constants with a
> smaller operand field, the range of constants being determined by the
> highest and lowest bits that are set, so for example you could not load
> 0xf000000f as an immediate value, but you could load 0xf0000000, as it only
> requires 4 contiguous bits, it can be loaded as 0xF << 28.
>
>
>
> Regards
>
>
>
> Phil.
>
>
>
> From: l... [mailto:l...] On Behalf Of
> skiddybird
> Sent: 08 March 2012 18:19
> To: l...
> Subject: [lpc2000] confusion on startup code of LPC2129
>
>
>
>
>
> hi,fellows,
> For the demo port of FreeRTOS V7.1.0 for LPC2129 using IAR toolchain, I have
> many questions regarding the startup code to consult you.
> The relevant code is as below.
>
> SECTION .intvec:CODE:NOROOT(2)
>
> PUBLIC __vector
> PUBLIC __vector_0x14
> PUBLIC __iar_program_start
> EXTERN vPortYieldProcessor
>
> ARM
> __vector:
> ;;
> ldr pc,[pc,#+24] ;; Reset
> ldr pc,[pc,#+24] ;; Undefined instructions
> ;; ldr pc,[pc,#+24] ;; Software interrupt (SWI/SVC)
> b vPortYieldProcessor
> ldr pc,[pc,#+24] ;; Prefetch abort
> ldr pc,[pc,#+24] ;; Data abort
> __vector_0x14
> DC32 0 ;; RESERVED
> ldr pc, [PC, #-0xFF0] ;; IRQ
> ldr pc,[pc,#+24] ;; FIQ
>
> DC32 __iar_program_start ;; Reset
> DC32 undef_handler ;; Undefined instructions
> DC32 0 ;; Software interrupt (SWI/SVC)
> DC32 prefetch_handler ;; Prefetch abort
> DC32 data_handler ;; Data abort
> DC32 0 ;; RESERVED
> DC32 0 ;; IRQ
> DC32 fiq_handler ;; FIQ
>
> undef_handler
> b undef_handler
>
> prefetch_handler
> b prefetch_handler
>
> data_handler
> b data_handler
>
> fiq_handler
> b fiq_handler
>
> the disassembly code shown by IAR is as below.
>
> 0x0: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x20] ?cstartup
> 0x4: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x24] undef_handler
> 0x8: 0xea000310 B vPortYieldProcessor ; 0xc50
> 0xc: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x2c] prefetch_handler
> FIQ_MODE:
> USR_MODE:
> 0x10: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x30] data_handler
> __vector_0x14:
> 0x14: 0xb4c04c88 STRBLT R4, [R0], #0xc88
> 0x18: 0xe51ffff0 LDR PC, VICVectAddr ; 0x0 (0)
> 0x1c: 0xe59ff018 LDR PC, [PC, #0x18] ; [0x3c] fiq_handler
> 0x20: 0x00002450 ANDEQ R2, R0, R0, ASR R4
> 0x24: 0x00000040 ANDEQ R0, R0, R0, ASR #32
> 0x28: 0x00000000 ANDEQ R0, R0, R0
> 0x2c: 0x00000044 ANDEQ R0, R0, R4, ASR #32
> 0x30: 0x00000048 ANDEQ R0, R0, R8, ASR #32
> 0x34: 0x00000000 ANDEQ R0, R0, R0
> 0x38: 0x00000000 ANDEQ R0, R0, R0
> 0x3c: 0x0000004c ANDEQ R0, R0, R12, ASR #32
> undef_handler:
> 0x40: 0xeafffffe B undef_handler ; 0x40
> prefetch_handler:
> 0x44: 0xeafffffe B prefetch_handler ; 0x44
> data_handler:
> 0x48: 0xeafffffe B data_handler ; 0x48
> fiq_handler:
> 0x4c: 0xeafffffe B fiq_handler ; 0x4c
> 0x50: 0x00000000 ANDEQ R0, R0, R0
> 0x54: 0x00000000 ANDEQ R0, R0, R0
>
> The first question. At address 0x0 in disassembly part, the instruction sums
> the value in PC with 0x18, and since the instruction address is 0x0, is the
> current PC value 0x0 also? if true, 0x0 + 0x18 = 0x18, not 0x20, as the
> comment says. What is wrong?
> The second question. At address 0x14 and 0x28 in disassembly part, the
> instructions are different, but they are both produced from one assembly
> statement(DC32 0). Why does one cause result in two distinct effects?
> The third question. At address 0x20 in disassembly part, what does it stand
> for when Z bit in CPSR is high? And what are the roles of R2, R0 and R4 for
> the moment?
>
>
>