1 /*
2  * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #pragma once
8 
9 #include "xtensa/xtruntime.h"
10 
11 #define RSR(reg, at)         __asm__ volatile ("rsr %0, %1" : "=r" (at) : "i" (reg))
12 #define WSR(reg, at)         __asm__ volatile ("wsr %0, %1" : : "r" (at), "i" (reg))
13 #define XSR(reg, at)         __asm__ volatile ("xsr %0, %1" : "+r" (at) : "i" (reg))
14 
15 #define RER(reg, at)         __asm__ volatile ("rer %0, %1" : "=r" (at) : "r" (reg))
16 
17 #define WITLB(at, as)        __asm__ volatile ("witlb  %0, %1; \n isync \n " : : "r" (at), "r" (as))
18 #define WDTLB(at, as)        __asm__ volatile ("wdtlb  %0, %1; \n dsync \n " : : "r" (at), "r" (as))
19 
20 #define EXTRA_SAVE_AREA_SIZE 32
21 #define BASE_SAVE_AREA_SIZE  16
22 #define SAVE_AREA_OFFSET (EXTRA_SAVE_AREA_SIZE + BASE_SAVE_AREA_SIZE)
23 #define BASE_AREA_SP_OFFSET  12
24 
25 /* The SET_STACK implements a setting a new stack pointer (sp or a1).
26  * to do this the need reset PS_WOE, reset WINDOWSTART, update SP, and return PS_WOE.
27  *
28  * In addition, if a windowOverflow8/12 happens the exception handler expects to be able to look at
29  * the previous frames stackpointer to find the extra save area. So this function will reserve space
30  * for this area as well as initialise the previous sp that points to it
31  *
32  * Note: It has 2 implementations one for using in assembler files (*.S) and one for using in C.
33  *
34  * C code prototype for SET_STACK:
35  *   uint32_t ps_reg;
36  *   uint32_t w_base;
37  *
38  *   uint32_t sp = (uint32_t)new_sp - SAVE_AREA_OFFSET; \
39     *(uint32_t*)(sp - 12) = (uint32_t)new_sp; \
40 
41  *   RSR(PS, ps_reg);
42  *   ps_reg &= ~(PS_WOE_MASK | PS_OWB_MASK | PS_CALLINC_MASK);
43  *   WSR(PS, ps_reg);
44  *
45  *   RSR(WINDOWBASE, w_base);
46  *   WSR(WINDOWSTART, (1 << w_base));
47  *
48  *   asm volatile ( "movi sp, "XTSTR( (SOC_DRAM_LOW + (SOC_DRAM_HIGH - SOC_DRAM_LOW) / 2) )"");
49  *
50  *   RSR(PS, ps_reg);
51  *   ps_reg |= (PS_WOE_MASK);
52  *   WSR(PS, ps_reg);
53 */
54 #ifdef __ASSEMBLER__
55     .macro SET_STACK  new_sp tmp1 tmp2
56     addi tmp1, new_sp, -SAVE_AREA_OFFSET
57     addi tmp2, tmp1, -BASE_AREA_SP_OFFSET
58     s32i new_sp, tmp2, 0
59     addi new_sp, tmp1, 0
60     rsr.ps \tmp1
61     movi \tmp2, ~(PS_WOE_MASK | PS_OWB_MASK | PS_CALLINC_MASK)
62     and \tmp1, \tmp1, \tmp2
63     wsr.ps \tmp1
64     rsync
65 
66     rsr.windowbase \tmp1
67     ssl	\tmp1
68     movi \tmp1, 1
69     sll	\tmp1, \tmp1
70     wsr.windowstart \tmp1
71     rsync
72 
73     mov sp, \new_sp
74 
75     rsr.ps \tmp1
76     movi \tmp2, (PS_WOE)
77     or \tmp1, \tmp1, \tmp2
78     wsr.ps \tmp1
79     rsync
80     .endm
81 #else
82 
83 #define SET_STACK(new_sp) \
84     do { \
85         uint32_t sp = (uint32_t)new_sp - SAVE_AREA_OFFSET; \
86         *(uint32_t*)(sp - BASE_AREA_SP_OFFSET) = (uint32_t)new_sp; \
87         const uint32_t mask = ~(PS_WOE_MASK | PS_OWB_MASK | PS_CALLINC_MASK); \
88         uint32_t tmp1 = 0, tmp2 = 0; \
89         __asm__ volatile ( \
90           "rsr.ps %1 \n"\
91           "and %1, %1, %3 \n"\
92           "wsr.ps %1 \n"\
93           "rsync \n"\
94           " \n"\
95           "rsr.windowbase %1 \n"\
96           "ssl	%1 \n"\
97           "movi %1, 1 \n"\
98           "sll	%1, %1 \n"\
99           "wsr.windowstart %1 \n"\
100           "rsync \n"\
101           " \n"\
102           "movi a0, 0\n" \
103           "mov sp, %0 \n"\
104           "rsr.ps %1 \n"\
105           " \n"\
106           "movi %2, " XTSTR( PS_WOE_MASK ) "\n"\
107           " \n"\
108           "or %1, %1, %2 \n"\
109           "wsr.ps %1 \n"\
110           "rsync \n"\
111           : "+r"(sp), "+r"(tmp1), "+r"(tmp2) : "r"(mask)); \
112     } while (0);
113 #endif // __ASSEMBLER__
114