git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@142 35acf78f-673a-0410-8e92-d51de3d6d3f4

This commit is contained in:
gdisirio 2007-12-17 14:57:44 +00:00
parent 430010715e
commit 0bb20d36f4
10 changed files with 238 additions and 203 deletions

View File

@ -162,19 +162,11 @@ void chSysPuts(char *msg) {
__attribute__((naked, weak)) __attribute__((naked, weak))
void IrqHandler(void) { void IrqHandler(void) {
asm(".code 32 \n\t" \ chSysIRQEnterI();
"stmfd sp!, {r0-r3, r12, lr} \n\t");
#ifdef THUMB /* nothing */
asm("add r0, pc, #1 \n\t" \
"bx r0 \n\t" \ chSysIRQExitI();
".code 16 \n\t");
VICVectAddr = 0;
asm("ldr r0, =IrqCommon \n\t" \
"bx r0 \n\t");
#else
VICVectAddr = 0;
asm("b IrqCommon \n\t");
#endif
} }
/* /*
@ -183,21 +175,148 @@ void IrqHandler(void) {
__attribute__((naked, weak)) __attribute__((naked, weak))
void T0IrqHandler(void) { void T0IrqHandler(void) {
asm(".code 32 \n\t" \ chSysIRQEnterI();
"stmfd sp!, {r0-r3, r12, lr} \n\t");
T0IR = 1; /* Clear interrupt on match MR0. */
chSysTimerHandlerI();
chSysIRQExitI();
}
/*
* Common IRQ exit code, \p chSysIRQExitI() just jumps here.
*
* System stack frame structure after a context switch in the
* interrupt handler:
*
* High +------------+
* | LR_USR | -+
* | R12 | |
* | R3 | |
* | R2 | | External context: IRQ handler frame
* | R1 | |
* | R0 | |
* | LR_IRQ | | (user code return address)
* | SPSR | -+ (user code status)
* | .... | <- chSchDoRescheduleI() stack frame, optimize it for space
* | LR | -+ (system code return address)
* | R11 | |
* | R10 | |
* | R9 | |
* | R8 | | Internal context: chSysSwitchI() frame
* | (R7) | | (optional, see CH_CURRP_REGISTER_CACHE)
* | R6 | |
* | R5 | |
* SP-> | R4 | -+
* Low +------------+
*/
__attribute__((naked, weak))
void IrqCommon(void) {
register BOOL b asm("r0");
VICVectAddr = 0;
b = chSchRescRequiredI();
#ifdef THUMB #ifdef THUMB
asm("add r0, pc, #1 \n\t" \ asm(".p2align 2,, \n\t" \
"bx r0 \n\t" \ "mov lr, pc \n\t" \
".code 16 \n\t"); "bx lr \n\t" \
T0IR = 1; /* Clear interrupt on match MR0. */ ".code 32 \n\t");
chSysTimerHandlerI(); #endif
VICVectAddr = 0; /*
asm("ldr r0, =IrqCommon \n\t" \ * If a reschedulation is not required then just returns from the IRQ.
"bx r0 \n\t"); */
asm("cmp r0, #0 \n\t" \
"ldmeqfd sp!, {r0-r3, r12, lr} \n\t" \
"subeqs pc, lr, #4 \n\t");
/*
* Reschedulation required, saves the external context on the
* system/user stack and empties the IRQ stack.
*/
asm(".set MODE_IRQ, 0x12 \n\t" \
".set MODE_SYS, 0x1F \n\t" \
".set I_BIT, 0x80 \n\t" \
"ldmfd sp!, {r0-r3, r12, lr} \n\t" \
"msr CPSR_c, #MODE_SYS | I_BIT \n\t" \
"stmfd sp!, {r0-r3, r12, lr} \n\t" \
"msr CPSR_c, #MODE_IRQ | I_BIT \n\t" \
"mrs r0, SPSR \n\t" \
"mov r1, lr \n\t" \
"msr CPSR_c, #MODE_SYS | I_BIT \n\t" \
"stmfd sp!, {r0, r1} \n\t");
#ifdef THUMB_NO_INTERWORKING
asm("add r0, pc, #1 \n\t" \
"bx r0 \n\t" \
".code 16 \n\t" \
"bl chSchDoRescheduleI \n\t" \
".p2align 2,, \n\t" \
"mov lr, pc \n\t" \
"bx lr \n\t" \
".code 32 \n\t");
#else #else
T0IR = 1; /* Clear interrupt on match MR0. */ asm("bl chSchDoRescheduleI \n\t");
chSysTimerHandlerI(); #endif
VICVectAddr = 0;
asm("b IrqCommon \n\t"); /*
* Restores the external context.
*/
asm("ldmfd sp!, {r0, r1} \n\t" \
"msr CPSR_c, #MODE_IRQ | I_BIT \n\t" \
"msr SPSR_fsxc, r0 \n\t" \
"mov lr, r1 \n\t" \
"msr CPSR_c, #MODE_SYS | I_BIT \n\t" \
"ldmfd sp!, {r0-r3, r12, lr} \n\t" \
"msr CPSR_c, #MODE_IRQ | I_BIT \n\t" \
"subs pc, lr, #4 \n\t");
/*
* Threads entry/exit code. It is declared weak so you can easily replace it.
* NOTE: It is always invoked in ARM mode, it does the mode switching.
* NOTE: It is included into IrqCommon to make sure the symbol refers to
* 32 bit code.
*/
asm(".set F_BIT, 0x40 \n\t" \
".weak threadstart \n\t" \
".globl threadstart \n\t" \
"threadstart: \n\t" \
"msr CPSR_c, #MODE_SYS \n\t");
#ifndef THUMB_NO_INTERWORKING
asm("mov r0, r5 \n\t" \
"mov lr, pc \n\t" \
"bx r4 \n\t" \
"bl chThdExit \n\t");
#else
asm("add r0, pc, #1 \n\t" \
"bx r0 \n\t" \
".code 16 \n\t" \
"mov r0, r5 \n\t" \
"bl jmpr4 \n\t" \
"bl chThdExit \n\t" \
"jmpr4: \n\t" \
"bx r4 \n\t");
#endif #endif
} }
/*
* System halt.
*/
__attribute__((naked, weak))
void chSysHalt(void) {
asm(".set F_BIT, 0x40 \n\t" \
".set I_BIT, 0x80 \n\t");
#ifdef THUMB
asm(".p2align 2,, \n\t" \
"mov r0, pc \n\t" \
"bx r0 \n\t");
#endif
asm(".code 32 \n\t" \
".weak _halt32 \n\t" \
".globl _halt32 \n\t" \
"_halt32: \n\t" \
"mrs r0, CPSR \n\t" \
"orr r0, #I_BIT | F_BIT \n\t" \
"msr CPSR_c, r0 \n\t" \
".loop: \n\t" \
"b .loop \n\t");
}

