diff --git a/include/libopencm3/cm3/sync.h b/include/libopencm3/cm3/sync.h new file mode 100644 index 00000000..ccec5e8c --- /dev/null +++ b/include/libopencm3/cm3/sync.h @@ -0,0 +1,48 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Fergus Noble + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef LIBOPENCM3_CM3_SYNC_H +#define LIBOPENCM3_CM3_SYNC_H + +#include "common.h" + +/* Implements synchronisation primatives as discussed in the ARM document + * DHT0008A (ID081709) "ARM Synchronization Primitives" and the ARM v7-M + * Architecture Reference Manual. +*/ + +/* --- Exclusive load and store instructions ------------------------------- */ + +u32 __ldrex(volatile u32* addr); +u32 __strex(u32 val, volatile u32* addr); +void __dmb(void); + +/* --- Convenience functions ----------------------------------------------- */ + +/* Here we implement some simple synchronisation primatives. */ + +typedef u32 mutex_t; + +#define MUTEX_UNLOCKED 0 +#define MUTEX_LOCKED 1 + +void mutex_lock(mutex_t* m); +void mutex_unlock(mutex_t* m); + +#endif diff --git a/lib/Makefile.include b/lib/Makefile.include index f9eeefe4..7b76d649 100644 --- a/lib/Makefile.include +++ b/lib/Makefile.include @@ -24,7 +24,7 @@ Q := @ endif # common objects -OBJS += vector.o systick.o scb.o nvic.o assert.o +OBJS += vector.o systick.o scb.o nvic.o assert.o sync.o all: $(SRCLIBDIR)/$(LIBNAME).a diff --git a/lib/cm3/sync.c b/lib/cm3/sync.c new file mode 100644 index 00000000..b7bf604f --- /dev/null +++ b/lib/cm3/sync.c @@ -0,0 +1,67 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2012 Fergus Noble + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +u32 __ldrex(volatile u32* addr) +{ + u32 res; + __asm__ volatile ("ldrex %0, [%1]" : "=r" (res) : "r" (addr)); + return res; +} + +u32 __strex(u32 val, volatile u32* addr) +{ + u32 res; + __asm__ volatile ("strex %0, %2, [%1]" : + "=&r" (res) : "r" (addr), "r" (val)); + return res; +} + +void __dmb() +{ + __asm__ volatile ("dmb"); +} + +void mutex_lock(mutex_t* m) +{ + u32 status = 0; + + do { + /* Wait until the mutex is unlocked. */ + while (__ldrex(m) != MUTEX_UNLOCKED); + + /* Try to acquire it. */ + status = __strex(MUTEX_LOCKED, m); + + /* Did we get it? If not then try again. */ + } while (status != 0); + + /* Execute the mysterious Data Memory Barrier instruction! */ + __dmb(); +} + +void mutex_unlock(mutex_t* m) +{ + __dmb(); + + /* Free the lock. */ + *m = MUTEX_UNLOCKED; +} +