Revision 5d240918e6813b5c050eeff0c06480ee29e66df9 authored by Linus Torvalds on 28 November 2005, 23:03:28 UTC, committed by Linus Torvalds on 28 November 2005, 23:03:28 UTC
2 parent s cba2fa1 + cb3592b
Raw File
coreasm.h
#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*/

back to top