mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Alexandre Abadie
fce6e4032d
- 'bounderies' -> 'boundaries' - 'compressable' -> 'compressible' - 'Substracts' -> 'Subtracts'
140 lines
3.4 KiB
C
140 lines
3.4 KiB
C
/*
|
|
* Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
|
|
*
|
|
* 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
|
|
* boundaries.
|
|
* 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 <kaspar@schleiser.de>
|
|
*/
|
|
|
|
#ifndef ZPTR_H
|
|
#define ZPTR_H
|
|
|
|
#include <assert.h>
|
|
#include <stdint.h>
|
|
#include <inttypes.h>
|
|
|
|
#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 compressible 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)
|
|
*
|
|
* Subtracts 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 */
|
|
/** @} */
|