123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526 |
- #ifndef XTENSA_COREASM_H
- #define XTENSA_COREASM_H
- /*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/coreasm.h -- assembler-specific
- * definitions that depend on CORE configuration.
- *
- * Source for configuration-independent binaries (which link in a
- * configuration-specific HAL library) must NEVER include this file.
- * It is perfectly normal, however, for the HAL itself to include this
- * file.
- *
- * This file must NOT include xtensa/config/system.h. Any assembler
- * header file that depends on system information should likely go in
- * a new systemasm.h (or sysasm.h) header file.
- *
- * NOTE: macro beqi32 is NOT configuration-dependent, and is placed
- * here til we will have configuration-independent header file.
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file "COPYING" in the main directory of
- * this archive for more details.
- *
- * Copyright (C) 2002 Tensilica Inc.
- */
- #include <xtensa/config/core.h>
- #include <xtensa/config/specreg.h>
- /*
- * Assembly-language specific definitions (assembly macros, etc.).
- */
- /*----------------------------------------------------------------------
- * find_ms_setbit
- *
- * This macro finds the most significant bit that is set in <as>
- * and return its index + <base> in <ad>, or <base> - 1 if <as> is zero.
- * The index counts starting at zero for the lsbit, so the return
- * value ranges from <base>-1 (no bit set) to <base>+31 (msbit set).
- *
- * Parameters:
- * <ad> destination address register (any register)
- * <as> source address register
- * <at> temporary address register (must be different than <as>)
- * <base> constant value added to result (usually 0 or 1)
- * On entry:
- * <ad> = undefined if different than <as>
- * <as> = value whose most significant set bit is to be found
- * <at> = undefined
- * no other registers are used by this macro.
- * On exit:
- * <ad> = <base> + index of msbit set in original <as>,
- * = <base> - 1 if original <as> was zero.
- * <as> clobbered (if not <ad>)
- * <at> clobbered (if not <ad>)
- * Example:
- * find_ms_setbit a0, a4, a0, 0 -- return in a0 index of msbit set in a4
- */
- .macro find_ms_setbit ad, as, at, base
- #if XCHAL_HAVE_NSA
- movi \at, 31+\base
- nsau \as, \as // get index of \as, numbered from msbit (32 if absent)
- sub \ad, \at, \as // get numbering from lsbit (0..31, -1 if absent)
- #else /* XCHAL_HAVE_NSA */
- movi \at, \base // start with result of 0 (point to lsbit of 32)
- beqz \as, 2f // special case for zero argument: return -1
- bltui \as, 0x10000, 1f // is it one of the 16 lsbits? (if so, check lower 16 bits)
- addi \at, \at, 16 // no, increment result to upper 16 bits (of 32)
- //srli \as, \as, 16 // check upper half (shift right 16 bits)
- extui \as, \as, 16, 16 // check upper half (shift right 16 bits)
- 1: bltui \as, 0x100, 1f // is it one of the 8 lsbits? (if so, check lower 8 bits)
- addi \at, \at, 8 // no, increment result to upper 8 bits (of 16)
- srli \as, \as, 8 // shift right to check upper 8 bits
- 1: bltui \as, 0x10, 1f // is it one of the 4 lsbits? (if so, check lower 4 bits)
- addi \at, \at, 4 // no, increment result to upper 4 bits (of 8)
- srli \as, \as, 4 // shift right 4 bits to check upper half
- 1: bltui \as, 0x4, 1f // is it one of the 2 lsbits? (if so, check lower 2 bits)
- addi \at, \at, 2 // no, increment result to upper 2 bits (of 4)
- srli \as, \as, 2 // shift right 2 bits to check upper half
- 1: bltui \as, 0x2, 1f // is it the lsbit?
- addi \at, \at, 2 // no, increment result to upper bit (of 2)
- 2: addi \at, \at, -1 // (from just above: add 1; from beqz: return -1)
- //srli \as, \as, 1
- 1: // done! \at contains index of msbit set (or -1 if none set)
- .if 0x\ad - 0x\at // destination different than \at ? (works because regs are a0-a15)
- mov \ad, \at // then move result to \ad
- .endif
- #endif /* XCHAL_HAVE_NSA */
- .endm // find_ms_setbit
- /*----------------------------------------------------------------------
- * find_ls_setbit
- *
- * This macro finds the least significant bit that is set in <as>,
- * and return its index in <ad>.
- * Usage is the same as for the find_ms_setbit macro.
- * Example:
- * find_ls_setbit a0, a4, a0, 0 -- return in a0 index of lsbit set in a4
- */
- .macro find_ls_setbit ad, as, at, base
- neg \at, \as // keep only the least-significant bit that is set...
- and \as, \at, \as // ... in \as
- find_ms_setbit \ad, \as, \at, \base
- .endm // find_ls_setbit
- /*----------------------------------------------------------------------
- * find_ls_one
- *
- * Same as find_ls_setbit with base zero.
- * Source (as) and destination (ad) registers must be different.
- * Provided for backward compatibility.
- */
- .macro find_ls_one ad, as
- find_ls_setbit \ad, \as, \ad, 0
- .endm // find_ls_one
- /*----------------------------------------------------------------------
- * floop, floopnez, floopgtz, floopend
- *
- * These macros are used for fast inner loops that
- * work whether or not the Loops options is configured.
- * If the Loops option is configured, they simply use
- * the zero-overhead LOOP instructions; otherwise
- * they use explicit decrement and branch instructions.
- *
- * They are used in pairs, with floop, floopnez or floopgtz
- * at the beginning of the loop, and floopend at the end.
- *
- * Each pair of loop macro calls must be given the loop count
- * address register and a unique label for that loop.
- *
- * Example:
- *
- * movi a3, 16 // loop 16 times
- * floop a3, myloop1
- * :
- * bnez a7, end1 // exit loop if a7 != 0
- * :
- * floopend a3, myloop1
- * end1:
- *
- * Like the LOOP instructions, these macros cannot be
- * nested, must include at least one instruction,
- * cannot call functions inside the loop, etc.
- * The loop can be exited by jumping to the instruction
- * following floopend (or elsewhere outside the loop),
- * or continued by jumping to a NOP instruction placed
- * immediately before floopend.
- *
- * Unlike LOOP instructions, the register passed to floop*
- * cannot be used inside the loop, because it is used as
- * the loop counter if the Loops option is not configured.
- * And its value is undefined after exiting the loop.
- * And because the loop counter register is active inside
- * the loop, you can't easily use this construct to loop
- * across a register file using ROTW as you might with LOOP
- * instructions, unless you copy the loop register along.
- */
- /* Named label version of the macros: */
- .macro floop ar, endlabel
- floop_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
- .endm
- .macro floopnez ar, endlabel
- floopnez_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
- .endm
- .macro floopgtz ar, endlabel
- floopgtz_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
- .endm
- .macro floopend ar, endlabel
- floopend_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
- .endm
- /* Numbered local label version of the macros: */
- #if 0 /*UNTESTED*/
- .macro floop89 ar
- floop_ \ar, 8, 9f
- .endm
- .macro floopnez89 ar
- floopnez_ \ar, 8, 9f
- .endm
- .macro floopgtz89 ar
- floopgtz_ \ar, 8, 9f
- .endm
- .macro floopend89 ar
- floopend_ \ar, 8b, 9
- .endm
- #endif /*0*/
- /* Underlying version of the macros: */
- .macro floop_ ar, startlabel, endlabelref
- .ifdef _infloop_
- .if _infloop_
- .err // Error: floop cannot be nested
- .endif
- .endif
- .set _infloop_, 1
- #if XCHAL_HAVE_LOOPS
- loop \ar, \endlabelref
- #else /* XCHAL_HAVE_LOOPS */
- \startlabel:
- addi \ar, \ar, -1
- #endif /* XCHAL_HAVE_LOOPS */
- .endm // floop_
- .macro floopnez_ ar, startlabel, endlabelref
- .ifdef _infloop_
- .if _infloop_
- .err // Error: floopnez cannot be nested
- .endif
- .endif
- .set _infloop_, 1
- #if XCHAL_HAVE_LOOPS
- loopnez \ar, \endlabelref
- #else /* XCHAL_HAVE_LOOPS */
- beqz \ar, \endlabelref
- \startlabel:
- addi \ar, \ar, -1
- #endif /* XCHAL_HAVE_LOOPS */
- .endm // floopnez_
- .macro floopgtz_ ar, startlabel, endlabelref
- .ifdef _infloop_
- .if _infloop_
- .err // Error: floopgtz cannot be nested
- .endif
- .endif
- .set _infloop_, 1
- #if XCHAL_HAVE_LOOPS
- loopgtz \ar, \endlabelref
- #else /* XCHAL_HAVE_LOOPS */
- bltz \ar, \endlabelref
- beqz \ar, \endlabelref
- \startlabel:
- addi \ar, \ar, -1
- #endif /* XCHAL_HAVE_LOOPS */
- .endm // floopgtz_
- .macro floopend_ ar, startlabelref, endlabel
- .ifndef _infloop_
- .err // Error: floopend without matching floopXXX
- .endif
- .ifeq _infloop_
- .err // Error: floopend without matching floopXXX
- .endif
- .set _infloop_, 0
- #if ! XCHAL_HAVE_LOOPS
- bnez \ar, \startlabelref
- #endif /* XCHAL_HAVE_LOOPS */
- \endlabel:
- .endm // floopend_
- /*----------------------------------------------------------------------
- * crsil -- conditional RSIL (read/set interrupt level)
- *
- * Executes the RSIL instruction if it exists, else just reads PS.
- * The RSIL instruction does not exist in the new exception architecture
- * if the interrupt option is not selected.
- */
- .macro crsil ar, newlevel
- #if XCHAL_HAVE_OLD_EXC_ARCH || XCHAL_HAVE_INTERRUPTS
- rsil \ar, \newlevel
- #else
- rsr \ar, PS
- #endif
- .endm // crsil
- /*----------------------------------------------------------------------
- * window_spill{4,8,12}
- *
- * These macros spill callers' register windows to the stack.
- * They work for both privileged and non-privileged tasks.
- * Must be called from a windowed ABI context, eg. within
- * a windowed ABI function (ie. valid stack frame, window
- * exceptions enabled, not in exception mode, etc).
- *
- * This macro requires a single invocation of the window_spill_common
- * macro in the same assembly unit and section.
- *
- * Note that using window_spill{4,8,12} macros is more efficient
- * than calling a function implemented using window_spill_function,
- * because the latter needs extra code to figure out the size of
- * the call to the spilling function.
- *
- * Example usage:
- *
- * .text
- * .align 4
- * .global some_function
- * .type some_function,@function
- * some_function:
- * entry a1, 16
- * :
- * :
- *
- * window_spill4 // spill windows of some_function's callers; preserves a0..a3 only;
- * // to use window_spill{8,12} in this example function we'd have
- * // to increase space allocated by the entry instruction, because
- * // 16 bytes only allows call4; 32 or 48 bytes (+locals) are needed
- * // for call8/window_spill8 or call12/window_spill12 respectively.
- * :
- *
- * retw
- *
- * window_spill_common // instantiates code used by window_spill4
- *
- *
- * On entry:
- * none (if window_spill4)
- * stack frame has enough space allocated for call8 (if window_spill8)
- * stack frame has enough space allocated for call12 (if window_spill12)
- * On exit:
- * a4..a15 clobbered (if window_spill4)
- * a8..a15 clobbered (if window_spill8)
- * a12..a15 clobbered (if window_spill12)
- * no caller windows are in live registers
- */
- .macro window_spill4
- #if XCHAL_HAVE_WINDOWED
- # if XCHAL_NUM_AREGS == 16
- movi a15, 0 // for 16-register files, no need to call to reach the end
- # elif XCHAL_NUM_AREGS == 32
- call4 .L__wdwspill_assist28 // call deep enough to clear out any live callers
- # elif XCHAL_NUM_AREGS == 64
- call4 .L__wdwspill_assist60 // call deep enough to clear out any live callers
- # endif
- #endif
- .endm // window_spill4
- .macro window_spill8
- #if XCHAL_HAVE_WINDOWED
- # if XCHAL_NUM_AREGS == 16
- movi a15, 0 // for 16-register files, no need to call to reach the end
- # elif XCHAL_NUM_AREGS == 32
- call8 .L__wdwspill_assist24 // call deep enough to clear out any live callers
- # elif XCHAL_NUM_AREGS == 64
- call8 .L__wdwspill_assist56 // call deep enough to clear out any live callers
- # endif
- #endif
- .endm // window_spill8
- .macro window_spill12
- #if XCHAL_HAVE_WINDOWED
- # if XCHAL_NUM_AREGS == 16
- movi a15, 0 // for 16-register files, no need to call to reach the end
- # elif XCHAL_NUM_AREGS == 32
- call12 .L__wdwspill_assist20 // call deep enough to clear out any live callers
- # elif XCHAL_NUM_AREGS == 64
- call12 .L__wdwspill_assist52 // call deep enough to clear out any live callers
- # endif
- #endif
- .endm // window_spill12
- /*----------------------------------------------------------------------
- * window_spill_function
- *
- * This macro outputs a function that will spill its caller's callers'
- * register windows to the stack. Eg. it could be used to implement
- * a version of xthal_window_spill() that works in non-privileged tasks.
- * This works for both privileged and non-privileged tasks.
- *
- * Typical usage:
- *
- * .text
- * .align 4
- * .global my_spill_function
- * .type my_spill_function,@function
- * my_spill_function:
- * window_spill_function
- *
- * On entry to resulting function:
- * none
- * On exit from resulting function:
- * none (no caller windows are in live registers)
- */
- .macro window_spill_function
- #if XCHAL_HAVE_WINDOWED
- # if XCHAL_NUM_AREGS == 32
- entry sp, 48
- bbci.l a0, 31, 1f // branch if called with call4
- bbsi.l a0, 30, 2f // branch if called with call12
- call8 .L__wdwspill_assist16 // called with call8, only need another 8
- retw
- 1: call12 .L__wdwspill_assist16 // called with call4, only need another 12
- retw
- 2: call4 .L__wdwspill_assist16 // called with call12, only need another 4
- retw
- # elif XCHAL_NUM_AREGS == 64
- entry sp, 48
- bbci.l a0, 31, 1f // branch if called with call4
- bbsi.l a0, 30, 2f // branch if called with call12
- call4 .L__wdwspill_assist52 // called with call8, only need a call4
- retw
- 1: call8 .L__wdwspill_assist52 // called with call4, only need a call8
- retw
- 2: call12 .L__wdwspill_assist40 // called with call12, can skip a call12
- retw
- # elif XCHAL_NUM_AREGS == 16
- entry sp, 16
- bbci.l a0, 31, 1f // branch if called with call4
- bbsi.l a0, 30, 2f // branch if called with call12
- movi a7, 0 // called with call8
- retw
- 1: movi a11, 0 // called with call4
- 2: retw // if called with call12, everything already spilled
- // movi a15, 0 // trick to spill all but the direct caller
- // j 1f
- // // The entry instruction is magical in the assembler (gets auto-aligned)
- // // so we have to jump to it to avoid falling through the padding.
- // // We need entry/retw to know where to return.
- //1: entry sp, 16
- // retw
- # else
- # error "unrecognized address register file size"
- # endif
- #endif /* XCHAL_HAVE_WINDOWED */
- window_spill_common
- .endm // window_spill_function
- /*----------------------------------------------------------------------
- * window_spill_common
- *
- * Common code used by any number of invocations of the window_spill##
- * and window_spill_function macros.
- *
- * Must be instantiated exactly once within a given assembly unit,
- * within call/j range of and same section as window_spill##
- * macro invocations for that assembly unit.
- * (Is automatically instantiated by the window_spill_function macro.)
- */
- .macro window_spill_common
- #if XCHAL_HAVE_WINDOWED && (XCHAL_NUM_AREGS == 32 || XCHAL_NUM_AREGS == 64)
- .ifndef .L__wdwspill_defined
- # if XCHAL_NUM_AREGS >= 64
- .L__wdwspill_assist60:
- entry sp, 32
- call8 .L__wdwspill_assist52
- retw
- .L__wdwspill_assist56:
- entry sp, 16
- call4 .L__wdwspill_assist52
- retw
- .L__wdwspill_assist52:
- entry sp, 48
- call12 .L__wdwspill_assist40
- retw
- .L__wdwspill_assist40:
- entry sp, 48
- call12 .L__wdwspill_assist28
- retw
- # endif
- .L__wdwspill_assist28:
- entry sp, 48
- call12 .L__wdwspill_assist16
- retw
- .L__wdwspill_assist24:
- entry sp, 32
- call8 .L__wdwspill_assist16
- retw
- .L__wdwspill_assist20:
- entry sp, 16
- call4 .L__wdwspill_assist16
- retw
- .L__wdwspill_assist16:
- entry sp, 16
- movi a15, 0
- retw
- .set .L__wdwspill_defined, 1
- .endif
- #endif /* XCHAL_HAVE_WINDOWED with 32 or 64 aregs */
- .endm // window_spill_common
- /*----------------------------------------------------------------------
- * beqi32
- *
- * macro implements version of beqi for arbitrary 32-bit immidiate value
- *
- * beqi32 ax, ay, imm32, label
- *
- * Compares value in register ax with imm32 value and jumps to label if
- * equal. Clobberes register ay if needed
- *
- */
- .macro beqi32 ax, ay, imm, label
- .ifeq ((\imm-1) & ~7) // 1..8 ?
- beqi \ax, \imm, \label
- .else
- .ifeq (\imm+1) // -1 ?
- beqi \ax, \imm, \label
- .else
- .ifeq (\imm) // 0 ?
- beqz \ax, \label
- .else
- // We could also handle immediates 10,12,16,32,64,128,256
- // but it would be a long macro...
- movi \ay, \imm
- beq \ax, \ay, \label
- .endif
- .endif
- .endif
- .endm // beqi32
- #endif /*XTENSA_COREASM_H*/
|