Преглед изворни кода

newlib: implement 8/16-bit atomic operations for riscv

Alexey Lapshin пре 3 година
родитељ
комит
a32bbedcd9

+ 4 - 0
components/newlib/port/CMakeLists.txt

@@ -1 +1,5 @@
 target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/esp_time_impl.c")
+
+if(CONFIG_IDF_TARGET_ARCH_RISCV)
+    target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/riscv/port_stdatomic.S")
+endif()

+ 659 - 0
components/newlib/port/riscv/port_stdatomic.S

@@ -0,0 +1,659 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#if __riscv_atomic == 1
+
+.macro ALIGNED_PTR_2 ptr, offset
+    andi    \ptr, a0, -4         // aligned ptr
+    sub     \offset, a0, \ptr
+    slli    \offset, \offset, 3  // offset (in bits) between ptr and aligned ptr
+    li      t6, 24
+    bne     \offset, t6, 1f      // do atomic operation in case var is not splited between 2 words
+    lr.w    t2, (a0)             // invokes 'Load access fault!'
+1:
+.endm
+
+    .global __atomic_load_2
+    .type   __atomic_load_2, @function
+__atomic_load_2:
+    ALIGNED_PTR_2 t0, t1
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     t4, t2, t1
+    slli    a0, t4, 0x10
+    srli    a0, a0, 0x10
+    ret
+    .size   __atomic_load_2, . - __atomic_load_2
+
+
+    .global __atomic_store_2
+    .type   __atomic_store_2, @function
+__atomic_store_2:
+    ALIGNED_PTR_2 t0, t1
+    li      t6, 0xffff
+    sll     t6, t6, t1
+    not     t6, t6       // t6 - bitwise mask
+    sll     t5, a1, t1   // t5 - shifted new value to easy place into aligned memory
+1:                       // do not change registers (t0, t1, t5, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    and     t3, t2, t6   // t3 - masked aliged memory. Atomic variable part is zeroed here
+    or      t4, t5, t3   // t4 - combine desire half-word with half-word from origin aligned memory
+    sc.w    t3, t4, (t0) // t3 - atomic write result (0 - success)
+    bnez    t3, 1b
+    ret
+    .size   __atomic_store_2, . - __atomic_store_2
+
+
+    .global __atomic_exchange_2
+    .type   __atomic_exchange_2, @function
+__atomic_exchange_2:
+    ALIGNED_PTR_2 t0, t1
+    li      t6, 0xffff
+    sll     t6, t6, t1
+    not     t6, t6       // t6 - bitwise mask
+    sll     t5, a1, t1   // t5 - shifted new value to easy place into aligned memory
+1:                       // do not change registers (t0, t1, t5, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    and     t3, t2, t6   // t3 - masked aliged memory. Atomic variable part is zeroed here
+    or      t4, t5, t3   // t4 - combine desire half-word with half-word from origin aligned memory
+    sc.w    t3, t4, (t0) // t3 - atomic write result (0 - success)
+    bnez    t3, 1b
+    srl     t4, t2, t1
+    slli    a0, t4, 0x10
+    srli    a0, a0, 0x10
+    ret
+    .size   __atomic_exchange_2, . - __atomic_exchange_2
+
+
+    .global __atomic_compare_exchange_2
+    .type   __atomic_compare_exchange_2, @function
+__atomic_compare_exchange_2:
+    ALIGNED_PTR_2 t0, t1
+    li      t6, 0xffff0000
+    srl     t6, t6, t1   // t6 - bitwise mask (0xffff0000/0x0000ffff)
+    lhu     t5, (a1)
+    sll     t5, t5, t1   // t5 - shifted expect value to easy compare with aligned memory
+    sll     t4, a2, t1   // t4 - shifted desired value to easy place into aligned memory
+1:                       // do not change registers (t0, t1, t4, t5) after this label
+    not     t6, t6
+    lr.w    t2, (t0)     // t2 - load atomic
+    and     t3, t2, t6   // t3 - prepare half-word from aligned memory to compare with expected (t5)
+    bne     t3, t5, 2f
+    not     t6, t6
+    and     t2, t2, t6
+    or      t3, t4, t2   // t3 - combine desire half-word with half-word from origin aligned memory
+    sc.w    t2, t3, (t0) // t2 - atomic write result (0 - success)
+    bnez    t2, 1b
+    li      a0, 1
+    ret
+2:
+    srl     t3, t3, t1
+    sh      t3, (a1)     // store atomic value into expect variable
+    li      a0, 0
+    ret
+    .size   __atomic_compare_exchange_2, . - __atomic_compare_exchange_2
+
+
+    .global __atomic_fetch_or_2
+    .type   __atomic_fetch_or_2, @function
+__atomic_fetch_or_2:
+    ALIGNED_PTR_2 t0, t1
+    sll     t2, a1, t1   // t2 - shifted value half-word.
+    amoor.w t0, t2, (t0) // t0 - shifted value before atomic operation performed
+    srl     t0, t0, t1
+    slli    a0, t0, 0x10
+    srli    a0, a0, 0x10
+    ret
+    .size   __atomic_fetch_or_2, . - __atomic_fetch_or_2
+
+
+    .global __atomic_or_fetch_2
+    .type   __atomic_or_fetch_2, @function
+__atomic_or_fetch_2:
+    ALIGNED_PTR_2 t0, t1
+    sll     t2, a1, t1   // t2 - shifted value half-word.
+    amoor.w t0, t2, (t0) // t0 - shifted value before atomic operation performed
+    srl     t2, t2, t1
+    slli    a0, t2, 0x10
+    srli    a0, a0, 0x10
+    ret
+    .size   __atomic_or_fetch_2, . - __atomic_or_fetch_2
+
+
+    .global __atomic_fetch_xor_2
+    .type   __atomic_fetch_xor_2, @function
+__atomic_fetch_xor_2:
+    ALIGNED_PTR_2 t0, t1
+    sll     t2, a1, t1    // t2 - shifted value half-word.
+    amoxor.w t0, t2, (t0) // t0 - shifted value before atomic operation performed
+    srl     t0, t0, t1
+    slli    a0, t0, 0x10
+    srli    a0, a0, 0x10
+    ret
+    .size   __atomic_fetch_xor_2, . - __atomic_fetch_xor_2
+
+
+    .global __atomic_xor_fetch_2
+    .type   __atomic_xor_fetch_2, @function
+__atomic_xor_fetch_2:
+    ALIGNED_PTR_2 t0, t1
+    sll     t2, a1, t1    // t2 - shifted value half-word.
+    amoxor.w t0, t2, (t0) // t0 - shifted value before atomic operation performed
+    srl     t2, t2, t1
+    slli    a0, t2, 0x10
+    srli    a0, a0, 0x10
+    ret
+    .size   __atomic_xor_fetch_2, . - __atomic_xor_fetch_2
+
+
+    .global __atomic_fetch_and_2
+    .type   __atomic_fetch_and_2, @function
+__atomic_fetch_and_2:
+    ALIGNED_PTR_2 t0, t1
+    li      t6, 0xffff0000  // t6 - bitwise mask
+    srl     t6, t6, t1      // t6 - using to fill non-atomic bytes with 0xff in aligned memory
+    sll     t2, a1, t1      // t2 - shifted value half-word.
+    or      t2, t2, t6      // t2 - 0xXXXXffff or 0xffffXXXX where is value halfword
+    amoand.w   t0, t2, (t0) // t0 - shifted value before atomic operation performed
+    srl     t0, t0, t1
+    slli    a0, t0, 0x10
+    srli    a0, a0, 0x10
+    ret
+    .size   __atomic_fetch_and_2, . - __atomic_fetch_and_2
+
+
+    .global __atomic_and_fetch_2
+    .type   __atomic_and_fetch_2, @function
+__atomic_and_fetch_2:
+    ALIGNED_PTR_2 t0, t1
+    li      t6, 0xffff0000  // t6 - bitwise mask
+    srl     t6, t6, t1      // t6 - using to fill non-atomic bytes with 0xff in aligned memory
+    sll     t2, a1, t1      // t2 - shifted value half-word.
+    or      t2, t2, t6      // t2 - 0xXXXXffff or 0xffffXXXX where XXXX is value halfword
+    amoand.w   t0, t2, (t0) // t0 - shifted value before atomic operation performed
+    srl     t2, t2, t1
+    slli    a0, t2, 0x10
+    srli    a0, a0, 0x10
+    ret
+    .size   __atomic_and_fetch_2, . - __atomic_and_fetch_2
+
+
+    .global __atomic_fetch_nand_2
+    .type   __atomic_fetch_nand_2, @function
+__atomic_fetch_nand_2:
+    ALIGNED_PTR_2 t0, t1
+    li      t5, 0xffff
+    sll     t5, t5, t1   // t5 - bitwise mask
+    not     t6, t5       // t6 - bitwise mask
+1:                       // do not change registers (t0, t1, t5, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     t3, t2, t1
+    and     t3, t3, a1
+    not     t3, t3       // t3 - atomic value to write
+    sll     t3, t3, t1
+    and     t4, t2, t6   // t4 - masked aliged memory. Atomic variable part is zeroed here
+    or      t4, t4, t3   // t4 - combine desire byte-word with origin aligned memory
+    sc.w    t4, t4, (t0) // t3 - atomic write result (0 - success)
+    bnez    t4, 1b
+    srl     t4, t2, t1
+    slli    a0, t4, 0x10
+    srli    a0, a0, 0x10
+    ret
+    .size   __atomic_fetch_nand_2, . - __atomic_fetch_nand_2
+
+
+    .global __atomic_nand_fetch_2
+    .type   __atomic_nand_fetch_2, @function
+__atomic_nand_fetch_2:
+    ALIGNED_PTR_2 t0, t1
+    li      t5, 0xffff
+    sll     t5, t5, t1   // t5 - bitwise mask
+    not     t6, t5       // t6 - bitwise mask
+1:                       // do not change registers (t0, t1, t5, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     t3, t2, t1
+    and     t3, t3, a1
+    not     t3, t3       // t3 - atomic value to write
+    sll     t3, t3, t1
+    and     t4, t2, t6   // t4 - masked aliged memory. Atomic variable part is zeroed here
+    or      t4, t4, t3   // t4 - combine desire byte-word with origin aligned memory
+    sc.w    t4, t4, (t0) // t3 - atomic write result (0 - success)
+    bnez    t4, 1b
+    srl     t4, t2, t1
+    slli    a0, t3, 0x10
+    srli    a0, a0, 0x10
+    ret
+    .size   __atomic_nand_fetch_2, . - __atomic_nand_fetch_2
+
+
+    .global __atomic_fetch_sub_2
+    .type   __atomic_fetch_sub_2, @function
+__atomic_fetch_sub_2:
+    ALIGNED_PTR_2 t0, t1
+    li      t5, 0xffff   // t5 - bitwise mask
+    not     t6, t5
+    srl     t6, t6, t1   // t6 - bitwise mask
+1:                       // do not change registers (t0, t1, t5, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     a0, t2, t1
+    and     a0, a0, t5   // a0 - value in atomic before performing operation
+    sub     t3, a0, a1
+    and     t3, t3, t5   // t3 - value to be written to atomic
+    sll     t3, t3, t1
+    and     t2, t2, t6
+    or      t3, t3, t2   // t3 - value to be written into aligned memory
+    sc.w    t2, t3, (t0) // t2 - atomic write result (0 - success)
+    bnez    t2, 1b
+    ret
+    .size   __atomic_fetch_sub_2, . - __atomic_fetch_sub_2
+
+
+    .global __atomic_sub_fetch_2
+    .type   __atomic_sub_fetch_2, @function
+__atomic_sub_fetch_2:
+    ALIGNED_PTR_2 t0, t1
+    li      t5, 0xffff   // t5 - bitwise mask
+    not     t6, t5
+    srl     t6, t6, t1   // t6 - bitwise mask
+1:                       // do not change registers (t0, t1, t5, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     t4, t2, t1
+    and     t4, t4, t5
+    sub     t4, t4, a1
+    and     t4, t4, t5   // t4 - value to be written to atomic
+    sll     t4, t4, t1
+    and     t2, t2, t6
+    or      t4, t4, t2   // t4 - value to be written into aligned memory
+    sc.w    t2, t4, (t0) // t2 - atomic write result (0 - success)
+    bnez    t2, 1b
+    srl     t4, t4, t1
+    slli    a0, t4, 0x10
+    srli    a0, a0, 0x10
+    ret
+    .size   __atomic_sub_fetch_2, . - __atomic_sub_fetch_2
+
+
+    .global __atomic_fetch_add_2
+    .type   __atomic_fetch_add_2, @function
+__atomic_fetch_add_2:
+    ALIGNED_PTR_2 t0, t1
+    li      t5, 0xffff   // t5 - bitwise mask
+    not     t6, t5
+    srl     t6, t6, t1   // t6 - bitwise mask
+1:                       // do not change registers (t0, t1, t5, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     t4, t2, t1
+    and     t4, t4, t5   // t4 - half-word value in atomic before performing operation
+    add     t3, t4, a1
+    and     t4, t4, t5   // t3 - half-word value to be written to atomic
+    sll     t3, t3, t1
+    and     t2, t2, t6
+    or      t3, t3, t2   // t3 - value to be written into aligned memory
+    sc.w    t2, t3, (t0) // t2 - atomic write result (0 - success)
+    bnez    t2, 1b
+    slli    a0, t4, 0x10
+    srli    a0, a0, 0x10
+    ret
+    .size   __atomic_fetch_add_2, . - __atomic_fetch_add_2
+
+
+    .global __atomic_add_fetch_2
+    .type   __atomic_add_fetch_2, @function
+__atomic_add_fetch_2:
+    ALIGNED_PTR_2 t0, t1
+    li      t5, 0xffff   // t5 - bitwise mask
+    not     t6, t5
+    srl     t6, t6, t1   // t6 - bitwise mask
+1:                       // do not change registers (t0, t1, t5, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     t4, t2, t1
+    and     t4, t4, t5
+    add     t4, t4, a1
+    and     t4, t4, t5   // t4 - value to be written to atomic
+    sll     t4, t4, t1
+    and     t2, t2, t6
+    or      t4, t4, t2   // t4 - value to be written into aligned memory
+    sc.w    t2, t4, (t0) // t2 - atomic write result (0 - success)
+    bnez    t2, 1b
+    srl     t4, t4, t1
+    slli    a0, t4, 0x10
+    srli    a0, a0, 0x10
+    ret
+    .size   __atomic_add_fetch_2, . - __atomic_add_fetch_2
+
+
+    .global __atomic_load_1
+    .type   __atomic_load_1, @function
+__atomic_load_1:
+    andi    t0, a0, -4   // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3    // t1 - offset (in bits) between ptr and aligned ptr
+    li      t6, 0xff
+    sll     t6, t6, t1
+    not     t6, t6       // t6 - bitwise mask
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     t4, t2, t1
+    andi    a0, t4, 0xff
+    ret
+    .size   __atomic_load_1, . - __atomic_load_1
+
+
+    .global __atomic_store_1
+    .type   __atomic_store_1, @function
+__atomic_store_1:
+    andi    t0, a0, -4   // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3    // t1 - offset (in bits) between ptr and aligned ptr
+    li      t6, 0xff
+    sll     t6, t6, t1
+    not     t6, t6       // t6 - bitwise mask
+    sll     t5, a1, t1   // t5 - shifted new value to easy place into aligned memory
+1:                       // do not change registers (t0, t1, t5, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    and     t3, t2, t6   // t3 - masked aliged memory. Atomic variable part is zeroed here
+    or      t4, t5, t3   // t4 - combine desire byte-word with origin aligned memory
+    sc.w    t3, t4, (t0) // t3 - atomic write result (0 - success)
+    bnez    t3, 1b
+    ret
+    .size   __atomic_store_1, . - __atomic_store_1
+
+
+    .global __atomic_exchange_1
+    .type   __atomic_exchange_1, @function
+__atomic_exchange_1:
+    andi    t0, a0, -4   // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3    // t1 - offset (in bits) between ptr and aligned ptr
+    li      t6, 0xff
+    sll     t6, t6, t1
+    not     t6, t6       // t6 - bitwise mask
+    sll     t5, a1, t1   // t5 - shifted new value to easy place into aligned memory
+1:                       // do not change registers (t0, t1, t5, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    and     t3, t2, t6   // t3 - masked aliged memory. Atomic variable part is zeroed here
+    or      t4, t5, t3   // t4 - combine desire byte-word with origin aligned memory
+    sc.w    t3, t4, (t0) // t3 - atomic write result (0 - success)
+    bnez    t3, 1b
+    srl     t4, t2, t1
+    andi    a0, t4, 0xff
+    ret
+    .size   __atomic_exchange_1, . - __atomic_exchange_1
+
+
+    .global __atomic_compare_exchange_1
+    .type   __atomic_compare_exchange_1, @function
+__atomic_compare_exchange_1:
+    andi    t0, a0, -4   // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3    // t1 - offset (in bits) between ptr and aligned ptr
+    li      t6, 0xff
+    sll     t6, t6, t1
+    not     t6, t6       // t6 - bitwise mask
+    lbu     t5, (a1)
+    sll     t5, t5, t1   // t5 - shifted expect value to easy compare with aligned memory
+    sll     t4, a2, t1   // t4 - shifted desired value to easy place into aligned memory
+1:                       // do not change registers (t0, t1, t4, t5) after this label
+    not     t6, t6
+    lr.w    t2, (t0)     // t2 - load atomic
+    and     t3, t2, t6   // t3 - prepare half-word from aligned memory to compare with expected (t5)
+    bne     t3, t5, 2f   // goto fail
+    not     t6, t6
+    and     t2, t2, t6
+    or      t3, t4, t2   // t3 - combine desire half-word with half-word from origin aligned memory
+    sc.w    t2, t3, (t0) // t2 - atomic write result (0 - success)
+    bnez    t2, 1b       // retry
+    li      a0, 1
+    ret
+2:
+    srl     t3, t3, t1
+    sb      t3, (a1)     // store atomic value into expect variable
+    li      a0, 0
+    ret
+    .size   __atomic_compare_exchange_1, . - __atomic_compare_exchange_1
+
+
+    .global __atomic_fetch_or_1
+    .type   __atomic_fetch_or_1, @function
+__atomic_fetch_or_1:
+    andi    t0, a0, -4   // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3    // t1 - offset (in bits) between ptr and aligned ptr
+    sll     t2, a1, t1   // t2 - shifted value half-word.
+    amoor.w t0, t2, (t0) // t0 - shifted value before atomic operation performed
+    srl     t0, t0, t1
+    andi    a0, t0, 0xff
+    ret
+    .size   __atomic_fetch_or_1, . - __atomic_fetch_or_1
+
+
+    .global __atomic_or_fetch_1
+    .type   __atomic_or_fetch_1, @function
+__atomic_or_fetch_1:
+    andi    t0, a0, -4   // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3    // t1 - offset (in bits) between ptr and aligned ptr
+    sll     t2, a1, t1   // t2 - shifted byte-word value.
+    amoor.w t0, t2, (t0) // t0 - shifted value before atomic operation performed
+    srl     t2, t2, t1
+    andi    a0, t2, 0xff
+    ret
+    .size   __atomic_or_fetch_1, . - __atomic_or_fetch_1
+
+
+    .global __atomic_fetch_xor_1
+    .type   __atomic_fetch_xor_1, @function
+__atomic_fetch_xor_1:
+    andi    t0, a0, -4    // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3     // t1 - offset (in bits) between ptr and aligned ptr
+    sll     t2, a1, t1    // t2 - shifted value byte-word.
+    amoxor.w t0, t2, (t0) // t0 - shifted value before atomic operation performed
+    srl     t0, t0, t1
+    andi    a0, t0, 0xff
+    ret
+    .size   __atomic_fetch_xor_1, . - __atomic_fetch_xor_1
+
+
+    .global __atomic_xor_fetch_1
+    .type   __atomic_xor_fetch_1, @function
+__atomic_xor_fetch_1:
+    andi    t0, a0, -4     // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3      // t1 - offset (in bits) between ptr and aligned ptr
+    sll     t2, a1, t1     // t2 - shifted value byte-word.
+    amoxor.w t0, t2, (t0)  // t0 - shifted value before atomic operation performed
+    srl     t2, t2, t1
+    andi    a0, t2, 0xff
+    ret
+    .size   __atomic_xor_fetch_1, . - __atomic_xor_fetch_1
+
+
+    .global __atomic_fetch_and_1
+    .type   __atomic_fetch_and_1, @function
+__atomic_fetch_and_1:
+    andi    t0, a0, -4    // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3
+    li      t6, 0xff      // t6 - bitwise mask
+    sll     t6, t6, t1    // t6 - using to fill non-atomic bytes with 0xff in aligned memory
+    not     t6, t6
+    sll     t2, a1, t1    // t2 - shifted value byte-word.
+    or      t2, t2, t6    // t2 - (0xXXffffff or 0xffXXffff ...) where XX - new value to write
+    amoand.w t0, t2, (t0) // t0 - shifted value before atomic operation performed
+    srl     t0, t0, t1
+    andi    a0, t0, 0xff
+    ret
+    .size   __atomic_fetch_and_1, . - __atomic_fetch_and_1
+
+
+    .global __atomic_and_fetch_1
+    .type   __atomic_and_fetch_1, @function
+__atomic_and_fetch_1:
+    andi    t0, a0, -4    // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3
+    li      t6, 0xff      // t6 - bitwise mask
+    sll     t6, t6, t1    // t6 - using to fill non-atomic bytes with 0xff in aligned memory
+    not     t6, t6
+    sll     t2, a1, t1    // t2 - shifted value byte-word.
+    or      t2, t2, t6    // t2 - (0xXXffffff or 0xffXXffff ...) where XX - new value to write
+    amoand.w t0, t2, (t0) // t0 - shifted value before atomic operation performed
+    srl     t2, t2, t1
+    andi    a0, t2, 0xff
+    ret
+    .size   __atomic_and_fetch_1, . - __atomic_and_fetch_1
+
+
+    .global __atomic_nand_fetch_1
+    .type   __atomic_nand_fetch_1, @function
+__atomic_nand_fetch_1:
+    andi    t0, a0, -4   // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3    // t1 - offset (in bits) between ptr and aligned ptr
+    li      t6, 0xff
+    sll     t6, t6, t1
+    not     t6, t6       // t6 - bitwise mask
+1:                       // do not change registers (t0, t1, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     t3, t2, t1
+    and     t3, t3, a1
+    not     t3, t3       // t3 - atomic value to write
+    sll     t3, t3, t1
+    and     t4, t2, t6   // t4 - masked aliged memory. Atomic variable part is zeroed here
+    or      t4, t4, t3   // t4 - combine desire byte-word with origin aligned memory
+    sc.w    t3, t4, (t0) // t3 - atomic write result (0 - success)
+    bnez    t3, 1b
+    srl     t4, t4, t1
+    andi    a0, t4, 0xff
+    ret
+    .size   __atomic_nand_fetch_1, . - __atomic_nand_fetch_1
+
+
+    .global __atomic_fetch_nand_1
+    .type   __atomic_fetch_nand_1, @function
+__atomic_fetch_nand_1:
+    andi    t0, a0, -4   // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3    // t1 - offset (in bits) between ptr and aligned ptr
+    li      t6, 0xff
+    sll     t6, t6, t1
+    not     t6, t6       // t6 - bitwise mask
+1:                       // do not change registers (t0, t1, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     t3, t2, t1
+    and     t3, t3, a1
+    not     t3, t3       // t3 - atomic value to write
+    sll     t3, t3, t1
+    and     t4, t2, t6   // t4 - masked aliged memory. Atomic variable part is zeroed here
+    or      t4, t4, t3   // t4 - combine desire byte-word with origin aligned memory
+    sc.w    t3, t4, (t0) // t3 - atomic write result (0 - success)
+    bnez    t3, 1b
+    srl     t4, t2, t1
+    andi    a0, t4, 0xff
+    ret
+    .size   __atomic_fetch_nand_1, . - __atomic_fetch_nand_1
+
+
+    .global __atomic_fetch_sub_1
+    .type   __atomic_fetch_sub_1, @function
+__atomic_fetch_sub_1:
+    andi    t0, a0, -4   // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3    // t1 - offset (in bits) between ptr and aligned ptr
+    li      t6, 0xff
+    sll     t6, t6, t1
+    not     t6, t6       // t6 - bitwise mask
+1:                       // do not change registers (t0, t1, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     t4, t2, t1
+    andi    t4, t4, 0xff // t4 - value in atomic before performing operation
+    sub     t3, t4, a1
+    andi    t3, t3, 0xff // t3 - value to be written to atomic
+    sll     t3, t3, t1
+    and     t2, t2, t6
+    or      t3, t3, t2   // t3 - value to be written into aligned memory
+    sc.w    t2, t3, (t0) // t2 - atomic write result (0 - success)
+    bnez    t2, 1b
+    andi    a0, t4, 0xff
+    ret
+    .size   __atomic_fetch_sub_1, . - __atomic_fetch_sub_1
+
+
+    .global __atomic_sub_fetch_1
+    .type   __atomic_sub_fetch_1, @function
+__atomic_sub_fetch_1:
+    andi    t0, a0, -4   // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3    // t1 - offset (in bits) between ptr and aligned ptr
+    li      t6, 0xff
+    sll     t6, t6, t1
+    not     t6, t6       // t6 - bitwise mask
+1:                       // do not change registers (t0, t1, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     t3, t2, t1
+    andi    t3, t3, 0xff // t3 - value in atomic before performing operation
+    sub     t3, t3, a1
+    andi    t3, t3, 0xff // t3 - value to be written to atomic
+    sll     t3, t3, t1
+    and     t2, t2, t6
+    or      t3, t3, t2   // t3 - value to be written into aligned memory
+    sc.w    t2, t3, (t0) // t2 - atomic write result (0 - success)
+    bnez    t2, 1b
+    srl     t3, t3, t1
+    andi    a0, t3, 0xff
+    ret
+    .size   __atomic_sub_fetch_1, . - __atomic_sub_fetch_1
+
+
+    .global __atomic_fetch_add_1
+    .type   __atomic_fetch_add_1, @function
+__atomic_fetch_add_1:
+    andi    t0, a0, -4   // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3    // t1 - offset (in bits) between ptr and aligned ptr
+    li      t6, 0xff
+    sll     t6, t6, t1
+    not     t6, t6       // t6 - bitwise mask
+1:                       // do not change registers (t0, t1, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     t4, t2, t1
+    andi    t4, t4, 0xff // t4 - value in atomic before performing operation
+    add     t3, t4, a1
+    andi    t3, t3, 0xff // t3 - value to be written to atomic
+    sll     t3, t3, t1
+    and     t2, t2, t6
+    or      t3, t3, t2   // t3 - value to be written into aligned memory
+    sc.w    t2, t3, (t0) // t2 - atomic write result (0 - success)
+    bnez    t2, 1b
+    andi    a0, t4, 0xff
+    ret
+    .size   __atomic_fetch_add_1, . - __atomic_fetch_add_1
+
+
+    .global __atomic_add_fetch_1
+    .type   __atomic_add_fetch_1, @function
+__atomic_add_fetch_1:
+    andi    t0, a0, -4   // t0 - aligned ptr
+    sub     t1, a0, t0
+    slli    t1, t1, 3    // t1 - offset (in bits) between ptr and aligned ptr
+    li      t6, 0xff
+    sll     t6, t6, t1
+    not     t6, t6       // t6 - bitwise mask
+1:                       // do not change registers (t0, t1, t6) after this label
+    lr.w    t2, (t0)     // t2 - load atomic
+    srl     t3, t2, t1
+    andi    t3, t3, 0xff // t3 - value in atomic before performing operation
+    add     t3, t3, a1
+    andi    t3, t3, 0xff // t3 - value to be written to atomic
+    sll     t3, t3, t1
+    and     t2, t2, t6
+    or      t3, t3, t2   // t3 - value to be written into aligned memory
+    sc.w    t2, t3, (t0) // t2 - atomic write result (0 - success)
+    bnez    t2, 1b
+    srl     t3, t3, t1
+    andi    a0, t3, 0xff
+    ret
+    .size   __atomic_add_fetch_1, . - __atomic_add_fetch_1
+
+#endif // if __riscv_atomic == 1

+ 12 - 0
components/newlib/stdatomic.c

@@ -434,6 +434,18 @@ ATOMIC_STORE(1, unsigned char)
 ATOMIC_STORE(2, short unsigned int)
 ATOMIC_STORE(4, unsigned int)
 
+#elif __riscv_atomic == 1
+
+bool CLANG_ATOMIC_SUFFIX(__atomic_always_lock_free) (unsigned int size, const volatile void *) {
+  return size <= sizeof(int);
+}
+CLANG_DECLARE_ALIAS( __atomic_always_lock_free)
+
+bool CLANG_ATOMIC_SUFFIX(__atomic_is_lock_free) (unsigned int size, const volatile void *) {
+  return size <= sizeof(int);
+}
+CLANG_DECLARE_ALIAS( __atomic_is_lock_free)
+
 #endif // !HAS_ATOMICS_32
 
 #if !HAS_ATOMICS_64