From 8db6fcdc2e6f247e3a37153cbc4ab37779b4d4db Mon Sep 17 00:00:00 2001 From: Miquel Sabaté Solà Date: Thu, 29 Aug 2024 14:15:03 +0000 Subject: Provide an example on RISC-V atomic adds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miquel Sabaté Solà --- arch/riscv/usr/Makefile | 2 +- arch/riscv/usr/basics.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/riscv/usr/Makefile b/arch/riscv/usr/Makefile index 6e36dd6..5f1ef3f 100644 --- a/arch/riscv/usr/Makefile +++ b/arch/riscv/usr/Makefile @@ -13,7 +13,7 @@ all: clean $(EXE) .PHONY: $(EXE) $(EXE): - gcc $(CCFLAGS) -o $(EXE) main.c factorial.S string.S float.S + gcc $(CCFLAGS) -o $(EXE) basics.c factorial.S string.S float.S .PHONY: clean clean: diff --git a/arch/riscv/usr/basics.c b/arch/riscv/usr/basics.c index 4b5f289..4333072 100644 --- a/arch/riscv/usr/basics.c +++ b/arch/riscv/usr/basics.c @@ -80,10 +80,52 @@ void test_greater_than_ten(void) printf("greater_than_ten:\tOK\n"); } +/* + * Atomically add the integer pointed by `a` with the given `value`. Although + * this is a function, I've checked that the assembly produced by GCC on a + * decent optimization level actually inlines this. + */ +static inline void atomic_add(uint64_t *a, uint64_t value) +{ + /* + * The execution is a mere `amoadd` instruction, but it will set on `t0` the + * result. If it fails (e.g. the address was already being used), then `t0 = + * 0` and `beqz` will instruct it to try again. + * + * As for the 'A' RISC-V specific constraint, it means "An address that is + * held in a general-purpose register". GCC will then do the magic and + * convert it to `amoadd.d t0, a1, (a0)` or something like that. Note that + * we have to pass the '+' constraint modifier because the address will be + * both read and written atomically. + * + * See: https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html. + */ + asm volatile(".Latomic_retry:\n\t" + "amoadd.d t0, %1, %0\n\t" + "beqz t0, .Latomic_retry" + : "+A" (*a) + : "r" (value) + : "memory"); +} + +void test_atomic_add(void) +{ + uint64_t i = 4; + + atomic_add(&i, 0); + assert(i == 4); + + atomic_add(&i, 2); + assert(i == 6); + + printf("atomic_add:\t\tOK\n"); +} + int main() { test_factorial(); test_reverse_string(); test_is_palindrome(); test_greater_than_ten(); + test_atomic_add(); } -- cgit v1.2.3