EmbeddedRelated.com
Forums
Memfault Beyond the Launch

{To TomW} GCC-Bug in IRQs

Started by Sten March 25, 2006
--- In l..., Richard Duits wrote:
>
> I think VIC_GCCFIX_IRQ_EPILOGUE should be:
>
> #define VIC_GCCFIX_IRQ_EPILOGUE() \
> __asm__ __volatile__( " ldmia sp!, {r0-r12,pc}^
> \n");
> The "^" tells the arm to copy SPSR to CPSR.
>
> Richard.

Yes, I think you're correct. Since pc is included in the register_list
it is a LDM(3)-type, to copy SPSR of the current mode (SPSR_irq) to
CPSR, "^" is needed.
ARM ARM pg. A4-34.

Roger

> Sten wrote:
> > frankcallaghan9 wrote:
> > >
> > > Hi Guys,
> > > I've just hit this problem in my UART handler, I'm new to the ARM
> > > and haven't used it's asm yet! could one of you ASM gurus
> > > please post the required inline entry/exit code for us dummys
> > > thanks,
> >
> > Hello Frank,
> >
> > if you want to use "manually" written prologue/epilogue instead of a
> > stub try this:
> >
> > #define
> > VIC_GCCFIX_IRQ_PROLOGUE()
\
> > __asm__ __volatile__( " sub lr, lr,
> > #4 \n" \
> > " stmdb sp!,
> > {r0-r12,lr} \n");
> > #define VIC_GCCFIX_IRQ_EPILOGUE() \
> > __asm__ __volatile__( " ldmia sp!,
> > {r0-r12,pc} \n");
> >
> > void myIRQ(void) __attribute__((interrupt("IRQ"), naked));
> >
> > void myIRQ(void) {
> > VIC_GCCFIX_IRQ_PROLOGUE();
> > /* ... */
> > VIC_GCCFIX_IRQ_EPILOGUE();
> > }
> >
> > Sten
>

Yahoo! Groups Links

An Engineer's Guide to the LPC2100 Series

> David Hawkins:

> irq_isr:
> sub lr, lr, #4
> stmfd sp!, {r0-r3, ip, lr}
> bl irq_handler
> ldmfd sp!, {r0-r3, ip, pc}^
> /* VICVectAddr dispatch loop */
> void irq_handler(void)

wouldn't this handler need the "naked" attribute when using the stub
above? would you please write out the declaration in full?

> {
> /* Process IRQ interrupts */
> irq_handler_t handler;
> while (VICIRQStatus) {
> /* Get the address of the highest priority handler */
> handler = (irq_handler_t)VICVectAddr;
>
> /* Execute the handler */
> (*handler)();
>
> /* Acknowledge the VIC */
> VICVectAddr = 0;
> }
> }

clemens

Yahoo! Groups Links
Hi Clemens,

> wouldn't this handler need the "naked" attribute when using the stub
> above? would you please write out the declaration in full?

With the assembler coded stub in place, the functions loaded
into the VIC are standard C functions. The code requires no
attributes anywhere. Maximum portability.

Given that the functions called by the VIC are standard,
they adhere to the ACPS, and so the assembler stub just
handles the caller save registers and expects the compiler
to do-the-right-thing for the rest.

The example code below demonstrates this ...

Cheers
Dave
/* ex10_main.c
*
* Software generated EINT[0:3] example (non-nested IRQs)
*/
#include "led.h"

/* ----------------------------
* LPC2138 registers
* ----------------------------
*/
#define VICIRQStatus (*((volatile unsigned long *) 0xFFFFF000))
#define VICIntSelect (*((volatile unsigned long *) 0xFFFFF00C))
#define VICIntEnable (*((volatile unsigned long *) 0xFFFFF010))
#define VICSoftInt (*((volatile unsigned long *) 0xFFFFF018))
#define VICSoftIntClear (*((volatile unsigned long *) 0xFFFFF01C))
#define VICVectAddr (*((volatile unsigned long *) 0xFFFFF030))
#define VICDefVectAddr (*((volatile unsigned long *) 0xFFFFF034))
#define VICVectAddr0 (*((volatile unsigned long *) 0xFFFFF100))
#define VICVectAddr1 (*((volatile unsigned long *) 0xFFFFF104))
#define VICVectAddr2 (*((volatile unsigned long *) 0xFFFFF108))
#define VICVectAddr3 (*((volatile unsigned long *) 0xFFFFF10C))
#define VICVectCntl0 (*((volatile unsigned long *) 0xFFFFF200))
#define VICVectCntl1 (*((volatile unsigned long *) 0xFFFFF204))
#define VICVectCntl2 (*((volatile unsigned long *) 0xFFFFF208))
#define VICVectCntl3 (*((volatile unsigned long *) 0xFFFFF20C))

/* ----------------------------
* Function declarations and globals
* ----------------------------
*/
void irq_init();
void fiq_handler(void);
typedef void(*irq_handler_t)(void);

void irq_handler(void);
void eint0_handler(void);
void eint1_handler(void);
void eint2_handler(void);
void eint3_handler(void);

/* IRQ register bit locations */
#define EINT0 (1 << 14)
#define EINT1 (2 << 14)
#define EINT2 (4 << 14)
#define EINT3 (8 << 14)

/* ----------------------------
* Function definitions
* ----------------------------
*/

/* Setup the IRQ interrupts */
void irq_init(void)
{
/* Setup the VIC to have EINT[0:3] generate IRQs */
VICIntSelect = 0; /* Select IRQ */
VICVectAddr0 = (unsigned long)eint0_handler;/* Vector 0 */
VICVectAddr1 = (unsigned long)eint1_handler;/* Vector 1 */
VICVectAddr2 = (unsigned long)eint2_handler;/* Vector 2 */
VICVectAddr3 = (unsigned long)eint3_handler;/* Vector 3 */
VICVectCntl0 = 0x20 | 14; /* EINT0 Interrupt */
VICVectCntl1 = 0x20 | 15; /* EINT1 Interrupt */
VICVectCntl2 = 0x20 | 16; /* EINT2 Interrupt */
VICVectCntl3 = 0x20 | 17; /* EINT3 Interrupt */
VICIntEnable = (0xF << 14); /* Enable */

}

/* VICVectAddr dispatch loop */
void irq_handler(void)
{
/* Process IRQ interrupts */
irq_handler_t handler;
while (VICIRQStatus) {
/* Get the address of the highest priority handler */
handler = (irq_handler_t)VICVectAddr;

/* Execute the handler */
(*handler)();

/* Acknowledge the VIC */
VICVectAddr = 0;
}
}

void eint0_handler(void)
{
/* Clear interrupt source */
VICSoftIntClear = EINT0;

/* Processing EINT0 complete */
led_clr(1);
}

void eint1_handler(void)
{
/* Clear interrupt source */
VICSoftIntClear = EINT1;

/* Process EINT1 */

/* Trigger EINT0 */
led_set(1);
VICSoftInt = EINT0;

/* Processing EINT1 complete */
led_clr(2);
}

void eint2_handler(void)
{
/* Clear interrupt source */
VICSoftIntClear = EINT2;

/* Process EINT2 */

/* Trigger EINT1 */
led_set(2);
VICSoftInt = EINT1;

/* Processing EINT2 complete */
led_clr(4);
}

void eint3_handler(void)
{
/* Clear interrupt source */
VICSoftIntClear = EINT3;

/* Process EINT3 */

/* Trigger EINT2 */
led_set(4);
VICSoftInt = EINT2;

/* Processing EINT3 complete */
led_clr(8);
}

/* Empty handler (since the startup code references it) */
void fiq_handler(void)
{
return;
}

/* ----------------------------
* Application
* ----------------------------
*/
int main (void)
{
led_init();
/* Start low */
led(0);
irq_init();
while(1) {
/* Trigger EINT3 */
led_set(8);
VICSoftInt = EINT3;
}
return 0;
}
/* ex10a_start.s */

.global main
.global _start

/* Symbols defined by the linker script */
.global _etext
.global _data
.global _edata
.global _bss
.global _ebss

/* External functions */
.global fiq_handler
.global irq_handler

.text
.arm

/* ----------------------------
* Exception vectors
* ----------------------------
*/
_start:
b reset /* reset */
b loop /* undefined instruction */
b loop /* software interrupt */
b loop /* prefetch abort */
b loop /* data abort */
nop /* reserved for the bootloader checksum */
ldr pc, irq_addr

/* FIQ ISR */
fiq_isr:
sub lr, lr, #4
stmfd sp!, {r0-r3, ip, lr}
bl fiq_handler
ldmfd sp!, {r0-r3, ip, pc}^

irq_addr: .word irq_isr
irq_isr:
sub lr, lr, #4
stmfd sp!, {r0-r3, ip, lr}
bl irq_handler
ldmfd sp!, {r0-r3, ip, pc}^

/* ----------------------------
* LPC21xx PLL setup
* ----------------------------
*/
reset:
/* Use r0 for indirect addressing */
ldr r0, PLLBASE

/* PLLCFG = PLLCFG_VALUE */
mov r3, #PLLCFG_VALUE
str r3, [r0, #PLLCFG_OFFSET]

/* PLLCON = PLLCON_PLLE */
mov r3, #PLLCON_PLLE
str r3, [r0, #PLLCON_OFFSET]

/* PLLFEED = PLLFEED1, PLLFEED2 */
mov r1, #PLLFEED1
mov r2, #PLLFEED2
str r1, [r0, #PLLFEED_OFFSET]
str r2, [r0, #PLLFEED_OFFSET]

/* while ((PLLSTAT & PLLSTAT_PLOCK) == 0); */
pll_loop:
ldr r3, [r0, #PLLSTAT_OFFSET]
tst r3, #PLLSTAT_PLOCK
beq pll_loop

/* PLLCON = PLLCON_PLLC|PLLCON_PLLE */
mov r3, #PLLCON_PLLC|PLLCON_PLLE
str r3, [r0, #PLLCON_OFFSET]

/* PLLFEED = PLLFEED1, PLLFEED2 */
str r1, [r0, #PLLFEED_OFFSET]
str r2, [r0, #PLLFEED_OFFSET]

/* ----------------------------
* LPC21xx MAM setup
* ----------------------------
*/
mam_init:
/* Use r0 for indirect addressing */
ldr r0, MAMBASE

/* MAMCR = MAMCR_VALUE */
mov r1, #MAMCR_VALUE
str r1, [r0, #MAMCR_OFFSET]

/* MAMTIM = MAMTIM_VALUE */
mov r1, #MAMTIM_VALUE
str r1, [r0, #MAMTIM_OFFSET]

/* ----------------------------
* LPC21xx stacks setup
* ----------------------------
*/
stacks_init:
ldr r0, STACK_START

/* FIQ mode stack */
msr CPSR_c, #FIQ_MODE|IRQ_DISABLE|FIQ_DISABLE
mov sp, r0
sub r0, r0, #FIQ_STACK_SIZE

/* IRQ mode stack */
msr CPSR_c, #IRQ_MODE|IRQ_DISABLE|FIQ_DISABLE
mov sp, r0
sub r0, r0, #IRQ_STACK_SIZE

/* Supervisor mode stack */
msr CPSR_c, #SVC_MODE|IRQ_DISABLE|FIQ_DISABLE
mov sp, r0
sub r0, r0, #SVC_STACK_SIZE

/* Undefined mode stack */
msr CPSR_c, #UND_MODE|IRQ_DISABLE|FIQ_DISABLE
mov sp, r0
sub r0, r0, #UND_STACK_SIZE

/* Abort mode stack */
msr CPSR_c, #ABT_MODE|IRQ_DISABLE|FIQ_DISABLE
mov sp, r0
sub r0, r0, #ABT_STACK_SIZE

/* System mode stack */
/* msr CPSR_c, #SYS_MODE|IRQ_DISABLE|FIQ_DISABLE*/
msr CPSR_c, #SYS_MODE
mov sp, r0

/* Leave the processor in system mode */

/* ----------------------------
* C runtime setup
* ----------------------------
*/
runtime_init:
/* Copy .data */
ldr r0, data_source
ldr r1, data_start
ldr r2, data_end
copy_data:
cmp r1, r2
ldrne r3, [r0], #4
strne r3, [r1], #4
bne copy_data

/* Clear .bss */
ldr r0, =0
ldr r1, bss_start
ldr r2, bss_end
clear_bss:
cmp r1, r2
strne r0, [r1], #4
bne clear_bss

/* Jump to main */
bl main

/* Catch return from main */
loop: b loop

/* ----------------------------
* 32-bit constants (and storage)
* ----------------------------
*
* These 32-bit constants are used in ldr statements.
*/

/* LPC SRAM starts at 0x40000000, and there is 32Kb = 8000h */
STACK_START: .word 0x40008000
PLLBASE: .word 0xE01FC080
MAMBASE: .word 0xE01FC000

/* Linker symbols */
data_source: .word _etext
data_start: .word _data
data_end: .word _edata
bss_start: .word _bss
bss_end: .word _ebss

/* ----------------------------
* 8-bit constants
* ----------------------------
*
* These 8-bit constants are used as immediate values and offsets.
*/

/* PLL configuration */
.equ PLLCON_OFFSET, 0x0
.equ PLLCFG_OFFSET, 0x4
.equ PLLSTAT_OFFSET, 0x8
.equ PLLFEED_OFFSET, 0xC

.equ PLLCON_PLLE, (1 << 0)
.equ PLLCON_PLLC, (1 << 1)
.equ PLLSTAT_PLOCK, (1 << 10)
.equ PLLFEED1, 0xAA
.equ PLLFEED2, 0x55

.equ PLLCFG_VALUE, 0x24

/* MAM configuration */
.equ MAMCR_OFFSET, 0x0
.equ MAMTIM_OFFSET, 0x4

.equ MAMCR_VALUE, 0x2 /* fully enabled */
.equ MAMTIM_VALUE, 0x4 /* fetch cycles */

/* Stack configuration */
/* Processor modes (see pA2-11 ARM-ARM) */
.equ FIQ_MODE, 0x11
.equ IRQ_MODE, 0x12
.equ SVC_MODE, 0x13 /* reset mode */
.equ ABT_MODE, 0x17
.equ UND_MODE, 0x1B
.equ SYS_MODE, 0x1F

/* Stack sizes */
.equ FIQ_STACK_SIZE, 0x00000080 /* 32x32-bit words */
.equ IRQ_STACK_SIZE, 0x00000080
.equ SVC_STACK_SIZE, 0x00000080
.equ ABT_STACK_SIZE, 0x00000010 /* 4x32-bit words */
.equ UND_STACK_SIZE, 0x00000010
.equ SYS_STACK_SIZE, 0x00000400 /* 256x32-bit words */

/* CPSR interrupt disable bits */
.equ IRQ_DISABLE, (1 << 7)
.equ FIQ_DISABLE, (1 << 6)

.end

Yahoo! Groups Links

Memfault Beyond the Launch