Skip to content

Commit

Permalink
Implement threads
Browse files Browse the repository at this point in the history
This is preliminary thread support. Do *not* use!
Threading works, libraries aren't yet thread-safe.
  • Loading branch information
ReservedField committed May 26, 2016
1 parent 6a68546 commit c222885
Show file tree
Hide file tree
Showing 22 changed files with 1,893 additions and 82 deletions.
32 changes: 25 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
TARGET := libevicsdk
TARGET_CRT0 := $(TARGET)_crt0

# We make the following assumptions on Windows:
# arm-none-eabi gcc and binutils are compiled for Windows,
# so if you are using Cygwin, we will need path translations
Expand All @@ -25,7 +22,10 @@ OBJS := $(NUVOSDK)/Device/Nuvoton/M451Series/Source/system_M451Series.o \
src/startup/initfini.o \
src/startup/sbrk.o \
src/startup/init.o \
src/startup/mainthread.o \
src/startup/sleep.o \
src/thread/Thread.o \
src/thread/Queue.o \
src/sysinfo/SysInfo.o \
src/dataflash/Dataflash.o \
src/display/Display_SSD.o \
Expand All @@ -41,8 +41,16 @@ OBJS := $(NUVOSDK)/Device/Nuvoton/M451Series/Source/system_M451Series.o \
src/battery/Battery.o \
src/atomizer/Atomizer.o

ifneq ($(EVICSDK_FPU_SUPPORT),)
FPUSPEC := fpu
else
FPUSPEC := nofpu
endif

TAGNAME := src/startup/evicsdk_tag
OBJS_CRT0 := src/startup/startup.o \
src/startup/fpsetup_$(FPUSPEC).o \
src/thread/ContextSwitch_$(FPUSPEC).o \
$(TAGNAME).o

AEABI_OBJS := src/aeabi/aeabi_memset-thumb2.o \
Expand All @@ -51,8 +59,6 @@ AEABI_OBJS := src/aeabi/aeabi_memset-thumb2.o \
OUTDIR := lib
DOCDIR := doc

CPU := cortex-m4