View File

@ -92,7 +92,7 @@ extern void chSysUnlock(void);
#define INT_REQUIRED_STACK 0x10 #define INT_REQUIRED_STACK 0x10
#else /* !THUMB */ #else /* !THUMB */
#define INT_REQUIRED_STACK 0 #define INT_REQUIRED_STACK 0
#endif /* THUMB */ #endif /* !THUMB */
#define StackAlign(n) ((((n) - 1) | 3) + 1) #define StackAlign(n) ((((n) - 1) | 3) + 1)
#define UserStackSize(n) StackAlign(sizeof(Thread) + \ #define UserStackSize(n) StackAlign(sizeof(Thread) + \
sizeof(struct intctx) + \ sizeof(struct intctx) + \
@ -101,16 +101,37 @@ extern void chSysUnlock(void);
INT_REQUIRED_STACK) INT_REQUIRED_STACK)
#define WorkingArea(s, n) ULONG32 s[UserStackSize(n) >> 2]; #define WorkingArea(s, n) ULONG32 s[UserStackSize(n) >> 2];
#ifdef THUMB
#define chSysIRQEnterI() { \
asm(".code 32 \n\t" \
"stmfd sp!, {r0-r3, r12, lr} \n\t" \
"add r0, pc, #1 \n\t" \
"bx r0 \n\t" \
".code 16 \n\t"); \
}
#define chSysIRQExitI() { \
VICVectAddr = 0; \
asm("ldr r0, =IrqCommon \n\t" \
"bx r0 \n\t"); \
}
#else /* !THUMB */
#define chSysIRQEnterI() { \
asm("stmfd sp!, {r0-r3, r12, lr} \n\t"); \
}
#define chSysIRQExitI() { \
asm("b IrqCommon \n\t"); \
}
#endif /* !THUMB */
/* It requires zero bytes, but better be safe.*/ /* It requires zero bytes, but better be safe.*/
#define IDLE_THREAD_STACK_SIZE 8 #define IDLE_THREAD_STACK_SIZE 8
void _IdleThread(void *p) __attribute__((noreturn)); void _IdleThread(void *p) __attribute__((noreturn));
void chSysHalt(void) __attribute__((noreturn)); void chSysHalt(void);
void chSysSwitchI(Context *oldp, Context *newp); void chSysSwitchI(Context *oldp, Context *newp);
void chSysPuts(char *msg); void chSysPuts(char *msg);
void threadstart(void); void threadstart(void);
void DefFiqHandler(void);
void DefIrqHandler(void);
void SpuriousHandler(void);
#endif /* _CHCORE_H_ */ #endif /* _CHCORE_H_ */

