From 5dc32b14cc9a2c324aa1d8babe5932e433c97364 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Mon, 18 Jul 2016 16:03:55 +0200 Subject: [PATCH] sys: zptr: initial commit Provides functionality to compress pointers from 32bit to 16bit if possible. --- makefiles/pseudomodules.inc.mk | 1 + sys/Makefile.include | 4 + sys/include/zptr.h | 139 +++++++++++++++++++++++++++++++++ sys/zptr/Makefile.include | 14 ++++ 4 files changed, 158 insertions(+) create mode 100644 sys/include/zptr.h create mode 100644 sys/zptr/Makefile.include diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 620365e0be..521d5e6e14 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -93,6 +93,7 @@ PSEUDOMODULES += stdio_cdc_acm PSEUDOMODULES += stdio_uart_rx PSEUDOMODULES += suit_% PSEUDOMODULES += wakaama_objects_% +PSEUDOMODULES += zptr # handle suit_v4 being a distinct module NO_PSEUDOMODULES += suit_v4 diff --git a/sys/Makefile.include b/sys/Makefile.include index b4b3a2dd2a..b81b2fbc43 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -111,3 +111,7 @@ endif ifneq (,$(filter clif, $(USEMODULE))) INCLUDES += -I$(RIOTBASE)/sys/clif/include endif + +ifneq (,$(filter zptr,$(USEMODULE))) + include $(RIOTBASE)/sys/zptr/Makefile.include +endif diff --git a/sys/include/zptr.h b/sys/include/zptr.h new file mode 100644 index 0000000000..4d63e2ae0f --- /dev/null +++ b/sys/include/zptr.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2017 Kaspar Schleiser + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup sys_util_zptr Pointer Compression + * @ingroup sys + * @brief Provides 32bit -> 16bit pointer compression + * + * On many platforms, some pointers may have to be aligned, e.g., to 4 byte + * bounderies. + * On 32bit platforms, that makes it possible to store all possible aligned + * 32bit pointers in a 16bit value as long as the total memory is small (e.g., + * with 4 byte alignment, all pointers within 256kb RAM can be represented by a + * 16bit value). This can save memory, at the cost of some instructions for + * compression/decompression. + * + * In order to use pointer compression, ZPTR_BASE needs to be defined to a (4 + * byte aligned) base address. + * + * A printf format macro (PRIzptr) is provided. + * + * You can then use zptr_t instead of a pointer type, using the supplied functions to compress / decompress, + * e.g., + * + * void func(void *ptr) { + * printf("%"PRIzptr"\n", ptr); + * ... + * free(ptr); + * } + * + * ... would become + * + * void func(zptr_t zptr); + * printf("%"PRIzptr"\n", zptr); + * ... + * free(zptrd(zptr)); + * } + * + * + * If ZPTR_BASE is unset, @ref zptr_t / @ref zptrc() / @ref zptrd() will + * transparently and without overhead compile to normal (uncompressed) pointer + * operations. + * + * @{ + * + * @file + * @brief 32bit -> 16bit pointer compression implementation + * + * @author Kaspar Schleiser + */ + +#ifndef ZPTR_H +#define ZPTR_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if ZPTR_BASE || defined(DOXYGEN) + +/** + * @brief zptr type definition + */ +typedef uint16_t zptr_t; + +/** + * @brief zptr printf format definition + */ +#define PRIzptr PRIu16 + +/** + * @brief zptr highest compressible address + */ +#define ZPTR_MAX_ADDR ((uintptr_t)ZPTR_BASE + (1 << 18)) + +/** + * @brief Determine if a pointer is compressable by zptrc() + * @param[in] pointer pointer to check + * @returns 1 if pointer can be compressed, 0 if not + */ +static inline int zptr_check(void *pointer) +{ + uintptr_t int_ptr = (uintptr_t)pointer; + return ((!(int_ptr & 0x3)) \ + && (int_ptr >= (uintptr_t)ZPTR_BASE) \ + && (int_ptr < ZPTR_MAX_ADDR)); +} + +/** + * @brief Compress a pointer (if possible) + * + * Substracts ZPTR_BASE, then right-shifts @p pointer by two. + * + * @param[in] pointer pointer to compress + * @returns compressed pointer + */ +static inline zptr_t zptrc(void *pointer) +{ + assert(zptr_check(pointer)); + return (uint16_t)(((uint32_t)pointer - (uint32_t)ZPTR_BASE) >> 2); +} + +/** + * @brief Decompress a pointer + * + * Left-shifts zptr_t by two, then adds ZPTR_BASE. + * + * @param[in] zptr compressed pointer + * @returns decompressed pointer + */ +static inline void *zptrd(zptr_t zptr) +{ + return (void *)(ZPTR_BASE + ((uint32_t)zptr << 2)); +} + +#else /* ZPTR_BASE */ +/* fallback implementation */ +typedef void *zptr_t; +#define PRIzptr "p" +static inline int zptr_check(void *pointer) { (void)pointer; return 0; } +static inline zptr_t zptrc(void *pointer) { return (zptr_t)pointer; } +static inline void *zptrd(zptr_t zptr) { return (void *)zptr; } +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZPTR_H */ +/** @} */ diff --git a/sys/zptr/Makefile.include b/sys/zptr/Makefile.include new file mode 100644 index 0000000000..b76368512b --- /dev/null +++ b/sys/zptr/Makefile.include @@ -0,0 +1,14 @@ +# zptr can use pointer compression of four byte aligned pointers, by right- +# shifting them by two and stuffing in an uint16_t. +# That only works on 32bit platforms, if total RAM size is <=2**18 and the +# start address is known. +ifneq (,$(filter arch_32bit,$(FEATURES_USED))) + ifneq (,$(RAM_START_ADDR)) + ifneq (,$(RAM_LEN)) + # this handles 0xXXX and xxxK + ifeq (1,$(shell echo $$(($(subst K,*1024,$(RAM_LEN)) <= 262144)))) + CFLAGS += -DZPTR_BASE=$(RAM_START_ADDR) + endif + endif + endif +endif