Skip to content

Support picolib #357

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,5 @@ jobs:
run: pushd examples; ./build_all.sh || exit; popd
- name: ci-debug-build
run: pushd examples/blink; make debug RAM_START=0x20004000 FLASH_INIT=0x30051 || exit; popd
- name: ci-build-picolib
run: pushd examples/tests/hello_loop; make clean; make PICOLIB=1 || exit; popd
74 changes: 49 additions & 25 deletions Configuration.mk
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ override CPPFLAGS_PIC += \
-Wl,--emit-relocs\
-fPIC

ifneq ($(PICOLIB),)
# Use picolib for libc. We need to include the `picolib-tock` library which
# maps Tock's system-level functions to the names that picolib expects.
EXTERN_LIBS += $(TOCK_USERLAND_BASE_DIR)/picolib-tock
endif

################################################################################
##
## RISC-V compiler/linker flags
Expand Down Expand Up @@ -256,10 +262,19 @@ else ifeq ($(CC_rv32_version_major),13)
else
NEWLIB_VERSION_rv32 := 4.3.0.20230120
endif
NEWLIB_VERSION_rv32i := $(NEWLIB_VERSION_rv32)
NEWLIB_VERSION_rv32imc := $(NEWLIB_VERSION_rv32)
NEWLIB_VERSION_rv32imac := $(NEWLIB_VERSION_rv32)
NEWLIB_BASE_DIR_rv32 := $(TOCK_USERLAND_BASE_DIR)/lib/libtock-newlib-$(NEWLIB_VERSION_rv32)

ifeq ($(PICOLIB),)
# Use newlib
TOCK_LIBC_FOLDER_rv32 := libtock-newlib-$(NEWLIB_VERSION_rv32)
else
# Use picolib
TOCK_LIBC_FOLDER_rv32 := libtock-picolib-1.8.5
endif

TOCK_LIBC_FOLDER_rv32i := $(TOCK_LIBC_FOLDER_rv32)
TOCK_LIBC_FOLDER_rv32imc := $(TOCK_LIBC_FOLDER_rv32)
TOCK_LIBC_FOLDER_rv32imac := $(TOCK_LIBC_FOLDER_rv32)
TOCK_LIBC_BASE_DIR_rv32 := $(TOCK_USERLAND_BASE_DIR)/lib/$(TOCK_LIBC_FOLDER_rv32)

