162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * include/asm-xtensa/asmmacro.h
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
562306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
662306a36Sopenharmony_ci * for more details.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (C) 2005 Tensilica Inc.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#ifndef _XTENSA_ASMMACRO_H
1262306a36Sopenharmony_ci#define _XTENSA_ASMMACRO_H
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <asm-generic/export.h>
1562306a36Sopenharmony_ci#include <asm/core.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * Some little helpers for loops. Use zero-overhead-loops
1962306a36Sopenharmony_ci * where applicable and if supported by the processor.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * __loopi ar, at, size, inc
2262306a36Sopenharmony_ci *         ar	register initialized with the start address
2362306a36Sopenharmony_ci *	   at	scratch register used by macro
2462306a36Sopenharmony_ci *	   size	size immediate value
2562306a36Sopenharmony_ci *	   inc	increment
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * __loops ar, as, at, inc_log2[, mask_log2][, cond][, ncond]
2862306a36Sopenharmony_ci *	   ar	register initialized with the start address
2962306a36Sopenharmony_ci *	   as	register initialized with the size
3062306a36Sopenharmony_ci *	   at	scratch register use by macro
3162306a36Sopenharmony_ci *	   inc_log2	increment [in log2]
3262306a36Sopenharmony_ci *	   mask_log2	mask [in log2]
3362306a36Sopenharmony_ci *	   cond		true condition (used in loop'cond')
3462306a36Sopenharmony_ci *	   ncond	false condition (used in b'ncond')
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * __loop  as
3762306a36Sopenharmony_ci *	   restart loop. 'as' register must not have been modified!
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci * __endla ar, as, incr
4062306a36Sopenharmony_ci *	   ar	start address (modified)
4162306a36Sopenharmony_ci *	   as	scratch register used by __loops/__loopi macros or
4262306a36Sopenharmony_ci *		end address used by __loopt macro
4362306a36Sopenharmony_ci *	   inc	increment
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/*
4762306a36Sopenharmony_ci * loop for given size as immediate
4862306a36Sopenharmony_ci */
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	.macro	__loopi ar, at, size, incr
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#if XCHAL_HAVE_LOOPS
5362306a36Sopenharmony_ci		movi	\at, ((\size + \incr - 1) / (\incr))
5462306a36Sopenharmony_ci		loop	\at, 99f
5562306a36Sopenharmony_ci#else
5662306a36Sopenharmony_ci		addi	\at, \ar, \size
5762306a36Sopenharmony_ci		98:
5862306a36Sopenharmony_ci#endif
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	.endm
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/*
6362306a36Sopenharmony_ci * loop for given size in register
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	.macro	__loops	ar, as, at, incr_log2, mask_log2, cond, ncond
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#if XCHAL_HAVE_LOOPS
6962306a36Sopenharmony_ci		.ifgt \incr_log2 - 1
7062306a36Sopenharmony_ci			addi	\at, \as, (1 << \incr_log2) - 1
7162306a36Sopenharmony_ci			.ifnc \mask_log2,
7262306a36Sopenharmony_ci				extui	\at, \at, \incr_log2, \mask_log2
7362306a36Sopenharmony_ci			.else
7462306a36Sopenharmony_ci				srli	\at, \at, \incr_log2
7562306a36Sopenharmony_ci			.endif
7662306a36Sopenharmony_ci		.endif
7762306a36Sopenharmony_ci		loop\cond	\at, 99f
7862306a36Sopenharmony_ci#else
7962306a36Sopenharmony_ci		.ifnc \mask_log2,
8062306a36Sopenharmony_ci			extui	\at, \as, \incr_log2, \mask_log2
8162306a36Sopenharmony_ci		.else
8262306a36Sopenharmony_ci			.ifnc \ncond,
8362306a36Sopenharmony_ci				srli	\at, \as, \incr_log2
8462306a36Sopenharmony_ci			.endif
8562306a36Sopenharmony_ci		.endif
8662306a36Sopenharmony_ci		.ifnc \ncond,
8762306a36Sopenharmony_ci			b\ncond	\at, 99f
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci		.endif
9062306a36Sopenharmony_ci		.ifnc \mask_log2,
9162306a36Sopenharmony_ci			slli	\at, \at, \incr_log2
9262306a36Sopenharmony_ci			add	\at, \ar, \at
9362306a36Sopenharmony_ci		.else
9462306a36Sopenharmony_ci			add	\at, \ar, \as
9562306a36Sopenharmony_ci		.endif
9662306a36Sopenharmony_ci#endif
9762306a36Sopenharmony_ci		98:
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	.endm
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/*
10262306a36Sopenharmony_ci * loop from ar to as
10362306a36Sopenharmony_ci */
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	.macro	__loopt	ar, as, at, incr_log2
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#if XCHAL_HAVE_LOOPS
10862306a36Sopenharmony_ci		sub	\at, \as, \ar
10962306a36Sopenharmony_ci		.ifgt	\incr_log2 - 1
11062306a36Sopenharmony_ci			addi	\at, \at, (1 << \incr_log2) - 1
11162306a36Sopenharmony_ci			srli	\at, \at, \incr_log2
11262306a36Sopenharmony_ci		.endif
11362306a36Sopenharmony_ci		loop	\at, 99f
11462306a36Sopenharmony_ci#else
11562306a36Sopenharmony_ci		98:
11662306a36Sopenharmony_ci#endif
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	.endm
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/*
12162306a36Sopenharmony_ci * restart loop. registers must be unchanged
12262306a36Sopenharmony_ci */
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	.macro	__loop	as
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci#if XCHAL_HAVE_LOOPS
12762306a36Sopenharmony_ci		loop	\as, 99f
12862306a36Sopenharmony_ci#else
12962306a36Sopenharmony_ci		98:
13062306a36Sopenharmony_ci#endif
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	.endm
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/*
13562306a36Sopenharmony_ci * end of loop with no increment of the address.
13662306a36Sopenharmony_ci */
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	.macro	__endl	ar, as
13962306a36Sopenharmony_ci#if !XCHAL_HAVE_LOOPS
14062306a36Sopenharmony_ci		bltu	\ar, \as, 98b
14162306a36Sopenharmony_ci#endif
14262306a36Sopenharmony_ci		99:
14362306a36Sopenharmony_ci	.endm
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/*
14662306a36Sopenharmony_ci * end of loop with increment of the address.
14762306a36Sopenharmony_ci */
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	.macro	__endla	ar, as, incr
15062306a36Sopenharmony_ci		addi	\ar, \ar, \incr
15162306a36Sopenharmony_ci		__endl	\ar \as
15262306a36Sopenharmony_ci	.endm
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/* Load or store instructions that may cause exceptions use the EX macro. */
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci#define EX(handler)				\
15762306a36Sopenharmony_ci	.section __ex_table, "a";		\
15862306a36Sopenharmony_ci	.word	97f, handler;			\
15962306a36Sopenharmony_ci	.previous				\
16062306a36Sopenharmony_ci97:
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/*
16462306a36Sopenharmony_ci * Extract unaligned word that is split between two registers w0 and w1
16562306a36Sopenharmony_ci * into r regardless of machine endianness. SAR must be loaded with the
16662306a36Sopenharmony_ci * starting bit of the word (see __ssa8).
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	.macro __src_b	r, w0, w1
17062306a36Sopenharmony_ci#ifdef __XTENSA_EB__
17162306a36Sopenharmony_ci		src	\r, \w0, \w1
17262306a36Sopenharmony_ci#else
17362306a36Sopenharmony_ci		src	\r, \w1, \w0
17462306a36Sopenharmony_ci#endif
17562306a36Sopenharmony_ci	.endm
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci/*
17862306a36Sopenharmony_ci * Load 2 lowest address bits of r into SAR for __src_b to extract unaligned
17962306a36Sopenharmony_ci * word starting at r from two registers loaded from consecutive aligned
18062306a36Sopenharmony_ci * addresses covering r regardless of machine endianness.
18162306a36Sopenharmony_ci *
18262306a36Sopenharmony_ci *      r   0   1   2   3
18362306a36Sopenharmony_ci * LE SAR   0   8  16  24
18462306a36Sopenharmony_ci * BE SAR  32  24  16   8
18562306a36Sopenharmony_ci */
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	.macro __ssa8	r
18862306a36Sopenharmony_ci#ifdef __XTENSA_EB__
18962306a36Sopenharmony_ci		ssa8b	\r
19062306a36Sopenharmony_ci#else
19162306a36Sopenharmony_ci		ssa8l	\r
19262306a36Sopenharmony_ci#endif
19362306a36Sopenharmony_ci	.endm
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	.macro	do_nsau cnt, val, tmp, a
19662306a36Sopenharmony_ci#if XCHAL_HAVE_NSA
19762306a36Sopenharmony_ci	nsau	\cnt, \val
19862306a36Sopenharmony_ci#else
19962306a36Sopenharmony_ci	mov	\a, \val
20062306a36Sopenharmony_ci	movi	\cnt, 0
20162306a36Sopenharmony_ci	extui	\tmp, \a, 16, 16
20262306a36Sopenharmony_ci	bnez	\tmp, 0f
20362306a36Sopenharmony_ci	movi	\cnt, 16
20462306a36Sopenharmony_ci	slli	\a, \a, 16
20562306a36Sopenharmony_ci0:
20662306a36Sopenharmony_ci	extui	\tmp, \a, 24, 8
20762306a36Sopenharmony_ci	bnez	\tmp, 1f
20862306a36Sopenharmony_ci	addi	\cnt, \cnt, 8
20962306a36Sopenharmony_ci	slli	\a, \a, 8
21062306a36Sopenharmony_ci1:
21162306a36Sopenharmony_ci	movi	\tmp, __nsau_data
21262306a36Sopenharmony_ci	extui	\a, \a, 24, 8
21362306a36Sopenharmony_ci	add	\tmp, \tmp, \a
21462306a36Sopenharmony_ci	l8ui	\tmp, \tmp, 0
21562306a36Sopenharmony_ci	add	\cnt, \cnt, \tmp
21662306a36Sopenharmony_ci#endif /* !XCHAL_HAVE_NSA */
21762306a36Sopenharmony_ci	.endm
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	.macro	do_abs dst, src, tmp
22062306a36Sopenharmony_ci#if XCHAL_HAVE_ABS
22162306a36Sopenharmony_ci	abs	\dst, \src
22262306a36Sopenharmony_ci#else
22362306a36Sopenharmony_ci	neg	\tmp, \src
22462306a36Sopenharmony_ci	movgez	\tmp, \src, \src
22562306a36Sopenharmony_ci	mov	\dst, \tmp
22662306a36Sopenharmony_ci#endif
22762306a36Sopenharmony_ci	.endm
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci#if defined(__XTENSA_WINDOWED_ABI__)
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci/* Assembly instructions for windowed kernel ABI. */
23262306a36Sopenharmony_ci#define KABI_W
23362306a36Sopenharmony_ci/* Assembly instructions for call0 kernel ABI (will be ignored). */
23462306a36Sopenharmony_ci#define KABI_C0 #
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci#define XTENSA_FRAME_SIZE_RESERVE	16
23762306a36Sopenharmony_ci#define XTENSA_SPILL_STACK_RESERVE	32
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci#define abi_entry(frame_size) \
24062306a36Sopenharmony_ci	entry sp, (XTENSA_FRAME_SIZE_RESERVE + \
24162306a36Sopenharmony_ci		   (((frame_size) + XTENSA_STACK_ALIGNMENT - 1) & \
24262306a36Sopenharmony_ci		    -XTENSA_STACK_ALIGNMENT))
24362306a36Sopenharmony_ci#define abi_entry_default abi_entry(0)
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci#define abi_ret(frame_size) retw
24662306a36Sopenharmony_ci#define abi_ret_default retw
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/* direct call */
24962306a36Sopenharmony_ci#define abi_call call4
25062306a36Sopenharmony_ci	/* indirect call */
25162306a36Sopenharmony_ci#define abi_callx callx4
25262306a36Sopenharmony_ci	/* outgoing call argument registers */
25362306a36Sopenharmony_ci#define abi_arg0 a6
25462306a36Sopenharmony_ci#define abi_arg1 a7
25562306a36Sopenharmony_ci#define abi_arg2 a8
25662306a36Sopenharmony_ci#define abi_arg3 a9
25762306a36Sopenharmony_ci#define abi_arg4 a10
25862306a36Sopenharmony_ci#define abi_arg5 a11
25962306a36Sopenharmony_ci	/* return value */
26062306a36Sopenharmony_ci#define abi_rv a6
26162306a36Sopenharmony_ci	/* registers preserved across call */
26262306a36Sopenharmony_ci#define abi_saved0 a2
26362306a36Sopenharmony_ci#define abi_saved1 a3
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/* none of the above */
26662306a36Sopenharmony_ci#define abi_tmp0 a4
26762306a36Sopenharmony_ci#define abi_tmp1 a5
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci#elif defined(__XTENSA_CALL0_ABI__)
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/* Assembly instructions for windowed kernel ABI (will be ignored). */
27262306a36Sopenharmony_ci#define KABI_W #
27362306a36Sopenharmony_ci/* Assembly instructions for call0 kernel ABI. */
27462306a36Sopenharmony_ci#define KABI_C0
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci#define XTENSA_SPILL_STACK_RESERVE	0
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci#define abi_entry(frame_size) __abi_entry (frame_size)
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	.macro	__abi_entry frame_size
28162306a36Sopenharmony_ci	.ifgt \frame_size
28262306a36Sopenharmony_ci	addi sp, sp, -(((\frame_size) + XTENSA_STACK_ALIGNMENT - 1) & \
28362306a36Sopenharmony_ci		       -XTENSA_STACK_ALIGNMENT)
28462306a36Sopenharmony_ci	.endif
28562306a36Sopenharmony_ci	.endm
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci#define abi_entry_default
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci#define abi_ret(frame_size) __abi_ret (frame_size)
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	.macro	__abi_ret frame_size
29262306a36Sopenharmony_ci	.ifgt \frame_size
29362306a36Sopenharmony_ci	addi sp, sp, (((\frame_size) + XTENSA_STACK_ALIGNMENT - 1) & \
29462306a36Sopenharmony_ci		      -XTENSA_STACK_ALIGNMENT)
29562306a36Sopenharmony_ci	.endif
29662306a36Sopenharmony_ci	ret
29762306a36Sopenharmony_ci	.endm
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci#define abi_ret_default ret
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	/* direct call */
30262306a36Sopenharmony_ci#define abi_call call0
30362306a36Sopenharmony_ci	/* indirect call */
30462306a36Sopenharmony_ci#define abi_callx callx0
30562306a36Sopenharmony_ci	/* outgoing call argument registers */
30662306a36Sopenharmony_ci#define abi_arg0 a2
30762306a36Sopenharmony_ci#define abi_arg1 a3
30862306a36Sopenharmony_ci#define abi_arg2 a4
30962306a36Sopenharmony_ci#define abi_arg3 a5
31062306a36Sopenharmony_ci#define abi_arg4 a6
31162306a36Sopenharmony_ci#define abi_arg5 a7
31262306a36Sopenharmony_ci	/* return value */
31362306a36Sopenharmony_ci#define abi_rv a2
31462306a36Sopenharmony_ci	/* registers preserved across call */
31562306a36Sopenharmony_ci#define abi_saved0 a12
31662306a36Sopenharmony_ci#define abi_saved1 a13
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	/* none of the above */
31962306a36Sopenharmony_ci#define abi_tmp0 a8
32062306a36Sopenharmony_ci#define abi_tmp1 a9
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci#else
32362306a36Sopenharmony_ci#error Unsupported Xtensa ABI
32462306a36Sopenharmony_ci#endif
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci#if defined(USER_SUPPORT_WINDOWED)
32762306a36Sopenharmony_ci/* Assembly instructions for windowed user ABI. */
32862306a36Sopenharmony_ci#define UABI_W
32962306a36Sopenharmony_ci/* Assembly instructions for call0 user ABI (will be ignored). */
33062306a36Sopenharmony_ci#define UABI_C0 #
33162306a36Sopenharmony_ci#else
33262306a36Sopenharmony_ci/* Assembly instructions for windowed user ABI (will be ignored). */
33362306a36Sopenharmony_ci#define UABI_W #
33462306a36Sopenharmony_ci/* Assembly instructions for call0 user ABI. */
33562306a36Sopenharmony_ci#define UABI_C0
33662306a36Sopenharmony_ci#endif
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci#define __XTENSA_HANDLER	.section ".exception.text", "ax"
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci#endif /* _XTENSA_ASMMACRO_H */
341