Mercurial > ecos
diff packages/hal/sparclite/arch/current/src/icontext.c @ 2:443894e2e912 ecos-v1_2_1-release
Block commit of eCos version 1.2.1
| author | jlarmour |
|---|---|
| date | Tue, 11 May 1999 12:24:34 +0000 |
| parents | |
| children | d376b777e2ce |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/hal/sparclite/arch/current/src/icontext.c @@ -0,0 +1,472 @@ +/*============================================================================= +// +// icontext.c +// +// SPARClite HAL context init function +// +//============================================================================= +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Cygnus eCos Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://sourceware.cygnus.com/ecos +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Cygnus Operating System, released +// September 30, 1998. +// +// The Initial Developer of the Original Code is Cygnus. Portions created +// by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): hmt +// Contributors: hmt +// Date: 1998-12-14 +// Purpose: HAL context initialization function +// Description: Initialize a HAL context for SPARClite; this is in C and out +// of line because there is too much of it for a simple macro. +// +//####DESCRIPTIONEND#### +// +//===========================================================================*/ + +#include <pkgconf/hal.h> + +#include <cyg/hal/hal_arch.h> // HAL header + +#include <cyg/infra/cyg_type.h> + +#include <cyg/hal/vectors.h> // SAVE_REGS_SIZE, __WINSIZE, ... + +/*---------------------------------------------------------------------------*/ + +/* We lay out the stack in the manner that the PCS demands: + * frame pointer -----> [top of stack] + * Argument spill area (6 words) + * Return Arg pointer + * Initial saved register window (i[8], l[8]) + * for use by program when it starts + * [rest of] saved register object (various) + * stack pointer -----> saved register window (i[8], l[8]) + * to allow us to be interrupted. + * + * ie. frame pointer -> + * struct HAL_FrameStructure + * stack pointer -> struct HAL_SavedRegisters + * + * and when the context "resumes" sp is incremented by 40 * 4, the size of + * a _struct HAL_SavedRegisters_ which points it at the extant but unused + * _struct HAL_FrameStructure_ as the PCS requires. The frame pointer is + * left pointing off the top of stack. + * + * + * Thus the stack is the same if created from an already executing context: + * + * frame pointer -----> + * [temporaries and locals] + * [more arguments] + * Argument spill area (6 words) + * Return Arg pointer + * [sp at entry]------> Previous saved register window (i[8], l[8]) + * for use by program when it starts + * [rest of] saved register object (various) + * stack pointer -----> saved register window (i[8], l[8]) + * to allow us to be interrupted. + */ + +CYG_ADDRESS +hal_thread_init_context( CYG_WORD sparg, + CYG_WORD thread, + CYG_WORD entry, + CYG_WORD id ) +{ + register CYG_WORD fp = sparg; + register CYG_WORD sp = 0; + register HAL_SavedRegisters *regs; + register HAL_FrameStructure *frame; + int i; + + if ( 0 == (id & 0xffff0000) ) + id <<= 16; + + fp &= ~7; // round down to double alignment + + frame = (HAL_FrameStructure *)( + fp - sizeof( HAL_FrameStructure ) ); + + regs = (HAL_SavedRegisters *)( + ((CYG_WORD)frame) - sizeof(HAL_SavedRegisters) ); + + sp = (CYG_WORD)regs; + + for ( i = 0; i < 6; i++ ) { + frame->spill_args[i] = id | 0xa0 | i; + } + frame->composite_return_ptr = 0; + + for ( i = 0; i < 8; i++ ) { + frame->li.i[i] = id | ( 56 + i ); + frame->li.l[i] = id | ( 48 + i ); + regs ->li.i[i] = id | ( 24 + i ); + regs ->li.l[i] = id | ( 16 + i ); + regs ->o[i] = id | ( 8 + i ); + regs ->g[i] = id | ( i ); + } + + // first terminate the linked list on the stack in the initial + // (already saved) register window: + frame->li.i[6] = regs->li.i[6] = (cyg_uint32)fp; // frame pointer + frame->li.i[7] = regs->li.i[7] = (cyg_uint32)0; // no ret addr here + + // and set up other saved regs as if called from just before + // the entry point: + regs->o[7] = (entry - 8); + regs->o[6] = sp; + + // this is the argument that the entry point is called with + regs->o[0] = thread; + + // this is the initial CWP; quite arbitrary really, the WIM is set up + // accordingly in hal_thread_load_context(). + + regs->g[0] = 7; + + return (CYG_ADDRESS)sp; +} + +// --------------------------------------------------------------------------- + +//#define THREAD_DEBUG_SERIAL_VERBOSE + +#ifdef THREAD_DEBUG_SERIAL_VERBOSE // NOT INCLUDED + +// This is unpleasant to try to debug, because these routines are called +// WHEN THE PROGRAM IS NOT RUNNING from the CygMon's GDB stubs - so you +// can't use any normal output: these little routines use the serial +// line directly, so are best used when debugging via Ethernet, so you +// just have a separate output stream to read. Nasty... + +#include <cyg/hal/hal_diag.h> + +#undef HAL_DIAG_WRITE_CHAR +#define HAL_DIAG_WRITE_CHAR(_c_) CYG_MACRO_START \ + SLEB_LED = (_c_); \ + HAL_DIAG_WRITE_CHAR_DIRECT( _c_ ); \ +CYG_MACRO_END + +static void swritec( char c ) +{ + HAL_DIAG_WRITE_CHAR( c ); +} + +static void swrites( char *s ) +{ + char c; + while ( 0 != (c = *s++) ) + HAL_DIAG_WRITE_CHAR( c ); +} + +static void swritex( cyg_uint32 x ) +{ + int i; + swrites( "0x" ); + for ( i = 28; i >= 0; i-= 4 ) { + char c = "0123456789abcdef"[ 0xf & (x >> i) ]; + HAL_DIAG_WRITE_CHAR( c ); + } +} + +#define newline() swrites( "\n\r" ) + +static void x8( char *s, unsigned long *xp ) +{ + int i; + for ( i = 0; i < 8; i++ ) { + swrites( s ); + swritec( '0' + i ); + swrites( " = " ); + swritex( xp[i] ); + if ( 3 == (i & 3) ) + newline(); + else + swrites( " " ); + } +} + +#endif // THREAD_DEBUG_SERIAL_VERBOSE ... NOT INCLUDED + +// --------------------------------------------------------------------------- +// Routines in icontext.c used here because they're quite large for +// the SPARClite (note param order); these are used in talking to GDB. + +enum regnames {G0 = 0, G1, G2, G3, G4, G5, G6, G7, + O0, O1, O2, O3, O4, O5, SP, O7, + L0, L1, L2, L3, L4, L5, L6, L7, + I0, I1, I2, I3, I4, I5, FP, I7, + + F0, F1, F2, F3, F4, F5, F6, F7, + F8, F9, F10, F11, F12, F13, F14, F15, + F16, F17, F18, F19, F20, F21, F22, F23, + F24, F25, F26, F27, F28, F29, F30, F31, + Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR}; + +typedef unsigned long target_register_t; + +void +cyg_hal_sparc_get_gdb_regs( void *gdb_regset, + HAL_SavedRegisters *eCos_regset ) +{ + target_register_t *gdb = (target_register_t *)gdb_regset; + int reg; + cyg_uint32 scratch = 0; + cyg_uint32 *sptrap; + HAL_SavedWindow *trapli, *ctxli; + + if ( 0 == eCos_regset->g[0] || + 0xc0 == (0xe0 & eCos_regset->g[0]) ) { + // Then it's an interrupt stack saved state: + // (either minimal, or a saved PSR with traps disabled) + // The saved register set is pretty minimal, so we have to grub + // around in the stack to find out some truth... + sptrap = (cyg_uint32 *)eCos_regset; // point to the IL save area for + sptrap -= 24; // the trap handler, for PC, NPC + trapli = (HAL_SavedWindow *)sptrap; // Get at those regs + + ctxli = (HAL_SavedWindow *)(trapli->i[6]); // (the frame pointer) + // and get at the interruptee's regs + + // Pick up interruptee's registers from all over the stack: + for ( reg = 0; reg < 8 ; reg++ ) { + gdb[ G0 + reg ] = eCos_regset->g[reg]; + gdb[ O0 + reg ] = trapli->i[reg]; + gdb[ L0 + reg ] = ctxli->l[reg]; + gdb[ I0 + reg ] = ctxli->i[reg]; + } + + // Clear out G0 which is always 0 (but abused in eCos_regset) + // and the FP regs which we do not have: + gdb[ G0 ] = 0; + for ( reg = F0; reg <= F31; reg++ ) + gdb[ reg ] = 0; + + // In the save context _of the trap handler_ registers are as follows: + // %l0 = psr (with this CWP/window-level in it) + // %l1 = pc + // %l2 = npc + // %l3 = vector number (1-15 for interrupts) + // %l4 = Y register preserved + gdb[ Y ] = trapli->l[4]; + + scratch = trapli->l[0]; // the PSR in the trap handler + scratch++; // back to interupted thread's window + scratch &=~ 0x38; // clear ET and any CWP overflow + gdb[ PSR ] = scratch; + gdb[ WIM ] = 1 << ((__WINBITS & (1 + scratch))); + + // Read _a_ TBR value and ignore the current trap details: + asm volatile ( "rd %%tbr, %0" : "=r"(scratch) : ); + gdb[ TBR ] = (scratch &~ 0xfff); + + gdb[ PC ] = trapli->l[1]; + gdb[ NPC ] = trapli->l[2]; + + gdb[ FPSR ] = 0; + gdb[ CPSR ] = 0; + +#ifdef THREAD_DEBUG_SERIAL_VERBOSE + newline(); + swrites( "-----------------------------------------------------" ); newline(); + swrites( "-------------- INTERRUPT STACK GET ------------------" ); newline(); + swrites( "eCos regset at " ); swritex( eCos_regset ); newline(); + swrites( " trapli " ); swritex( trapli ); newline(); + swrites( " ctxli " ); swritex( ctxli ); newline(); + x8( "global ", &(gdb[G0]) ); + x8( " in ", &(gdb[I0]) ); + x8( " local ", &(gdb[L0]) ); + x8( " out ", &(gdb[O0]) ); + swrites( "gdb PC = " ); swritex( gdb[ PC ] ); newline(); + swrites( "gdb NPC = " ); swritex( gdb[ NPC ] ); newline(); + swrites( "gdb PSR = " ); swritex( gdb[ PSR ] ); newline(); +#endif + + } + else { + // It's a synchronous context switch that led to this object. + // Pick up interruptee's registers from the saved context: + for ( reg = 0; reg < 8 ; reg++ ) { +#ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM + gdb[ G0 + reg ] = 0; + gdb[ O0 + reg ] = 0; +#else + gdb[ G0 + reg ] = eCos_regset->g[reg]; + gdb[ O0 + reg ] = eCos_regset->o[reg]; +#endif + gdb[ L0 + reg ] = eCos_regset->li.l[reg]; + gdb[ I0 + reg ] = eCos_regset->li.i[reg]; + } + +#ifdef CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM + // Set up the stack pointer by arithmetic and the return address + gdb[ SP ] = ((cyg_uint32)(eCos_regset)); + gdb[ O7 ] = eCos_regset->o[ 7 ]; +#else + // Clear out G0 which is always 0 (but abused in eCos_regset) + gdb[ G0 ] = 0; +#endif + // and clear the FP regs which we do not have: + for ( reg = F0; reg <= F31; reg++ ) + gdb[ reg ] = 0; + + gdb[ Y ] = 0; // it's not preserved. + + scratch = eCos_regset->g[ 0 ]; // the PSR in the saved context + gdb[ PSR ] = scratch; // return it verbatim. + gdb[ WIM ] = 1 << ((__WINBITS & (1 + scratch))); + + // Read _a_ TBR value and ignore the current trap details: + asm volatile ( "rd %%tbr, %0" : "=r"(scratch) : ); + gdb[ TBR ] = (scratch &~ 0xfff); + + gdb[ PC ] = eCos_regset->o[ 7 ]; // the return address + gdb[ NPC ] = 4 + gdb[ PC ]; + + gdb[ FPSR ] = 0; + gdb[ CPSR ] = 0; + +#ifdef THREAD_DEBUG_SERIAL_VERBOSE + newline(); + swrites( "-----------------------------------------------------" ); newline(); + swrites( "-------------- SYNCHRONOUS SWITCH GET----------------" ); newline(); + swrites( "eCos regset at " ); swritex( eCos_regset ); newline(); + x8( "global ", &(gdb[G0]) ); + x8( " in ", &(gdb[I0]) ); + x8( " local ", &(gdb[L0]) ); + x8( " out ", &(gdb[O0]) ); + swrites( "gdb PC = " ); swritex( gdb[ PC ] ); newline(); + swrites( "gdb NPC = " ); swritex( gdb[ NPC ] ); newline(); + swrites( "gdb PSR = " ); swritex( gdb[ PSR ] ); newline(); +#endif + } + +} + +// --------------------------------------------------------------------------- + +void +cyg_hal_sparc_set_gdb_regs( HAL_SavedRegisters *eCos_regset, + void *gdb_regset ) +{ + target_register_t *gdb = (target_register_t *)gdb_regset; + int reg; + cyg_uint32 scratch = 0; + cyg_uint32 *sptrap; + HAL_SavedWindow *trapli, *ctxli; + + // Guess where the eCos register set really is: + if ( 0 == eCos_regset->g[0] || + 0xc0 == (0xe0 & eCos_regset->g[0]) ) { + // Then it's an interrupt stack saved state: + // (either minimal, or a saved PSR with traps disabled) + // The saved register set is pretty minimal, so we have to grub + // around in the stack to find out some truth... + sptrap = (cyg_uint32 *)eCos_regset; // point to the IL save area for + sptrap -= 24; // the trap handler, for PC, NPC + trapli = (HAL_SavedWindow *)sptrap; // Get at those regs + + ctxli = (HAL_SavedWindow *)(trapli->i[6]); // (the frame pointer) + // and get at the interruptee's regs + + scratch = eCos_regset->g[0]; + + // Put back interruptee's registers all over the stack: + for ( reg = 0; reg < 8 ; reg++ ) { + eCos_regset->g[reg] = gdb[ G0 + reg ] ; + trapli->i[reg] = gdb[ O0 + reg ] ; + ctxli->l[reg] = gdb[ L0 + reg ] ; + ctxli->i[reg] = gdb[ I0 + reg ] ; + } + + // Put back the eCos G0 which is always 0 (but abused in eCos_regset) + eCos_regset->g[0] = scratch; + + // In the save context _of the trap handler_ registers are as follows: + // %l0 = psr (with this CWP/window-level in it) + // %l1 = pc + // %l2 = npc + // %l3 = vector number (1-15 for interrupts) + // %l4 = Y register preserved + trapli->l[4] = gdb[ Y ]; + + // I am *not* interfering with the saved PSR, nor the TBR nor WIM. + + // put back return PC and NPC + trapli->l[1] = gdb[ PC ] ; + trapli->l[2] = gdb[ NPC ]; + +#ifdef THREAD_DEBUG_SERIAL_VERBOSE + newline(); + swrites( "-----------------------------------------------------" ); newline(); + swrites( "-------------- INTERRUPT STACK SET ------------------" ); newline(); + swrites( "eCos regset at " ); swritex( eCos_regset ); newline(); + swrites( " trapli " ); swritex( trapli ); newline(); + swrites( " ctxli " ); swritex( ctxli ); newline(); + x8( "global ", &(gdb[G0]) ); + x8( " in ", &(gdb[I0]) ); + x8( " local ", &(gdb[L0]) ); + x8( " out ", &(gdb[O0]) ); + swrites( "gdb PC = " ); swritex( gdb[ PC ] ); newline(); + swrites( "gdb NPC = " ); swritex( gdb[ NPC ] ); newline(); + swrites( "gdb PSR = " ); swritex( gdb[ PSR ] ); newline(); +#endif + + } + else { + // It's a synchronous context switch that led to this object. + // Pick up interruptee's registers from the saved context: + + scratch = eCos_regset->g[0]; + + for ( reg = 0; reg < 8 ; reg++ ) { + eCos_regset->g[reg] = gdb[ G0 + reg ]; + eCos_regset->o[reg] = gdb[ O0 + reg ]; + eCos_regset->li.l[reg] = gdb[ L0 + reg ]; + eCos_regset->li.i[reg] = gdb[ I0 + reg ]; + } + + // Put back the eCos G0 which is always 0 (but abused in eCos_regset) + eCos_regset->g[0] = scratch; + + // I am *not* interfering with the saved PSR, nor the TBR nor WIM. + + // The PC is in o7, altering it via GDB's PC is not on. + // Setting the NPC in a voluntary context is meaningless. + +#ifdef THREAD_DEBUG_SERIAL_VERBOSE + newline(); + swrites( "-----------------------------------------------------" ); newline(); + swrites( "-------------- SYNCHRONOUS SWITCH SET ---------------" ); newline(); + swrites( "eCos regset at " ); swritex( eCos_regset ); newline(); + x8( "global ", &(gdb[G0]) ); + x8( " in ", &(gdb[I0]) ); + x8( " local ", &(gdb[L0]) ); + x8( " out ", &(gdb[O0]) ); + swrites( "gdb PC = " ); swritex( gdb[ PC ] ); newline(); + swrites( "gdb NPC = " ); swritex( gdb[ NPC ] ); newline(); + swrites( "gdb PSR = " ); swritex( gdb[ PSR ] ); newline(); +#endif + } + +} + +/*---------------------------------------------------------------------------*/ +// EOF icontext.c