View File

@ -34,73 +34,15 @@
.code 32 .code 32
.balign 4 .balign 4
.globl threadstart
threadstart:
msr CPSR_c, #MODE_SYS
#ifndef THUMB_NO_INTERWORKING
mov r0, r5
mov lr, pc
bx r4
bl chThdExit
#else
add r0, pc, #1
bx r0
.code 16
mov r0, r5
bl jmpr4
bl chThdExit
jmpr4: bx r4
.code 32
#endif
.weak UndHandler
.globl UndHandler
UndHandler:
.weak SwiHandler
.globl SwiHandler
SwiHandler:
.weak PrefetchHandler
.globl PrefetchHandler
PrefetchHandler:
.weak AbortHandler
.globl AbortHandler
AbortHandler:
.weak FiqHandler
.globl FiqHandler
FiqHandler:
b halt32
.weak chSysHalt
#ifdef THUMB_NO_INTERWORKING
.code 16
.globl chSysHalt
chSysHalt:
mov r0, pc
bx r0
.code 32
#else
.globl chSysHalt
chSysHalt:
#endif
halt32:
mrs r0, CPSR
orr r0, #I_BIT | F_BIT
msr CPSR_c, r0
.loop: b .loop
#ifdef THUMB #ifdef THUMB
.globl chSysLock .globl chSysLock
chSysLock: chSysLock:
msr CPSR_c, #0x9F msr CPSR_c, #MODE_SYS | I_BIT
bx lr bx lr
.globl chSysUnlock .globl chSysUnlock
chSysUnlock: chSysUnlock:
msr CPSR_c, #0x1F msr CPSR_c, #MODE_SYS
bx lr bx lr
#endif #endif
@ -127,80 +69,3 @@ chSysSwitchI:
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
#endif #endif
#endif /* CH_CURRP_REGISTER_CACHE */ #endif /* CH_CURRP_REGISTER_CACHE */
/*
* Common exit point for all IRQ routines, it performs the rescheduling if
* required.
* System stack frame structure after a context switch in the
* interrupt handler:
*
* High +------------+
* | LR_USR | -+
* | R12 | |
* | R3 | |
* | R2 | | External context: IRQ handler frame
* | R1 | |
* | R0 | |
* | LR_IRQ | | (user code return address)
* | SPSR | -+ (user code status)
* | .... | <- mk_DoRescheduleI() stack frame, optimize it for space
* | LR | -+ (system code return address)
* | R11 | |
* | R10 | |
* | R9 | |
* | R8 | | Internal context: mk_SwitchI() frame
* | (R7) | | (optional, see CH_CURRP_REGISTER_CACHE)
* | R6 | |
* | R5 | |
* SP-> | R4 | -+
* Low +------------+
*/
#ifdef THUMB_NO_INTERWORKING
.code 16
.globl IrqCommon
IrqCommon:
bl chSchRescRequiredI
mov lr, pc
bx lr
.code 32
#else
.globl IrqCommon
IrqCommon:
bl chSchRescRequiredI
#endif
cmp r0, #0 // Simply returns if a
ldmeqfd sp!, {r0-r3, r12, lr} // reschedule is not
subeqs pc, lr, #4 // required.
// Saves the IRQ mode registers in the system stack.
ldmfd sp!, {r0-r3, r12, lr} // IRQ stack now empty.
msr CPSR_c, #MODE_SYS | I_BIT
stmfd sp!, {r0-r3, r12, lr} // Registers on System Stack.
msr CPSR_c, #MODE_IRQ | I_BIT
mrs r0, SPSR
mov r1, lr
msr CPSR_c, #MODE_SYS | I_BIT
stmfd sp!, {r0, r1} // Push R0=SPSR, R1=LR_IRQ.
// Context switch.
#ifdef THUMB_NO_INTERWORKING
add r0, pc, #1
bx r0
.code 16
bl chSchDoRescheduleI
mov lr, pc
bx lr
.code 32
#else
bl chSchDoRescheduleI
#endif
// Re-establish the IRQ conditions again.
ldmfd sp!, {r0, r1} // Pop R0=SPSR, R1=LR_IRQ.
msr CPSR_c, #MODE_IRQ | I_BIT
msr SPSR_fsxc, r0
mov lr, r1
msr CPSR_c, #MODE_SYS | I_BIT
ldmfd sp!, {r0-r3, r12, lr}
msr CPSR_c, #MODE_IRQ | I_BIT
subs pc, lr, #4

