From 009a2eef6e00e9a98f4835d9064f33fbbb4c80d6 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Mon, 7 Jun 2021 21:54:55 +0200 Subject: [PATCH] stdlib: add TinyMT-based rand, and malloc/etc for gint --- 3rdparty/tinymt32/rand.c | 14 +++ 3rdparty/tinymt32/tinymt32.c | 121 ++++++++++++++++++++++++++ 3rdparty/tinymt32/tinymt32.h | 40 +++++++++ CMakeLists.txt | 9 ++ README.md | 3 + STATUS | 11 ++- include/fxlibc/printf.h | 6 +- include/stdlib.h | 22 +++-- src/libc/stdlib/calloc.c | 27 ++---- src/libc/stdlib/target/gint/free.c | 8 ++ src/libc/stdlib/target/gint/malloc.c | 8 ++ src/libc/stdlib/target/gint/realloc.c | 8 ++ 12 files changed, 244 insertions(+), 33 deletions(-) create mode 100644 3rdparty/tinymt32/rand.c create mode 100644 3rdparty/tinymt32/tinymt32.c create mode 100644 3rdparty/tinymt32/tinymt32.h create mode 100644 src/libc/stdlib/target/gint/free.c create mode 100644 src/libc/stdlib/target/gint/malloc.c create mode 100644 src/libc/stdlib/target/gint/realloc.c diff --git a/3rdparty/tinymt32/rand.c b/3rdparty/tinymt32/rand.c new file mode 100644 index 0000000..a9266d1 --- /dev/null +++ b/3rdparty/tinymt32/rand.c @@ -0,0 +1,14 @@ +#include +#include "tinymt32.h" + +static tinymt32_t random; + +void srand(unsigned int seed) +{ + tinymt32_init(&random, seed); +} + +int rand(void) +{ + return tinymt32_generate_uint32(&random) & 0x7fffffff; +} diff --git a/3rdparty/tinymt32/tinymt32.c b/3rdparty/tinymt32/tinymt32.c new file mode 100644 index 0000000..898ae98 --- /dev/null +++ b/3rdparty/tinymt32/tinymt32.c @@ -0,0 +1,121 @@ +/** + * @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 + */ + +/* Note: this is a stripped-down version of TinyMT that only includes the + 32-bit integer generator. For the full version, please see + . */ + +#include "tinymt32.h" + +#define TINYMT32_SH0 1 +#define TINYMT32_SH1 10 +#define TINYMT32_SH8 8 +#define TINYMT32_MASK 0x7fffffff + +/** + * This function changes internal state of tinymt32. + * Users should not call this function directly. + * @param random tinymt internal status + */ +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 + */ +static uint32_t tinymt32_temper(tinymt32_t * random) { + uint32_t t0, t1; + t0 = random->status[3]; +#if defined(LINEARITY_CHECK) + t1 = random->status[0] + ^ (random->status[2] >> TINYMT32_SH8); +#else + t1 = random->status[0] + + (random->status[2] >> TINYMT32_SH8); +#endif + t0 ^= t1; + t0 ^= -((int32_t)(t1 & 1)) & random->tmat; + return t0; +} + +/** + * 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) + */ +uint32_t tinymt32_generate_uint32(tinymt32_t * random) { + tinymt32_next_state(random); + return tinymt32_temper(random); +} + +#define MIN_LOOP 8 +#define PRE_LOOP 8 + +/** + * 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); + } +} diff --git a/3rdparty/tinymt32/tinymt32.h b/3rdparty/tinymt32/tinymt32.h new file mode 100644 index 0000000..9bb2f5c --- /dev/null +++ b/3rdparty/tinymt32/tinymt32.h @@ -0,0 +1,40 @@ +#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 + */ + +/* Note: this is a stripped-down version of TinyMT that only includes the + 32-bit integer generator. For the full version, please see + . */ + +#include + +/** + * 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; + +uint32_t tinymt32_generate_uint32(tinymt32_t *random); +void tinymt32_init(tinymt32_t *random, uint32_t seed); + +#endif diff --git a/CMakeLists.txt b/CMakeLists.txt index 50ffd8c..5436bc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,8 @@ endif() set(SOURCES # 3rdparty 3rdparty/grisu2b_59_56/grisu2b_59_56.c + 3rdparty/tinymt32/rand.c + 3rdparty/tinymt32/tinymt32.c # assert src/libc/assert/assert.c # ctype @@ -229,6 +231,13 @@ if(sh-generic IN_LIST TARGET_FOLDERS) src/target/sh-generic/cpucap.c) endif() +if(gint IN_LIST TARGET_FOLDERS) + list(APPEND SOURCES + src/libc/stdlib/target/gint/free.c + src/libc/stdlib/target/gint/malloc.c + src/libc/stdlib/target/gint/realloc.c) +endif() + if(casiowin-fx IN_LIST TARGET_FOLDERS) list(APPEND SOURCES src/posix/unistd/target/casiowin-fx/close.S) diff --git a/README.md b/README.md index 159bb0e..aaa4cbe 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,9 @@ Or see the LICENSE file. FxLibc also includes third-party code that is distributed under its own license. Currently, this includes: +* A stripped-down version of the [TinyMT random number generator](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index.html) + ([GitHub repository](https://github.com/MersenneTwister-Lab/TinyMT)) by + Mutsuo Saito and Makoto Matsumoto. See `src/3rdparty/tinymt32/LICENSE.txt`. * A stripped-down version of the [Grisu2b floating-point representation algorithm](https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf) with α=-59 and γ=-56, by Florian Loitsch. See `src/3rdparty/grisu2b_59_56/README` diff --git a/STATUS b/STATUS index 3de77b1..6e7fcc4 100644 --- a/STATUS +++ b/STATUS @@ -96,13 +96,18 @@ DONE: Function/symbol/macro is defined, builds, links, and is tested ! 7.19.10 Error-handling functions: TODO 7.20 - 7.20 RAND_MAX, MB_CUR_MAX: TODO + 7.20 RAND_MAX: DONE +! 7.20 MB_CUR_MAX: TODO 7.20.1.1 atof: DONE 7.20.1.2 atoi, atol, atoll: DONE 7.20.1.3 strtod, strtof, strtold: DONE 7.20.1.4 strtol, strtoul, strtoll, strtoull: DONE -! 7.20.2 Pseudo-random sequence generation functions: TODO -! 7.20.3 Memory management functions: TODO (check existing code first) + 7.20.2.1 rand: DONE + 7.20.2.2 srand: DONE + 7.20.3.1 calloc: DONE + 7.20.3.2 free: DONE (at least gint) + 7.20.3.3 malloc: DONE (at least gint) + 7.20.3.4 realloc: DONE (at least gint) 7.20.4.1 abort: DONE ! 7.20.4.2 atexit: TODO 7.20.4.3 exit: DONE (missing stream flushing/closing/etc) diff --git a/include/fxlibc/printf.h b/include/fxlibc/printf.h index 161587e..80cbd52 100644 --- a/include/fxlibc/printf.h +++ b/include/fxlibc/printf.h @@ -31,7 +31,7 @@ struct __printf_output { }; /* Generic formatted printing. */ -int __printf( +extern int __printf( struct __printf_output * restrict __out, char const * restrict __format, va_list *__args); @@ -46,7 +46,7 @@ int __printf( ** code from the fxlibc library and registers formatters for all 6 ** floating-point formats. */ -void __printf_enable_fp(void); +extern void __printf_enable_fp(void); /* Format extension API. */ @@ -219,7 +219,7 @@ struct __printf_geometry ** 5. Turn remaining padding into spaces at the left (if opt->alignment == NUL) ** or right (if opt->alignment == '-'). */ -void __printf_compute_geometry( +extern void __printf_compute_geometry( struct __printf_format *__opt, struct __printf_geometry *__geometry); diff --git a/include/stdlib.h b/include/stdlib.h index 5b54c43..ecd7dcf 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -32,15 +32,15 @@ extern void free(void *__ptr); /* Abort execution; raises SIGABRT and leaves quickly with _Exit(). */ __attribute__((noreturn)) -void abort(void); +extern void abort(void); /* Exit; calls handlers, flushes and closes streams and temporary files. */ __attribute__((noreturn)) -void exit(int __status); +extern void exit(int __status); /* Exit immediately, bypassing exit handlers or signal handlers. */ __attribute__((noreturn)) -void _Exit(int __status); +extern void _Exit(int __status); /* Integer arithmetic functions. */ @@ -74,9 +74,9 @@ typedef struct { long long int quot, rem; } lldiv_t; -div_t div(int __num, int __denom); -ldiv_t ldiv(long int __num, long int __denom); -lldiv_t lldiv(long long int __num, long long int __denom); +extern div_t div(int __num, int __denom); +extern ldiv_t ldiv(long int __num, long int __denom); +extern lldiv_t lldiv(long long int __num, long long int __denom); /* Simplified numeric conversion functions. */ @@ -133,4 +133,14 @@ extern long double strtold( char const * restrict __ptr, char ** restrict __endptr); +/* Pseudo-random sequence generation functions. */ + +#define RAND_MAX 0x7fffffff + +/* Seed the PRNG. */ +extern void srand(unsigned int seed); + +/* Generate a pseudo-random number between 0 and RAND_MAX. */ +extern int rand(void); + #endif /*__STDLIB_H__*/ diff --git a/src/libc/stdlib/calloc.c b/src/libc/stdlib/calloc.c index 91e3b95..2508447 100644 --- a/src/libc/stdlib/calloc.c +++ b/src/libc/stdlib/calloc.c @@ -1,29 +1,14 @@ #include #include -#include -/* -** The calloc() function allocates memory for an array of nmemb elements of size -** bytes each and returns a pointer to the allocated memory. The memory is set -** to zero. If nmemb or size is 0, then calloc() returns either NULL, or a -** unique pointer value that can later be successfully passed to free(). If the -** multiplication of nmemb and size would result in integer overflow, then -** calloc() returns an error. By contrast, an integer overflow would not be -** detected in the following call to malloc(), with the result that an incorrectly -** sized block of memory would be allocated: `malloc(nmemb * size);` -*/ void *calloc(size_t nmemb, size_t size) { - // check error - if (size == 0 || nmemb == 0) - return (NULL); + unsigned int total_size; - // Try to allowate the area - void *ret = malloc(nmemb * size); - if (ret == NULL) - return (NULL); + if(__builtin_umul_overflow(nmemb, size, &total_size)) + return NULL; - // wipe the area - memset(ret, 0x00, size); - return (ret); + void *mem = malloc(total_size); + if(mem) memset(mem, 0, size); + return mem; } diff --git a/src/libc/stdlib/target/gint/free.c b/src/libc/stdlib/target/gint/free.c new file mode 100644 index 0000000..5fad8d1 --- /dev/null +++ b/src/libc/stdlib/target/gint/free.c @@ -0,0 +1,8 @@ +#include + +extern void kfree(void *ptr); + +void free(void *ptr) +{ + return kfree(ptr); +} diff --git a/src/libc/stdlib/target/gint/malloc.c b/src/libc/stdlib/target/gint/malloc.c new file mode 100644 index 0000000..5bd2104 --- /dev/null +++ b/src/libc/stdlib/target/gint/malloc.c @@ -0,0 +1,8 @@ +#include + +extern void *kmalloc(size_t size, char const *arena_name); + +void *malloc(size_t size) +{ + return kmalloc(size, NULL); +} diff --git a/src/libc/stdlib/target/gint/realloc.c b/src/libc/stdlib/target/gint/realloc.c new file mode 100644 index 0000000..b37c445 --- /dev/null +++ b/src/libc/stdlib/target/gint/realloc.c @@ -0,0 +1,8 @@ +#include + +extern void *krealloc(void *ptr, size_t size); + +void *realloc(void *ptr, size_t size) +{ + return krealloc(ptr, size); +}