Line data Source code
1 0 : /**
2 : * Copyright (c) 2024 NextSilicon
3 : * SPDX-License-Identifier: Apache-2.0
4 : */
5 :
6 : #ifndef ZEPHYR_INCLUDE_ARCH_RISCV_ATOMIC_H_
7 : #define ZEPHYR_INCLUDE_ARCH_RISCV_ATOMIC_H_
8 :
9 : #ifdef __cplusplus
10 : extern "C" {
11 : #endif
12 :
13 : /* The standard RISC-V atomic-instruction extension, "A", specifies
14 : * the number of instructions that atomically read-modify-write memory,
15 : * which RISC-V harts should support in order to synchronise harts
16 : * running in the same memory space. This is the subset of RISC-V
17 : * atomic-instructions not present in atomic_builtin.h file.
18 : */
19 :
20 : #ifdef CONFIG_64BIT
21 : static ALWAYS_INLINE atomic_val_t atomic_swap(const atomic_t *target, atomic_val_t newval)
22 : {
23 : atomic_val_t ret;
24 :
25 : __asm__ volatile("amoswap.d.aq %0, %1, %2"
26 : : "=r"(ret)
27 : : "r"(newval), "A"(*target)
28 : : "memory");
29 :
30 : return ret;
31 : }
32 :
33 : static ALWAYS_INLINE atomic_val_t atomic_max(atomic_t *target, atomic_val_t value)
34 : {
35 : atomic_val_t ret;
36 :
37 : __asm__ volatile("amomax.d.aq %0, %1, %2"
38 : : "=r"(ret)
39 : : "r"(value), "A"(*target)
40 : : "memory");
41 :
42 : return ret;
43 : }
44 :
45 : static ALWAYS_INLINE atomic_val_t atomic_min(atomic_t *target, atomic_val_t value)
46 : {
47 : atomic_val_t ret;
48 :
49 : __asm__ volatile("amomin.d.aq %0, %1, %2"
50 : : "=r"(ret)
51 : : "r"(value), "A"(*target)
52 : : "memory");
53 :
54 : return ret;
55 : }
56 :
57 : static ALWAYS_INLINE atomic_val_t atomic_maxu(unsigned long *target, unsigned long value)
58 : {
59 : unsigned long ret;
60 :
61 : __asm__ volatile("amomaxu.d.aq %0, %1, %2"
62 : : "=r"(ret)
63 : : "r"(value), "A"(*target)
64 : : "memory");
65 :
66 : return ret;
67 : }
68 :
69 : static ALWAYS_INLINE atomic_val_t atomic_minu(unsigned long *target, unsigned long value)
70 : {
71 : unsigned long ret;
72 :
73 : __asm__ volatile("amominu.d.aq %0, %1, %2"
74 : : "=r"(ret)
75 : : "r"(value), "A"(*target)
76 : : "memory");
77 :
78 : return ret;
79 : }
80 :
81 : #else
82 :
83 1 : static ALWAYS_INLINE atomic_val_t atomic_swap(const atomic_t *target, atomic_val_t newval)
84 : {
85 : atomic_val_t ret;
86 :
87 : __asm__ volatile("amoswap.w.aq %0, %1, %2"
88 : : "=r"(ret)
89 : : "r"(newval), "A"(*target)
90 : : "memory");
91 :
92 : return ret;
93 : }
94 :
95 0 : static ALWAYS_INLINE atomic_val_t atomic_max(atomic_t *target, atomic_val_t value)
96 : {
97 : atomic_val_t ret;
98 :
99 : __asm__ volatile("amomax.w.aq %0, %1, %2"
100 : : "=r"(ret)
101 : : "r"(value), "A"(*target)
102 : : "memory");
103 :
104 : return ret;
105 : }
106 :
107 0 : static ALWAYS_INLINE atomic_val_t atomic_min(atomic_t *target, atomic_val_t value)
108 : {
109 : atomic_val_t ret;
110 :
111 : __asm__ volatile("amomin.w.aq %0, %1, %2"
112 : : "=r"(ret)
113 : : "r"(value), "A"(*target)
114 : : "memory");
115 :
116 : return ret;
117 : }
118 :
119 0 : static ALWAYS_INLINE unsigned long atomic_maxu(unsigned long *target, unsigned long value)
120 : {
121 : unsigned long ret;
122 :
123 : __asm__ volatile("amomaxu.w.aq %0, %1, %2"
124 : : "=r"(ret)
125 : : "r"(value), "A"(*target)
126 : : "memory");
127 :
128 : return ret;
129 : }
130 :
131 0 : static ALWAYS_INLINE unsigned long atomic_minu(unsigned long *target, unsigned long value)
132 : {
133 : unsigned long ret;
134 :
135 : __asm__ volatile("amominu.w.aq %0, %1, %2"
136 : : "=r"(ret)
137 : : "r"(value), "A"(*target)
138 : : "memory");
139 :
140 : return ret;
141 : }
142 :
143 : #endif /* CONFIG_64BIT */
144 :
145 : #ifdef __cplusplus
146 : }
147 : #endif
148 :
149 : #endif /* ZEPHYR_INCLUDE_ARCH_RISCV_ATOMIC_H_ */
|