diff --git a/Source/hoc-clk/bpmpfw/Makefile b/Source/hoc-clk/bpmpfw/Makefile index 0631e56b..7af3a478 100644 --- a/Source/hoc-clk/bpmpfw/Makefile +++ b/Source/hoc-clk/bpmpfw/Makefile @@ -8,15 +8,26 @@ BUILDDIR := build OUTPUTDIR := out SOURCEDIR := source -OBJS := $(BUILDDIR)/start.o $(BUILDDIR)/main.o +LIBCDIR := $(SOURCEDIR)/libc -ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork +CPP_SOURCES := $(wildcard $(SOURCEDIR)/*.cpp) +C_SOURCES := $(wildcard $(LIBCDIR)/src/*.c) +S_SOURCES := $(wildcard $(SOURCEDIR)/*.s) + +OBJS := $(patsubst $(SOURCEDIR)/%.cpp,$(BUILDDIR)/%.o,$(CPP_SOURCES)) \ + $(patsubst $(LIBCDIR)/src/%.c,$(BUILDDIR)/libc/%.o,$(C_SOURCES)) \ + $(patsubst $(SOURCEDIR)/%.s,$(BUILDDIR)/%.o,$(S_SOURCES)) + +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork +INCLUDE := -I$(SOURCEDIR) -I$(LIBCDIR)/include -I$(LIBCDIR)/include/fslc +CFLAGS := $(ARCH) -O2 -g -ffreestanding -nostdlib -ffunction-sections -fdata-sections \ + -fomit-frame-pointer -std=gnu11 -Wall -Wextra $(CUSTOMDEFINES) CXXFLAGS := $(ARCH) -O2 -g -ffreestanding -nostdlib -fno-exceptions -fno-rtti \ -fno-unwind-tables -fno-threadsafe-statics -ffunction-sections -fdata-sections \ -fomit-frame-pointer -std=gnu++20 -Wall -Wextra $(CUSTOMDEFINES) -ASFLAGS := $(ARCH) -g -LDFLAGS := $(ARCH) -nostartfiles -nodefaultlibs -Wl,--nmagic,--gc-sections \ - -T $(SOURCEDIR)/../bpmpfw.ld -lgcc +ASFLAGS := $(ARCH) -g +LDFLAGS := $(ARCH) -nostartfiles -nodefaultlibs -Wl,--nmagic,--gc-sections \ + -T $(SOURCEDIR)/../bpmpfw.ld -lgcc BIN_TARGET := $(OUTPUTDIR)/$(TARGET).bin @@ -32,13 +43,19 @@ $(BUILDDIR)/$(TARGET).elf: $(OBJS) @$(CXX) $(LDFLAGS) $(OBJS) -o $@ $(BUILDDIR)/%.o: $(SOURCEDIR)/%.cpp | $(BUILDDIR) - @$(CXX) $(CXXFLAGS) -I$(SOURCEDIR) -c $< -o $@ + @$(CXX) $(CXXFLAGS) $(INCLUDE) -c $< -o $@ + +$(BUILDDIR)/libc/%.o: $(LIBCDIR)/src/%.c | $(BUILDDIR)/libc + @$(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ $(BUILDDIR)/%.o: $(SOURCEDIR)/%.s | $(BUILDDIR) - @$(CXX) $(ASFLAGS) -I$(SOURCEDIR) -c $< -o $@ + @$(CXX) $(ASFLAGS) $(INCLUDE) -c $< -o $@ $(BUILDDIR): @mkdir -p $(BUILDDIR) +$(BUILDDIR)/libc: | $(BUILDDIR) + @mkdir -p $(BUILDDIR)/libc + clean: @rm -rf $(BUILDDIR) $(OUTPUTDIR) diff --git a/Source/hoc-clk/bpmpfw/out/bpmpfw.bin b/Source/hoc-clk/bpmpfw/out/bpmpfw.bin index c6d35308..04f7484e 100644 Binary files a/Source/hoc-clk/bpmpfw/out/bpmpfw.bin and b/Source/hoc-clk/bpmpfw/out/bpmpfw.bin differ diff --git a/Source/hoc-clk/bpmpfw/source/libc/LICENSE b/Source/hoc-clk/bpmpfw/source/libc/LICENSE new file mode 100644 index 00000000..3ea91fc4 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015-2016 Jurģis Brigmanis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Source/hoc-clk/bpmpfw/source/libc/include/assert.h b/Source/hoc-clk/bpmpfw/source/libc/include/assert.h new file mode 100644 index 00000000..a022cf62 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/include/assert.h @@ -0,0 +1,6 @@ +#ifndef _STD_ASSERT_H +#define _STD_ASSERT_H + +#include "fslc/fslc_assert.h" + +#endif /* _STD_ASSERT_H */ diff --git a/Source/hoc-clk/bpmpfw/source/libc/include/fslc/fslc_assert.h b/Source/hoc-clk/bpmpfw/source/libc/include/fslc/fslc_assert.h new file mode 100644 index 00000000..131498df --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/include/fslc/fslc_assert.h @@ -0,0 +1,35 @@ +#ifndef FSLC_ASSERT_H +#define FSLC_ASSERT_H + +#ifndef ALT_FSLC_NAMES + +#define fslc_assert assert + +#endif /* ALT_FSLC_NAMES */ + + +#ifdef NDEBUG + +#define fslc_assert(expr) ((void)0) + +#else /* NDEBUG */ + +/* Note: __PRETTY_FUNCTION__ is GCC specific */ +#define fslc_assert(expr) ((expr) ? (void)0 : __fslc_assert_fail(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__)) + +#endif /* NDEBUG */ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + void __fslc_assert_fail(const char *expr, const char *file, unsigned int line, const char *func); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* FSLC_ASSERT_H */ diff --git a/Source/hoc-clk/bpmpfw/source/libc/include/fslc/fslc_stdio.h b/Source/hoc-clk/bpmpfw/source/libc/include/fslc/fslc_stdio.h new file mode 100644 index 00000000..ffdc222d --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/include/fslc/fslc_stdio.h @@ -0,0 +1,74 @@ +#ifndef FSLC_STDIO_H +#define FSLC_STDIO_H + +#include +#include + +#ifndef ALT_FSLC_NAMES + +#define FSLC_FILE FILE +#define fslc_stdout stdout +#define fslc_stdin stdin +#define fslc_putchar putchar +#define fslc_fputc fputc +#define fslc_fputs fputs +#define fslc_puts puts + +#define fslc_vfprintf vfprintf +#define fslc_vprintf vprintf +#define fslc_fprintf fprintf +#define fslc_printf printf + +#define fslc_fwrite fwrite +#define fslc_fread fread + +#define fslc_getc getc +#define fslc_getchar getchar +#define fslc_ungetc ungetc +#define fslc_fgets fgets + +#endif /* ALT_FSLC_NAMES */ + +typedef struct _FSLC_FILE FSLC_FILE; + +struct _FSLC_FILE +{ + void *user_ptr; + int (*putc)(int c, FSLC_FILE *stream); + int (*getc)(FSLC_FILE *stream); + void (*pre_output)(FSLC_FILE *stream); + void (*post_output)(FSLC_FILE *stream); + int ungetc_buf; +}; + +extern FSLC_FILE *fslc_stdout; +extern FSLC_FILE *fslc_stdin; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + int fslc_putchar(int c); + int fslc_fputc(int c, FSLC_FILE *stream); + int fslc_fputs(const char *str, FSLC_FILE *stream); + int fslc_puts(const char *str); + + int fslc_vfprintf(FSLC_FILE *stream, const char *format, va_list arg); + int fslc_vprintf(const char *format, va_list arg); + int fslc_fprintf(FSLC_FILE *stream, const char *format, ...); + int fslc_printf(const char *format, ...); + + size_t fslc_fwrite(const void *ptr, size_t size, size_t count, FSLC_FILE *stream); + size_t fslc_fread(void *ptr, size_t size, size_t count, FSLC_FILE *stream); + + int fslc_getc(FSLC_FILE *stream); + int fslc_getchar(void); + int fslc_ungetc(int c, FSLC_FILE *stream); + char *fslc_fgets(char *str, int num, FSLC_FILE *stream); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +#endif /* FSLC_STDIO_H */ diff --git a/Source/hoc-clk/bpmpfw/source/libc/include/fslc/fslc_stdlib.h b/Source/hoc-clk/bpmpfw/source/libc/include/fslc/fslc_stdlib.h new file mode 100644 index 00000000..021b67aa --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/include/fslc/fslc_stdlib.h @@ -0,0 +1,25 @@ +#ifndef FSLC_STDLIB_H +#define FSLC_STDLIB_H + +#include + +#ifndef ALT_FSLC_NAMES + +#define fslc_bsearch bsearch + +#endif /* ALT_FSLC_NAMES */ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + void *fslc_bsearch(const void *key, const void *base, size_t num, size_t size, int (*cmp_proc)(const void *, const void *)); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* FSLC_STDLIB_H */ diff --git a/Source/hoc-clk/bpmpfw/source/libc/include/fslc/fslc_string.h b/Source/hoc-clk/bpmpfw/source/libc/include/fslc/fslc_string.h new file mode 100644 index 00000000..a869054d --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/include/fslc/fslc_string.h @@ -0,0 +1,50 @@ +#ifndef FSLC_STRING_H +#define FSLC_STRING_H + +#include + +#ifndef ALT_FSLC_NAMES +#define fslc_memset memset +#define fslc_memcpy memcpy +#define fslc_memmove memmove +#define fslc_memcmp memcmp + +#define fslc_strlen strlen +#define fslc_strcpy strcpy +#define fslc_strncpy strncpy +#define fslc_strcmp strcmp +#define fslc_strncmp strncmp +#define fslc_strchr strchr +#define fslc_strstr strstr +#define fslc_strpbrk strpbrk +#define fslc_strspn strspn +#define fslc_strtok_r strtok_r + +#endif /* ALT_FSLC_NAMES */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + void *fslc_memset(void *ptr, int value, size_t num); + void *fslc_memcpy(void *dest, const void *src, size_t len); + void *fslc_memmove(void *dest, const void *src, size_t len); + int fslc_memcmp(const void *ptr1, const void *ptr2, size_t num); + + size_t fslc_strlen(const char *str); + char *fslc_strcpy(char *dest, const char *src); + char *fslc_strncpy(char *dest, const char *src, size_t len); + int fslc_strcmp(const char *str1, const char *str2); + int fslc_strncmp(const char *str1, const char *str2, size_t num); + char *fslc_strchr(const char *str, int c); + char *fslc_strstr(const char *search_in, const char *search_for); + char *fslc_strpbrk(const char *str, const char *delim); + size_t fslc_strspn(const char *str, const char *delim); + char *fslc_strtok_r(char *str, const char *delim, char **save_p); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +#endif /* FSLC_STRING_H */ diff --git a/Source/hoc-clk/bpmpfw/source/libc/include/fslc/stdlibx.h b/Source/hoc-clk/bpmpfw/source/libc/include/fslc/stdlibx.h new file mode 100644 index 00000000..2b86a1a4 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/include/fslc/stdlibx.h @@ -0,0 +1,23 @@ +#ifndef FSLC_STDLIBX_H +#define FSLC_STDLIBX_H + +#include + +#ifndef ALT_FSLC_NAMES + +#define fslc_bsearch_i bsearch_i + +#endif /* ALT_FSLC_NAMES */ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + int fslc_bsearch_i(const void *key, const void *base, size_t num, size_t size, int (*cmp_proc)(const void *, const void *)); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* FSLC_STDLIBX_H */ diff --git a/Source/hoc-clk/bpmpfw/source/libc/include/fslc/stringx.h b/Source/hoc-clk/bpmpfw/source/libc/include/fslc/stringx.h new file mode 100644 index 00000000..193d8913 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/include/fslc/stringx.h @@ -0,0 +1,33 @@ +#ifndef FSLC_STRINGX_H +#define FSLC_STRINGX_H + +#include + +#ifndef ALT_FSLC_NAMES + +#define fslc_memset_l memset_l +#define fslc_strcpy_e strcpy_e +#define fslc_strncpy_e strncpy_e + +#endif /* ALT_FSLC_NAMES */ + +#if __SIZEOF_LONG__ == 4 +#define memset_32 memset_l +#elif __SIZEOF_LONG__ == 8 +#define memset_32(A, V, S) memset_l(A, (((unsigned long)(V)<<32)|(V)), S) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + void *fslc_memset_l(void *ptr, unsigned long value, size_t num); + char *fslc_strcpy_e(char *dest, const char *src); + char *fslc_strncpy_e(char *dest, const char *src, size_t len); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* FSLC_STRINGX_H */ diff --git a/Source/hoc-clk/bpmpfw/source/libc/include/stdio.h b/Source/hoc-clk/bpmpfw/source/libc/include/stdio.h new file mode 100644 index 00000000..fb4853f2 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/include/stdio.h @@ -0,0 +1,6 @@ +#ifndef _STD_STDIO_H +#define _STD_STDIO_H + +#include "fslc/fslc_stdio.h" + +#endif /* _STD_STDIO_H */ diff --git a/Source/hoc-clk/bpmpfw/source/libc/include/stdlib.h b/Source/hoc-clk/bpmpfw/source/libc/include/stdlib.h new file mode 100644 index 00000000..34259177 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/include/stdlib.h @@ -0,0 +1,6 @@ +#ifndef _STD_STDLIB_H +#define _STD_STDLIB_H + +#include "fslc/fslc_stdlib.h" + +#endif /* _STD_STDLIB_H */ diff --git a/Source/hoc-clk/bpmpfw/source/libc/include/string.h b/Source/hoc-clk/bpmpfw/source/libc/include/string.h new file mode 100644 index 00000000..c35eec9c --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/include/string.h @@ -0,0 +1,6 @@ +#ifndef _STD_STRING_H +#define _STD_STRING_H + +#include "fslc/fslc_string.h" + +#endif /* _STD_STRING_H */ diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_bsearch.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_bsearch.c new file mode 100644 index 00000000..1f25f704 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_bsearch.c @@ -0,0 +1,12 @@ +#include "fslc_stdlib.h" +#include "stdlibx.h" + +void *fslc_bsearch(const void *key, const void *base, size_t num, size_t size, int (*cmp_proc)(const void *, const void *)) +{ + int sidx = fslc_bsearch_i(key, base, num, size, cmp_proc); + + if (sidx < 0) + return NULL; + + return (char *)base + (sidx * size); +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_bsearch_i.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_bsearch_i.c new file mode 100644 index 00000000..52cf54b4 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_bsearch_i.c @@ -0,0 +1,31 @@ +#include + +int fslc_bsearch_i(const void *key, const void *base, size_t num, size_t size, int (*cmp_proc)(const void *, const void *)) +{ + int lo = 0; + int hi = num - 1; + + char *cbase = (char *)base; + + while (lo <= hi) + { + int i = lo + ((hi - lo) >> 1); + + char *ptr = cbase + (i * size); + int cmp = cmp_proc(key, ptr); + + if (cmp == 0) + return i; + + if (cmp > 0) + { + lo = i + 1; + } + else + { + hi = i - 1; + } + } + + return ~lo; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_fprintf.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_fprintf.c new file mode 100644 index 00000000..688d5912 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_fprintf.c @@ -0,0 +1,10 @@ +#include "fslc_stdio.h" + +int fslc_fprintf(FSLC_FILE *stream, const char *format, ...) +{ + va_list args; + va_start(args, format); + int r = fslc_vfprintf(stream, format, args); + va_end(args); + return r; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_fputc.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_fputc.c new file mode 100644 index 00000000..2745b827 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_fputc.c @@ -0,0 +1,12 @@ +#include "fslc_stdio.h" + +int fslc_fputc(int c, FSLC_FILE *stream) +{ + if (stream->pre_output) stream->pre_output(stream); + + int r = stream->putc(c, stream); + + if (stream->post_output) stream->post_output(stream); + + return r; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_fputs.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_fputs.c new file mode 100644 index 00000000..be8d13a9 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_fputs.c @@ -0,0 +1,15 @@ +#include "fslc_stdio.h" + +int _fslc_fputs_impl(const char *str, FSLC_FILE *stream); + +int fslc_fputs(const char *str, FSLC_FILE *stream) +{ + if (stream->pre_output) stream->pre_output(stream); + + int r = _fslc_fputs_impl(str, stream); + + if (stream->post_output) stream->post_output(stream); + + return r; +} + diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_fputs_impl.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_fputs_impl.c new file mode 100644 index 00000000..9743de6b --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_fputs_impl.c @@ -0,0 +1,13 @@ +#include "fslc_stdio.h" + +int _fslc_fputs_impl(const char *str, FSLC_FILE *stream) +{ + int res = 0; + for (;*str; ++str) + { + int pr = stream->putc(*str, stream); + if (pr < 0) return pr; + ++res; + } + return res; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memcmp.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memcmp.c new file mode 100644 index 00000000..6719b878 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memcmp.c @@ -0,0 +1,38 @@ +#include "fslc_string.h" +#include + +int fslc_memcmp(const void *ptr1, const void *ptr2, size_t num) +{ + unsigned char *b_p1 = (unsigned char *)ptr1; + unsigned char *b_p2 = (unsigned char *)ptr2; + + for (;((uintptr_t)b_p1 & (sizeof(long)-1)) && num > 0; ++b_p1, ++b_p2, --num) + { + if (*b_p1 != *b_p2) + { + return *b_p1 > *b_p2 ? 1 : -1; + } + } + + unsigned long *w_p1 = (unsigned long *)b_p1; + unsigned long *w_p2 = (unsigned long *)b_p2; + for (;num >= sizeof(unsigned long); ++w_p1, ++w_p2, num -= sizeof(unsigned long)) + { + if (*w_p1 != *w_p2) + { + return *w_p1 > *w_p2 ? 1 : -1; + } + } + + b_p1 = (unsigned char *)w_p1; + b_p2 = (unsigned char *)w_p2; + for (; num > 0; ++b_p1, ++b_p2, --num) + { + if (*b_p1 != *b_p2) + { + return *b_p1 > *b_p2 ? 1 : -1; + } + } + + return 0; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memcpy.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memcpy.c new file mode 100644 index 00000000..2383248c --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memcpy.c @@ -0,0 +1,40 @@ +#include "fslc_string.h" +#include + +void *fslc_memcpy(void *dest, const void *src, size_t len) +{ + /* Copy byte-by-byte up to word-aligned. + * + * There's a possibility, that src and dest have different offsets + * to word boundary and can not both be used efficiently. + * + * In this case we use align to dest argument, because it then can be + * written in one operation, instead of read-modify-write of 2 words. + * + * Most of the time both parameters should be word-aligned, however. + */ + unsigned char *b_src = (unsigned char *)src; + unsigned char *b_dst = (unsigned char *)dest; + for (;((uintptr_t)b_dst & (sizeof(unsigned long)-1)) && len > 0; b_src++, b_dst++, len--) + { + *b_dst = *b_src; + } + + /* Then all word-aligned */ + unsigned long *w_src = (unsigned long*)b_src; + unsigned long *w_dst = (unsigned long*)b_dst; + for (;len >= sizeof(unsigned long); w_src++, w_dst++, len -= sizeof(unsigned long)) + { + *w_dst = *w_src; + } + + /* And byte-by-byte the rest */ + b_src = (unsigned char *)w_src; + b_dst = (unsigned char *)w_dst; + for (; len > 0; b_src++, b_dst++, len--) + { + *b_dst = *b_src; + } + + return dest; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memmove.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memmove.c new file mode 100644 index 00000000..68426ca6 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memmove.c @@ -0,0 +1,69 @@ +#include "fslc_string.h" +#include + +void *fslc_memmove(void *dest, const void *src, size_t len) +{ + unsigned char *b_dst = (unsigned char *)dest; + unsigned char *b_src = (unsigned char *)src; + + /* Need to check if memory regions overlaps. Then if the dest address is + * larger than source, we need to copy backwards (or else source regions + * ending will be overwritten by writes to dest, before they are read). + * + * In other cases it works identically as memcpy(). Same considerations + * about address alignment applies here. + */ + if ( b_dst < b_src + len && b_dst > b_src) + { + b_src += len; + b_dst += len; + + /* Byte-by-byte down to word-aligned. */ + for (;((uintptr_t)b_dst & (sizeof(unsigned long)-1)) && len > 0; ) + { + b_src--, b_dst--, len--; + *b_dst = *b_src; + } + + /* Then all word-aligned */ + unsigned long *w_src = (unsigned long*)b_src; + unsigned long *w_dst = (unsigned long*)b_dst; + for (;len >= sizeof(unsigned long); ) + { + w_src--, w_dst--, len -= sizeof(unsigned long); + *w_dst = *w_src; + } + + /* And byte-by-byte the rest */ + b_src = (unsigned char *)w_src; + b_dst = (unsigned char *)w_dst; + for (; len > 0; ) + { + b_src--, b_dst--, len--; + *b_dst = *b_src; + } + } else { + /* Byte-by-byte up to word-aligned. */ + for (;((uintptr_t)b_dst & (sizeof(unsigned long)-1)) && len > 0; b_src++, b_dst++, len--) + { + *b_dst = *b_src; + } + + /* Then all word-aligned */ + unsigned long *w_src = (unsigned long *)b_src; + unsigned long *w_dst = (unsigned long *)b_dst; + for (;len >= sizeof(unsigned long); w_src++, w_dst++, len -= sizeof(unsigned long)) + { + *w_dst = *w_src; + } + + /* And byte-by-byte the rest */ + b_src = (unsigned char *)w_src; + b_dst = (unsigned char *)w_dst; + for (; len > 0; b_src++, b_dst++, len--) + { + *b_dst = *b_src; + } + } + return dest; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memset.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memset.c new file mode 100644 index 00000000..321211f8 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memset.c @@ -0,0 +1,22 @@ +#include "fslc_string.h" +#include "stringx.h" + +void *fslc_memset(void *ptr, int value, size_t num) +{ + /* Will use memset_l() to actually fill the memory region. If value is non-zero, we need + * to replicate lowest byte to all the long's bytes. + */ + if (value) + { + unsigned char c_val = value; + unsigned long l_val = (c_val << 0) | (c_val << 8) | (c_val << 16) | (c_val << 24); + + #if __SIZEOF_LONG__ == 8 + l_val |= l_val << 32; + #endif + + return fslc_memset_l(ptr, l_val, num); + } + else + return fslc_memset_l(ptr, value, num); +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memset_l.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memset_l.c new file mode 100644 index 00000000..f4d46336 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_memset_l.c @@ -0,0 +1,31 @@ +#include "stringx.h" +#include + +void *fslc_memset_l(void *ptr, unsigned long value, size_t num) +{ + unsigned char *b_src = (unsigned char *)&value; + unsigned char *b_dst = (unsigned char *)ptr; + + /* Byte by byte - to aligned word address */ + b_src += ((uintptr_t)b_dst & (sizeof(unsigned long)-1)); + for (;((uintptr_t)b_dst & (sizeof(unsigned long)-1)) && num > 0; b_dst++,b_src++,num--) + { + *b_dst = *b_src; + } + + /* All aligned */ + unsigned long *w_dst = (unsigned long *)b_dst; + for (;num >= sizeof(unsigned long); w_dst++,num -= sizeof(unsigned long)) + { + *w_dst= value; + } + + /* Unaligned ending */ + b_src = (unsigned char *)&value; + b_dst = (unsigned char *)w_dst; + for (; num > 0; b_dst++,b_src++,num--) + { + *b_dst = *b_src; + } + return ptr; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_printf.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_printf.c new file mode 100644 index 00000000..2609e377 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_printf.c @@ -0,0 +1,10 @@ +#include "fslc_stdio.h" + +int fslc_printf(const char *format, ...) +{ + va_list args; + va_start(args, format); + int r = fslc_vfprintf(fslc_stdout, format, args); + va_end(args); + return r; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_putchar.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_putchar.c new file mode 100644 index 00000000..d4c1a54d --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_putchar.c @@ -0,0 +1,6 @@ +#include "fslc_stdio.h" + +int fslc_putchar(int c) +{ + return fslc_fputc(c, fslc_stdout); +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_puts.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_puts.c new file mode 100644 index 00000000..c1f5d94c --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_puts.c @@ -0,0 +1,21 @@ +#include "fslc_stdio.h" + +int _fslc_fputs_impl(const char *str, FSLC_FILE *stream); + +int fslc_puts(const char *str) +{ + if (fslc_stdout->pre_output) fslc_stdout->pre_output(fslc_stdout); + + int r = _fslc_fputs_impl(str, fslc_stdout); + + if (r >= 0) + { + int nlr = fslc_stdout->putc('\n', fslc_stdout); + if (nlr < 0) + r = nlr; + } + + if (fslc_stdout->post_output) fslc_stdout->post_output(fslc_stdout); + + return r; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_stdout.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_stdout.c new file mode 100644 index 00000000..5418196a --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_stdout.c @@ -0,0 +1,3 @@ +#include "fslc_stdio.h" + +FSLC_FILE *fslc_stdout; diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strchr.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strchr.c new file mode 100644 index 00000000..cf3e239c --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strchr.c @@ -0,0 +1,10 @@ +#include "fslc_string.h" + +char *fslc_strchr(const char *str, int c) +{ + for (;*str; ++str) + if (*str == c) + return (char *)str; + + return NULL; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strcmp.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strcmp.c new file mode 100644 index 00000000..216e147a --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strcmp.c @@ -0,0 +1,8 @@ +#include "fslc_string.h" + +int fslc_strcmp(const char *str1, const char *str2) +{ + for( ; *str1 && *str1 == *str2; ++str1, ++str2); + + return *((unsigned char *)str1) - *((unsigned char *)str2); +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strcpy.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strcpy.c new file mode 100644 index 00000000..e0fe5011 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strcpy.c @@ -0,0 +1,8 @@ +#include "fslc_string.h" +#include "stringx.h" + +char *fslc_strcpy(char *dest, const char *src) +{ + fslc_strcpy_e(dest, src); + return dest; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strcpy_e.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strcpy_e.c new file mode 100644 index 00000000..313243a5 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strcpy_e.c @@ -0,0 +1,10 @@ +#include "stringx.h" + +char *fslc_strcpy_e(char *dest, const char *src) +{ + for(; *src; ++src, ++dest) + *dest = *src; + + *dest = 0; + return dest; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strlen.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strlen.c new file mode 100644 index 00000000..15543224 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strlen.c @@ -0,0 +1,9 @@ +#include "fslc_string.h" + +size_t fslc_strlen(const char *str) +{ + size_t res = 0; + for(; *str; ++str) ++res; + + return res; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strncmp.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strncmp.c new file mode 100644 index 00000000..3ad69714 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strncmp.c @@ -0,0 +1,8 @@ +#include "fslc_string.h" + +int fslc_strncmp(const char *str1, const char *str2, size_t num) +{ + for( ; *str1 && *str1 == *str2 && num > 1; ++str1, ++str2, --num); + + return *((unsigned char *)str1) - *((unsigned char *)str2); +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strncpy.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strncpy.c new file mode 100644 index 00000000..13e74f4a --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strncpy.c @@ -0,0 +1,9 @@ +#include "fslc_string.h" + +char *_fslc_strncpy_impl(char *dest, const char *src, size_t len); + +char *fslc_strncpy(char *dest, const char *src, size_t len) +{ + _fslc_strncpy_impl(dest, src, len); + return dest; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strncpy_e.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strncpy_e.c new file mode 100644 index 00000000..b0ab743e --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strncpy_e.c @@ -0,0 +1,9 @@ +#include "stringx.h" + +char *_fslc_strncpy_impl(char *dest, const char *src, size_t len); + +char *fslc_strncpy_e(char *dest, const char *src, size_t len) +{ + char *r = _fslc_strncpy_impl(dest, src, len); + return *r ? r + 1: r; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strncpy_impl.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strncpy_impl.c new file mode 100644 index 00000000..76e80a3c --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strncpy_impl.c @@ -0,0 +1,10 @@ +#include + +char *_fslc_strncpy_impl(char *dest, const char *src, size_t len) +{ + for(; *src && len > 1; ++src, ++dest, --len) + *dest = *src; + + *dest = *src; + return dest; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strpbrk.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strpbrk.c new file mode 100644 index 00000000..743b5256 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strpbrk.c @@ -0,0 +1,14 @@ +#include "fslc_string.h" + +char *fslc_strpbrk(const char *str, const char *delim) +{ + for (; *str; ++str) + { + const char *d; + for (d = delim; *d; ++d) + if (*str == *d) + return (char *)str; + } + + return NULL; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strspn.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strspn.c new file mode 100644 index 00000000..583a0d2d --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strspn.c @@ -0,0 +1,18 @@ +#include "fslc_string.h" + +size_t fslc_strspn(const char *str, const char *delim) +{ + size_t r; + + for (r = 0; *str; ++str, ++r) + { + const char *d; + for (d = delim; *d; ++d) + if (*str == *d) // skip to next if found + break; + + if (*d == 0) // inner loop exited on \0 - char was not there + break; + } + return r; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strstr.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strstr.c new file mode 100644 index 00000000..99966c97 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strstr.c @@ -0,0 +1,23 @@ +#include "fslc_string.h" + +char *fslc_strstr(const char *search_in, const char *search_for) +{ + while (*search_in) + { + char *rc = fslc_strchr(search_in, search_for[0]); // find first char + + if (rc) + { + const char *si = rc + 1, *sf = search_for + 1; // search strcmp-style from second char + for( ; *si && *si == *sf; ++si, ++sf); + + if (*sf == 0) return rc; // end of search-for - found result + + search_in = rc + 1; // not this one, continue from next char + } + else + return NULL; // did not find first char - exit + } + + return NULL; // reached end of source - did not find +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strtok_r.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strtok_r.c new file mode 100644 index 00000000..5859eb5e --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_strtok_r.c @@ -0,0 +1,27 @@ +#include "fslc_string.h" + +char *fslc_strtok_r(char *str, const char *delim, char **save_p) +{ + if (str) + *save_p = str; + + if (*save_p == NULL) + return NULL; + + char *r = *save_p + fslc_strspn(*save_p, delim); + + char *p = fslc_strpbrk(r, delim); + + if (p) + { + *(p++) = 0; + *save_p = p; + } + else + { + if (*r == 0) r = NULL; + *save_p = NULL; + } + + return r; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_vfprintf.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_vfprintf.c new file mode 100644 index 00000000..53424299 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_vfprintf.c @@ -0,0 +1,347 @@ +#include "fslc_stdio.h" + +/* There'a a funny behaviour of va_list and va_arg() macros: + * - on x86_64 compiler generates a branch of some sort for each va_arg() macro. Normally it is not a problem, + * however it kinda screws up branch coverage analysis. Therefore I decided to move va_arg() accesses into + * dedicated functions, minimizing the issue to one untaken branch per access function. + * - passing va_list by value works fine on x86_64, but makes some tests to fail on i386. It seems that modifications + * done by va_arg() is not passed back to caller. Subsequent calls to va_arg() or access functions returns wrong + * values on that platform. + * - OK, then. Let's pass pointer to va_list instead. Not so fast. Works fine on i386, but fails to compile on + * x86_64. Fine! Wrapping va_list into a dedicated struct and passing around pointer to it. + * + * Why such a fuss about a few untaken branches in tests? Well, just because! Also, if I ever decide to refactor + * _fslc_vfprintf_impl() - the case statement is getting a bit long and messy, it should make things easier if + * argument list can be passed around freely (as opposed to using it from single function). + */ + +struct va_list_w +{ + va_list arg; +}; + +/* Prototype for printf's internal implementation */ +static int _fslc_vfprintf_impl(FSLC_FILE *stream, const char *format, struct va_list_w *args); + + +/* Main exported function */ +int fslc_vfprintf(FSLC_FILE *stream, const char *format, va_list arg) +{ + if (stream->pre_output) stream->pre_output(stream); + + struct va_list_w argw; + va_copy(argw.arg, arg); // can not assign directly, should make a copy + + int res = _fslc_vfprintf_impl(stream, format, &argw); + + va_end(argw.arg); // and free it after use + + if (stream->post_output) stream->post_output(stream); + + return res; +} + +/* Prototype to private FSLIBC function - implemented elsewhere */ +int _fslc_fputs_impl(const char *str, FSLC_FILE *stream); + + +/* Prototypes for internal functions */ +static int _fslc_put_sint_l(signed long v, FSLC_FILE *stream); +static int _fslc_put_uint_l(unsigned long v, FSLC_FILE *stream); +static int _fslc_put_hex_l(unsigned long v, FSLC_FILE *stream, char alpha); + +static int _get_sint_arg(struct va_list_w *arg); +static unsigned _get_uint_arg(struct va_list_w *arg); +static long long _get_slonglong_arg(struct va_list_w *arg); +static unsigned long long _get_ulonglong_arg(struct va_list_w *arg); +static void *_get_ptr_arg(struct va_list_w *arg); + +/* There are some considerations when formatting Integers for output: + * - on 32-bit systems integers will mostly be 32 bits long, except when one REALLY + * wants to print long long. It should be more optimal to use 32-bit calculations + * when possible and invoke 64-bit only when needed. To support that we provide 2 + * separate implementations. + * - on 64-bit systems may be 32 or 64 bits, but there is no real benefit from + * using shorter bit size. Hence common implementation. + * - this library does not aim to support systems with shorter integer sizes (like 16-bit) + * but it it did, it would probably make sense to provide optimized ports for these cases + * as well. + * + * Buffer size calculations: + * Max UInt32 fits in 10 bytes (+1 for zero terminator) decimal + * 2**32 - 1 == 4294967295z + * FFFFFFFFz + * 01234567890 + * + * Max UInt64 fits in 10 bytes (and +1 for \0) + * 2**64 -1 == 18446744073709551615z + * FFFFFFFFFFFFFFFFz + * 012345678901234567890 + */ + +#define BUFSIZE_LONG_LONG_DECIMAL 20 +#define BUFSIZE_LONG_HEX (__SIZEOF_LONG__ * 2) +#define BUFSIZE_LONG_LONG_HEX (__SIZEOF_LONG_LONG__ * 2) +#if __SIZEOF_LONG__ == 4 + +#define BUFSIZE_LONG_DECIMAL 10 +static int _fslc_put_sint_ll(signed long long v, FSLC_FILE *stream); +static int _fslc_put_uint_ll(unsigned long long v, FSLC_FILE *stream); +static int _fslc_put_hex_ll(unsigned long long v, FSLC_FILE *stream, char alpha); + +#define _get_slong_arg _get_sint_arg +#define _get_ulong_arg _get_uint_arg + +#elif __SIZEOF_LONG__ == 8 + +#define BUFSIZE_LONG_DECIMAL BUFSIZE_LONG_LONG_DECIMAL +#define _fslc_put_sint_ll _fslc_put_sint_l +#define _fslc_put_uint_ll _fslc_put_uint_l +#define _fslc_put_hex_ll _fslc_put_hex_l + +#define _get_slong_arg _get_slonglong_arg +#define _get_ulong_arg _get_ulonglong_arg + +#endif + +#define FLAG_LONG 1 +#define FLAG_VERYLONG 3 + +static int _fslc_vfprintf_impl(FSLC_FILE *stream, const char *format, struct va_list_w *arg) +{ + int res = 0; + int pr; + const char *c; + + for (c = format; *c; ++c) + { + if (*c == '%') + { + int flags = 0; + + for (;;) + { + ++c; + switch (*c) + { + case 's': + pr = _fslc_fputs_impl((const char *)_get_ptr_arg(arg), stream); + if (pr < 0) return pr; + res += pr; + break; + + case 'c': + pr = stream->putc(_get_sint_arg(arg), stream); + if (pr < 0) return pr; + ++res; + break; + + case '%': + pr = stream->putc('%', stream); + if (pr < 0) return pr; + ++res; + break; + + case 'i': + case 'd': + if ((flags & FLAG_VERYLONG) == FLAG_VERYLONG) + pr = _fslc_put_sint_ll(_get_slonglong_arg(arg), stream); + else if (flags & FLAG_LONG) + pr = _fslc_put_sint_l(_get_slong_arg(arg), stream); + else + pr = _fslc_put_sint_l(_get_sint_arg(arg), stream); + + if (pr < 0) return pr; + res += pr; + break; + + case 'u': + if ((flags & FLAG_VERYLONG) == FLAG_VERYLONG) + pr = _fslc_put_uint_ll(_get_ulonglong_arg(arg), stream); + else if (flags & FLAG_LONG) + pr = _fslc_put_uint_l(_get_ulong_arg(arg), stream); + else + pr = _fslc_put_uint_l(_get_uint_arg(arg), stream); + + if (pr < 0) return pr; + res += pr; + break; + + case 'x': + if ((flags & FLAG_VERYLONG) == FLAG_VERYLONG) + pr = _fslc_put_hex_ll(_get_ulonglong_arg(arg), stream, 'a'); + else if (flags & FLAG_LONG) + pr = _fslc_put_hex_l(_get_ulong_arg(arg), stream, 'a'); + else + pr = _fslc_put_hex_l(_get_uint_arg(arg), stream, 'a'); + + if (pr < 0) return pr; + res += pr; + break; + + case 'X': + if ((flags & FLAG_VERYLONG) == FLAG_VERYLONG) + pr = _fslc_put_hex_ll(_get_ulonglong_arg(arg), stream, 'A'); + else if (flags & FLAG_LONG) + pr = _fslc_put_hex_l(_get_ulong_arg(arg), stream, 'A'); + else + pr = _fslc_put_hex_l(_get_uint_arg(arg), stream, 'A'); + + if (pr < 0) return pr; + res += pr; + break; + + case 'p': + pr = _fslc_fputs_impl("0x", stream); + if (pr < 0) return pr; + res += pr; + + pr = _fslc_put_hex_l(_get_ulong_arg(arg), stream, 'a'); + + if (pr < 0) return pr; + res += pr; + break; + + case 'l': + if (flags & FLAG_LONG) + flags |= FLAG_VERYLONG; + else + flags |= FLAG_LONG; + continue; + } + break; + } + } else { + pr = stream->putc(*c, stream); + if (pr < 0) return pr; + ++res; + } + } + + return res; +} + +static int _get_sint_arg(struct va_list_w *arg) +{ + return va_arg(arg->arg, signed int); +} + +static unsigned _get_uint_arg(struct va_list_w *arg) +{ + return va_arg(arg->arg, unsigned int); +} + +static long long _get_slonglong_arg(struct va_list_w *arg) +{ + return va_arg(arg->arg, signed long long); +} + +static unsigned long long _get_ulonglong_arg(struct va_list_w *arg) +{ + return va_arg(arg->arg, unsigned long long); +} + +static void *_get_ptr_arg(struct va_list_w *arg) +{ + return va_arg(arg->arg, void *); +} + +static int _fslc_put_sint_l(signed long v, FSLC_FILE *stream) +{ + if (v < 0) + { + int pr = stream->putc('-', stream); + if (pr < 0) return pr; + + pr = _fslc_put_uint_l(-v, stream); + if (pr < 0) return pr; + + return pr+1; + } else + return _fslc_put_uint_l(v, stream); +} + +static int _fslc_put_uint_l(unsigned long v, FSLC_FILE *stream) +{ + char dbuff[BUFSIZE_LONG_DECIMAL+1], *p; + + dbuff[BUFSIZE_LONG_DECIMAL] = 0; + + for (p = dbuff + BUFSIZE_LONG_DECIMAL; v ; v /= 10) + { + *(--p) = (v % 10) + '0'; + } + + if (*p == 0) *(--p) = '0'; + + return _fslc_fputs_impl(p, stream); +} + +static int _fslc_put_hex_l(unsigned long v, FSLC_FILE *stream, char alpha) +{ + char dbuff[BUFSIZE_LONG_HEX+1], *p; + + dbuff[BUFSIZE_LONG_HEX] = 0; + + for (p = dbuff + BUFSIZE_LONG_HEX; v ; v >>= 4) + { + char digit = (v & 0xF); + *(--p) = digit < 10 ? digit + '0' : digit - 10 + alpha; + } + + if (*p == 0) *(--p) = '0'; + + return _fslc_fputs_impl(p, stream); +} + +#if __SIZEOF_LONG__ == 4 + +static int _fslc_put_sint_ll(signed long long v, FSLC_FILE *stream) +{ + if (v < 0) + { + int pr = stream->putc('-', stream); + if (pr < 0) return pr; + + pr = _fslc_put_uint_ll(-v, stream); + if (pr < 0) return pr; + + return pr+1; + } else + return _fslc_put_uint_ll(v, stream); +} + +static int _fslc_put_uint_ll(unsigned long long v, FSLC_FILE *stream) +{ + char dbuff[BUFSIZE_LONG_LONG_DECIMAL+1], *p; + + dbuff[BUFSIZE_LONG_LONG_DECIMAL] = 0; + + for (p = dbuff + BUFSIZE_LONG_LONG_DECIMAL; v ; v /= 10) + { + *(--p) = (v % 10) + '0'; + } + + if (*p == 0) *(--p) = '0'; + + return _fslc_fputs_impl(p, stream); +} + +static int _fslc_put_hex_ll(unsigned long long v, FSLC_FILE *stream, char alpha) +{ + char dbuff[BUFSIZE_LONG_LONG_HEX+1], *p; + + dbuff[BUFSIZE_LONG_LONG_HEX] = 0; + + for (p = dbuff + BUFSIZE_LONG_LONG_HEX; v ; v >>= 4) + { + char digit = (v & 0xF); + *(--p) = digit < 10 ? digit + '0' : digit - 10 + alpha; + } + + if (*p == 0) *(--p) = '0'; + + return _fslc_fputs_impl(p, stream); +} + +#endif diff --git a/Source/hoc-clk/bpmpfw/source/libc/src/fslc_vprintf.c b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_vprintf.c new file mode 100644 index 00000000..6f5abd1e --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc/src/fslc_vprintf.c @@ -0,0 +1,6 @@ +#include "fslc_stdio.h" + +int fslc_vprintf(const char *format, va_list arg) +{ + return fslc_vfprintf(fslc_stdout, format, arg); +} diff --git a/Source/hoc-clk/bpmpfw/source/libc_platform.cpp b/Source/hoc-clk/bpmpfw/source/libc_platform.cpp new file mode 100644 index 00000000..3f3efc4c --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc_platform.cpp @@ -0,0 +1,18 @@ +#include + +#include "regs.hpp" + +namespace { + + int UartStreamPutc(int c, FILE *) { + UartPutc(static_cast(c)); + return c; + } + + FILE g_uartStdout = { nullptr, UartStreamPutc, nullptr, nullptr, nullptr, -1 }; + +} // namespace + +void InitializeLibc() { + stdout = &g_uartStdout; +} diff --git a/Source/hoc-clk/bpmpfw/source/libc_platform.hpp b/Source/hoc-clk/bpmpfw/source/libc_platform.hpp new file mode 100644 index 00000000..4268a9c5 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/libc_platform.hpp @@ -0,0 +1,3 @@ +#pragma once + +void InitializeLibc(); diff --git a/Source/hoc-clk/bpmpfw/source/main.cpp b/Source/hoc-clk/bpmpfw/source/main.cpp index e08baa22..4e57d8db 100644 --- a/Source/hoc-clk/bpmpfw/source/main.cpp +++ b/Source/hoc-clk/bpmpfw/source/main.cpp @@ -1,7 +1,12 @@ +#include + +#include "libc_platform.hpp" #include "regs.hpp" extern "C" void main() { - UartPuts("[bpmpfw]: Hello from BPMP-FW\n"); + InitializeLibc(); + + printf("[hoc-bpmpfw] Starting bpmpfw\n"); for (;;); } diff --git a/Source/hoc-clk/bpmpfw/source/regs.hpp b/Source/hoc-clk/bpmpfw/source/regs.hpp index 00efd9eb..4f8d5965 100644 --- a/Source/hoc-clk/bpmpfw/source/regs.hpp +++ b/Source/hoc-clk/bpmpfw/source/regs.hpp @@ -7,6 +7,11 @@ using u32 = std::uint32_t; #define MMIO32(addr) (*reinterpret_cast(addr)) +constexpr u32 FwRamStart = 0x40004000; +constexpr u32 FwRamEnd = 0x4000C000; +constexpr u32 WorkRamStart = FwRamEnd; +constexpr u32 WorkRamEnd = 0x40010000; + constexpr u32 FlowCtlrBase = 0x60007000; constexpr u32 FlowCtlrHaltCopEvents = 0x004; diff --git a/Source/hoc-clk/sysmodule/perms.json b/Source/hoc-clk/sysmodule/perms.json index 01728ddf..57e821af 100644 --- a/Source/hoc-clk/sysmodule/perms.json +++ b/Source/hoc-clk/sysmodule/perms.json @@ -3,7 +3,7 @@ "title_id": "0x00FF0000636C6BFF", "title_id_range_min": "0x00FF0000636C6BFF", "title_id_range_max": "0x00FF0000636C6BFF", - "main_thread_stack_size": "0x0000C000", + "main_thread_stack_size": "0x0000F000", "main_thread_priority": 16, "default_cpu_id": 3, "process_category": 1, diff --git a/Source/hoc-clk/sysmodule/src/board/board.cpp b/Source/hoc-clk/sysmodule/src/board/board.cpp index 8bfeb2bb..da191e6d 100644 --- a/Source/hoc-clk/sysmodule/src/board/board.cpp +++ b/Source/hoc-clk/sysmodule/src/board/board.cpp @@ -182,6 +182,7 @@ namespace board { if (R_FAILED(bpmpfwRc)) { fileUtils::LogLine("[bpmp] StartBpmfwExecution failed: 0x%x", bpmpfwRc); } + bpmp::StartSleepMonitorThread(); // PMC exosphere check SecmonArgs args = {}; @@ -211,6 +212,8 @@ namespace board { } void Exit() { + bpmp::StopSleepMonitorThread(); + if (HOSSVC_HAS_CLKRST) { clkrstExit(); } else { diff --git a/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp b/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp index e7390bdc..41c0792b 100644 --- a/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp +++ b/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp @@ -64,6 +64,38 @@ namespace bpmp { return *reinterpret_cast(base_va + offset); } + // Late in the boot chain, otherwise a fatal will occur from invalid boot state + constexpr u32 pscDependencies[] = { PscPmModuleId_Olsc }; + constexpr PscPmModuleId PscModuleId = (PscPmModuleId)705; + + PscPmModule s_pscModule; + bool s_pscPrepared = false; + Thread s_pscThread; + bool s_pscExit = false; + + void PscThreadFunc(void *) { + while (!s_pscExit) { + Result rc = eventWait(&s_pscModule.event, 1'000'000'000ULL); + if (R_FAILED(rc)) { + continue; // Timeout + } + + PscPmState state; + u32 flags; + rc = pscPmModuleGetRequest(&s_pscModule, &state, &flags); + if (R_SUCCEEDED(rc)) { + if (state == PscPmState_Awake) { + Result wrc = StartBpmfwExecution(); + if (R_FAILED(wrc)) { + fileUtils::LogLine("[bpmp] restart after wake failed: 0x%x", wrc); + } + } + + pscPmModuleAcknowledge(&s_pscModule, state); + } + } + } + } // namespace Result StartBpmfwExecution() { @@ -137,4 +169,48 @@ namespace bpmp { return 0; } + void StartSleepMonitorThread() { + if (!IsPatchedExosphere()) { + fileUtils::LogLine("[bpmp] Cant start BPMP without exosphere patch"); + return; + } + + Result rc = pscmInitialize(); + if (R_FAILED(rc)) { + fileUtils::LogLine("[bpmp] pscmInitialize failed: 0x%x", rc); + return; + } + + rc = pscmGetPmModule(&s_pscModule, PscModuleId, pscDependencies, sizeof(pscDependencies) / sizeof(u32), true); + if (R_FAILED(rc)) { + fileUtils::LogLine("[bpmp] pscmGetPmModule failed: 0x%x", rc); + pscmExit(); + return; + } + s_pscPrepared = true; + + rc = threadCreate(&s_pscThread, PscThreadFunc, nullptr, NULL, 0x1000, 0x10, 3); + if (R_FAILED(rc)) { + fileUtils::LogLine("[bpmp] failed to create psc thread: 0x%x", rc); + return; + } + threadStart(&s_pscThread); + } + + void StopSleepMonitorThread() { + if (!s_pscPrepared) { + return; + } + + s_pscExit = true; + eventFire(&s_pscModule.event); + threadWaitForExit(&s_pscThread); + threadClose(&s_pscThread); + + pscPmModuleFinalize(&s_pscModule); + pscPmModuleClose(&s_pscModule); + pscmExit(); + s_pscPrepared = false; + } + } // namespace bpmp diff --git a/Source/hoc-clk/sysmodule/src/bpmp/bpmp.hpp b/Source/hoc-clk/sysmodule/src/bpmp/bpmp.hpp index e860f662..7a57069c 100644 --- a/Source/hoc-clk/sysmodule/src/bpmp/bpmp.hpp +++ b/Source/hoc-clk/sysmodule/src/bpmp/bpmp.hpp @@ -20,4 +20,7 @@ namespace bpmp { Result StartBpmfwExecution(); + + void StartSleepMonitorThread(); + void StopSleepMonitorThread(); } diff --git a/Source/hoc-clk/sysmodule/src/file/file_utils.cpp b/Source/hoc-clk/sysmodule/src/file/file_utils.cpp index 8af7e964..f519a198 100644 --- a/Source/hoc-clk/sysmodule/src/file/file_utils.cpp +++ b/Source/hoc-clk/sysmodule/src/file/file_utils.cpp @@ -103,7 +103,7 @@ namespace fileUtils { va_list args; va_start(args, format); - char buff[0xfff]; + char buff[0x200]; int len = vsnprintf(buff, sizeof(buff), format, args); va_end(args); diff --git a/Source/hoc-clk/sysmodule/src/main.cpp b/Source/hoc-clk/sysmodule/src/main.cpp index f7c5b0c1..f2452f05 100644 --- a/Source/hoc-clk/sysmodule/src/main.cpp +++ b/Source/hoc-clk/sysmodule/src/main.cpp @@ -38,7 +38,7 @@ #include "mgr/clock_manager.hpp" -#define INNER_HEAP_SIZE 0x40000 +#define INNER_HEAP_SIZE 0x48000 extern "C" { void virtmemSetup(void); diff --git a/Source/hoc-clk/sysmodule/src/mgr/clock_manager.cpp b/Source/hoc-clk/sysmodule/src/mgr/clock_manager.cpp index 223692ab..c035c11e 100644 --- a/Source/hoc-clk/sysmodule/src/mgr/clock_manager.cpp +++ b/Source/hoc-clk/sysmodule/src/mgr/clock_manager.cpp @@ -30,7 +30,6 @@ #include #include "../board/board.hpp" -#include "../bpmp/bpmp.hpp" #include "../display/aula.hpp" #include "../display/display_refresh_rate.hpp" #include "../file/config.hpp" @@ -41,7 +40,6 @@ #include "../hos/process_management.hpp" #include "../i2c/i2cDrv.h" #include "../ipc/ipc_service.hpp" -#include "../mapping/mem_map.hpp" #include "../soc/gm20b.hpp" #include "../util/lockable_mutex.h" #include "clock_manager.hpp" @@ -357,23 +355,6 @@ namespace clockManager { if (++tick > 10) { tick = 0; - // Restart BPMP after sleep. - if (IsPatchedExosphere()) { - svcSleepThread(1'500'000'000); - constexpr u32 FlowCtlrPhysBase = 0x60007000; - constexpr u32 FlowCtlrHaltCopEvents = 0x004; - constexpr u32 HaltCopEventsModeShift = 29; - constexpr u32 HaltCopEventsModeStop = 2; - - u32 haltReg = SmcReadWriteRegister(FlowCtlrPhysBase + FlowCtlrHaltCopEvents, 0, 0); - if ((haltReg >> HaltCopEventsModeShift) == HaltCopEventsModeStop) { - Result rc = bpmp::StartBpmfwExecution(); - if (R_FAILED(rc)) { - fileUtils::LogLine("[bpmp] restart after sleep failed: 0x%x", rc); - } - } - } - if (config::GetConfigValue(HocClkConfigValue_BatteryChargeCurrent)) { I2c_Bq24193_SetFastChargeCurrentLimit(config::GetConfigValue(HocClkConfigValue_BatteryChargeCurrent)); }