diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cd3216..524d8d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,10 +40,7 @@ set(SOURCES src/libs/bfile.c src/libs/justui.c src/libs/libimg.c - src/libs/memory.c src/libs/openlibm.c - src/libs/printf.c - src/libs/tinymt.c src/mem/mem.c src/perf/cpucache.c src/perf/cpucache.S diff --git a/include/gintctl/libs.h b/include/gintctl/libs.h index 54ab3b4..729318f 100644 --- a/include/gintctl/libs.h +++ b/include/gintctl/libs.h @@ -5,15 +5,6 @@ #ifndef GINTCTL_LIBS #define GINTCTL_LIBS -/* gintctl_libs_tinymt(): TinyMT32 random number generation */ -void gintctl_libs_tinymt(void); - -/* gintctl_libs_printf(): printf() function */ -void gintctl_libs_printf(void); - -/* gintctl_libs_memory(): Core memory functions */ -void gintctl_libs_memory(void); - /* gintctl_libs_openlibm(): OpenLibm floating-point functions */ void gintctl_libs_openlibm(void); diff --git a/src/gintctl.c b/src/gintctl.c index a2739ad..e12ee5b 100644 --- a/src/gintctl.c +++ b/src/gintctl.c @@ -78,12 +78,6 @@ struct menu menu_perf = { struct menu menu_libs = { _("Libraries", "External and standard libraries"), .entries = { - { "libc: " _("TinyMT32", "TinyMT random number generation"), - gintctl_libs_tinymt, 0 }, - { "libc: " _("printf family", "Formatted printing (with Grisu2b)"), - gintctl_libs_printf, 0 }, - { "libc: " _("mem functions", "Core memory functions"), - gintctl_libs_memory, 0 }, { "libm: " _("OpenLibm", "OpenLibm floating-point functions"), gintctl_libs_openlibm, 0 }, { "libimg" _("",": Image transforms"), diff --git a/src/libs/memory.c b/src/libs/memory.c deleted file mode 100644 index b3f3144..0000000 --- a/src/libs/memory.c +++ /dev/null @@ -1,309 +0,0 @@ -//--- -// gintctl:libs:memory - Automated core memory function tests -// -// These tests are meant to check all size/alignment scenarii for the core -// memory functions. Two intervals of sizes are tested: -// * 12..15 bytes, expected to be handled naively -// * 192..195 bytes, expected to trigger alignment-related optimizations -// For each of these intervals, all alignments possibilities are tested: -// * 4n + { 0,1,2,3 } for the source address -// * 4n + { 0,1,2,3 } for destination address -// Also, the source and destination regions are made to overlap to allow -// non-trivial memmove() cases to be checked. -//--- - -#include -#include -#include -#include - -#include -#include - -#include - -/* Source buffer, used as a data source when copying */ -GALIGNED(4) static uint8_t *src; -/* Destination buffer, used as destination when copying or clearing */ -GALIGNED(4) static uint8_t *dst; -/* System buffer, used to reproduce the behavior on the system and compare */ -GALIGNED(4) static uint8_t *sys; -/* Temporary buffer, used by the naive memmove() */ -GALIGNED(4) static uint8_t *tmp; - -/* Fill buffer with non-zero and position-sensitive data */ -static void fill(uint8_t *buf, int start) -{ - for(int i = 0; i < 256; i++) buf[i] = start+i; -} -/* Clear buffer */ -static void clear(uint8_t *buf) -{ - for(int i = 0; i < 256; i++) buf[i] = 0; -} -/* Check buffer equality (returns zero on equal) */ -static int cmp(uint8_t *lft, uint8_t *rgt) -{ - for(int i = 0; i < 256; i++) if(lft[i] != rgt[i]) return 1; - return 0; -} - -/* Code of exception that occurs during a memory access */ -static uint32_t exception = 0; -/* Exception-catching function */ -static int catch_exc(uint32_t code) -{ - if(code == 0x100 || code == 0x0e0) - { - exception = code; - gint_exc_skip(1); - return 0; - } - return 1; -} - -//--- -// Naive functions (reference behaviour) -//--- - -static void *naive_memcpy(void *_dst, void const *_src, size_t len) -{ - uint8_t *dst = _dst; - uint8_t const *src = _src; - - while(len--) *dst++ = *src++; - return _dst; -} -static void *naive_memset(void *_dst, int byte, size_t len) -{ - uint8_t *dst = _dst; - - while(len--) *dst++ = byte; - return _dst; -} -static void *naive_memmove(void *_dst, void const *_src, size_t len) -{ - naive_memcpy(tmp, _src, len); - naive_memcpy(_dst, tmp, len); - return _dst; -} -static int naive_memcmp(void const *_s1, void const *_s2, size_t len) -{ - uint8_t const *s1 = _s1, *s2 = _s2; - - for(size_t i = 0; i < len; i++) - { - if(s1[i] != s2[i]) return s1[i] - s2[i]; - } - return 0; -} - -//--- -// Testing functions -//--- - -static int test_memcpy(int off_dst, int off_src, size_t len) -{ - clear(dst); - clear(sys); - - memcpy(dst + off_dst, src + off_src, len); - naive_memcpy(sys + off_dst, src + off_src, len); - - return cmp(dst, sys); -} - -static int test_memset(int off_dst, GUNUSED int off_src, size_t len) -{ - fill(dst, 0); - fill(sys, 0); - - memset(dst + off_dst, 0, len); - naive_memset(sys + off_dst, 0, len); - - return cmp(dst, sys); -} - -static int test_memmove(int off_dst, int off_src, size_t len) -{ - fill(dst, 0); - fill(sys, 0); - - memmove(dst + off_dst, dst + off_src, len); - naive_memmove(sys + off_dst, sys + off_src, len); - - return cmp(dst, sys); -} - -static int test_memcmp(int off_dst, int off_src, size_t len) -{ - /* Create data that matches at the provided offsets */ - fill(dst, -off_dst); - fill(sys, -off_src); - - /* Check equality */ - if(memcmp(dst + off_dst, sys + off_src, len) != - naive_memcmp(dst + off_dst, sys + off_src, len)) return 1; - - /* Check that changing any single byte results in a mismatch */ - for(size_t i = 0; i < len; i++) - { - dst[off_dst + i] ^= 0xff; - if(memcmp(dst + off_dst, sys + off_src, len) != - naive_memcmp(dst + off_dst, sys + off_src, len)) return 1; - dst[off_dst + i] ^= 0xff; - } - - return 0; -} - -//--- -// Automated tests -//--- - -/* exc(): Wrapper that accounts for exceptions */ -static int exc(int (*func)(int of_dst, int off_src, size_t len), int off_dst, - int off_src, size_t len) -{ - exception = 0; - gint_exc_catch(catch_exc); - - int ret = func(off_dst, off_src, len); - - gint_exc_catch(NULL); - - return exception ? (int)exception : ret; -} - -/* test(): Check core memory functions in various size/alignment scenarii - - The function to test takes three arguments: two buffer offsets and the size - of the operation. Bounds need no be checked. It must return 0 in case of - success and non-zero in case of failure. - - @func Function to test, will be called with various sizes and alignments - @count If non-null, set to number of tests performed - Returns the number of failed tests; thus, non-zero indicates failure. */ -static void test(int (*func)(int off_dst, int off_src, size_t len), - uint8_t *results) -{ - int current_test = 0; - - /* For each source and destination alignment... */ - for(int src_al = 0; src_al < 4; src_al++) - for(int dst_al = 0; dst_al < 4; dst_al++, current_test += 16) - /* For each "alignment" of operation size... */ - for(int len_al = 0; len_al < 4; len_al++) - { - int b = current_test + len_al; - - /* Try a small size first */ - results[b] = exc(func, 96+dst_al, 96+src_al, 12+len_al); - /* Then a medium region without overlapping */ - results[b+4] = exc(func, 4+dst_al, 128+src_al, 92+len_al); - /* A large region with left-right overlapping */ - results[b+8] = exc(func, 64+dst_al, 96 +src_al, 128+len_al); - /* A large region with right-left overlapping */ - results[b+12] = exc(func, 96+dst_al, 64 +src_al, 128+len_al); - } -} - -//--- -// Main function -//--- - -#define dcenter(x, y, ...) \ - dprint_opt(x, y, C_BLACK, C_NONE, DTEXT_CENTER, DTEXT_TOP, __VA_ARGS__) -#define dright(x, y, ...) \ - dprint_opt(x, y, C_BLACK, C_NONE, DTEXT_RIGHT, DTEXT_TOP, __VA_ARGS__) - -/* gintctl_libs_memory(): Core memory functions */ -void gintctl_libs_memory(void) -{ - dclear(C_WHITE); - dtext_opt(DWIDTH / 2, DHEIGHT / 2, C_BLACK, C_NONE, DTEXT_CENTER, - DTEXT_MIDDLE, "Testing..."); - dupdate(); - - uint8_t buf_src[256]; - uint8_t buf_dst[256]; - uint8_t buf_sys[256]; - uint8_t buf_tmp[256]; - - src = buf_src; - dst = buf_dst; - sys = buf_sys; - tmp = buf_tmp; - - GUNUSED int key = 0, tab = 0; - - uint8_t results[4][256]; - char const *names[4] = { "memcpy", "memset", "memmove", "memcmp" }; - int scores[4] = { 0 }; - - test(test_memcpy, results[0]); - test(test_memset, results[1]); - test(test_memmove, results[2]); - test(test_memcmp, results[3]); - - for(int i = 0; i < 4; i++) - for(int t = 0; t < 256; t++) - { - scores[i] += !results[i][t]; - } - - while(key != KEY_EXIT) - { - dclear(C_WHITE); - - #ifdef FX9860G - row_title("Core memory functions"); - - for(int i = 0; i < 4; i++) - row_print(i+3, 1, "%-7s: %d/256", names[i], scores[i]); - #endif - - #ifdef FXCG50 - row_title("libc: Core memory functions"); - - dprint(10, 19, C_BLACK, "%s", names[tab]); - dprint(10, 31, C_BLACK, "%d/256", scores[tab]); - - dcenter(234, 19, "Source align and destination align"); - for(int i = 0; i < 16; i++) - dprint(84+19*i, 31, C_BLACK, "%d%d", i >> 2, i & 3); - - dprint(10, 44, C_BLACK, "Small"); - dprint(10, 84, C_BLACK, "Large"); - dprint(10, 124, C_BLACK, "Inter1"); - dprint(10, 164, C_BLACK, "Inter2"); - for(int i = 0; i < 16; i++) - dright(78, 44+10*i, "%d", i & 3); - - for(int y = 0; y < 16; y++) - for(int x = 0; x < 16; x++) - { - int x1=82+19*x, y1=43+10*y; - - int fg = C_BLACK; - if(results[tab][16 * x + y] == 1) fg = C_RED; - if(results[tab][16 * x + y] == 0) fg = C_GREEN; - - drect_border(x1,y1,x1+19,y1+10, fg, 1, C_BLACK); - } - - fkey_menu(1, "MEMCPY"); - fkey_menu(2, "MEMSET"); - fkey_menu(3, "MEMMOVE"); - fkey_menu(4, "MEMCMP"); - #endif - - dupdate(); - key = getkey().key; - - if(key == KEY_F1) tab = 0; - if(key == KEY_F2) tab = 1; - if(key == KEY_F3) tab = 2; - if(key == KEY_F4) tab = 3; - } -} diff --git a/src/libs/printf.c b/src/libs/printf.c deleted file mode 100644 index 90133c0..0000000 --- a/src/libs/printf.c +++ /dev/null @@ -1,283 +0,0 @@ -#include -#include - -#include -#include - -#include -#include -#include - -#define NAN __builtin_nan("") -#define INFINITY __builtin_inf() - -#define SCROLL_HEIGHT _(9,12) - -struct printf_test { - char const *format; - - /* Argument information is set by macros below */ - enum { - TYPE_I32, TYPE_U32, TYPE_STR, TYPE_PTR, TYPE_U64, TYPE_DBL - } type; - union { - int i32; - uint32_t u32; - char const *str; - void *ptr; - uint64_t u64; - double dbl; - }; - char const *argument_as_string; - char const *solution; -}; - -#define I32(i) TYPE_I32, { .i32 = i }, #i -#define U32(u) TYPE_U32, { .u32 = u }, #u -#define STR(s) TYPE_STR, { .str = s }, #s -#define PTR(p) TYPE_PTR, { .ptr = (void *)p }, #p -#define U64(u) TYPE_U64, { .u64 = u }, #u -#define DBL(d) TYPE_DBL, { .dbl = d }, #d - -static struct printf_test const tests[] = { - /* Base cases with length and precision */ - { "%d", I32(-849), "-849" }, - { "%7i", I32(78372), " 78372" }, - { "%3d", I32(65536), "65536" }, - { "%6.4d", I32(17), " 0017" }, - { "%6.3d", I32(-1876), " -1876" }, - { "%.0d", I32(0), "" }, - { "%.d", I32(0), "" }, - /* Sign */ - { "%+i", I32(15), "+15" }, - { "% 7i", I32(78372), " 78372" }, - { "% d", I32(65536), " 65536" }, - /* Alignment */ - { "%08d", I32(-839), "-0000839" }, - { "%-6.4d", I32(17), "0017 " }, - { "%-+6.4i", I32(17), "+0017 " }, - /* Bases */ - { "%d", I32(0xcb7), "3255" }, - { "%x", U32(0xcb7), "cb7" }, - { "%X", U32(0xcb7), "CB7" }, - { "%o", U32(0xcb7), "6267" }, - /* Argument size */ - { "%lld", U64(10000000000ll), "10000000000" }, - { "%llx", U64(0x123456789abull), "123456789ab" }, - /* Alternative prefixes */ - { "%#x", U32(0x7b), "0x7b" }, - { "%#X", U32(0x7b), "0X7B" }, - { "%#o", U32(255), "0377" }, - /* Pointers */ - { "%p", PTR(0xa44b0000), "0xa44b0000" }, - /* Characters and strings */ - { "%s", STR("HellWrld!"), "HellWrld!" }, - { "%-8.5s", STR("Hello, World!"), "Hello " }, - { "%c", I32(100), "d" }, - { "%6c", I32('#'), " #", }, - /* Floating-point special values */ - { "%f", DBL(NAN), "nan" }, - { "%3.5F", DBL(NAN), "NAN" }, - { "%+2F", DBL(-INFINITY), "-INF" }, - { "%10G", DBL(INFINITY), "INF" }, - { "%+g", DBL(INFINITY), "inf" }, - { "%7.3e", DBL(-INFINITY), "-inf" }, - { "%8E", DBL(NAN), "NAN" }, - /* Simple floating-point cases */ - { "%f", DBL(13e3), "13000.000000" }, - { "%.3f", DBL(-13e3), "-13000.000" }, - { "%.F", DBL(13e3), "13000" }, - { "%f", DBL(-12.42), "-12.420000" }, - { "%.0f", DBL(-12.42), "-12", }, - { "%.1f", DBL(12.42), "12.4", }, - { "%.8F", DBL(12.42), "12.42000000" }, - { "%F", DBL(0.0312), "0.031200" }, - { "%.4f", DBL(0.0312), "0.0312" }, - { "%.2f", DBL(-0.0312), "-0.03", }, - { "%.0f", DBL(0.0312), "0", }, - /* Floating-point rounding */ - { "%.f", DBL(1.75), "2", }, - { "%.1f", DBL(1.75), "1.8", }, - { "%.3F", DBL(0.0625), "0.063", }, - { "%.1F", DBL(-99.99), "-100.0" }, - { "%.2F", DBL(12999.992), "12999.99" }, - { "%.2f", DBL(12999.995), "13000.00" }, - /* General options with floating-point */ - { "%09.3F", DBL(123.4567), "00123.457" }, - { "%05.0f", DBL(99.99), "00100" }, - { "%+11f", DBL(0.0035678), " +0.003568" }, - { "%- 11F", DBL(0.0035678), " 0.003568 " }, - /* Simple exponent cases */ - { "%e", DBL(3.876), "3.876000e+00" }, - { "%E", DBL(-38473.34254), "-3.847334E+04" }, - { "%.2e", DBL(187.2), "1.87e+02" }, - { "%.1e", DBL(-18.27), "-1.8e+01" }, - { "%e", DBL(1e-10), "1.000000e-10" }, - { "%E", DBL(3.873e180), "3.873000E+180" }, - { "%.e", DBL(0.0005), "5e-04" }, - { "%.E", DBL(128.37), "1E+02" }, - { "%.5e", DBL(912.3), "9.12300e+02" }, - /* Exponent with rounding and general options */ - { "%11.3e", DBL(12.499), " 1.250e+01" }, - { "% -11.E", DBL(358.7), " 4E+02 " }, - { "%+e", DBL(14.99999), "+1.499999e+01" }, - { "%+e", DBL(14.999999), "+1.500000e+01" }, - /* Exponent sizes */ - { "%.2e", DBL(1e10), "1.00e+10" }, - { "%.2e", DBL(1e100), "1.00e+100" }, - { "%.2e", DBL(1e-10), "1.00e-10" }, - { "%.2e", DBL(1e-100), "1.00e-100" }, - /* Format selection and trailing zero elimination in %g */ - { "%g", DBL(124), "124" }, - { "%g", DBL(2.3), "2.3" }, - { "%g", DBL(0.0001), "0.0001" }, - { "%G", DBL(0.00001), "1E-05" }, - { "%g", DBL(834e-93), "8.34e-91" }, - { "%g", DBL(32842914732), "3.28429e+10" }, - { "%g", DBL(123456), "123456" }, - { "%G", DBL(1234567), "1.23457E+06" }, - { "%G", DBL(123000), "123000" }, - /* Rounding and general options in %g */ - { "%.3g", DBL(1278), "1.28e+03" }, - { "%+.8g", DBL(1.23e5), "+123000" }, - { "%- 12.8g", DBL(123000.01), " 123000.01 " }, - { "%0.8g", DBL(123000.001), "123000" }, - { "%08.8g", DBL(123000.001), "00123000" }, - { "%g", DBL(1.234567), "1.23457" }, - { "%.1g", DBL(1.8), "2" }, - /* Edge cases of significant digit count in %g */ - { "%.4g", DBL(999.93), "999.9" }, - { "%.4g", DBL(999.97), "1000" }, - { "%.5g", DBL(999.97), "999.97" }, - { "%.8G", DBL(999.97), "999.97" }, - { "%.4g", DBL(1.0001), "1", }, - /* Elimination of trailing zeros in %g */ - { "%.3g", DBL(3002), "3e+03" }, - { "%.5g", DBL(0.00000034), "3.4e-07" }, - { "%.6g", DBL(999.9997), "1000" }, - /* NULL terminator */ - { NULL } -}; - -static void run_tests(struct printf_test const *tests, char answers[][16], - int *passed) -{ - for(int i = 0; tests[i].format; i++) - { - struct printf_test const *t = &tests[i]; - - #define run(TYPE, field) case TYPE: \ - snprintf(answers[i], 16, t->format, t->field); \ - break; - - switch(t->type) - { - run(TYPE_I32, i32) - run(TYPE_U32, u32) - run(TYPE_STR, str) - run(TYPE_PTR, ptr) - run(TYPE_U64, u64) - run(TYPE_DBL, dbl) - } - - passed[i] = !strcmp(answers[i], t->solution); - } -} - -static void draw(struct printf_test const *tests, char answers[][16], - int *passed, int offset) -{ - int total_passed=0, total=0; - for(int i = 0; tests[i].format; i++) - { - total_passed += passed[i]; - total++; - } - - dclear(C_WHITE); - - #ifdef FX9860G - extern font_t font_mini; - font_t const *old_font = dfont(&font_mini); - - dprint( 1, 0, C_BLACK, "ID"); - dprint(13, 0, C_BLACK, "Format"); - dprint(43, 0, C_BLACK, "Output"); - dprint(99, 0, C_BLACK, "%d/%d", total_passed, total); - dhline(6, C_BLACK); - - for(int i = 0; i < SCROLL_HEIGHT; i++) - { - struct printf_test const *t = &tests[offset+i]; - int y = (i+1) * 6 + 2; - dprint( 1, y, C_BLACK, "%d", offset+i+1); - dprint(13, y, C_BLACK, "%s", t->format); - dprint(43, y, C_BLACK, "%s", answers[offset+i][0] - ? answers[offset+i] : ""); - dprint(99, y, C_BLACK, "%s", passed[offset+i]?"Ok":"Err"); - } - dfont(old_font); - #endif - - #ifdef FXCG50 - row_title("libc: Formatted printing functions"); - - row_print(1, 2, "ID"); - row_print(1, 5, "Format"); - row_print(1, 13, "Argument"); - row_print(1, 29, "Answer"); - dline(12, 34, 355, 34, C_BLACK); - - for(int i = 0; i < SCROLL_HEIGHT; i++) - { - struct printf_test const *t = &tests[offset+i]; - int y = row_y(i+2) + 2; - dprint( 14, y, C_BLACK, "%d", offset+i+1); - dprint( 38, y, C_BLACK, "%s", t->format); - dprint(102, y, C_BLACK, "%s", t->argument_as_string); - - int fg = passed[offset+i] ? C_RGB(0,31,0) : C_RGB(31,0,0); - dprint_opt(230, y, fg, C_NONE, DTEXT_LEFT, DTEXT_TOP, "%s", - answers[offset+i][0] ? answers[offset+i] : ""); - } - - row_print(14, 1, "Passed: %d/%d", total_passed, total); - #endif - - scrollbar_px( - /* view */ _(8,37), _(60,201), - /* range */ 0, total, - /* visible */ offset, SCROLL_HEIGHT); - dupdate(); -} - -/* gintctl_libs_printf(): printf() function */ -void gintctl_libs_printf(void) -{ - key_event_t ev; - int key=0, total=0, offset=0; - for(int i = 0; tests[i].format; i++) total++; - - int test_count = sizeof tests / sizeof tests[0]; - char answers[test_count][16]; - int passed[test_count]; - run_tests(tests, answers, passed); - - while(key != KEY_EXIT) - { - draw(tests, answers, passed, offset); - key = (ev = getkey()).key; - - int scroll_max = total - SCROLL_HEIGHT; - if(key == KEY_UP) - { - if(ev.shift || keydown(KEY_SHIFT)) offset = 0; - else if(offset > 0) offset--; - } - if(key == KEY_DOWN) - { - if(ev.shift || keydown(KEY_SHIFT)) offset = scroll_max; - else if(offset < scroll_max) offset++; - } - } -} diff --git a/src/libs/tinymt.c b/src/libs/tinymt.c deleted file mode 100644 index 6dbdd94..0000000 --- a/src/libs/tinymt.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include - -#include -#include - -#include - -void gintctl_libs_tinymt(void) -{ - int key = 0; - - uint32_t seed = 0xdeadbeef; - srand(seed); - uint32_t values[32]; - for(int i = 0; i < 32; i++) values[i] = rand(); - - dclear(C_WHITE); - - #ifdef FX9860G - row_print(1, 1, "TinyMT random"); - - row_print(2, 1, "Seed: %08X", seed); - for(int i = 0; i < 12; i++) - row_print(3+(i >> 1), (i&1)?13:2, "%08X", values[i]); - #endif - - #ifdef FXCG50 - row_title("TinyMT random number generation"); - row_print(1, 1, "Seed: %08X", seed); - row_print(3, 1, "First values:"); - - for(int i = 0; i < 32; i++) - row_print(4+(i >> 2), 2+12*(i&3), "%08X", values[i]); - #endif - - dupdate(); - - while(key != KEY_EXIT) key = getkey().key; -}