summaryrefslogtreecommitdiff
path: root/bsp/ESP/ESP32_C6/idf_port/src/rt_atomic_cas_stub.c
blob: 1f8016c66cd0d3033e165c5bea20fc7ef99c1b76 (plain)
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
#include <rtthread.h>

/*
 * spi_common.c claims a bus with
 *     atomic_compare_exchange_strong(&spi_periph_claimed[host], &expected, value)
 * on an _Atomic bool, and an ESP32-C6 core can only reserve a whole word, so
 * this gcc emits a call to the out-of-line helper instead of an lr/sc sequence.
 * The install has no __atomic_compare_exchange_1:
 *     riscv32-esp-elf/bin/../lib/gcc/riscv32-esp-elf/11.2.0/libgcc.a  ->  0 hits
 * and there is no libatomic.a next to it, so the name stays undefined at link
 * time. The prototype below is the one the compiler itself declares -- it
 * rejects any other spelling with -Wbuiltin-declaration-mismatch -- and it
 * matches what the call site really passes: the address of the object, the
 * address of the expected byte, the desired byte, and two memory orders. The
 * `weak` argument is not passed in a register at all (an atomic_compare_exchange
 * weak/strong pair compiles to the same five loads), which is why it is ignored
 * here; the helper's answer is always the strong one, so a weak CAS merely gets
 * one it did not ask for.
 *
 * Masking interrupts is enough for this SoC: it has one core, so the only other
 * writer of these bytes is an interrupt handler.
 */
_Bool __atomic_compare_exchange_1(volatile void *object,
                                  void *expected,
                                  unsigned char desired,
                                  _Bool weak,
                                  int success,
                                  int failure)
{
    volatile unsigned char *addr = (volatile unsigned char *)object;
    unsigned char *compare = (unsigned char *)expected;
    rt_base_t level;
    _Bool exchanged;

    (void)weak;
    (void)success;
    (void)failure;

    level = rt_hw_interrupt_disable();

    if (*addr == *compare)
    {
        *addr = desired;
        exchanged = 1;
    }
    else
    {
        *compare = *addr;
        exchanged = 0;
    }

    rt_hw_interrupt_enable(level);

    return exchanged;
}