blob: c6f118528b8c5d60bd8805e0bf27fa6c0168f0e3 [file] [log] [blame]
/*
* xtos-internal.h -- internal definitions for single-threaded run-time
*
* Copyright (c) 2003-2010 Tensilica Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef XTOS_INTERNAL_H
#define XTOS_INTERNAL_H
#include <xtensa/config/core.h>
#include <xtensa/xtruntime.h>
#include <xtensa/xtruntime-frames.h>
#include <xtensa/xtensa-versions.h>
#ifndef XTOS_PARAMS_H /* this to allow indirect inclusion of this header from the outside */
#include "xtos-params.h"
#endif
/* Relative ordering of subpriorities within an interrupt level (or vector): */
#define XTOS_SPO_ZERO_LO 0 /* lower (eg. zero) numbered interrupts are lower priority than higher numbered interrupts */
#define XTOS_SPO_ZERO_HI 1 /* lower (eg. zero) numbered interrupts are higher priority than higher numbered interrupts */
/* Sanity check some parameters from xtos-params.h: */
#if XTOS_LOCKLEVEL < XCHAL_EXCM_LEVEL || XTOS_LOCKLEVEL > 15
# error Invalid XTOS_LOCKLEVEL value, must be >= EXCM_LEVEL and <= 15, please fix xtos-params.h
#endif
/* Mask of interrupts locked out at XTOS_LOCKLEVEL: */
#define XTOS_LOCKOUT_MASK XCHAL_INTLEVEL_ANDBELOW_MASK(XTOS_LOCKLEVEL)
/* Mask of interrupts that can still be enabled at XTOS_LOCKLEVEL: */
#define XTOS_UNLOCKABLE_MASK (0xFFFFFFFF-XTOS_LOCKOUT_MASK)
/* Don't set this: */
#define XTOS_HIGHINT_TRAMP 0 /* mapping high-pri ints to low-pri not auto-supported */
#define XTOS_VIRTUAL_INTERRUPT XTOS_HIGHINT_TRAMP /* partially-virtualized INTERRUPT register not currently supported */
#if XTOS_HIGHINT_TRAMP
# error Automatically-generated high-level interrupt trampolines are not presently supported.
#endif
/*
* If single interrupt at level-one, sub-prioritization is irrelevant:
*/
#if defined(XCHAL_INTLEVEL1_NUM)
# undef XTOS_SUBPRI
# define XTOS_SUBPRI 0 /* override - only one interrupt */
#endif
/*
* In XEA1, the INTENABLE special register must be virtualized to provide
* standard XTOS functionality.
* In XEA2, this is only needed for software interrupt prioritization.
*/
#if XTOS_SUBPRI || XCHAL_HAVE_XEA1
#define XTOS_VIRTUAL_INTENABLE 1
#else
#define XTOS_VIRTUAL_INTENABLE 0
#endif
/*
* If single interrupt per priority, then fairness is irrelevant:
*/
#if (XTOS_SUBPRI && !XTOS_SUBPRI_GROUPS) || defined(XCHAL_INTLEVEL1_NUM)
# undef XTOS_INT_FAIRNESS
# define XTOS_INT_FAIRNESS 0
#endif
/* Identify special case interrupt handling code in int-lowpri-dispatcher.S: */
#define XTOS_INT_SPECIALCASE (XTOS_SUBPRI_ORDER == XTOS_SPO_ZERO_HI && XTOS_INT_FAIRNESS == 0 && XTOS_SUBPRI_GROUPS == 0)
/*
* Determine whether to extend the interrupt entry array:
*/
#define XIE_EXTEND (XTOS_VIRTUAL_INTENABLE && !XTOS_INT_SPECIALCASE)
/* If we have the NSAU instruction, ordering of interrupts is reversed in _xtos_interrupt_table[]: */
#if XCHAL_HAVE_NSA
# define MAPINT(n) ((XCHAL_NUM_INTERRUPTS-1)-(n))
# ifdef _ASMLANGUAGE
.macro mapint an
neg \an, \an
addi \an, \an, XCHAL_NUM_INTERRUPTS-1
.endm
# endif
#else /* no NSA */
# define MAPINT(n) (n)
# ifdef _ASMLANGUAGE
.macro mapint an
.endm
# endif
#endif
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
/*********** Useful macros ***********/
/*
* A useful looping macro:
* 'iterate' invokes 'what' (an instruction, pseudo-op or other macro)
* multiple times, passing it a numbered parameter from 'from' to 'to'
* inclusively. Does not invoke 'what' at all if from > to.
* Maximum difference between 'from' and 'to' is 99 minus nesting depth
* (GNU 'as' doesn't allow nesting deeper than 100).
*/
.macro iterate from, to, what
.ifeq ((\to-\from) & ~0xFFF)
\what \from
iterate "(\from+1)", \to, \what
.endif
.endm // iterate
// rsilft
//
// Execute RSIL \ar, \tolevel if \tolevel is different than \fromlevel.
// This way the RSIL is avoided if we know at assembly time that
// it will not change the level. Typically, this means the \ar register
// is ignored, ie. RSIL is used only to change PS.INTLEVEL.
//
.macro rsilft ar, fromlevel, tolevel
#if XCHAL_HAVE_INTERRUPTS
.if \fromlevel - \tolevel
rsil \ar, \tolevel
.endif
#endif
.endm
// Save LOOP and MAC16 registers, if configured, to the exception stack
// frame pointed to by address register \esf, using \aa and \ab as temporaries.
//
// This macro essentially saves optional registers that the compiler uses by
// default when present.
// Note that the acclo/acchi subset of MAC16 may be used even if others
// multipliers are present (e.g. mul16, mul32).
//
// Only two temp registers required for this code to be optimal (no interlocks) in both
// T10xx (Athens) and Xtensa LX microarchitectures (both 5 and 7 stage pipes):
//
.macro save_loops_mac16 esf, aa, ab
#if XCHAL_HAVE_LOOPS
rsr \aa, LCOUNT
rsr \ab, LBEG
s32i \aa, \esf, UEXC_lcount
rsr \aa, LEND
s32i \ab, \esf, UEXC_lbeg
s32i \aa, \esf, UEXC_lend
#endif
#if XCHAL_HAVE_MAC16
rsr \aa, ACCLO
rsr \ab, ACCHI
s32i \aa, \esf, UEXC_acclo
s32i \ab, \esf, UEXC_acchi
# if XTOS_SAVE_ALL_MAC16
rsr \aa, M0
rsr \ab, M1
s32i \aa, \esf, UEXC_mr + 0
s32i \ab, \esf, UEXC_mr + 4
rsr \aa, M2
rsr \ab, M3
s32i \aa, \esf, UEXC_mr + 8
s32i \ab, \esf, UEXC_mr + 12
# endif
#endif
.endm
// Restore LOOP and MAC16 registers, if configured, from the exception stack
// frame pointed to by address register \esf, using \aa, \ab and \ac as temporaries.
//
// Three temp registers are required for this code to be optimal (no interlocks) in
// Xtensa LX microarchitectures with 7-stage pipe; otherwise only two
// registers would be needed.
//
.macro restore_loops_mac16 esf, aa, ab, ac
#if XCHAL_HAVE_LOOPS
l32i \aa, \esf, UEXC_lcount
l32i \ab, \esf, UEXC_lbeg
l32i \ac, \esf, UEXC_lend
wsr \aa, LCOUNT
wsr \ab, LBEG
wsr \ac, LEND
#endif
#if XCHAL_HAVE_MAC16
l32i \aa, \esf, UEXC_acclo
l32i \ab, \esf, UEXC_acchi
# if XTOS_SAVE_ALL_MAC16
l32i \ac, \esf, UEXC_mr + 0
wsr \aa, ACCLO
wsr \ab, ACCHI
wsr \ac, M0
l32i \aa, \esf, UEXC_mr + 4
l32i \ab, \esf, UEXC_mr + 8
l32i \ac, \esf, UEXC_mr + 12
wsr \aa, M1
wsr \ab, M2
wsr \ac, M3
# else
wsr \aa, ACCLO
wsr \ab, ACCHI
# endif
#endif
.endm
/* Offsets from _xtos_intstruct structure: */
.struct 0
#if XTOS_VIRTUAL_INTENABLE
XTOS_ENABLED_OFS: .space 4 /* _xtos_enabled variable */
XTOS_VPRI_ENABLED_OFS: .space 4 /* _xtos_vpri_enabled variable */
#endif
#if XTOS_VIRTUAL_INTERRUPT
XTOS_PENDING_OFS: .space 4 /* _xtos_pending variable */
#endif
.text
#if XTOS_VIRTUAL_INTENABLE
// Update INTENABLE register, computing it as follows:
// INTENABLE = _xtos_enabled & _xtos_vpri_enabled
// [ & ~_xtos_pending ]
//
// Entry:
// register ax = &_xtos_intstruct
// register ay, az undefined (temporaries)
// PS.INTLEVEL set to XTOS_LOCKLEVEL or higher (eg. via xtos_lock)
// window overflows prevented (PS.WOE=0, PS.EXCM=1, or overflows
// already done for registers ax, ay, az)
//
// Exit:
// registers ax, ay, az clobbered
// PS unchanged
// caller needs to SYNC (?) for INTENABLE changes to take effect
//
// Note: in other software prioritization schemes/implementations,
// the term <_xtos_vpri_enabled> in the above expression is often
// replaced with another expression that computes the set of
// interrupts allowed to be enabled at the current software virtualized
// interrupt priority.
//
// For example, a simple alternative implementation of software
// prioritization for XTOS might have been the following:
// INTENABLE = _xtos_enabled & (vpri_enabled | UNLOCKABLE_MASK)
// which removes the need for the interrupt dispatcher to 'or' the
// UNLOCKABLE_MASK bits into _xtos_vpri_enabled, and lets other code
// disable all lockout level interrupts by just clearing _xtos_vpri_enabled
// rather than setting it to UNLOCKABLE_MASK.
// Other implementations sometimes use a table, eg:
// INTENABLE = _xtos_enabled & enable_table[current_vpri]
// The HAL (used by some 3rd party OSes) uses essentially a table-driven
// version, with other tables enabling run-time changing of priorities.
//
.macro xtos_update_intenable ax, ay, az
//movi \ax, _xtos_intstruct
l32i \ay, \ax, XTOS_VPRI_ENABLED_OFS // ay = _xtos_vpri_enabled
l32i \az, \ax, XTOS_ENABLED_OFS // az = _xtos_enabled
//interlock
and \az, \az, \ay // az = _xtos_enabled & _xtos_vpri_enabled
# if XTOS_VIRTUAL_INTERRUPT
l32i \ay, \ax, XTOS_PENDING_OFS // ay = _xtos_pending
movi \ax, -1
xor \ay, \ay, \ax // ay = ~_xtos_pending
and \az, \az, \ay // az &= ~_xtos_pending
# endif
wsr \az, INTENABLE
.endm
#endif /* VIRTUAL_INTENABLE */
.macro xtos_lock ax
rsil \ax, XTOS_LOCKLEVEL // lockout
.endm
.macro xtos_unlock ax
wsr \ax, PS // unlock
rsync
.endm
/* Offsets to XtosIntHandlerEntry structure fields (see below): */
# define XIE_HANDLER 0
# define XIE_ARG 4
# define XIE_SIZE 8
# if XIE_EXTEND
# define XIE_VPRIMASK (XIE_SIZE*XCHAL_NUM_INTERRUPTS+0) /* if VIRTUAL_INTENABLE [SUBPRI||XEA1] && !SPECIALCASE */
# define XIE_LEVELMASK (XIE_SIZE*XCHAL_NUM_INTERRUPTS+4) /* [fairness preloop] if FAIRNESS && SUBPRI [&& SUBPRI_GROUPS] */
# endif
/* To simplify code: */
# if XCHAL_HAVE_NSA
# define IFNSA(a,b) a
# else
# define IFNSA(a,b) b
# endif
#else /* !_ASMLANGUAGE && !__ASSEMBLER__ */
/*
* Interrupt handler table entry.
* Unregistered entries have 'handler' point to _xtos_unhandled_interrupt().
*/
typedef struct XtosIntHandlerEntry {
_xtos_handler handler;
void * arg;
} XtosIntHandlerEntry;
# if XIE_EXTEND
typedef struct XtosIntMaskEntry {
unsigned vpri_mask; /* mask of interrupts enabled when this interrupt is taken */
unsigned level_mask; /* mask of interrupts at this interrupt's level */
} XtosIntMaskEntry;
# endif
#endif /* !_ASMLANGUAGE && !__ASSEMBLER__ */
/*
* Notes...
*
* XEA1 and interrupt-SUBPRIoritization both imply virtualization of INTENABLE.
* Synchronous trampoloines imply partial virtualization of the INTERRUPT
* register, which in turn also implies virtualization of INTENABLE register.
* High-level interrupts manipulating the set of enabled interrupts implies
* at least a high XTOS_LOCK_LEVEL, although not necessarily INTENABLE virtualization.
*
* With INTENABLE register virtualization, at all times the INTENABLE
* register reflects the expression:
* (set of interrupts enabled) & (set of interrupts enabled by current
* virtual priority)
*
* Unrelated (DBREAK semantics):
*
* A[31-6] = DBA[3-6]
* ---------------------
* A[5-0] & DBC[5-C] & szmask
*
* = DBA[5-0] & szmask
* ^___ ???
*/
/* Report whether the XSR instruction is available (conservative): */
#define HAVE_XSR (XCHAL_HAVE_XEA2 || !XCHAL_HAVE_EXCEPTIONS)
/*
* This is more accurate, but not a reliable test in software releases prior to 6.0
* (where the targeted hardware parameter was not explicit in the XPG):
*
*#define HAVE_XSR (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_T1040_0)
*/
/* Macros for supporting hi-level and medium-level interrupt handling. */
#if XCHAL_NUM_INTLEVELS > 6
#error Template files (*-template.S) limit support to interrupt levels <= 6
#endif
#if defined(__XTENSA_WINDOWED_ABI__) && XCHAL_HAVE_CALL4AND12 == 0
#error CALL8-only is not supported!
#endif
#define INTERRUPT_IS_HI(level) \
( XCHAL_HAVE_INTERRUPTS && \
(XCHAL_EXCM_LEVEL < level) && \
(XCHAL_NUM_INTLEVELS >= level) && \
(XCHAL_HAVE_DEBUG ? XCHAL_DEBUGLEVEL != level : 1))
#define INTERRUPT_IS_MED(level) \
(XCHAL_HAVE_INTERRUPTS && (XCHAL_EXCM_LEVEL >= level))
#define _JOIN(x,y) x ## y
#define JOIN(x,y) _JOIN(x,y)
#define _JOIN3(a,b,c) a ## b ## c
#define JOIN3(a,b,c) _JOIN3(a,b,c)
#define LABEL(x,y) JOIN3(x,_INTERRUPT_LEVEL,y)
#define EXCSAVE_LEVEL JOIN(EXCSAVE_,_INTERRUPT_LEVEL)
#define INTLEVEL_VSIZE JOIN3(XSHAL_INTLEVEL,_INTERRUPT_LEVEL,_VECTOR_SIZE)
#endif /* XTOS_INTERNAL_H */