-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathxtutils.h
More file actions
98 lines (87 loc) · 2.98 KB
/
xtutils.h
File metadata and controls
98 lines (87 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
* Copyright 2024 SZIGETI János
*
* This file is part of Bilis ESP32 Basic, which is released under GNU General Public License.version 3.
* See LICENSE or <https://www.gnu.org/licenses/> for full license details.
*/
#ifndef XTUTILS_H
#define XTUTILS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include "esp_attr.h"
// ============== Defines ==============
#define XCHAL_HAVE_S32C1I 1
#define SOC_CPU_CORES_NUM 2
// ============== Implementation ==============
// -------------- Interface functions --------------
#ifdef __XTENSA__
/* Taken from https://github.com/espressif/esp-idf/blob/master/components/xtensa/include/xt_utils.h
* which is released under SPDX-License-Identifier: Apache-2.0 */
FORCE_INLINE_ATTR bool xt_utils_compare_and_set(volatile uint32_t *addr, uint32_t compare_value, uint32_t new_value) {
#if XCHAL_HAVE_S32C1I
#ifdef __clang_analyzer__
//Teach clang-tidy that "addr" cannot be const as it can be updated by S32C1I instruction
volatile uint32_t temp;
temp = *addr;
*addr = temp;
#endif
// Atomic compare and set using S32C1I instruction
uint32_t old_value = new_value;
__asm__ __volatile__ (
"WSR %2, SCOMPARE1 \n"
"S32C1I %0, %1, 0 \n"
: "=r"(old_value)
: "r"(addr), "r"(compare_value), "0"(old_value)
);
return (old_value == compare_value);
#else // XCHAL_HAVE_S32C1I
// Single core target has no atomic CAS instruction. We can achieve atomicity by disabling interrupts
uint32_t intr_level;
__asm__ __volatile__ ("rsil %0, " XTSTR(XCHAL_EXCM_LEVEL) "\n"
: "=r"(intr_level));
// Compare and set
uint32_t old_value;
old_value = *addr;
if (old_value == compare_value) {
*addr = new_value;
}
// Restore interrupts
__asm__ __volatile__ ("memw \n"
"wsr %0, ps\n"
::"r"(intr_level));
return (old_value == compare_value);
#endif // XCHAL_HAVE_S32C1I
}
/* Taken from https://github.com/espressif/esp-idf/blob/master/components/xtensa/include/xt_utils.h
* which is released under SPDX-License-Identifier: Apache-2.0 */
FORCE_INLINE_ATTR __attribute__ ((pure)) uint32_t xt_utils_get_core_id(void) {
/*
Note: We depend on SOC_CPU_CORES_NUM instead of XCHAL_HAVE_PRID as some single Xtensa targets (such as ESP32-S2) have
the PRID register even though they are single core.
*/
#if SOC_CPU_CORES_NUM > 1
// Read and extract bit 13 of special register PRID
uint32_t id;
__asm__ __volatile__ (
"rsr.prid %0\n"
"extui %0,%0,13,1"
: "=r"(id));
return id;
#else
return 0;
#endif // SOC_CPU_CORES_NUM > 1
}
#else
FORCE_INLINE_ATTR bool xt_utils_compare_and_set(volatile uint32_t *addr, uint32_t compare_value, uint32_t new_value) {
return true;
}
FORCE_INLINE_ATTR __attribute__ ((pure)) uint32_t xt_utils_get_core_id(void) {
return 0U;
}
#endif // __XTENSA__
#ifdef __cplusplus
}
#endif
#endif /* XTUTILS_H */