diff --git a/Makefile.dep b/Makefile.dep index 09eda58953..f6540c64d6 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -429,3 +429,14 @@ endif ifneq (,$(filter ethos,$(USEMODULE))) USEMODULE += netdev2_eth endif + +ifneq (,$(filter random,$(USEMODULE))) + # select default prng + ifeq (,$(filter prng_%,$(USEMODULE))) + USEMODULE += prng_tinymt32 + endif + + ifneq (,$(filter prng_tinymt32,$(USEMODULE))) + USEMODULE += tinymt32 + endif +endif diff --git a/doc/doxygen/riot.doxyfile b/doc/doxygen/riot.doxyfile index 9f63588ad6..00ae19be94 100644 --- a/doc/doxygen/riot.doxyfile +++ b/doc/doxygen/riot.doxyfile @@ -842,6 +842,7 @@ EXCLUDE_PATTERNS = */board/*/tools/* \ */cpu/ezr32wg/include/ezr* \ */pkg/*/*/* \ */pkg/tlsf/patch.txt \ + */sys/random/tinymt32/* \ # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index dfbd168888..831cd0bb96 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -80,6 +80,10 @@ #include "net/fib.h" #endif +#ifdef MODULE_TINYMT32 +#include "random.h" +#endif + #define ENABLE_DEBUG (0) #include "debug.h" @@ -90,6 +94,9 @@ void auto_init(void) config_load(); #endif +#ifdef MODULE_TINYMT32 + genrand_init(0); +#endif #ifdef MODULE_XTIMER DEBUG("Auto init xtimer module.\n"); xtimer_init(); diff --git a/sys/random/Makefile b/sys/random/Makefile index 7e79cc14ab..5c2f869aeb 100644 --- a/sys/random/Makefile +++ b/sys/random/Makefile @@ -1,6 +1,3 @@ -ifeq (,$(filter prng_%,$(USEMODULE))) - USEMODULE += prng_mersenne -endif ifneq (,$(filter prng_mersenne,$(USEMODULE))) SRC += mersenne.c endif @@ -10,5 +7,9 @@ endif ifneq (,$(filter prng_musl_lcg,$(USEMODULE))) SRC += musl_lcg.c endif +ifneq (,$(filter prng_tinymt32,$(USEMODULE))) + SRC += prng_tinymt32.c + DIRS += tinymt32 +endif include $(RIOTBASE)/Makefile.base diff --git a/sys/random/prng_tinymt32.c b/sys/random/prng_tinymt32.c new file mode 100644 index 0000000000..78150ebbd1 --- /dev/null +++ b/sys/random/prng_tinymt32.c @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2015 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. + */ + + /** + * @ingroup sys_random + * @{ + * @file + * + * @brief Glue-code for tinymt32 + * + * See https://github.com/MersenneTwister-Lab/TinyMT for details. + * + * @author Kaspar Schleiser + * @} + */ + +#include + +#include "tinymt32/tinymt32.h" + +static tinymt32_t _random; + +void genrand_init(uint32_t seed) +{ + tinymt32_init(&_random, seed); +} + +uint32_t genrand_uint32(void) +{ + return tinymt32_generate_uint32(&_random); +} diff --git a/sys/random/tinymt32/LICENSE.txt b/sys/random/tinymt32/LICENSE.txt new file mode 100644 index 0000000000..2ba0bf4ab3 --- /dev/null +++ b/sys/random/tinymt32/LICENSE.txt @@ -0,0 +1,30 @@ +Copyright (c) 2011, 2013 Mutsuo Saito, Makoto Matsumoto, +Hiroshima University and The University of Tokyo. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the Hiroshima University nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/sys/random/tinymt32/Makefile b/sys/random/tinymt32/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/sys/random/tinymt32/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/random/tinymt32/tinymt32.c b/sys/random/tinymt32/tinymt32.c new file mode 100644 index 0000000000..0a896c1770 --- /dev/null +++ b/sys/random/tinymt32/tinymt32.c @@ -0,0 +1,151 @@ +/** + * @file tinymt32.c + * + * @brief Tiny Mersenne Twister only 127 bit internal state + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (The University of Tokyo) + * + * Copyright (C) 2011 Mutsuo Saito, Makoto Matsumoto, + * Hiroshima University and The University of Tokyo. + * All rights reserved. + * + * The 3-clause BSD License is applied to this software, see + * LICENSE.txt + */ +#include "tinymt32.h" +#define MIN_LOOP 8 +#define PRE_LOOP 8 + +/** + * This function represents a function used in the initialization + * by init_by_array + * @param x 32-bit integer + * @return 32-bit integer + */ +static uint32_t ini_func1(uint32_t x) +{ + return (x ^ (x >> 27)) * UINT32_C(1664525); +} + +/** + * This function represents a function used in the initialization + * by init_by_array + * @param x 32-bit integer + * @return 32-bit integer + */ +static uint32_t ini_func2(uint32_t x) +{ + return (x ^ (x >> 27)) * UINT32_C(1566083941); +} + +/** + * This function certificate the period of 2^127-1. + * @param random tinymt state vector. + */ +static void period_certification(tinymt32_t *random) +{ + if ((random->status[0] & TINYMT32_MASK) == 0 && + random->status[1] == 0 && + random->status[2] == 0 && + random->status[3] == 0) { + random->status[0] = 'T'; + random->status[1] = 'I'; + random->status[2] = 'N'; + random->status[3] = 'Y'; + } +} + +/** + * This function initializes the internal state array with a 32-bit + * unsigned integer seed. + * @param random tinymt state vector. + * @param seed a 32-bit unsigned integer used as a seed. + */ +void tinymt32_init(tinymt32_t *random, uint32_t seed) +{ + random->status[0] = seed; + random->status[1] = random->mat1; + random->status[2] = random->mat2; + random->status[3] = random->tmat; + for (int i = 1; i < MIN_LOOP; i++) { + random->status[i & 3] ^= i + UINT32_C(1812433253) + * (random->status[(i - 1) & 3] + ^ (random->status[(i - 1) & 3] >> 30)); + } + period_certification(random); + for (int i = 0; i < PRE_LOOP; i++) { + tinymt32_next_state(random); + } +} + +/** + * This function initializes the internal state array, + * with an array of 32-bit unsigned integers used as seeds + * @param random tinymt state vector. + * @param init_key the array of 32-bit integers, used as a seed. + * @param key_length the length of init_key. + */ +void tinymt32_init_by_array(tinymt32_t *random, uint32_t init_key[], + int key_length) +{ + const int lag = 1; + const int mid = 1; + const int size = 4; + int i, j; + int count; + uint32_t r; + uint32_t *st = &random->status[0]; + + st[0] = 0; + st[1] = random->mat1; + st[2] = random->mat2; + st[3] = random->tmat; + if (key_length + 1 > MIN_LOOP) { + count = key_length + 1; + } + else { + count = MIN_LOOP; + } + r = ini_func1(st[0] ^ st[mid % size] + ^ st[(size - 1) % size]); + st[mid % size] += r; + r += key_length; + st[(mid + lag) % size] += r; + st[0] = r; + count--; + for (i = 1, j = 0; (j < count) && (j < key_length); j++) { + r = ini_func1(st[i % size] + ^ st[(i + mid) % size] + ^ st[(i + size - 1) % size]); + st[(i + mid) % size] += r; + r += init_key[j] + i; + st[(i + mid + lag) % size] += r; + st[i % size] = r; + i = (i + 1) % size; + } + for (; j < count; j++) { + r = ini_func1(st[i % size] + ^ st[(i + mid) % size] + ^ st[(i + size - 1) % size]); + st[(i + mid) % size] += r; + r += i; + st[(i + mid + lag) % size] += r; + st[i % size] = r; + i = (i + 1) % size; + } + for (j = 0; j < size; j++) { + r = ini_func2(st[i % size] + + st[(i + mid) % size] + + st[(i + size - 1) % size]); + st[(i + mid) % size] ^= r; + r -= i; + st[(i + mid + lag) % size] ^= r; + st[i % size] = r; + i = (i + 1) % size; + } + period_certification(random); + for (i = 0; i < PRE_LOOP; i++) { + tinymt32_next_state(random); + } +} diff --git a/sys/random/tinymt32/tinymt32.h b/sys/random/tinymt32/tinymt32.h new file mode 100644 index 0000000000..1b483fd99b --- /dev/null +++ b/sys/random/tinymt32/tinymt32.h @@ -0,0 +1,233 @@ +#ifndef TINYMT32_H +#define TINYMT32_H +/** + * @file tinymt32.h + * + * @brief Tiny Mersenne Twister only 127 bit internal state + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (University of Tokyo) + * + * Copyright (C) 2011 Mutsuo Saito, Makoto Matsumoto, + * Hiroshima University and The University of Tokyo. + * All rights reserved. + * + * The 3-clause BSD License is applied to this software, see + * LICENSE.txt + */ + +#include +#include + +#define TINYMT32_MEXP 127 +#define TINYMT32_SH0 1 +#define TINYMT32_SH1 10 +#define TINYMT32_SH8 8 +#define TINYMT32_MASK UINT32_C(0x7fffffff) +#define TINYMT32_MUL (1.0f / 16777216.0f) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * tinymt32 internal state vector and parameters + */ +struct TINYMT32_T { + uint32_t status[4]; + uint32_t mat1; + uint32_t mat2; + uint32_t tmat; +}; + +typedef struct TINYMT32_T tinymt32_t; + +void tinymt32_init(tinymt32_t *random, uint32_t seed); +void tinymt32_init_by_array(tinymt32_t *random, uint32_t init_key[], + int key_length); + +inline static int tinymt32_get_mexp(tinymt32_t *random) +{ + (void) random; + return TINYMT32_MEXP; +} + +/** + * This function changes internal state of tinymt32. + * Users should not call this function directly. + * @param random tinymt internal status + */ +inline static void tinymt32_next_state(tinymt32_t *random) +{ + uint32_t x; + uint32_t y; + + y = random->status[3]; + x = (random->status[0] & TINYMT32_MASK) + ^ random->status[1] + ^ random->status[2]; + x ^= (x << TINYMT32_SH0); + y ^= (y >> TINYMT32_SH0) ^ x; + random->status[0] = random->status[1]; + random->status[1] = random->status[2]; + random->status[2] = x ^ (y << TINYMT32_SH1); + random->status[3] = y; + random->status[1] ^= -((int32_t)(y & 1)) & random->mat1; + random->status[2] ^= -((int32_t)(y & 1)) & random->mat2; +} + +/** + * This function outputs 32-bit unsigned integer from internal state. + * Users should not call this function directly. + * @param random tinymt internal status + * @return 32-bit unsigned pseudorandom number + */ +inline static uint32_t tinymt32_temper(tinymt32_t *random) +{ + uint32_t t0, t1; + + t0 = random->status[3]; + t1 = random->status[0] + (random->status[2] >> TINYMT32_SH8); + t0 ^= t1; + t0 ^= -((int32_t)(t1 & 1)) & random->tmat; + return t0; +} + +/** + * This function outputs floating point number from internal state. + * Users should not call this function directly. + * @param random tinymt internal status + * @return floating point number r (1.0 <= r < 2.0) + */ +inline static float tinymt32_temper_conv(tinymt32_t *random) +{ + uint32_t t0, t1; + + union { + uint32_t u; + float f; + } conv; + + t0 = random->status[3]; + t1 = random->status[0] + (random->status[2] >> TINYMT32_SH8); + t0 ^= t1; + conv.u = ((t0 ^ (-((int32_t)(t1 & 1)) & random->tmat)) >> 9) + | UINT32_C(0x3f800000); + return conv.f; +} + +/** + * This function outputs floating point number from internal state. + * Users should not call this function directly. + * @param random tinymt internal status + * @return floating point number r (1.0 < r < 2.0) + */ +inline static float tinymt32_temper_conv_open(tinymt32_t *random) +{ + uint32_t t0, t1; + + union { + uint32_t u; + float f; + } conv; + + t0 = random->status[3]; + t1 = random->status[0] + (random->status[2] >> TINYMT32_SH8); + t0 ^= t1; + conv.u = ((t0 ^ (-((int32_t)(t1 & 1)) & random->tmat)) >> 9) + | UINT32_C(0x3f800001); + return conv.f; +} + +/** + * This function outputs 32-bit unsigned integer from internal state. + * @param random tinymt internal status + * @return 32-bit unsigned integer r (0 <= r < 2^32) + */ +inline static uint32_t tinymt32_generate_uint32(tinymt32_t *random) +{ + tinymt32_next_state(random); + return tinymt32_temper(random); +} + +/** + * This function outputs floating point number from internal state. + * This function is implemented using multiplying by (1 / 2^24). + * floating point multiplication is faster than using union trick in + * my Intel CPU. + * @param random tinymt internal status + * @return floating point number r (0.0 <= r < 1.0) + */ +inline static float tinymt32_generate_float(tinymt32_t *random) +{ + tinymt32_next_state(random); + return (tinymt32_temper(random) >> 8) * TINYMT32_MUL; +} + +/** + * This function outputs floating point number from internal state. + * This function is implemented using union trick. + * @param random tinymt internal status + * @return floating point number r (1.0 <= r < 2.0) + */ +inline static float tinymt32_generate_float12(tinymt32_t *random) +{ + tinymt32_next_state(random); + return tinymt32_temper_conv(random); +} + +/** + * This function outputs floating point number from internal state. + * This function is implemented using union trick. + * @param random tinymt internal status + * @return floating point number r (0.0 <= r < 1.0) + */ +inline static float tinymt32_generate_float01(tinymt32_t *random) +{ + tinymt32_next_state(random); + return tinymt32_temper_conv(random) - 1.0f; +} + +/** + * This function outputs floating point number from internal state. + * This function may return 1.0 and never returns 0.0. + * @param random tinymt internal status + * @return floating point number r (0.0 < r <= 1.0) + */ +inline static float tinymt32_generate_floatOC(tinymt32_t *random) +{ + tinymt32_next_state(random); + return 1.0f - tinymt32_generate_float(random); +} + +/** + * This function outputs floating point number from internal state. + * This function returns neither 0.0 nor 1.0. + * @param random tinymt internal status + * @return floating point number r (0.0 < r < 1.0) + */ +inline static float tinymt32_generate_floatOO(tinymt32_t *random) +{ + tinymt32_next_state(random); + return tinymt32_temper_conv_open(random) - 1.0f; +} + +/** + * This function outputs double precision floating point number from + * internal state. The returned value has 32-bit precision. + * In other words, this function makes one double precision floating point + * number from one 32-bit unsigned integer. + * @param random tinymt internal status + * @return floating point number r (0.0 < r <= 1.0) + */ +inline static double tinymt32_generate_32double(tinymt32_t *random) +{ + tinymt32_next_state(random); + return tinymt32_temper(random) * (1.0 / 4294967296.0); +} + +#ifdef __cplusplus +} +#endif + +#endif