mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
339 lines
6.6 KiB
339 lines
6.6 KiB
/* |
|
* include/asm-xtensa/asmmacro.h |
|
* |
|
* 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) 2005 Tensilica Inc. |
|
*/ |
|
|
|
#ifndef _XTENSA_ASMMACRO_H |
|
#define _XTENSA_ASMMACRO_H |
|
|
|
#include <asm/core.h> |
|
|
|
/* |
|
* Some little helpers for loops. Use zero-overhead-loops |
|
* where applicable and if supported by the processor. |
|
* |
|
* __loopi ar, at, size, inc |
|
* ar register initialized with the start address |
|
* at scratch register used by macro |
|
* size size immediate value |
|
* inc increment |
|
* |
|
* __loops ar, as, at, inc_log2[, mask_log2][, cond][, ncond] |
|
* ar register initialized with the start address |
|
* as register initialized with the size |
|
* at scratch register use by macro |
|
* inc_log2 increment [in log2] |
|
* mask_log2 mask [in log2] |
|
* cond true condition (used in loop'cond') |
|
* ncond false condition (used in b'ncond') |
|
* |
|
* __loop as |
|
* restart loop. 'as' register must not have been modified! |
|
* |
|
* __endla ar, as, incr |
|
* ar start address (modified) |
|
* as scratch register used by __loops/__loopi macros or |
|
* end address used by __loopt macro |
|
* inc increment |
|
*/ |
|
|
|
/* |
|
* loop for given size as immediate |
|
*/ |
|
|
|
.macro __loopi ar, at, size, incr |
|
|
|
#if XCHAL_HAVE_LOOPS |
|
movi \at, ((\size + \incr - 1) / (\incr)) |
|
loop \at, 99f |
|
#else |
|
addi \at, \ar, \size |
|
98: |
|
#endif |
|
|
|
.endm |
|
|
|
/* |
|
* loop for given size in register |
|
*/ |
|
|
|
.macro __loops ar, as, at, incr_log2, mask_log2, cond, ncond |
|
|
|
#if XCHAL_HAVE_LOOPS |
|
.ifgt \incr_log2 - 1 |
|
addi \at, \as, (1 << \incr_log2) - 1 |
|
.ifnc \mask_log2, |
|
extui \at, \at, \incr_log2, \mask_log2 |
|
.else |
|
srli \at, \at, \incr_log2 |
|
.endif |
|
.endif |
|
loop\cond \at, 99f |
|
#else |
|
.ifnc \mask_log2, |
|
extui \at, \as, \incr_log2, \mask_log2 |
|
.else |
|
.ifnc \ncond, |
|
srli \at, \as, \incr_log2 |
|
.endif |
|
.endif |
|
.ifnc \ncond, |
|
b\ncond \at, 99f |
|
|
|
.endif |
|
.ifnc \mask_log2, |
|
slli \at, \at, \incr_log2 |
|
add \at, \ar, \at |
|
.else |
|
add \at, \ar, \as |
|
.endif |
|
#endif |
|
98: |
|
|
|
.endm |
|
|
|
/* |
|
* loop from ar to as |
|
*/ |
|
|
|
.macro __loopt ar, as, at, incr_log2 |
|
|
|
#if XCHAL_HAVE_LOOPS |
|
sub \at, \as, \ar |
|
.ifgt \incr_log2 - 1 |
|
addi \at, \at, (1 << \incr_log2) - 1 |
|
srli \at, \at, \incr_log2 |
|
.endif |
|
loop \at, 99f |
|
#else |
|
98: |
|
#endif |
|
|
|
.endm |
|
|
|
/* |
|
* restart loop. registers must be unchanged |
|
*/ |
|
|
|
.macro __loop as |
|
|
|
#if XCHAL_HAVE_LOOPS |
|
loop \as, 99f |
|
#else |
|
98: |
|
#endif |
|
|
|
.endm |
|
|
|
/* |
|
* end of loop with no increment of the address. |
|
*/ |
|
|
|
.macro __endl ar, as |
|
#if !XCHAL_HAVE_LOOPS |
|
bltu \ar, \as, 98b |
|
#endif |
|
99: |
|
.endm |
|
|
|
/* |
|
* end of loop with increment of the address. |
|
*/ |
|
|
|
.macro __endla ar, as, incr |
|
addi \ar, \ar, \incr |
|
__endl \ar \as |
|
.endm |
|
|
|
/* Load or store instructions that may cause exceptions use the EX macro. */ |
|
|
|
#define EX(handler) \ |
|
.section __ex_table, "a"; \ |
|
.word 97f, handler; \ |
|
.previous \ |
|
97: |
|
|
|
|
|
/* |
|
* Extract unaligned word that is split between two registers w0 and w1 |
|
* into r regardless of machine endianness. SAR must be loaded with the |
|
* starting bit of the word (see __ssa8). |
|
*/ |
|
|
|
.macro __src_b r, w0, w1 |
|
#ifdef __XTENSA_EB__ |
|
src \r, \w0, \w1 |
|
#else |
|
src \r, \w1, \w0 |
|
#endif |
|
.endm |
|
|
|
/* |
|
* Load 2 lowest address bits of r into SAR for __src_b to extract unaligned |
|
* word starting at r from two registers loaded from consecutive aligned |
|
* addresses covering r regardless of machine endianness. |
|
* |
|
* r 0 1 2 3 |
|
* LE SAR 0 8 16 24 |
|
* BE SAR 32 24 16 8 |
|
*/ |
|
|
|
.macro __ssa8 r |
|
#ifdef __XTENSA_EB__ |
|
ssa8b \r |
|
#else |
|
ssa8l \r |
|
#endif |
|
.endm |
|
|
|
.macro do_nsau cnt, val, tmp, a |
|
#if XCHAL_HAVE_NSA |
|
nsau \cnt, \val |
|
#else |
|
mov \a, \val |
|
movi \cnt, 0 |
|
extui \tmp, \a, 16, 16 |
|
bnez \tmp, 0f |
|
movi \cnt, 16 |
|
slli \a, \a, 16 |
|
0: |
|
extui \tmp, \a, 24, 8 |
|
bnez \tmp, 1f |
|
addi \cnt, \cnt, 8 |
|
slli \a, \a, 8 |
|
1: |
|
movi \tmp, __nsau_data |
|
extui \a, \a, 24, 8 |
|
add \tmp, \tmp, \a |
|
l8ui \tmp, \tmp, 0 |
|
add \cnt, \cnt, \tmp |
|
#endif /* !XCHAL_HAVE_NSA */ |
|
.endm |
|
|
|
.macro do_abs dst, src, tmp |
|
#if XCHAL_HAVE_ABS |
|
abs \dst, \src |
|
#else |
|
neg \tmp, \src |
|
movgez \tmp, \src, \src |
|
mov \dst, \tmp |
|
#endif |
|
.endm |
|
|
|
#if defined(__XTENSA_WINDOWED_ABI__) |
|
|
|
/* Assembly instructions for windowed kernel ABI. */ |
|
#define KABI_W |
|
/* Assembly instructions for call0 kernel ABI (will be ignored). */ |
|
#define KABI_C0 # |
|
|
|
#define XTENSA_FRAME_SIZE_RESERVE 16 |
|
#define XTENSA_SPILL_STACK_RESERVE 32 |
|
|
|
#define abi_entry(frame_size) \ |
|
entry sp, (XTENSA_FRAME_SIZE_RESERVE + \ |
|
(((frame_size) + XTENSA_STACK_ALIGNMENT - 1) & \ |
|
-XTENSA_STACK_ALIGNMENT)) |
|
#define abi_entry_default abi_entry(0) |
|
|
|
#define abi_ret(frame_size) retw |
|
#define abi_ret_default retw |
|
|
|
/* direct call */ |
|
#define abi_call call4 |
|
/* indirect call */ |
|
#define abi_callx callx4 |
|
/* outgoing call argument registers */ |
|
#define abi_arg0 a6 |
|
#define abi_arg1 a7 |
|
#define abi_arg2 a8 |
|
#define abi_arg3 a9 |
|
#define abi_arg4 a10 |
|
#define abi_arg5 a11 |
|
/* return value */ |
|
#define abi_rv a6 |
|
/* registers preserved across call */ |
|
#define abi_saved0 a2 |
|
#define abi_saved1 a3 |
|
|
|
/* none of the above */ |
|
#define abi_tmp0 a4 |
|
#define abi_tmp1 a5 |
|
|
|
#elif defined(__XTENSA_CALL0_ABI__) |
|
|
|
/* Assembly instructions for windowed kernel ABI (will be ignored). */ |
|
#define KABI_W # |
|
/* Assembly instructions for call0 kernel ABI. */ |
|
#define KABI_C0 |
|
|
|
#define XTENSA_SPILL_STACK_RESERVE 0 |
|
|
|
#define abi_entry(frame_size) __abi_entry (frame_size) |
|
|
|
.macro __abi_entry frame_size |
|
.ifgt \frame_size |
|
addi sp, sp, -(((\frame_size) + XTENSA_STACK_ALIGNMENT - 1) & \ |
|
-XTENSA_STACK_ALIGNMENT) |
|
.endif |
|
.endm |
|
|
|
#define abi_entry_default |
|
|
|
#define abi_ret(frame_size) __abi_ret (frame_size) |
|
|
|
.macro __abi_ret frame_size |
|
.ifgt \frame_size |
|
addi sp, sp, (((\frame_size) + XTENSA_STACK_ALIGNMENT - 1) & \ |
|
-XTENSA_STACK_ALIGNMENT) |
|
.endif |
|
ret |
|
.endm |
|
|
|
#define abi_ret_default ret |
|
|
|
/* direct call */ |
|
#define abi_call call0 |
|
/* indirect call */ |
|
#define abi_callx callx0 |
|
/* outgoing call argument registers */ |
|
#define abi_arg0 a2 |
|
#define abi_arg1 a3 |
|
#define abi_arg2 a4 |
|
#define abi_arg3 a5 |
|
#define abi_arg4 a6 |
|
#define abi_arg5 a7 |
|
/* return value */ |
|
#define abi_rv a2 |
|
/* registers preserved across call */ |
|
#define abi_saved0 a12 |
|
#define abi_saved1 a13 |
|
|
|
/* none of the above */ |
|
#define abi_tmp0 a8 |
|
#define abi_tmp1 a9 |
|
|
|
#else |
|
#error Unsupported Xtensa ABI |
|
#endif |
|
|
|
#if defined(USER_SUPPORT_WINDOWED) |
|
/* Assembly instructions for windowed user ABI. */ |
|
#define UABI_W |
|
/* Assembly instructions for call0 user ABI (will be ignored). */ |
|
#define UABI_C0 # |
|
#else |
|
/* Assembly instructions for windowed user ABI (will be ignored). */ |
|
#define UABI_W # |
|
/* Assembly instructions for call0 user ABI. */ |
|
#define UABI_C0 |
|
#endif |
|
|
|
#define __XTENSA_HANDLER .section ".exception.text", "ax" |
|
|
|
#endif /* _XTENSA_ASMMACRO_H */
|
|
|