EmbeddedRelated.com
Forums

Need help with ARM linker file

Started by Paul Marcel December 6, 2004
Hi,

I need to know how to set up a IRQ stack for the Atmel arm7tdmi ARM
processor. I'm not sure where / how to do it. I think that I need to
set it up in boot.s and in ram.ld.

I'm embedding mininal code to illustrate what I'm trying to do:
boot.s, irq.s, main.c, ram.ld, makefile.

I haven't been able to find any example of how this is done. I hope
someone knows.

thank you,
Paul


BOOT.S:
-----------

.section .text
.code 32
.global vectors
vectors:
        b        reset                    @ 0x00 Reset
        b        exception                @ 0x04 Undefined instruction
        b        exception                @ 0x08 SWI
        b        exception                @ 0xc0 Prefetch abort
        b        exception                @ 0x10 Data abort
        b        exception                @ 0x14 reserved vector
        ldr      pc, [pc, # -0xF20]       @ 0x18 irqs fffff100
(AIC_IVR)
        @ldr     pc, [pc, #0xfffff100]    @ 0x18 irqs fffff100
(AIC_IVR)
        b        exception                @ 0x1c fast irqs
exception:                                @ 0x20
        b        exception
reset:  ldr        r1, bss_start          @ defined in ram.ld 0x4c
        ldr        r2, bss_end            @ defined in ram.ld 0x50
        ldr        r3, =0
loop:   cmp        r1,r2
        strne        r3,[r1],#+4
        bne        loop
        ldr        r13,stack_pointer      @ Initialize the stack
pointer
        bl        main
        b        vectors
stack_pointer:   .word _stack_top         @ defined in ram.ld
bss_start:       .word __bss_start__      @ defined in ram.ld 0x4c
bss_end:         .word __bss_end__        @ defined in ram.ld 0x50
        .end

IRQ.S
=========
        .section .text
        .code 32
irq:    b        0
        .end

MAIN.C
=========
int main ( void )  {
   return 0;
}

RAM.LD:
=================

ENTRY(vectors)
SEARCH_DIR(.)
MEMORY {
   sram : org = 0x00000000, len = 256K
}
SECTIONS {
        .text : {
                *(.text);
                . = ALIGN(4);
        } > sram
        .data ADDR(.text) + SIZEOF(.text) : {
                datastart = .;
                __data_start__ = . ;
                *(.data)
                . = ALIGN(4);
                __data_end__ = . ;
                edata  =  .;
                _edata  =  .;
        } > sram
        .bss ADDR(.data) + SIZEOF(.data) : {
                __bss_start__ = . ;
                *(.bss); *(COMMON)
                __bss_end__ = . ;
                _stack_bottom = . ;
                . += 0x800 ;
                _stack_top = . ;
        } > sram
        end = .;
        _end = .;
        __end__ = .;

        /* Symbols */
        .stab 0 (NOLOAD) : {
                [ .stab ]
        }
        .stabstr 0 (NOLOAD) : {
                [ .stabstr ]
        }
}

MAKEFILE:
============

LD             = ram.ld
CFLAGS         = -g -I. -IC:\flo4\logger\gnu -mcpu=arm7tdmi
ASFLAGS        = -mcpu=arm7tdmi -gstabs
LDFLAGS        = -Tram.ld -nostartfiles -Lgcc -L.
OBJS           = boot.o irq.o main.o
EXE            = test.elf
BIN            = test.bin
DIS            = test.lst
HEX            = test.hex
S              = test.srec
MAP            = test.map
$(BIN): $(EXE)
        arm-none-elf-objcopy -O binary $(EXE) $(BIN)
        arm-none-elf-objcopy -O ihex $(EXE) $(HEX)
        arm-none-elf-objcopy -O srec $(EXE) $(S)
        arm-none-elf-nm $(EXE) >$(MAP)
        arm-none-elf-objdump -D -S $(EXE) >$(DIS)
        ls -l test.*
$(EXE): $(OBJS)
        arm-none-elf-gcc $(LDFLAGS) -o $(EXE) $(OBJS)
$(OBJS): $(LD)
$(OBJS): Makefile
%.o:%.c
        arm-none-elf-gcc -c $(CFLAGS) $< -o $@
%.o:%.s
        arm-none-elf-as $(ASFLAGS) $< -o $@
clean:
        rm -f $(OBJS)
        rm -f $(EXE)
        rm -f $(BIN)
        rm -f $(DIS)
        rm -f $(HEX)
        rm -f $(S)
        rm -f $(MAP)


Paul Marcel wrote:
> Hi, > > I need to know how to set up a IRQ stack for the Atmel arm7tdmi ARM > processor. I'm not sure where / how to do it. I think that I need to > set it up in boot.s and in ram.ld. > > I'm embedding mininal code to illustrate what I'm trying to do: > boot.s, irq.s, main.c, ram.ld, makefile. > > I haven't been able to find any example of how this is done. I hope > someone knows. > > thank you, > Paul >
Setting up the IRQ stack pointer needs you to be in IRQ mode. To do this: - set PSR so that IRQ and FIQ are forbidden - change mode in PSR to IRQ - load r13 (sp) - restore PSR Please note that the CPU is in supervisor mode after reset. This is OK if you're not going to use software interrupts, else change mode to system mode at start. User mode won't go: you cannot manipulate the mode and interrupt bits in user mode. If you run a simple non-nestable interrupt service in system mode, you might get by without using an IRQ stack at all, ---- irqentry: @@ Keep the following instructions, if the interrupt disable @@ timing patch is needed, see Atmel application note 1156A mrs r13,spsr @ get saved PSR tst r13,#0x80 @ interrupts enabled? subnes pc,lr,#4 @ yes - immediate interrupt dismiss @@ end if timing patch ldr r13,=save_area stm r13,{r0-r14}^ @ save user registers mrs r0,cpsr orr r0,r0,#0x1f @ system mode msr cpsr,r0 @ handle the interrupt in system mode, @ could e.g. bl to a C routine to do it @ remember to send EOI to interrupt controller mrs 0,cpsr bic r0,r0,#0x1f orr r0,r0,#0x12 @ IRQ mode msr cpsr,r0 ldm r13,{r0-r14}^ @ restore user registers nop @ banked ldm recovery delay subs pc,lr,#4 @ dismiss the interrupt ---- Disclaimer: Code manually copied from working kernel. All bugs are guaranteed. HTH -- Tauno Voipio tauno voipio (at) iki fi
"Paul Marcel" <paulmarcell@charter.net> wrote in message
news:906ar0ledgmfra42gcap9i0l4p6c0ucikb@4ax.com...
> > Hi, > > I need to know how to set up a IRQ stack for the Atmel arm7tdmi ARM > processor. I'm not sure where / how to do it. I think that I need to > set it up in boot.s and in ram.ld. > > I'm embedding mininal code to illustrate what I'm trying to do: > boot.s, irq.s, main.c, ram.ld, makefile. > > I haven't been able to find any example of how this is done. I hope > someone knows. > > thank you, > Paul >
<snip> You need to setup the stacks in your startup code as follows: First define the size of the stack for each mode: .set UND_STACK_SIZE, 0x00000004 .set ABT_STACK_SIZE, 0x00000004 .set FIQ_STACK_SIZE, 0x00000004 .set IRQ_STACK_SIZE, 0X00000400 .set SVC_STACK_SIZE, 0x00000400 A few other constants just for ease of reading. .set MODE_USR, 0x10 /* User Mode */ .set MODE_FIQ, 0x11 /* FIQ Mode */ .set MODE_IRQ, 0x12 /* IRQ Mode */ .set MODE_SVC, 0x13 /* Supervisor Mode */ .set MODE_ABT, 0x17 /* Abort Mode */ .set MODE_UND, 0x1B /* Undefined Mode */ .set MODE_SYS, 0x1F /* System Mode */ ////// CODE /////// /* Load R0 with the address for the first stack */ ldr r0, .START_ADDRESS /* Switch to the mode for which you are going to setup the stack. */ msr CPSR_c, #MODE_UND|I_BIT|F_BIT /* Undefined Instruction mode */ /* Move the stack address into the stack pointer. */ mov sp, r0 /* Move the address past the stack just setup. */ sub r0, r0, #UND_STACK_SIZE /* Repeat for every mode. */ msr CPSR_c, #MODE_ABT|I_BIT|F_BIT /* Abort Mode */ mov sp, r0 sub r0, r0, #ABT_STACK_SIZE msr CPSR_c, #MODE_FIQ|I_BIT|F_BIT /* FIQ Mode */ mov sp, r0 sub r0, r0, #FIQ_STACK_SIZE msr CPSR_c, #MODE_IRQ|I_BIT|F_BIT /* IRQ Mode */ mov sp, r0 sub r0, r0, #IRQ_STACK_SIZE msr CPSR_c, #MODE_SVC|I_BIT|F_BIT /* Supervisor Mode */ mov sp, r0 sub r0, r0, #SVC_STACK_SIZE msr CPSR_c, #MODE_SYS|I_BIT|F_BIT /* System Mode */ mov sp, r0 ///// CODE END ////// This holds the RAM address to use for the stack in R0. For each mode you switch to the MODE, then copy the value from R0 into the stack pointer. Then modifiy R0 by however many bytes you want to be available for that stack, before moving onto the next mode and repeating. Hope this helps. Richard. http://www.FreeRTOS.org
On Tue, 07 Dec 2004 09:05:04 GMT, "Richard" <Nowhere@Nowhere.com>
wrote:

> >You need to setup the stacks in your startup code as follows: > >First define the size of the stack for each mode: >.set UND_STACK_SIZE, 0x00000004 >.set ABT_STACK_SIZE, 0x00000004 >.set FIQ_STACK_SIZE, 0x00000004 >.set IRQ_STACK_SIZE, 0X00000400 >.set SVC_STACK_SIZE, 0x00000400 > >A few other constants just for ease of reading. >.set MODE_USR, 0x10 /* User Mode */ >.set MODE_FIQ, 0x11 /* FIQ Mode */ >.set MODE_IRQ, 0x12 /* IRQ Mode */ >.set MODE_SVC, 0x13 /* Supervisor Mode */ >.set MODE_ABT, 0x17 /* Abort Mode */ >.set MODE_UND, 0x1B /* Undefined Mode */ >.set MODE_SYS, 0x1F /* System Mode */ > > > >////// CODE /////// > >/* Load R0 with the address for the first stack */ >ldr r0, .START_ADDRESS >/* Switch to the mode for which you are going to setup the stack. */ >msr CPSR_c, #MODE_UND|I_BIT|F_BIT /* Undefined Instruction mode */ >/* Move the stack address into the stack pointer. */ >mov sp, r0 >/* Move the address past the stack just setup. */ >sub r0, r0, #UND_STACK_SIZE >/* Repeat for every mode. */ >msr CPSR_c, #MODE_ABT|I_BIT|F_BIT /* Abort Mode */ >mov sp, r0 >sub r0, r0, #ABT_STACK_SIZE >msr CPSR_c, #MODE_FIQ|I_BIT|F_BIT /* FIQ Mode */ >mov sp, r0 >sub r0, r0, #FIQ_STACK_SIZE >msr CPSR_c, #MODE_IRQ|I_BIT|F_BIT /* IRQ Mode */ >mov sp, r0 >sub r0, r0, #IRQ_STACK_SIZE >msr CPSR_c, #MODE_SVC|I_BIT|F_BIT /* Supervisor Mode */ >mov sp, r0 >sub r0, r0, #SVC_STACK_SIZE >msr CPSR_c, #MODE_SYS|I_BIT|F_BIT /* System Mode */ >mov sp, r0 > >///// CODE END ////// > >This holds the RAM address to use for the stack in R0. For each mode you >switch to the MODE, then copy the value from R0 into the stack pointer. >Then modifiy R0 by however many bytes you want to be available for that >stack, before moving onto the next mode and repeating. > >Hope this helps. > >Richard. > >http://www.FreeRTOS.org >
I think that I'm finally starting to see how this works. I added most of your code and this still builds. I only modified boot.s. But I still need clarification of ".START_ADDRESS" and the relation between boot.s and ram.ld. I've left in my old stack initialization stuff from a non-interrupt example. I'll remove that eventually. What do I need to do in ram.ld to make this work? Do all the stacks go in the .bss section? Also should I zero each stack after setting the sp? Can I just set the stacks up in boot.s and not have to mess with ram.ld? Paul BOOT.S: ============= .section .text .code 32 .global vectors @ define the size of the stack for each mode: .set UND_STACK_SIZE, 0x00000004 .set ABT_STACK_SIZE, 0x00000004 .set FIQ_STACK_SIZE, 0x00000004 .set IRQ_STACK_SIZE, 0X00000400 .set SVC_STACK_SIZE, 0x00000400 @ A few other constants just for ease of reading .set MODE_USR, 0x10 @ User Mode .set MODE_FIQ, 0x11 @ FIQ Mode .set MODE_IRQ, 0x12 @ IRQ Mode .set MODE_SVC, 0x13 @ Supervisor Mode .set MODE_ABT, 0x17 @ Abort Mode .set MODE_UND, 0x1B @ Undefined Mode .set MODE_SYS, 0x1F @ System Mode .equ F_BIT, 0x40 .equ I_BIT, 0x80 vectors: b reset @ 0x00 Reset b exception @ 0x04 Undefined instruction b exception @ 0x08 SWI b exception @ 0xc0 Prefetch abort b exception @ 0x10 Data abort b exception @ 0x14 reserved vector ldr pc, [pc, # -0xF20] @ 0x18 irqs fffff100 (AIC_IVR) @ldr pc, [pc, #0xfffff100] @ 0x18 irqs fffff100 (AIC_IVR) b exception @ 0x1c fast irqs exception: @ 0x20 b exception reset: @ old code ((((((((((((((((((((( @ Begin by clearing out the .bss section defined in ram.ld ldr r1, bss_start @ defined in ram.ld 0x4c ldr r2, bss_end @ defined in ram.ld 0x50 ldr r3, =0 clear_bss: cmp r1,r2 strne r3,[r1],#+4 bne clear_bss @))))))))))))))))))))))))))))) old code /*** @ old code: @ldr r13,stack_pointer @ Initialize the stack pointer @ldr r0, .START_ADDRESS @ Load R0 with the address for the first stack ***/ ldr r0, start_address @ Load R0 with the address for the first stack @ Switch to the mode for which you are going to setup the stack msr CPSR_c, #MODE_UND|I_BIT|F_BIT @ Undefined Instruction mode mov sp, r0 @ Move the stack address into the stack pointer sub r0, r0, #UND_STACK_SIZE @ Move the address past the stack just setup msr CPSR_c, #MODE_ABT|I_BIT|F_BIT @ Abort Mode mov sp, r0 sub r0, r0, #ABT_STACK_SIZE msr CPSR_c, #MODE_FIQ|I_BIT|F_BIT @ FIQ Mode mov sp, r0 sub r0, r0, #FIQ_STACK_SIZE msr CPSR_c, #MODE_IRQ|I_BIT|F_BIT @ IRQ Mode mov sp, r0 sub r0, r0, #IRQ_STACK_SIZE msr CPSR_c, #MODE_SVC|I_BIT|F_BIT @ Supervisor Mode mov sp, r0 sub r0, r0, #SVC_STACK_SIZE msr CPSR_c, #MODE_SYS|I_BIT|F_BIT @ System Mode mov sp, r0 bl main b vectors stack_pointer: .word _stack_top @ defined in ram.ld bss_start: .word __bss_start__ @ defined in ram.ld 0x4c bss_end: .word __bss_end__ @ defined in ram.ld 0x50 start_address: .end RAM.LD: ========== ENTRY(vectors) SEARCH_DIR(.) MEMORY { sram : org = 0x00000000, len = 256K } SECTIONS { .text : { *(.text); . = ALIGN(4); } > sram .data ADDR(.text) + SIZEOF(.text) : { datastart = .; __data_start__ = . ; *(.data) . = ALIGN(4); __data_end__ = . ; edata = .; _edata = .; } > sram .bss ADDR(.data) + SIZEOF(.data) : { __bss_start__ = . ; *(.bss); *(COMMON) __bss_end__ = . ; _stack_bottom = . ; . += 0x800 ; _stack_top = . ; } > sram end = .; _end = .; __end__ = .; /* Symbols */ .stab 0 (NOLOAD) : { [ .stab ] } .stabstr 0 (NOLOAD) : { [ .stabstr ] } }
"Paul Marcel" <paulmarcell@charter.net> wrote in message
news:43mbr0lbgdadvo5jum6c2t6jldjremp2o0@4ax.com...
> On Tue, 07 Dec 2004 09:05:04 GMT, "Richard" <Nowhere@Nowhere.com> > wrote: > > > > >You need to setup the stacks in your startup code as follows: > > > >First define the size of the stack for each mode: > >.set UND_STACK_SIZE, 0x00000004 > >.set ABT_STACK_SIZE, 0x00000004 > >.set FIQ_STACK_SIZE, 0x00000004 > >.set IRQ_STACK_SIZE, 0X00000400 > >.set SVC_STACK_SIZE, 0x00000400 > > > >A few other constants just for ease of reading. > >.set MODE_USR, 0x10 /* User Mode */ > >.set MODE_FIQ, 0x11 /* FIQ Mode */ > >.set MODE_IRQ, 0x12 /* IRQ Mode */ > >.set MODE_SVC, 0x13 /* Supervisor Mode */ > >.set MODE_ABT, 0x17 /* Abort Mode */ > >.set MODE_UND, 0x1B /* Undefined Mode */ > >.set MODE_SYS, 0x1F /* System Mode */ > > > > > > > >////// CODE /////// > > > >/* Load R0 with the address for the first stack */ > >ldr r0, .START_ADDRESS > >/* Switch to the mode for which you are going to setup the stack. */ > >msr CPSR_c, #MODE_UND|I_BIT|F_BIT /* Undefined Instruction mode */ > >/* Move the stack address into the stack pointer. */ > >mov sp, r0 > >/* Move the address past the stack just setup. */ > >sub r0, r0, #UND_STACK_SIZE > >/* Repeat for every mode. */ > >msr CPSR_c, #MODE_ABT|I_BIT|F_BIT /* Abort Mode */ > >mov sp, r0 > >sub r0, r0, #ABT_STACK_SIZE > >msr CPSR_c, #MODE_FIQ|I_BIT|F_BIT /* FIQ Mode */ > >mov sp, r0 > >sub r0, r0, #FIQ_STACK_SIZE > >msr CPSR_c, #MODE_IRQ|I_BIT|F_BIT /* IRQ Mode */ > >mov sp, r0 > >sub r0, r0, #IRQ_STACK_SIZE > >msr CPSR_c, #MODE_SVC|I_BIT|F_BIT /* Supervisor Mode */ > >mov sp, r0 > >sub r0, r0, #SVC_STACK_SIZE > >msr CPSR_c, #MODE_SYS|I_BIT|F_BIT /* System Mode */ > >mov sp, r0 > > > >///// CODE END ////// > > > >This holds the RAM address to use for the stack in R0. For each mode you > >switch to the MODE, then copy the value from R0 into the stack pointer. > >Then modifiy R0 by however many bytes you want to be available for that > >stack, before moving onto the next mode and repeating. > > > >Hope this helps. > > > >Richard. > > > >http://www.FreeRTOS.org > > > > > I think that I'm finally starting to see how this works. I added most > of your code and this still builds. I only modified boot.s. But I > still need clarification of ".START_ADDRESS" and the relation between > boot.s and ram.ld. I've left in my old stack initialization stuff from > a non-interrupt example. I'll remove that eventually. What do I need > to do in ram.ld to make this work? Do all the stacks go in the .bss > section? Also should I zero each stack after setting the sp? Can I > just set the stacks up in boot.s and not have to mess with ram.ld? > > Paul >
Using my boot file .START_ADDRESS gets set to .LC6 - I changed it in demo code I posted to .START_ADDRESS to make it more explicit. This is basically the very top of the on chip RAM (minus 4 bytes for some reason). .LC6 is then set to __stack_end__ as per: // code from boot.s .align 0 .LC1: .word __bss_beg__ .LC2: .word __bss_end__ .LC3: .word __data_beg__ .LC4: .word __data_beg_src__ .LC5: .word __data_end__ .LC6: .word __stack_end__ // end of code If you want a full buildable demo you can download the FreeRTOS source code (link below) and look in the FreeRTOS/Demo/ARM7 directory where you will find a boot.s, linker scripts and a makefile. Unfortunately not for an Atmel device but the principals are the same. Regards. http://www.FreeRTOS.org