add atomic test

This commit is contained in:
Kizarm 2025-02-20 22:07:45 +01:00
parent c3d1d2706a
commit ac8425b22d
5 changed files with 123 additions and 0 deletions

53
V203F6P6/atomic/Makefile Normal file
View file

@ -0,0 +1,53 @@
TARGET?= ch32v203
TOOL ?= gcc
#TOOL ?= clang
PRJ = example
VPATH = . ./$(TARGET)
BLD = ./build/
DFLAGS = -d
LFLAGS = -g
LDLIBS =
BFLAGS = --strip-unneeded
CFLAGS = -MMD -Wall -Wno-parentheses -ggdb -fno-exceptions -ffunction-sections -fdata-sections
CFLAGS+= -I. -I./$(TARGET) -I./common
DEL = rm -f
# zdrojaky
OBJS = main.o
#OBJS +=
include $(TARGET)/$(TOOL).mk
BOBJS = $(addprefix $(BLD),$(OBJS))
all: $(BLD) $(PRJ).elf
# ... atd.
-include $(BLD)*.d
# linker
$(PRJ).elf: $(BOBJS)
-@echo [LD $(TOOL),$(TARGET)] $@
@$(LD) $(LFLAGS) -o $(PRJ).elf $(BOBJS) $(LDLIBS)
-@echo "size:"
@$(SIZE) $(PRJ).elf
-@echo "listing:"
$(DUMP) $(DFLAGS) $(PRJ).elf > $(PRJ).lst
-@echo "OK."
$(COPY) $(BFLAGS) -O binary $(PRJ).elf $(PRJ).bin
# preloz co je potreba
$(BLD)%.o: %.c
-@echo [CC $(TOOL),$(TARGET)] $@
@$(CC) -std=gnu99 -c $(CFLAGS) $< -o $@
$(BLD)%.o: %.cpp
-@echo [CX $(TOOL),$(TARGET)] $@
@$(CXX) -std=c++17 -fno-rtti -c $(CFLAGS) $< -o $@
$(BLD):
mkdir $(BLD)
flash: $(PRJ).elf
minichlink -w $(PRJ).bin flash -b
# vycisti
clean:
$(DEL) $(BLD)* *.lst *.bin *.elf *.map *~
.PHONY: all clean flash run

1
V203F6P6/atomic/ch32v203 Symbolic link
View file

@ -0,0 +1 @@
../ch32v203/

1
V203F6P6/atomic/common Symbolic link
View file

@ -0,0 +1 @@
../common/

45
V203F6P6/atomic/main.cpp Normal file
View file

@ -0,0 +1,45 @@
#include "system.h"
#include "gpio.h"
#include "atomic.h"
////////////////////////////////////////////////////////////////////////
/* Test atomického přístupu.
* RISC-V jádra QingKe V4B mají atomické rozšíření, opravdu funguje
* i když netuším jak. U Cortex-M3 jsem to ještě zkoumal, tady na to
* kašlu. Ono těch situací, kdy je to nezbytné zase tak moc není.
* */
////////////////////////////////////////////////////////////////////////
static constexpr unsigned ticks = SYSTEM_CORE_CLOCK / 1000u;
extern "C" [[gnu::interrupt]] void SysTick_Handler ();
////////////////////////////////////////////////////////////////////////
static inline int iabs (const int x) {
return x < 0 ? -x : +x;
}
static constexpr int INCREMENT = 16;
//static volatile int shared_cnt (0); // !!! špatně, opravdu musí být atomic
static atomic <int> shared__cnt (0);
static volatile int compare_cnt (0);
static int error_cnt (0); // čítač chyb
static GpioClass led (GPIOB, 8);
////////////////////////////////////////////////////////////////////////
void SysTick_Handler () {
SysTick.SR = 0u;
// přičítáme jakékoli větší číslo
shared__cnt += INCREMENT;
compare_cnt += INCREMENT;
// detekce chyby - rozdíl nesmí být větší než pohyb hodnoty v hlavní smyčce
if (iabs (shared__cnt - compare_cnt) > 1) {
led << false;
error_cnt += 1;
shared__cnt = compare_cnt;
}
}
int main () {
SysTick.Config (ticks);
led << true;
for (;;) { // smyčka by měla být co nejkratší
shared__cnt += 1; // Tady může vzniknout race condition, RISC sekvence RMW
shared__cnt -= 1; // vlivem přerušení zapíše špatnou hodnotu, atomic to jistí.
}
return 0;
}

23
V203F6P6/common/atomic.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef _ATOMIC_H_DEF_
#define _ATOMIC_H_DEF_
#define WR_MEMORDER __ATOMIC_SEQ_CST
#define RD_MEMORDER __ATOMIC_SEQ_CST
/* Velmi zjednodušené, ale v zásadě funkční.
* Asi to bude nutné trochu rozšířit, ale zatím to nebudu komplikovat.
* Použity jsou interní funkce gcc (clang), takže to není závislé na
* architektuře.
* */
template<class T> class atomic {
volatile T data;
public:
explicit atomic () noexcept : data( ) {}
explicit atomic (const T & v) noexcept : data(v) {}
atomic & operator= (volatile T & v) { __atomic_store_n (& data, v, WR_MEMORDER); return * this; }
atomic & operator= (const T & v) { __atomic_store_n (& data, v, WR_MEMORDER); return * this; }
operator T () const { return __atomic_load_n (& data, RD_MEMORDER); }
atomic & operator+= (const T & v) { __atomic_add_fetch (& data, v, WR_MEMORDER); return * this; }
atomic & operator-= (const T & v) { __atomic_sub_fetch (& data, v, WR_MEMORDER); return * this; }
};
#endif // _ATOMIC_H_DEF_