# Match compiler version to supported libtock-libc++ versions.
ifeq ($(CC_rv32_version_major),10)
Expand Down Expand Up @@ -299,7 +314,7 @@ override CFLAGS_rv32imac += $(CFLAGS_rv32)
# Set the base `CPPFLAGS` for all RISC-V variants based on the toolchain family.
override CPPFLAGS_rv32 += \
$(CPPFLAGS_toolchain_rv32) \
-isystem $(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/include \
-isystem $(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/include \
-isystem $(LIBCPP_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/include/c++/$(LIBCPP_VERSION_rv32) \
-isystem $(LIBCPP_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/include/c++/$(LIBCPP_VERSION_rv32)/riscv64-unknown-elf

Expand Down Expand Up @@ -330,26 +345,26 @@ override WLFLAGS_rv32imc += $(WLFLAGS_rv32)
override WLFLAGS_rv32imac += $(WLFLAGS_rv32)

override SYSTEM_LIBS_rv32i += \
$(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a \
$(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a
$(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a \
$(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a

override SYSTEM_LIBS_CXX_rv32i += \
$(LIBCPP_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a \
$(LIBCPP_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libsupc++.a \
$(LIBCPP_BASE_DIR_rv32)/riscv/lib/gcc/riscv64-unknown-elf/$(LIBCPP_VERSION_rv32)/rv32i/ilp32/libgcc.a

override SYSTEM_LIBS_rv32imc += \
$(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32im/ilp32/libc.a \
$(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32im/ilp32/libm.a
$(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32im/ilp32/libc.a \
$(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32im/ilp32/libm.a

override SYSTEM_LIBS_CXX_rv32imc += \
$(LIBCPP_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32im/ilp32/libstdc++.a \
$(LIBCPP_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32im/ilp32/libsupc++.a \
$(LIBCPP_BASE_DIR_rv32)/riscv/lib/gcc/riscv64-unknown-elf/$(LIBCPP_VERSION_rv32)/rv32im/ilp32/libgcc.a

override SYSTEM_LIBS_rv32imac += \
$(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32imac/ilp32/libc.a \
$(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32imac/ilp32/libm.a
$(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32imac/ilp32/libc.a \
$(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32imac/ilp32/libm.a

override SYSTEM_LIBS_CXX_rv32imac += \
$(LIBCPP_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32imac/ilp32/libstdc++.a \
Expand Down Expand Up @@ -396,11 +411,20 @@ else ifeq ($(CC_cortex-m_version_major),13)
else
NEWLIB_VERSION_cortex-m := 4.3.0.20230120
endif
NEWLIB_VERSION_cortex-m0 := $(NEWLIB_VERSION_cortex-m)
NEWLIB_VERSION_cortex-m3 := $(NEWLIB_VERSION_cortex-m)
NEWLIB_VERSION_cortex-m4 := $(NEWLIB_VERSION_cortex-m)
NEWLIB_VERSION_cortex-m7 := $(NEWLIB_VERSION_cortex-m)
NEWLIB_BASE_DIR_cortex-m := $(TOCK_USERLAND_BASE_DIR)/lib/libtock-newlib-$(NEWLIB_VERSION_cortex-m)

ifeq ($(PICOLIB),)
# Use newlib
TOCK_LIBC_FOLDER_cortex-m := libtock-newlib-$(NEWLIB_VERSION_cortex-m)
else
# Use picolib
TOCK_LIBC_FOLDER_cortex-m := libtock-picolib-1.8.5
endif

TOCK_LIBC_FOLDER_cortex-m0 := $(TOCK_LIBC_FOLDER_cortex-m)
TOCK_LIBC_FOLDER_cortex-m3 := $(TOCK_LIBC_FOLDER_cortex-m)
TOCK_LIBC_FOLDER_cortex-m4 := $(TOCK_LIBC_FOLDER_cortex-m)
TOCK_LIBC_FOLDER_cortex-m7 := $(TOCK_LIBC_FOLDER_cortex-m)
TOCK_LIBC_BASE_DIR_cortex-m := $(TOCK_USERLAND_BASE_DIR)/lib/$(TOCK_LIBC_FOLDER_cortex-m)

# Match compiler version to supported libtock-libc++ versions.
ifeq ($(CC_cortex-m_version_major),10)
Expand Down Expand Up @@ -441,7 +465,7 @@ override CPPFLAGS_cortex-m += \
-msingle-pic-base\
-mpic-register=r9\
-mno-pic-data-is-text-relative\
-isystem $(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/include\
-isystem $(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/include\
-isystem $(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/include/c++/$(LIBCPP_VERSION_cortex-m)\
-isystem $(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/include/c++/$(LIBCPP_VERSION_cortex-m)/arm-none-eabi

Expand All @@ -460,35 +484,35 @@ override CPPFLAGS_cortex-m7 += $(CPPFLAGS_cortex-m) \
-mcpu=cortex-m7

override SYSTEM_LIBS_cortex-m0 += \
$(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v6-m/nofp/libc.a \
$(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v6-m/nofp/libm.a
$(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v6-m/nofp/libc.a \
$(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v6-m/nofp/libm.a

override SYSTEM_LIBS_CXX_cortex-m0 += \
$(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v6-m/nofp/libstdc++.a \
$(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v6-m/nofp/libsupc++.a \
$(LIBCPP_BASE_DIR_cortex-m)/arm/lib/gcc/arm-none-eabi/$(LIBCPP_VERSION_cortex-m)/thumb/v6-m/nofp/libgcc.a

override SYSTEM_LIBS_cortex-m3 += \
$(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7-m/nofp/libc.a \
$(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7-m/nofp/libm.a
$(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7-m/nofp/libc.a \
$(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7-m/nofp/libm.a

override SYSTEM_LIBS_CXX_cortex-m3 += \
$(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7-m/nofp/libstdc++.a \
$(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7-m/nofp/libsupc++.a \
$(LIBCPP_BASE_DIR_cortex-m)/arm/lib/gcc/arm-none-eabi/$(LIBCPP_VERSION_cortex-m)/thumb/v7-m/nofp/libgcc.a

override SYSTEM_LIBS_cortex-m4 += \
$(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libc.a \
$(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libm.a
$(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libc.a \
$(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libm.a

override SYSTEM_LIBS_CXX_cortex-m4 += \
$(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libstdc++.a \
$(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libsupc++.a \
$(LIBCPP_BASE_DIR_cortex-m)/arm/lib/gcc/arm-none-eabi/$(LIBCPP_VERSION_cortex-m)/thumb/v7e-m/nofp/libgcc.a

override SYSTEM_LIBS_cortex-m7 += \
$(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libc.a \
$(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libm.a
$(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libc.a \
$(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libm.a

override SYSTEM_LIBS_CXX_cortex-m7 += \
$(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libstdc++.a \
Expand Down
47 changes: 41 additions & 6 deletions Precompiled.mk
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ RISCV_ARCHS := rv32i/ilp32 rv32im/ilp32 rv32imac/ilp32
# - $(3): Arch
define PRECOMPILED_NEWLIB_RULES

TOCK_NEWLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/%/$(1)/$(2)/lib/$(3)/libc.a
TOCK_NEWLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/%/$(1)/$(2)/lib/$(3)/libm.a
TOCK_NEWLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/libtock-newlib-%/$(1)/$(2)/lib/$(3)/libc.a
TOCK_NEWLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/libtock-newlib-%/$(1)/$(2)/lib/$(3)/libm.a

endef

Expand All @@ -55,10 +55,45 @@ $(foreach arch,$(RISCV_ARCHS),$(eval $(call PRECOMPILED_NEWLIB_RULES,riscv,riscv

# Target to download and extract newlib.
#
# % will match something like "libtock-newlib-4.2.0.20211231" which we then
# strip down to just the version with some string manipulation.
# `$*` will match the version number in the libtock-newlib folder name
# (something like "libtock-newlib-4.2.0.20211231").
$(TOCK_NEWLIB_TARGETS):
cd $(TOCK_USERLAND_BASE_DIR)/lib; ./fetch-newlib.sh $(patsubst libtock-newlib-%,%,$*)
cd $(TOCK_USERLAND_BASE_DIR)/lib; ./fetch-newlib.sh $*

################################################################################
# Picolib Rules
#
# These pre-compiled archives were created using the libtock-c/picolib folder.
################################################################################

# Rule to ensure that the picolib libraries for an architecture exist.
#
# Need to list all libraries which are possible targets into one variable. It is
# imperative that the wildcard `%` expands to the same value for every target to
# tell make that one invocation of this build rule will make all the target
# files.
#
# Arguments:
# - $(1): Family
# - $(2): Toolchain
# - $(3): Arch
define PRECOMPILED_PICOLIB_RULES

TOCK_PICOLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/libtock-picolib-%/$(1)/$(2)/lib/$(3)/libc.a
TOCK_PICOLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/libtock-picolib-%/$(1)/$(2)/lib/$(3)/libm.a

endef

TOCK_PICOLIB_TARGETS :=
$(foreach arch,$(ARM_ARCHS),$(eval $(call PRECOMPILED_PICOLIB_RULES,arm,arm-none-eabi,$(arch))))
$(foreach arch,$(RISCV_ARCHS),$(eval $(call PRECOMPILED_PICOLIB_RULES,riscv,riscv64-unknown-elf,$(arch))))

# Target to download and extract picolib.
#
# `$*` will match the version number in the libtock-picolib folder name
# (something like "libtock-picolib-1.8.5").
$(TOCK_PICOLIB_TARGETS):
cd $(TOCK_USERLAND_BASE_DIR)/lib; ./fetch-picolib.sh $*

################################################################################
# LIBC++ Rules
Expand All @@ -75,7 +110,7 @@ TOCK_CXXLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/%/$(1)/$(2)/lib/$(3)/libsu
# So this is supremely frustrating. The issue boils down to limitations of
# pattern rules in make.
#
# First: pattern rules are implicitly groups, and you aren't allowed to
# First: pattern rules are implicitly groups, and you aren't allowed to
# use the :g operator to merge groups. What this means in practice is that
# if you have many targets that are all generated by the same rule (i.e.,
# our unzip creates all the library archive targets), all of the targets
Expand Down
39 changes: 39 additions & 0 deletions lib/fetch-picolib.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env bash

PICOLIB_VERSION=$1

if [ $PICOLIB_VERSION = "1.8.5" ]; then
PICOLIB_SHA="5168a7ea6522717ec5867e0105a224fe7e3779371b095deedc2cd58da369d8cc"
fi

# Name of the pre-created compiled directories.
ZIP_FILE=libtock-picolib-$PICOLIB_VERSION.zip

# List of mirrors we support.
MIRRORS=(\
"https://www.cs.virginia.edu/~bjc8c/archive/tock"\
"https://alpha.mirror.svc.schuermann.io/files"\
)

let FOUND=0

# Try from each mirror until we successfully download a .zip file.
for MIRROR in ${MIRRORS[@]}; do
URL=$MIRROR/$ZIP_FILE
echo "Fetching picolib from ${MIRROR}..."
echo " Fetching ${URL}..."
wget -q "$URL" && (echo "$PICOLIB_SHA $ZIP_FILE" | sha256sum -c)
if [ $? -ne 0 ]; then
echo " WARNING: Fetching picolib from mirror $MIRROR failed!" >&2
else
let FOUND=1
break
fi
done

if [[ $FOUND -ne 0 ]]; then
unzip $ZIP_FILE
else
echo "ERROR: Unable to find tock-picolib"
exit -1
fi
8 changes: 4 additions & 4 deletions libtock-sync/sys.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "interface/console.h"

#include "tock_sys.h"

// XXX Suppress missing prototype warnings for this file as the headers should
// be in newlib internals, but first stab at including things didn't quite work
// and the warnings are just noise
Expand All @@ -11,8 +13,6 @@
// SYNCHRONOUS LIBC SUPPORT STUBS
// ------------------------------

int _write(__attribute__ ((unused)) int fd, const void* buf, uint32_t count) {
int written;
libtocksync_console_write((const uint8_t*) buf, count, &written);
return written;
int _write(int fd, const void* buf, uint32_t count) {
return _tock_write(fd, buf, count);
}
18 changes: 18 additions & 0 deletions libtock-sync/tock_sys.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "interface/console.h"

// XXX Suppress missing prototype warnings for this file as the headers should
// be in newlib internals, but first stab at including things didn't quite work
// and the warnings are just noise
#pragma GCC diagnostic ignored "-Wmissing-declarations"
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
#pragma GCC diagnostic ignored "-Wstrict-prototypes"

// ------------------------------
// SYNCHRONOUS LIBC SUPPORT STUBS
// ------------------------------

int _tock_write(__attribute__ ((unused)) int fd, const void* buf, uint32_t count) {
int written;
libtocksync_console_write((const uint8_t*) buf, count, &written);
return written;
}
11 changes: 11 additions & 0 deletions libtock-sync/tock_sys.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#ifdef __cplusplus
extern "C" {
#endif

int _tock_write(int fd, const void* buf, uint32_t count);

#ifdef __cplusplus
}
#endif
45 changes: 18 additions & 27 deletions libtock/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "interface/console.h"
#include "tock.h"
#include "tock_sys.h"

// XXX Suppress unused parameter warnings for this file as the implementations
// are currently all just stubs
Expand All @@ -28,29 +29,9 @@ void* __dso_handle = 0;
int _unlink(const char* pathname) {
return -1;
}

int _isatty(int fd) {
if (fd == 0) {
return 1;
}
return 0;
}
int _open(const char* path, int flags, ...) {
return -1;
}
int _close(int fd) {
return -1;
}
int _fstat(int fd, struct stat* st) {
st->st_mode = S_IFCHR;
return 0;
}
int _lseek(int fd, uint32_t offset, int whence) {
return 0;
}
int _read(int fd, void* buf, uint32_t count) {
return 0; // k_read(fd, (uint8_t*) buf, count);
}
void _exit(int __status) {
tock_exit((uint32_t) __status);
}
Expand All @@ -61,12 +42,22 @@ int _kill(pid_t pid, int sig) {
return -1;
}

// FOR NEWLIB
int _fstat(int fd, struct stat* st) {
return _tock_fstat(fd, st);
}
int _isatty(int fd) {
return _tock_isatty(fd);
}
int _read(int fd, void* buf, uint32_t count) {
return _tock_read(fd, buf, count);
}
int _lseek(int fd, uint32_t offset, int whence) {
return _tock_lseek(fd, offset, whence);
}
int _close(int fd) {
return _tock_close(fd);
}
caddr_t _sbrk(int incr) {
memop_return_t ret;
ret = memop(1, incr);
if (ret.status != TOCK_STATUSCODE_SUCCESS) {
errno = ENOMEM;
return (caddr_t) -1;
}
return (caddr_t) ret.data;
return _tock_sbrk(incr);
}
Loading
Loading