Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion ARM.CMSIS-Compiler.pdsc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
<releases>
<release version="2.2.1-dev">
Active Development ...
CLANG:
- Added standard I/O stream support for LLVM-libc
</release>
</releases>

Expand Down Expand Up @@ -245,7 +247,7 @@
<file category="header" name="config/stdio_cmsis_uart_config.h" attr="config" version="1.0.0" condition="STDIO UART CMSIS"/>
</files>
</component>
<component Cclass="CMSIS-Compiler" Cgroup="CORE" Cversion="1.2.0" condition="CLANG CortexDevice">
<component Cclass="CMSIS-Compiler" Cgroup="CORE" Cversion="1.3.0" condition="CLANG CortexDevice">
<description>Standard C Library Retarget Core</description>
<files>
<file category="sourceC" name="source/core/clang/retarget_syscalls.c"/>
Expand Down
177 changes: 176 additions & 1 deletion source/core/clang/retarget_syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -125,3 +299,4 @@ __attribute__((weak, __noreturn__))
void _exit (int status) {
for(;;){ ; }
}
#endif /* __LLVM_LIBC__ */
Loading