diff --git a/V203F6P6/atomic/Makefile b/V203F6P6/atomic/Makefile new file mode 100644 index 0000000..90590bc --- /dev/null +++ b/V203F6P6/atomic/Makefile @@ -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 diff --git a/V203F6P6/atomic/ch32v203 b/V203F6P6/atomic/ch32v203 new file mode 120000 index 0000000..7650c85 --- /dev/null +++ b/V203F6P6/atomic/ch32v203 @@ -0,0 +1 @@ +../ch32v203/ \ No newline at end of file diff --git a/V203F6P6/atomic/common b/V203F6P6/atomic/common new file mode 120000 index 0000000..8332399 --- /dev/null +++ b/V203F6P6/atomic/common @@ -0,0 +1 @@ +../common/ \ No newline at end of file diff --git a/V203F6P6/atomic/main.cpp b/V203F6P6/atomic/main.cpp new file mode 100644 index 0000000..e0d1f23 --- /dev/null +++ b/V203F6P6/atomic/main.cpp @@ -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 už 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 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; +} diff --git a/V203F6P6/common/atomic.h b/V203F6P6/common/atomic.h new file mode 100644 index 0000000..32edbf8 --- /dev/null +++ b/V203F6P6/common/atomic.h @@ -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 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_