diff options
author | Joel Sherrill <joel.sherrill@OARcorp.com> | 2006-10-23 17:17:50 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@OARcorp.com> | 2006-10-23 17:17:50 +0000 |
commit | d9a6ab3fed9e77a6343ee56571e4d9d767c8e979 (patch) | |
tree | 5cbb0283798520905ed50d799d1f19de959e7a55 /cpukit/score/cpu/bfin/cpu_asm.S | |
parent | 2006-10-22 Ralf Corsépius <ralf.corsepius@rtems.org> (diff) | |
download | rtems-d9a6ab3fed9e77a6343ee56571e4d9d767c8e979.tar.bz2 |
2006-10-23 Joel Sherrill <joel@OARcorp.com>
* .cvsignore, ChangeLog, Makefile.am, cpu.c, cpu_asm.S, irq.c,
preinstall.am, rtems/asm.h, rtems/score/bfin.h, rtems/score/cpu.h,
rtems/score/cpu_asm.h, rtems/score/types.h: New files.
Diffstat (limited to 'cpukit/score/cpu/bfin/cpu_asm.S')
-rw-r--r-- | cpukit/score/cpu/bfin/cpu_asm.S | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/cpukit/score/cpu/bfin/cpu_asm.S b/cpukit/score/cpu/bfin/cpu_asm.S new file mode 100644 index 0000000000..8f2dd63af1 --- /dev/null +++ b/cpukit/score/cpu/bfin/cpu_asm.S @@ -0,0 +1,406 @@ +/* cpu_asm.S + * + * This file contains the basic algorithms for all assembly code used + * in the Blackfin port of RTEMS. These algorithms must be implemented + * in assembly language + * + * Copyright (c) 2006 by Atos Automacao Industrial Ltda. + * written by Alain Schaefer <alain.schaefer@easc.ch> + * and Antonio Giovanini <antonio@atos.com.br> + * + * 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$ + */ + + +#include <rtems/asm.h> +#include <rtems/score/cpu_asm.h> +#include <rtems/score/bfin.h> + + +/* _CPU_Context_switch + * + * This routine performs a normal non-FP context switch. + * + * bfin Specific Information: + * + * For now we simply save all registers. + * + */ + +.globl __CPU_Context_switch +__CPU_Context_switch: + /* Start saving context R0 = current, R1=heir */ + /*save P0 first*/ + [FP+0x8] = P0; + P0 = R0; + [ P0 + R0_OFFSET ] = R0; + [ P0 + R1_OFFSET] = R1; + [ P0 + R2_OFFSET] = R2; + [ P0 + R4_OFFSET] = R4; + [ P0 + R3_OFFSET] = R3; + [ P0 + R5_OFFSET] = R5; + [ P0 + R6_OFFSET] = R6; + [ P0 + R7_OFFSET] = R7; + [ P0 + P1_OFFSET] = P1; + /* save the original value of P0 */ + P1 = [FP+0x8]; + [ P0 + P0_OFFSET] = P1; + [ P0 + P2_OFFSET] = P2; + [ P0 + P3_OFFSET] = P3; + [ P0 + P4_OFFSET] = P4; + [ P0 + P5_OFFSET] = P5; + [ P0 + FP_OFFSET] = FP; + [ P0 + SP_OFFSET] = SP; + + /* save ASTAT */ + R0 = ASTAT; + [P0 + ASTAT_OFFSET] = R0; + + /* save Loop Counters */ + R0 = LC0; + [P0 + LC0_OFFSET] = R0; + R0 = LC1; + [P0 + LC1_OFFSET] = R0; + + /* save Accumulators */ + R0 = A0.W; + [P0 + A0W_OFFSET] = R0; + R0 = A0.X; + [P0 + A0X_OFFSET] = R0; + R0 = A1.W; + [P0 + A1W_OFFSET] = R0; + R0 = A1.X; + [P0 + A1X_OFFSET] = R0; + + /* save Index Registers */ + R0 = I0; + [P0 + I0_OFFSET] = R0; + R0 = I1; + [P0 + I1_OFFSET] = R0; + R0 = I2; + [P0 + I2_OFFSET] = R0; + R0 = I3; + [P0 + I3_OFFSET] = R0; + + /* save Modifier Registers */ + R0 = M0; + [P0 + M0_OFFSET] = R0; + R0 = M1; + [P0 + M1_OFFSET] = R0; + R0 = M2; + [P0 + M2_OFFSET] = R0; + R0 = M3; + [P0 + M3_OFFSET] = R0; + + /* save Length Registers */ + R0 = L0; + [P0 + L0_OFFSET] = R0; + R0 = L1; + [P0 + L1_OFFSET] = R0; + R0 = L2; + [P0 + L2_OFFSET] = R0; + R0 = L3; + [P0 + L3_OFFSET] = R0; + + /* Base Registers */ + R0 = B0; + [P0 + B0_OFFSET] = R0; + R0 = B1; + [P0 + B1_OFFSET] = R0; + R0 = B2; + [P0 + B2_OFFSET] = R0; + R0 = B3; + [P0 + B3_OFFSET] = R0; + + /* save RETS */ + R0 = RETS; + [ P0 + RETS_OFFSET] = R0; + +restore: + P0 = R1; + R1 = [P0 + R1_OFFSET]; + R2 = [P0 + R2_OFFSET]; + R3 = [P0 + R3_OFFSET]; + R4 = [P0 + R4_OFFSET]; + R5 = [P0 + R5_OFFSET]; + R6 = [P0 + R6_OFFSET]; + R7 = [P0 + R7_OFFSET]; + + P2 = [P0 + P2_OFFSET]; + P3 = [P0 + P3_OFFSET]; + P4 = [P0 + P4_OFFSET]; + P5 = [P0 + P5_OFFSET]; + + /* might have to be placed more to the end */ + FP = [P0 + FP_OFFSET]; + SP = [P0 + SP_OFFSET]; + + /* save ASTAT */ + R0 = [P0 + ASTAT_OFFSET]; + ASTAT = R0; + + /* save Loop Counters */ + R0 = [P0 + LC0_OFFSET]; + LC0 = R0; + R0 = [P0 + LC1_OFFSET]; + LC1 = R0; + + /* save Accumulators */ + R0 = [P0 + A0W_OFFSET]; + A0.W = R0; + R0 = [P0 + A0X_OFFSET]; + A0.X = R0; + R0 = [P0 + A1W_OFFSET]; + A1.W = R0; + R0 = [P0 + A1X_OFFSET]; + A1.X = R0; + + /* save Index Registers */ + R0 = [P0 + I0_OFFSET]; + I0 = R0; + R0 = [P0 + I1_OFFSET]; + I1 = R0; + R0 = [P0 + I2_OFFSET]; + I2 = R0; + R0 = [P0 + I3_OFFSET]; + I3 = R0; + + /* save Modifier Registers */ + R0 = [P0 + M0_OFFSET]; + M0 = R0; + R0 = [P0 + M1_OFFSET]; + M1 = R0; + R0 = [P0 + M2_OFFSET]; + M2 = R0; + R0 = [P0 + M3_OFFSET]; + M3 = R0; + + /* save Length Registers */ + R0 = [P0 + L0_OFFSET]; + L0 = R0; + R0 = [P0 + L1_OFFSET]; + L1 = R0; + R0 = [P0 + L2_OFFSET]; + L2 = R0; + R0 = [P0 + L3_OFFSET]; + L3 = R0; + + /* Base Registers */ + R0 = [P0 + B0_OFFSET]; + B0 = R0; + R0 = [P0 + B1_OFFSET]; + B1 = R0; + R0 = [P0 + B2_OFFSET]; + B2 = R0; + R0 = [P0 + B3_OFFSET]; + B3 = R0; + + /* restore RETS */ + P1 = [P0 + RETS_OFFSET]; + RETS = P1; + + /* now restore the P1 + P0 */ + P1 = [P0 + R1_OFFSET]; + P0 = [P0 + P0_OFFSET]; + + rts; + + +/* + * _CPU_Context_restore + * + * This routine is generally used only to restart self in an + * efficient manner. It may simply be a label in _CPU_Context_switch. + * + * NOTE: May be unnecessary to reload some registers. + * + * Blackfin Specific Information: + * + * none + * + */ +.globl __CPU_Context_restore +__CPU_Context_restore: + jump restore; + + + +.globl __ISR_Thread_Dispatch +__ISR_Thread_Dispatch: + + .extern __Thread_Dispatch + R0.l = __Thread_Dispatch; + R0.h = __Thread_Dispatch; + + /* Puts the address of th Thread_Dispatch function on Stack + * Where it will be restored to the RTI register + */ + P0 = [FP]; + /* save the old reti */ + R1 = [P0+0xc]; + [P0+0xc] = R0; + /* + * Overwriting the RETS Register is save because Thread_Dispatch is + * disabled when we are between call/link or unlink/rts + */ + [P0+0x8] = R1; + + /* save old rets */ + + rts; + + +.globl __ISR_Handler +__ISR_Handler: + /* First of all check the Stackpointer and */ + /* switch to Scratchpad if necessary */ + + /* save P0 and R0 in the scratchpad */ + USP = P0; + + /* load base adress of scratchpad */ + P0.H = HI(SCRATCH); + P0.L = LO(SCRATCH); + + /* if SP is already inside the SCRATCHPAD */ + CC=SP<P0 (iu) + if !CC jump continue; + + /* set PO to top of scratchpad */ + P0.h=HI(SCRATCH_TOP); + P0.l=LO(SCRATCH_TOP); + /*save the old SP*/ + [P0] = SP; + /*P0 += -4;*/ + /*set the new Stackpointer*/ + SP = P0; + /*restore the old PO*/ + + /* The Stackpointer is now setup as we want */ + continue: + /* restore P0 and save some context */ + P0 = USP; + /* save some state on the isr stack (scratchpad), this enables interrupt nesting */ + [--SP] = RETI; + [--SP] = RETS; + [--SP] = ASTAT; + [--SP] = FP; + FP = SP; + [--SP] = (R7:0, P5:0) ; + + + /* Context is saved, now check which Instruction we were executing + * If we were between a call and link or between a unlink and rts + * we have to disable Thread_Dispatch because correct restore of context after + * Thread_Dispatch would not be possible. */ + + P0 = RETI; + R0 = W[P0]; + /* shift 16 bits to the right (select the high nibble ) */ + /*R0 >>= 16;*/ + + R3 = 0; + /* Check if RETI is a LINK instruction */ + R1.h = HI(0xE800); + R1.l = LO(0xE800); + CC=R0==R1; + if cc jump disablethreaddispatch; + + /* Check if RETI is a RTS instruction */ + R1.h = HI(0x0010); + R1.l = LO(0x0010); + CC=R0==R1; + if cc jump disablethreaddispatch; + + jump afterthreaddispatch; + + disablethreaddispatch: + /* _Thread_Dispatch_disable_level++ */ + .extern _Thread_Dispatch_disable_level + P0.H = __Thread_Dispatch_disable_level; + P0.L = __Thread_Dispatch_disable_level; + R0 = [P0]; + R0 += 1; + [P0] = R0; + R3 = 1; + + afterthreaddispatch: + /* Put R3 on the stack */ + [--SP] = R3; + + /* Obtain a bitlist of the pending interrupts. */ + P0.H = HI(IPEND); + P0.L = LO(IPEND); + R1 = [P0]; + + /* + * Search through the bit list stored in R0 to find the first enabled + * bit. The offset of this bit is the index of the interrupt that is + * to be handled. + */ + R0 = -1; + intloop: + R0 += 1; + R1 = ROT R1 by -1; + if !cc jump intloop; + + + /* pass SP as parameter to the C function */ + R1 = SP + + /* pass values by register as well as by stack */ + /* to comply with the c calling conventions */ + [--SP] = R0; + [--SP] = R1; + + .extern _ISR_Handler2 + call _ISR_Handler2 + + /* inc 2 to compensate the passing of arguments */ + R3 = [SP++]; + R3 = [SP++]; + /* check if _Thread_Dispatch_disable_level has been incremented */ + R3 = [SP++] + CC=R3==0 + if cc jump dont_decrement; + .extern _Thread_Dispatch_disable_level + P0.H = __Thread_Dispatch_disable_level; + P0.L = __Thread_Dispatch_disable_level; + R0 = [P0]; + R0 += -1; + [P0] = R0; + + dont_decrement: + + (R7:0, P5:0) = [SP++]; + FP = [SP++]; + ASTAT = [SP++]; + RETS = [SP++]; + RETI = [SP++]; + /* Interrupts are now disabled again */ + + /*should restore the old stack !!!*/ + /*if sp now points to SCRATCH_TOP */ + + /* load base adress of scratchpad */ + USP = P0; + P0.H = HI(SCRATCH_TOP); + P0.L = LO(SCRATCH_TOP); + + CC=SP==P0 + if !cc jump restoreP0 + /* restore the stack */ + SP=[P0]; + + restoreP0: + P0 = USP; + + /*now we should be on the old "user-stack" again */ + + /* return from interrupt, will jump to adress stored in RETI */ + RTI; + |