# We need to find out if on cygwin or not
ifeq ($(OS),Windows_NT)
ifeq (, $(findstring cygwin, $(shell gcc -dumpmachine)))
Expand Down Expand Up @@ -141,10 +147,22 @@ INCDIRS := $(foreach d,$(shell arm-none-eabi-gcc -x c -v -E /dev/null 2>&1 | sed
-I$(NUVOSDK)/StdDriver/inc \
-Iinclude

CFLAGS += -Wall -mcpu=$(CPU) -mthumb -Os -fdata-sections -ffunction-sections
CPUFLAGS := -mcpu=cortex-m4 -mthumb

ifneq ($(EVICSDK_FPU_SUPPORT),)
CPUFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS += -DEVICSDK_FPU_SUPPORT
TARGET := libevicsdk_fpu
else
TARGET := libevicsdk
endif

TARGET_CRT0 := $(TARGET)_crt0

CFLAGS += -Wall $(CPUFLAGS) -Os -fdata-sections -ffunction-sections
CFLAGS += $(INCDIRS)

ASFLAGS := -mcpu=$(CPU)
ASFLAGS := $(CPUFLAGS)

all: env_check gen_tag $(TARGET_CRT0).o $(TARGET).a

Expand Down
122 changes: 122 additions & 0 deletions include/AtomicOps.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* This file is part of eVic SDK.
*
* eVic SDK is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* eVic SDK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with eVic SDK. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2016 ReservedField
*/

#ifndef EVICSDK_ATOMICOPS_H
#define EVICSDK_ATOMICOPS_H

#include <stdint.h>

// extern "C" is omitted because none
// of this is going to be exported.

/* Always inline, no extern version. */
#define ATOMICOPS_INLINE __attribute__((always_inline)) static inline

/**
* Atomically stores a 32-bit value to memory, giving
* back the old value.
*
* @param ptr Memory to store the value to.
* @param newVal Value to store.
*
* @return Old value.
*/
ATOMICOPS_INLINE uint32_t AtomicOps_Swap(volatile uint32_t *ptr, uint32_t newVal) {
uint32_t oldVal, strexRet;

// TODO: too many memory barriers?
asm volatile("@ AtomicOps_Swap\n\t"
"dmb\n"
"1:\n\t"
"ldrex %0, [%2]\n\t"
"strex %1, %3, [%2]\n\t"
"teq %1, #0\n\t"
"bne 1b\n\t"
"dmb"
: "=&r" (oldVal), "=&r" (strexRet)
: "r" (ptr), "r" (newVal)
: "memory", "cc");

return oldVal;
}

/**
* Atomically stores a 32-bit value to memory, only if
* the value currently in memory is equal to the expected
* value, giving back the old value.
*
* @param ptr Memory to store the value to.
* @param expVal Expected value.
* @param newVal Value to store.
*
* @return Old value.
*/
ATOMICOPS_INLINE uint32_t AtomicOps_CmpSwap(volatile uint32_t *ptr, uint32_t expVal, uint32_t newVal) {
uint32_t loadVal, strexRet;

// TODO: too many memory barriers?
asm volatile("@ AtomicOps_CmpSwap\n\t"
"dmb\n"
"1:\n\t"
"ldrex %0, [%2]\n\t"
"teq %0, %3\n\t"
"itt eq\n\t"
"strexeq %1, %4, [%2]\n\t"
"teqeq %1, #1\n\t"
"beq 1b\n\t"
"dmb"
: "=&r" (loadVal), "=&r" (strexRet)
: "r" (ptr), "r" (expVal), "r" (newVal)
: "memory", "cc");

return loadVal;
}

/**
* Atomically adds to a 32-bit value in memory.
*
* @param ptr Memory where the first addend is and
* where the result will be stored.
* @param n Second addend.
*
* @return New value after addition.
*/
ATOMICOPS_INLINE uint32_t AtomicOps_Add(volatile uint32_t *ptr, uint32_t n) {
uint32_t result, strexRet;

// TODO: too many memory barriers?
asm volatile("@ AtomicOps_Add:\n\t"
"dmb\n"
"1:\n\t"
"ldrex %0, [%2]\n\t"
"add %0, %0, %3\n\t"
"strex %1, %0, [%2]\n\t"
"teq %1, #0\n\t"
"bne 1b\n\t"
"dmb"
: "=&r" (result), "=&r" (strexRet)
: "r" (ptr), "r" (n)
: "memory", "cc");

return result;
}

#undef ATOMICOPS_INLINE

#endif
94 changes: 94 additions & 0 deletions include/Queue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* This file is part of eVic SDK.
*
* eVic SDK is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* eVic SDK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with eVic SDK. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2016 ReservedField
*/

#ifndef EVICSDK_QUEUE_H
#define EVICSDK_QUEUE_H

#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* Queue.
*/
typedef struct {
/**< First item in queue. NULL when queue is empty. */
void *head;
/**< Last item in queue. */
void *tail;
} Queue_t;

/**
* Queue item header.
* This MUST be the first field in every item.
*/
typedef struct {
/** Next item in queue. */
void *next;
} Queue_Header_t;

/**
* Initializes an user-allocated queue.
*
* @param queue Queue.
*/
void Queue_Init(Queue_t *queue);

/**
* Pushes an item to the front of the queue.
*
* @param queue Queue.
* @param item Item to push.
*/
void Queue_PushFront(Queue_t *queue, void *item);

/**
* Pushes an item to the back of the queue.
*
* @param queue Queue.
* @param item Item to push.
*/
void Queue_PushBack(Queue_t *queue, void *item);

/**
* Pops the first item off the queue.
*
* @param queue Queue.
*
* @return First item, or NULL if the queue is empty.
*/
void *Queue_PopFront(Queue_t *queue);

/**
* Removes an item from the queue.
*
* @param queue Queue.
* @param prev Item preceding the one to be removed,
* or NULL if removing the first item.
* @param item Item to remove.
*/
void Queue_Remove(Queue_t *queue, void *prev, void *item);

#ifdef __cplusplus
}
#endif

#endif
Loading

0 comments on commit c222885

Please sign in to comment.