add atomic test
This commit is contained in:
parent
c3d1d2706a
commit
ac8425b22d
5 changed files with 123 additions and 0 deletions
53
V203F6P6/atomic/Makefile
Normal file
53
V203F6P6/atomic/Makefile
Normal 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
1
V203F6P6/atomic/ch32v203
Symbolic link
|
@ -0,0 +1 @@
|
|||
../ch32v203/
|
1
V203F6P6/atomic/common
Symbolic link
1
V203F6P6/atomic/common
Symbolic link
|
@ -0,0 +1 @@
|
|||
../common/
|
45
V203F6P6/atomic/main.cpp
Normal file
45
V203F6P6/atomic/main.cpp
Normal 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 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 <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
23
V203F6P6/common/atomic.h
Normal 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_
|
Loading…
Add table
Reference in a new issue