diff --git a/ARM.CMSIS-Compiler.pdsc b/ARM.CMSIS-Compiler.pdsc index c16f249..e0e3b3e 100644 --- a/ARM.CMSIS-Compiler.pdsc +++ b/ARM.CMSIS-Compiler.pdsc @@ -15,6 +15,8 @@ Active Development ... + CLANG: + - Added standard I/O stream support for LLVM-libc @@ -245,7 +247,7 @@ - + Standard C Library Retarget Core diff --git a/source/core/clang/retarget_syscalls.c b/source/core/clang/retarget_syscalls.c index 96260e3..834b74a 100644 --- a/source/core/clang/retarget_syscalls.c +++ b/source/core/clang/retarget_syscalls.c @@ -41,6 +41,181 @@ #endif #endif +#ifndef STDIN_ECHO +#define STDIN_ECHO 0 /* STDIN: echo to STDOUT */ +#endif +#ifndef STDOUT_CR_LF +#define STDOUT_CR_LF 0 /* STDOUT: add CR for LF */ +#endif +#ifndef STDERR_CR_LF +#define STDERR_CR_LF 0 /* STDERR: add CR for LF */ +#endif + +#if defined(__LLVM_LIBC__) + +/* Symbols used as cookie values to identify standard I/O stream */ +void *__llvm_libc_stdin_cookie = NULL; +void *__llvm_libc_stdout_cookie = NULL; +void *__llvm_libc_stderr_cookie = NULL; + +/** + Write bytes to a standard output stream. + + Called by LLVM-libc for all stdout/stderr writes. The cookie parameter + identifies the target stream: it matches the address of the + __llvm_libc_stdout_cookie or __llvm_libc_stderr_cookie symbol. + + \param[in] cookie Stream identifier + \param[in] buf Pointer to data buffer + \param[in] size Number of bytes to write + \return Number of bytes written, or -1 on error. +*/ +__attribute__((weak)) +ssize_t __llvm_libc_stdio_write(void *cookie, const char *buf, size_t size) { +#if (defined(RTE_CMSIS_Compiler_STDOUT) || defined(RTE_CMSIS_Compiler_STDERR)) + int ch; + ssize_t sz = 0; + const char *p = buf; +#else + (void)cookie; + (void)buf; + (void)size; +#endif + +#if defined(RTE_CMSIS_Compiler_STDOUT) + if (cookie == &__llvm_libc_stdout_cookie) { + while (sz < (ssize_t)size) { + ch = *p++; +#if (STDOUT_CR_LF != 0) + if (ch == '\n') { + if (stdout_putchar('\r') == -1) { + break; + } + } +#endif + if (stdout_putchar(ch) == -1) { + break; + } + sz++; + } + return (sz); + } +#endif + +#if defined(RTE_CMSIS_Compiler_STDERR) + if (cookie == &__llvm_libc_stderr_cookie) { + while (sz < (ssize_t)size) { + ch = *p++; +#if (STDERR_CR_LF != 0) + if (ch == '\n') { + if (stderr_putchar('\r') == -1) { + break; + } + } +#endif + if (stderr_putchar(ch) == -1) { + break; + } + sz++; + } + return (sz); + } +#endif + /* Not implemented */ + return (-1); +} + +/** + Read bytes from stdin. + + Called by LLVM-libc for all stdin reads. The cookie parameter matches the + address of the __llvm_libc_stdin_cookie symbol. + + \param[in] cookie Stream identifier + \param[out] buf Pointer to data buffer + \param[in] size Maximum number of bytes to read + \return Number of bytes read (> 0), 0 on end of input, + or a negative errno value on error. +*/ +__attribute__((weak)) +ssize_t __llvm_libc_stdio_read(void *cookie, char *buf, size_t size) { +#if defined(RTE_CMSIS_Compiler_STDIN) + int ch; + ssize_t sz = 0; + char *p = buf; +#else + (void)cookie; + (void)buf; + (void)size; +#endif + +#if defined(RTE_CMSIS_Compiler_STDIN) + if (cookie == &__llvm_libc_stdin_cookie) { + while (sz < (ssize_t)size) { + ch = stdin_getchar(); + if (ch < 0) { + break; + } + *p++ = (char)ch; +#if (STDIN_ECHO != 0) + stdout_putchar(ch); +#endif + sz++; + } + return sz; + } +#endif + /* Not implemented */ + return (-1); +} + +/** + Terminate a process. + + Called by LLVM-libc for all process termination. + The status parameter is the exit code passed to the exit() function. This + implementation does not support process termination, so it simply enters + an infinite loop. + + \param[in] status Exit code passed to exit() +*/ +__attribute__((weak, __noreturn__)) +void __llvm_libc_exit(int status) { + (void)status; + for (;;) { ; } +} + +/** + Set up the exceptions table and enable relevant interrupts. + + This function overrides crt0's _platform_setup_exceptions which sets VTOR + to its own minimal 16-entry vector table, breaking device IRQ handlers. + Restoring VTOR to the full CMSIS vector table (256 entries) ensures device- + specific interrupt vectors are resolved correctly. +*/ +__attribute__((weak)) +void _platform_setup_exceptions (void) {} + +/** + Set up the Memory Management Unit and caches. + + This function overrides crt0's _platform_setup_memory which may override settings + applied in vendor specific SystemInit. +*/ +__attribute__((weak)) +void _platform_setup_memory (void) {} + +/** + Set up architecture extensions that require special initialization. + + This function overrides crt0's _platform_setup_arch_extensions which may override + settings applied in vendor specific SystemInit. +*/ +__attribute__((weak)) +void _platform_setup_arch_extensions (void) {} + +#elif defined(__PICOLIBC_VERSION__) + #if defined(RTE_CMSIS_Compiler_STDIN) /** Get a character from the stdio @@ -93,7 +268,6 @@ static FILE __stdout = FDEV_SETUP_STREAM(stdout_putc, FILE *const stdout = &__stdout; #endif - #if defined(RTE_CMSIS_Compiler_STDERR) /** Put a character to the stderr @@ -125,3 +299,4 @@ __attribute__((weak, __noreturn__)) void _exit (int status) { for(;;){ ; } } +#endif /* __LLVM_LIBC__ */