diff options
| author | Bernard Xiong <[email protected]> | 2013-06-03 06:38:51 +0800 |
|---|---|---|
| committer | Bernard Xiong <[email protected]> | 2013-06-03 06:38:51 +0800 |
| commit | 3c04d0b0a06f6984829d682dbef4de280a139480 (patch) | |
| tree | 885fbea1d200aabf499869fe69cd36526c86339f /libcpu | |
| parent | 84da2a4dcc0a00ee02a83870990a3a27e5c1c344 (diff) | |
| parent | 8238f850369b82843e6d2cef050a412d9218436c (diff) | |
Merge branch 'master' of https://github.com/RT-Thread/rt-thread
Diffstat (limited to 'libcpu')
| -rw-r--r-- | libcpu/arm/cortex-r4/RM48x50.h | 39 | ||||
| -rw-r--r-- | libcpu/arm/cortex-r4/context_ccs.asm | 254 | ||||
| -rw-r--r-- | libcpu/arm/cortex-r4/cpu.c | 42 | ||||
| -rw-r--r-- | libcpu/arm/cortex-r4/interrupt.c | 106 | ||||
| -rw-r--r-- | libcpu/arm/cortex-r4/stack.c | 85 | ||||
| -rw-r--r-- | libcpu/arm/cortex-r4/trap.c | 150 |
6 files changed, 676 insertions, 0 deletions
diff --git a/libcpu/arm/cortex-r4/RM48x50.h b/libcpu/arm/cortex-r4/RM48x50.h new file mode 100644 index 0000000000..9f4bcc976f --- /dev/null +++ b/libcpu/arm/cortex-r4/RM48x50.h @@ -0,0 +1,39 @@ +#ifndef RM48X50_H +#define RM48X50_H + +#include <system.h> +#include <sys_vim.h> + +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define ABORTMODE 0x17 +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +struct rt_hw_register +{ + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long fp; + unsigned long ip; + unsigned long sp; + unsigned long lr; + unsigned long pc; + unsigned long cpsr; + unsigned long ORIG_r0; +}; + +#endif /* end of include guard: RM48X50_H */ + diff --git a/libcpu/arm/cortex-r4/context_ccs.asm b/libcpu/arm/cortex-r4/context_ccs.asm new file mode 100644 index 0000000000..dc4113f5e4 --- /dev/null +++ b/libcpu/arm/cortex-r4/context_ccs.asm @@ -0,0 +1,254 @@ +;/* +; * File : context_ccs.asm +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, RT-Thread Development Team +; * +; * The license and distribution terms for this file may be +; * found in the file LICENSE in this distribution or at +; * http://www.rt-thread.org/license/LICENSE +; * +; * Change Logs: +; * Date Author Notes +; * 2009-01-20 Bernard first version +; * 2011-07-22 Bernard added thumb mode porting +; * 2013-05-24 Grissiom port to CCS +; * 2013-05-26 Grissiom optimize for ARMv7 +; */ + + .text + .arm + .ref rt_thread_switch_interrupt_flag + .ref rt_interrupt_from_thread + .ref rt_interrupt_to_thread + .ref rt_interrupt_enter + .ref rt_interrupt_leave + .ref rt_hw_trap_irq + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ + .def rt_hw_interrupt_disable +rt_hw_interrupt_disable + MRS r0, cpsr + CPSID IF + BX lr + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ + .def rt_hw_interrupt_enable +rt_hw_interrupt_enable + MSR cpsr_c, r0 + BX lr + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ + .def rt_hw_context_switch +rt_hw_context_switch + STMDB sp!, {lr} ; push pc (lr should be pushed in place of PC) + STMDB sp!, {r0-r12, lr} ; push lr & register file + + MRS r4, cpsr + TST lr, #0x01 + ORRNE r4, r4, #0x20 ; it's thumb code + + STMDB sp!, {r4} ; push cpsr + + .if (__TI_VFP_SUPPORT__) + VMRS r4, fpexc + TST r4, #0x40000000 + BEQ __no_vfp_frame1 + VSTMDB sp!, {d0-d15} + VMRS r5, fpscr + ; TODO: add support for Common VFPv3. + ; Save registers like FPINST, FPINST2 + STMDB sp!, {r5} +__no_vfp_frame1 + STMDB sp!, {r4} + .endif + + STR sp, [r0] ; store sp in preempted tasks TCB + LDR sp, [r1] ; get new task stack pointer + + .if (__TI_VFP_SUPPORT__) + LDMIA sp!, {r0} ; get fpexc + VMSR fpexc, r0 ; restore fpexc + TST r0, #0x40000000 + BEQ __no_vfp_frame2 + LDMIA sp!, {r1} ; get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame2 + .endif + + LDMIA sp!, {r4} ; pop new task cpsr to spsr + MSR spsr_cxsf, r4 + + LDMIA sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ + .def rt_hw_context_switch_to +rt_hw_context_switch_to + LDR sp, [r0] ; get new task stack pointer + + .if (__TI_VFP_SUPPORT__) + LDMIA sp!, {r0} ; get fpexc + VMSR fpexc, r0 + TST r0, #0x40000000 + BEQ __no_vfp_frame_to + LDMIA sp!, {r1} ; get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame_to + .endif + + LDMIA sp!, {r4} ; pop new task cpsr to spsr + MSR spsr_cxsf, r4 + + LDMIA sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr + +;/* +; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); +; */ + + .def rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt + LDR r2, pintflag + LDR r3, [r2] + CMP r3, #1 + BEQ _reswitch + MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 1 + STR r3, [r2] + LDR r2, pfromthread ; set rt_interrupt_from_thread + STR r0, [r2] +_reswitch + LDR r2, ptothread ; set rt_interrupt_to_thread + STR r1, [r2] + BX lr + + .def IRQ_Handler +IRQ_Handler + STMDB sp!, {r0-r12,lr} + + .if (__TI_VFP_SUPPORT__) + VMRS r0, fpexc + TST r0, #0x40000000 + BEQ __no_vfp_frame_str_irq + VSTMDB sp!, {d0-d15} + VMRS r1, fpscr + ; TODO: add support for Common VFPv3. + ; Save registers like FPINST, FPINST2 + STMDB sp!, {r1} +__no_vfp_frame_str_irq + STMDB sp!, {r0} + .endif + + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + ; if rt_thread_switch_interrupt_flag set, jump to + ; rt_hw_context_switch_interrupt_do and don't return + LDR r0, pintflag + LDR r1, [r0] + CMP r1, #1 + BEQ rt_hw_context_switch_interrupt_do + + .if (__TI_VFP_SUPPORT__) + LDMIA sp!, {r0} ; get fpexc + VMSR fpexc, r0 + TST r0, #0x40000000 + BEQ __no_vfp_frame_ldr_irq + LDMIA sp!, {r1} ; get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame_ldr_irq + .endif + + LDMIA sp!, {r0-r12,lr} + SUBS pc, lr, #4 + +; /* +; * void rt_hw_context_switch_interrupt_do(rt_base_t flag) +; */ + .def rt_hw_context_switch_interrupt_do +rt_hw_context_switch_interrupt_do + MOV r1, #0 ; clear flag + STR r1, [r0] + + .if (__TI_VFP_SUPPORT__) + LDMIA sp!, {r0} ; get fpexc + VMSR fpexc, r0 + TST r0, #0x40000000 + BEQ __no_vfp_frame_do1 + LDMIA sp!, {r1} ; get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame_do1 + .endif + + LDMIA sp!, {r0-r12,lr} ; reload saved registers + STMDB sp, {r0-r3} ; save r0-r3. We will restore r0-r3 in the SVC + ; mode so there is no need to update SP. + SUB r1, sp, #16 ; save the right SP value in r1, so we could restore r0-r3. + SUB r2, lr, #4 ; save old task's pc to r2 + + MRS r3, spsr ; get cpsr of interrupt thread + + ; switch to SVC mode and no interrupt + CPSID IF, #0x13 + + STMDB sp!, {r2} ; push old task's pc + STMDB sp!, {r4-r12,lr} ; push old task's lr,r12-r4 + LDMIA r1!, {r4-r7} ; restore r0-r3 of the interrupted thread + STMDB sp!, {r4-r7} ; push old task's r3-r0. We don't need to push/pop them to + ; r0-r3 because we just want to transfer the data and don't + ; use them here. + STMDB sp!, {r3} ; push old task's cpsr + + .if (__TI_VFP_SUPPORT__) + VMRS r0, fpexc + TST r0, #0x40000000 + BEQ __no_vfp_frame_do2 + VSTMDB sp!, {d0-d15} + VMRS r1, fpscr + ; TODO: add support for Common VFPv3. + ; Save registers like FPINST, FPINST2 + STMDB sp!, {r1} +__no_vfp_frame_do2 + STMDB sp!, {r0} + .endif + + LDR r4, pfromthread + LDR r5, [r4] + STR sp, [r5] ; store sp in preempted tasks's TCB + + LDR r6, ptothread + LDR r6, [r6] + LDR sp, [r6] ; get new task's stack pointer + + .if (__TI_VFP_SUPPORT__) + LDMIA sp!, {r0} ; get fpexc + VMSR fpexc, r0 + TST r0, #0x40000000 + BEQ __no_vfp_frame_do3 + LDMIA sp!, {r1} ; get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame_do3 + .endif + + LDMIA sp!, {r4} ; pop new task's cpsr to spsr + MSR spsr_cxsf, r4 + + LDMIA sp!, {r0-r12,lr,pc}^ ; pop new task's r0-r12,lr & pc, copy spsr to cpsr + +pintflag .word rt_thread_switch_interrupt_flag +pfromthread .word rt_interrupt_from_thread +ptothread .word rt_interrupt_to_thread diff --git a/libcpu/arm/cortex-r4/cpu.c b/libcpu/arm/cortex-r4/cpu.c new file mode 100644 index 0000000000..569f7d0c29 --- /dev/null +++ b/libcpu/arm/cortex-r4/cpu.c @@ -0,0 +1,42 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + * 2013-05-24 Grissiom port to RM48x50 + */ + +#include <rtthread.h> + +/** + * @addtogroup RM48x50 + */ +/*@{*/ + +/** + * this function will reset CPU + * + */ +void rt_hw_cpu_reset() +{ +} + +/** + * this function will shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_kprintf("shutdown...\n"); + + while (1); +} + +/*@}*/ diff --git a/libcpu/arm/cortex-r4/interrupt.c b/libcpu/arm/cortex-r4/interrupt.c new file mode 100644 index 0000000000..8d0a977db9 --- /dev/null +++ b/libcpu/arm/cortex-r4/interrupt.c @@ -0,0 +1,106 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + * 2013-03-29 aozima Modify the interrupt interface implementations. + */ + +#include <rtthread.h> +#include <rthw.h> +#include "RM48x50.h" + +#define MAX_HANDLERS 96 + +/* exception and interrupt handler table */ +struct rt_irq_desc irq_desc[MAX_HANDLERS]; + +extern rt_uint32_t rt_interrupt_nest; + +/* exception and interrupt handler table */ +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +/** + * @addtogroup RM48x50 + */ + +/*@{*/ + +static void rt_hw_int_not_handle(int vector, void *param) +{ + rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); +} + +#define vimRAM (0xFFF82000U) + +void rt_hw_interrupt_init(void) +{ + register int i; + + rt_uint32_t *vect_addr; + + /* the initialization is done in sys_startup.c */ + + /* init exceptions table */ + rt_memset(irq_desc, 0x00, sizeof(irq_desc)); + for(i=0; i < MAX_HANDLERS; i++) + { + irq_desc[i].handler = rt_hw_int_not_handle; + + vect_addr = (rt_uint32_t *)(vimRAM + i*4); + *vect_addr = (rt_uint32_t)&irq_desc[i]; + } + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +void rt_hw_interrupt_mask(int vector) +{ + vimDisableInterrupt(vector); +} + +void rt_hw_interrupt_umask(int vector) +{ + vimEnableInterrupt(vector, SYS_IRQ); +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param handler the interrupt service routine to be installed + * @param param the parameter for interrupt service routine + * @name unused. + * + * @return the old handler + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if(vector >= 0 && vector < MAX_HANDLERS) + { + old_handler = irq_desc[vector].handler; + if (handler != RT_NULL) + { + irq_desc[vector].handler = handler; + irq_desc[vector].param = param; + } + } + + return old_handler; +} + +/*@}*/ diff --git a/libcpu/arm/cortex-r4/stack.c b/libcpu/arm/cortex-r4/stack.c new file mode 100644 index 0000000000..02dc84e6f1 --- /dev/null +++ b/libcpu/arm/cortex-r4/stack.c @@ -0,0 +1,85 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + * 2013-05-24 Grissiom port to RM48x50 + */ +#include <rtthread.h> +#include "RM48x50.h" +/** + * @addtogroup RM48x50 + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + unsigned long *stk; + + stk = (unsigned long*)stack_addr; + *( stk) = (unsigned long) tentry; /* entry point */ + *(--stk) = (unsigned long) texit; /* lr */ + *(--stk) = 0; /* r12 */ + *(--stk) = 0; /* r11 */ + *(--stk) = 0; /* r10 */ + *(--stk) = 0; /* r9 */ + *(--stk) = 0; /* r8 */ + *(--stk) = 0; /* r7 */ + *(--stk) = 0; /* r6 */ + *(--stk) = 0; /* r5 */ + *(--stk) = 0; /* r4 */ + *(--stk) = 0; /* r3 */ + *(--stk) = 0; /* r2 */ + *(--stk) = 0; /* r1 */ + *(--stk) = (unsigned long)parameter; /* r0 : argument */ + + /* cpsr */ + if ((rt_uint32_t)tentry & 0x01) + *(--stk) = SVCMODE | 0x20; /* thumb mode */ + else + *(--stk) = SVCMODE; /* arm mode */ + +#ifdef __TI_VFP_SUPPORT__ +#ifndef RT_VFP_LAZY_STACKING + { + #define VFP_DATA_NR 32 + int i; + + for (i = 0; i < VFP_DATA_NR; i++) + { + *(--stk) = 0; + } + /* FPSCR TODO: do we need to set the values other than 0? */ + *(--stk) = 0; + /* FPEXC. Enable the FVP if no lazy stacking. */ + *(--stk) = 0x40000000; + } +#else + /* FPEXC. Disable the FVP by default. */ + *(--stk) = 0x00000000; +#endif +#endif + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/libcpu/arm/cortex-r4/trap.c b/libcpu/arm/cortex-r4/trap.c new file mode 100644 index 0000000000..d77f9734da --- /dev/null +++ b/libcpu/arm/cortex-r4/trap.c @@ -0,0 +1,150 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + * 2013-05-24 Grissiom port to RM48x50 + */ + +#include <rtthread.h> +#include <rthw.h> +#include "RM48x50.h" +//#define BSP_INT_DEBUG + +/** + * @addtogroup RM48x50 + */ +/*@{*/ + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ +void rt_hw_show_register (struct rt_hw_register *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3); + rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7); + rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10); + rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip); + rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc); + rt_kprintf("cpsr:0x%08x\n", regs->cpsr); +} + +/** + * When ARM7TDMI comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_udef(struct rt_hw_register *regs) +{ + rt_kprintf("undefined instruction\n"); + rt_hw_show_register(regs); + if (rt_thread_self() != RT_NULL) + rt_kprintf("Current Thread: %s\n", rt_thread_self()->name); + rt_hw_cpu_shutdown(); +} + +/** + * The software interrupt instruction (SWI) is used for entering + * Supervisor mode, usually to request a particular supervisor + * function. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_swi(struct rt_hw_register *regs) +{ + rt_kprintf("software interrupt\n"); + rt_hw_show_register(regs); + if (rt_thread_self() != RT_NULL) + rt_kprintf("Current Thread: %s\n", rt_thread_self()->name); + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during an instruction prefetch. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_pabt(struct rt_hw_register *regs) +{ + rt_kprintf("prefetch abort\n"); + rt_hw_show_register(regs); + if (rt_thread_self() != RT_NULL) + rt_kprintf("Current Thread: %s\n", rt_thread_self()->name); + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during a data access. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_dabt(struct rt_hw_register *regs) +{ + rt_kprintf("Data Abort "); + rt_hw_show_register(regs); + if (rt_thread_self() != RT_NULL) + rt_kprintf("Current Thread: %s\n", rt_thread_self()->name); + rt_hw_cpu_shutdown(); +} + +/** + * Normally, system will never reach here + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_resv(struct rt_hw_register *regs) +{ + rt_kprintf("not used\n"); + rt_hw_show_register(regs); + if (rt_thread_self() != RT_NULL) + rt_kprintf("Current Thread: %s\n", rt_thread_self()->name); + rt_hw_cpu_shutdown(); +} + +/* + *#pragma CODE_STATE(rt_hw_trap_irq, 32) + *#pragma INTERRUPT(rt_hw_trap_irq, IRQ) + */ +extern rt_isr_handler_t isr_table[]; +void rt_hw_trap_irq(void) +{ + int irqno; + struct rt_irq_desc* irq; + extern struct rt_irq_desc irq_desc[]; + + irq = (struct rt_irq_desc*) vimREG->IRQVECREG; + irqno = ((rt_uint32_t) irq - (rt_uint32_t) &irq_desc[0])/sizeof(struct rt_irq_desc); + + /* invoke isr */ + irq->handler(irqno, irq->param); +} + +void rt_hw_trap_fiq(void) +{ + rt_kprintf("fast interrupt request\n"); +} + +/*@}*/ |