View File

@ -147,3 +147,24 @@ bssloop:
bl chSysHalt bl chSysHalt
.code 32 .code 32
#endif #endif
.weak UndHandler
.globl UndHandler
UndHandler:
.weak SwiHandler
.globl SwiHandler
SwiHandler:
.weak PrefetchHandler
.globl PrefetchHandler
PrefetchHandler:
.weak AbortHandler
.globl AbortHandler
AbortHandler:
.weak FiqHandler
.globl FiqHandler
FiqHandler:
b _halt32

View File

@ -60,6 +60,8 @@ typedef struct {
#define chSysLock() #define chSysLock()
#define chSysUnlock() #define chSysUnlock()
#define chSysPuts(msg) {} #define chSysPuts(msg) {}
#define chSysIRQEnterI()
#define chSysIRQExitI()
#define INT_REQUIRED_STACK 0 #define INT_REQUIRED_STACK 0
#define StackAlign(n) ((((n) - 1) | 3) + 1) #define StackAlign(n) ((((n) - 1) | 3) + 1)

View File

@ -60,6 +60,8 @@ typedef struct {
#define chSysLock() #define chSysLock()
#define chSysUnlock() #define chSysUnlock()
#define chSysPuts(msg) {} #define chSysPuts(msg) {}
#define chSysIRQEnterI()
#define chSysIRQExitI()
#define INT_REQUIRED_STACK 0 #define INT_REQUIRED_STACK 0
#define StackAlign(n) ((((n) - 1) | 3) + 1) #define StackAlign(n) ((((n) - 1) | 3) + 1)

View File

@ -55,7 +55,6 @@ static void ServeInterrupt(UART *u, FullDuplexDriver *com) {
switch (u->UART_IIR & IIR_SRC_MASK) { switch (u->UART_IIR & IIR_SRC_MASK) {
case IIR_SRC_NONE: case IIR_SRC_NONE:
VICVectAddr = 0;
return; return;
case IIR_SRC_ERROR: case IIR_SRC_ERROR:
SetError(u->UART_LSR, com); SetError(u->UART_LSR, com);
@ -98,37 +97,21 @@ static void ServeInterrupt(UART *u, FullDuplexDriver *com) {
__attribute__((naked, weak)) __attribute__((naked, weak))
void UART0IrqHandler(void) { void UART0IrqHandler(void) {
asm(".code 32 \n\t" \ chSysIRQEnterI();
"stmfd sp!, {r0-r3, r12, lr} \n\t");
#ifdef THUMB
asm("add r0, pc, #1 \n\t" \
"bx r0 \n\t" \
".code 16 \n\t");
ServeInterrupt(U0Base, &COM1); ServeInterrupt(U0Base, &COM1);
asm("ldr r0, =IrqCommon \n\t" \
"bx r0 \n\t"); chSysIRQExitI();
#else
ServeInterrupt(U0Base, &COM1);
asm("b IrqCommon \n\t");
#endif
} }
__attribute__((naked, weak)) __attribute__((naked, weak))
void UART1IrqHandler(void) { void UART1IrqHandler(void) {
asm(".code 32 \n\t" \ chSysIRQEnterI();
"stmfd sp!, {r0-r3, r12, lr} \n\t");
#ifdef THUMB
asm("add r0, pc, #1 \n\t" \
"bx r0 \n\t" \
".code 16 \n\t");
ServeInterrupt(U1Base, &COM2); ServeInterrupt(U1Base, &COM2);
asm("ldr r0, =IrqCommon \n\t" \
"bx r0 \n\t"); chSysIRQExitI();
#else
ServeInterrupt(U1Base, &COM2);
asm("b IrqCommon \n\t");
#endif
} }
#ifdef FIFO_PRELOAD #ifdef FIFO_PRELOAD

View File

@ -43,13 +43,20 @@ AVR-AT90CANx-GCC - Port on AVR AT90CAN128, not complete yet.
- NEW: Binary Mutexes, the new mechanism provides a complete implementation - NEW: Binary Mutexes, the new mechanism provides a complete implementation
of the "priority inheritance" algorithm as a tool for work around the of the "priority inheritance" algorithm as a tool for work around the
priority inversion problem. priority inversion problem.
The Mutexes are not meant to replace the Semaphores that are still the best The Mutexes are not meant to replace the Semaphores that still are the best
mechanism for synchronization between interrupt handlers and high level synchronization mechanism between interrupt handlers and high level
code, something Mutexes cannot do. code, something that Mutexes cannot do.
Soon an article will be added to the wiki describing pro and cons of the Soon an article will be added to the wiki describing pro and cons of the
various mechanisms and the correct use cases. various mechanisms and the correct use cases.
- RT Semaphores subsystem removed, the Mutexes implements a better solution - RT Semaphores subsystem removed, the Mutexes implements a better solution
for the same problem. for the same problem.
- Modified the test suite in order to have each test case to have the same
alignment enforced on functions. This is done to reduce MAM/Cache alignment
effects on the measurement.
- IRQ entry/exit code is now encapsulated into two new macros, see chcore.h
for details.
- Most of the asm code previously in chcore2.s is now inline asm code in
chcore.c (ARM port).
*** 0.4.5 *** *** 0.4.5 ***
- Moved the serial IRQ handlers and VIC vectors initialization inside the - Moved the serial IRQ handlers and VIC vectors initialization inside the

View File

@ -56,15 +56,15 @@ static void prio_enq(Thread *tp, ThreadsQueue *tqp) {
} }
/* /*
* 0 +++BA++------------------2+++--8++++++++++BR0---------------------------- * 0 +++BL++------------------2+++--8++++++++++BU0----------------------------
* 1 .......++AA++--2+++++++++BA....8..........++++++++BR8++++AR1------------- * 1 .......++AL++--2+++++++++BL....8..........++++++++BU8++++AU1-------------
* 2 .............++AA..............................................----++AR++ * 2 .............++AL..............................................----++AU++
* 8 .............................++AA........................++++++AR++...... * 8 .............................++AL........................++++++AU++......
* *
* *
* 5 ++++++++++++++++++AA+....9++++++++++++++AR5------------------------------ * 5 ++++++++++++++++++AL+....9++++++++++++++AU5------------------------------
* 7 .....................++-------------------------------------------------- * 7 .....................++--------------------------------------------------
* 9 .......................++AA.............+++++++++AR++++++++++++++++++++++ * 9 .......................++AL.............+++++++++AU++++++++++++++++++++++
*/ */
/** /**

View File

@ -100,6 +100,21 @@ typedef struct {
*/ */
#define chSysUnlock() #define chSysUnlock()
/**
* IRQ handler enter code.
* @note Usually IRQ handlers function are also declared naked.
* @note On some architectures this macro can be empty.
*/
#define chSysIRQEnterI()
/**
* IRQ handler exit code.
* @note Usually IRQ handlers function are also declared naked.
* @note This macro must perform the final reschedulation by using
* \p chSchRescRequiredI() and \p chSchDoRescheduleI().
*/
#define chSysIRQExitI()
void _IdleThread(void *p); void _IdleThread(void *p);
void chSysHalt(void); void chSysHalt(void);
void chSysSwitchI(Context *oldp, Context *newp); void chSysSwitchI(Context *oldp, Context *newp);