diff options
Diffstat (limited to 'cpukit/score/cpu/avr/cpu_asm.S')
-rw-r--r-- | cpukit/score/cpu/avr/cpu_asm.S | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/cpukit/score/cpu/avr/cpu_asm.S b/cpukit/score/cpu/avr/cpu_asm.S new file mode 100644 index 0000000000..6ad0f6a729 --- /dev/null +++ b/cpukit/score/cpu/avr/cpu_asm.S @@ -0,0 +1,461 @@ +/* cpu_asm.c ===> cpu_asm.S or cpu_asm.s + * + * This file contains the basic algorithms for all assembly code used + * in an specific CPU port of RTEMS. These algorithms must be implemented + * in assembly language + * + * NOTE: This is supposed to be a .S or .s file NOT a C file. + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +/* + * This is supposed to be an assembly file. This means that system.h + * and cpu.h should not be included in a "real" cpu_asm file. An + * implementation in assembly should include "cpu_asm.h> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/asm.h> +#include <avr/sfr_defs.h> +#include <rtems/score/percpu.h> + + +#define jmpb_hi r25 +#define jmpb_lo r24 +#define val_hi r23 +#define val_lo r22 + +#define ret_lo r24 +#define ret_hi r25 + + PUBLIC( setjmp ) + +SYM( setjmp ): + X_movw XL, jmpb_lo +/*;save call-saved registers and frame pointer*/ + .irp .L_regno, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,28,29 + st X+, r\.L_regno + .endr +/*;get return address*/ + + pop ZH + pop ZL +/*save stack pointer (after popping)*/ + + in ret_lo, AVR_STACK_POINTER_LO_ADDR + st X+, ret_lo + +#ifdef _HAVE_AVR_STACK_POINTER_HI + in ret_lo, AVR_STACK_POINTER_HI_ADDR + st X+, ret_lo +#else + st X+, ret_lo +#endif +/*save status reg (I flag)*/ + in ret_lo, AVR_STATUS_ADDR + st X+, ret_lo +/*save return addr*/ + st X+, ZL + st X+, ZH +/*return zero*/ + clr ret_hi + clr ret_lo + ijmp + + .size _U(setjmp),.-_U(setjmp) + + + .global _U(longjmp) + .type _U(longjmp), @function + +_U(longjmp): + X_movw XL, jmpb_lo +/*return value*/ + X_movw ret_lo, val_lo +/*if zero, change to 1*/ + cpi ret_lo, 1 + cpc ret_hi, __zero_reg__ + adc ret_lo, __zero_reg__ +/*restore call-saved registers and frame pointer*/ + .irp .L_regno, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,28,29 + ld r\.L_regno, X+ + .endr +/*; restore stack pointer (SP value before the setjmp() call) and SREG*/ + ld ZL, X+ + ld ZH, X+ + ld __tmp_reg__, X+ +#if defined (__AVR_XMEGA__) && __AVR_XMEGA__ + /* A write to SPL will automatically disable interrupts for up to 4 + instructions or until the next I/O memory write. */ + out AVR_STATUS_ADDR, __tmp_reg__ + out AVR_STACK_POINTER_LO_ADDR, ZL + out AVR_STACK_POINTER_HI_ADDR, ZH +#else +# ifdef _HAVE_AVR_STACK_POINTER_HI + /* interrupts disabled for shortest possible time (3 cycles) */ + cli + out AVR_STACK_POINTER_HI_ADDR, ZH +# endif + /* Restore status register (including the interrupt enable flag). + Interrupts are re-enabled only after the next instruction. */ + out AVR_STATUS_ADDR, __tmp_reg__ + out AVR_STACK_POINTER_LO_ADDR, ZL +#endif + ; get return address and jump + ld ZL, X+ + ld ZH, X+ +#if defined(__AVR_3_BYTE_PC__) && __AVR_3_BYTE_PC__ + ld __tmp_reg__, X+ +.L_jmp3: + push ZL + push ZH + push __tmp_reg__ + ret +#else + ijmp +#endif + .size _U(longjmp), . - _U(longjmp) + + + +/* + * _CPU_Context_save_fp_context + * + * This routine is responsible for saving the FP context + * at *fp_context_ptr. If the point to load the FP context + * from is changed then the pointer is modified by this routine. + * + * Sometimes a macro implementation of this is in cpu.h which dereferences + * the ** and a similarly named routine in this file is passed something + * like a (Context_Control_fp *). The general rule on making this decision + * is to avoid writing assembly language. + * + * NO_CPU Specific Information: + * + * XXX document implementation including references if appropriate + + +void _CPU_Context_save_fp( + Context_Control_fp **fp_context_ptr +) +{ +} +*/ + + PUBLIC(_CPU_Context_save_fp) + +SYM(_CPU_Context_save_fp): + ret + + + + + + + +/* + * _CPU_Context_restore_fp_context + * + * This routine is responsible for restoring the FP context + * at *fp_context_ptr. If the point to load the FP context + * from is changed then the pointer is modified by this routine. + * + * Sometimes a macro implementation of this is in cpu.h which dereferences + * the ** and a similarly named routine in this file is passed something + * like a (Context_Control_fp *). The general rule on making this decision + * is to avoid writing assembly language. + * + * NO_CPU Specific Information: + * + * XXX document implementation including references if appropriate + + +void _CPU_Context_restore_fp( + Context_Control_fp **fp_context_ptr +) +{ +} +*/ + + + PUBLIC(_CPU_Context_restore_fp) + +SYM(_CPU_Context_restore_fp): + ret + + + +/* _CPU_Context_switch + * + * This routine performs a normal non-FP context switch. + * + * NO_CPU Specific Information: + * + * XXX document implementation including references if appropriate + void _CPU_Context_switch( + Context_Control *run, + Context_Control *heir +); + +*/ + + PUBLIC(_CPU_Context_switch) +SYM(_CPU_Context_switch): + mov r26, r24 /*r26,r27 is X*/ + mov r27, r25 + mov r24, r22 + mov r25, r23 + /*save registers*/ +#if 1 +/*if this section is removed there is a problem.*/ +/*debug section start*/ + pop r22 + pop r23 + push r22 + push r23 +/*debug section end*/ +#endif + + push r2 + push r3 + push r4 + push r5 + push r6 + push r7 + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + push r16 + push r17 + + push r28 + push r29 + + /*load sreg*/ + lds r23,0x5f /*load sreg*/ + /*disable interrupts*/ + cli + /*load stack pointer*/ + lds r22,0x5d /*spl*/ + lds r21,0x5e /*sph*/ + /*save sreg and sp to context struct*/ + + /*save low then high byte --- verify this delete when verified*/ + st X+, r22 + st X+, r21 + st X, r23 + + PUBLIC(_CPU_Context_restore) + +SYM(_CPU_Context_restore): + mov r26,r24 /* R26/27 are X */ + mov r27,r25 + + /*restore stack pointer*/ + ld r25, X+ + ld r24, X+ + sts 0x5E,r24 /*sph*/ + sts 0x5D ,r25 /*spl*/ + /*restore registers from stack*/ + + + pop r29 + pop r28 + + + pop r17 + pop r16 + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop r7 + pop r6 + pop r5 + pop r4 + pop r3 + pop r2 + + /*restore sreg*/ + ld r25, X + sts 0x5f,r25 /*sreg*/ + pop r30 + pop r31 + IJMP + ret + + + +/*PAGE + * + * _CPU_Context_Initialize + * + * This kernel routine initializes the basic non-FP context area associated + * with each thread. + * + * Input parameters: + * the_context - pointer to the context area + * stack_base - address of memory for the SPARC + * size - size in bytes of the stack area + * new_level - interrupt level for this context area + * entry_point - the starting execution point for this this context + * is_fp - TRUE if this context is associated with an FP thread + * + * the_context is in r25,r24 + * entry point is in r13,r12 + * stack base is in r23, r22 + * size is in r21, r20, r19,r18 + * newleve is in r14,r15, r16, 17 + * + * + * Output parameters: NONE + */ + + PUBLIC(_CPU_Context_Initialize) +SYM(_CPU_Context_Initialize): + //save caller saved regs + PUSH R10 + PUSH R11 + PUSH R12 + PUSH R13 + PUSH R14 + PUSH R15 + PUSH R16 + PUSH R17 + PUSH R28 + PUSH R29 + //calculate new stack pointer + ADD R22, R18 + ADC R23, R19 + MOV R26, R22 + MOV R27, R23 + //Initialize stack with entry point + ST -X, R13 + ST -X, R12 + //store new stack pointer in context control + SBIW R26, 0X13 /*subtract 33 to account for registers*/ + MOV R28, R24 + MOV R29, R25 + STD Y+1, R27 //save stack pointer high to context control + ST Y, R26 //save stack pointer low to context control + //set interrupt level in new context + LDI R18, 0 //set sreg in new context to zero + STD Y+2, R18 //interrupts not enabled + MOV R18, R14 + CPI R18, 0 + BRNE NEW_LEVEL_ZERO + LDI R18, 0X80 //set sreg in new context to 0x80 + STD Y+2, R18 //interupts enabled +NEW_LEVEL_ZERO: + //restore caller saved regs + POP R29 + POP R28 + POP R17 + POP R16 + POP R15 + POP R14 + POP R13 + POP R12 + POP R11 + POP R10 + RET + + + +/* void __ISR_Handler() + * + * This routine provides the RTEMS interrupt management. + * + * NO_CPU Specific Information: + * + * XXX document implementation including references if appropriate + + +void _ISR_Handler(void) +{ + +*/ + /* + * This discussion ignores a lot of the ugly details in a real + * implementation such as saving enough registers/state to be + * able to do something real. Keep in mind that the goal is + * to invoke a user's ISR handler which is written in C and + * uses a certain set of registers. + * + * Also note that the exact order is to a large extent flexible. + * Hardware will dictate a sequence for a certain subset of + * _ISR_Handler while requirements for setting + */ + + /* + * At entry to "common" _ISR_Handler, the vector number must be + * available. On some CPUs the hardware puts either the vector + * number or the offset into the vector table for this ISR in a + * known place. If the hardware does not give us this information, + * then the assembly portion of RTEMS for this port will contain + * a set of distinct interrupt entry points which somehow place + * the vector number in a known place (which is safe if another + * interrupt nests this one) and branches to _ISR_Handler. + * + * save some or all context on stack + * may need to save some special interrupt information for exit + * + * #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE ) + * if ( _ISR_Nest_level == 0 ) + * switch to software interrupt stack + * #endif + * + * _ISR_Nest_level++; + * + * _Thread_Dispatch_disable_level++; + * + * (*_ISR_Vector_table[ vector ])( vector ); + * + * _Thread_Dispatch_disable_level--; + * + * --_ISR_Nest_level; + * + * if ( _ISR_Nest_level ) + * goto the label "exit interrupt (simple case)" + * + * if ( _Thread_Dispatch_disable_level ) + * goto the label "exit interrupt (simple case)" + * + * if ( _Thread_Dispatch_necessary ) { + * call _Thread_Dispatch() or prepare to return to _ISR_Dispatch + * prepare to get out of interrupt + * return from interrupt (maybe to _ISR_Dispatch) + * + * LABEL "exit interrupt (simple case): + * #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE ) + * if outermost interrupt + * restore stack + * #endif + * prepare to get out of interrupt + * return from interrupt + */ +/*} */ + PUBLIC(_ISR_Handler) + +SYM(_ISR_Handler): + ret |