Skip to content
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

Picolib support #9

Open
wants to merge 16 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
310 changes: 200 additions & 110 deletions IP/Controller/src/mkRVController.v

Large diffs are not rendered by default.

12 changes: 10 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ endif
CORE_LIST=$(patsubst riscv/%,%,$(wildcard riscv/*))
PE_LIST=$(addsuffix _pe, $(CORE_LIST))

all: $(PE_LIST)
all: $(PE_LIST) picolibc

list:
@echo $(CORE_LIST)
Expand All @@ -27,8 +27,16 @@ list:
%_setup: riscv/%/setup.sh
$<

picolibc: picolibc_support/build_picolibc.sh
picolibc_support/build_picolibc.sh $(PICOLIBC_OPTS)

uninstall:
rm -rf $(TAPASCO_HOME)/core/{${PE_LIST}}*

clean: uninstall
clean_picolib:
rm -rf picolibc_support/picolibc
rm -rf picolibc_support/picolibc-git
rm -rf picolibc_support/specs

clean: uninstall clean_picolib
rm -rf IP/riscv/
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ The folder **common** contains TCL scripts which place and connect common compon

The folder **specific_tcl** contains one TCL script per processor and places/connects the components which depend on the chosen processor, e.g. instantiate the correct IP and connect the memory busses.

The folder **picolibc_support** contains a script as well as an adjusted linker script and code for stdio support to build the [picolibc](https://github.com/picolibc/picolibc) for the RISC-V cores.

## Dependencies
The project might work with other configurations, but it was tested with the following setup:
* Vivado 2018.3
Expand Down Expand Up @@ -67,5 +69,31 @@ e.g. BRAM_SIZE=0x4000 makes a local memory size of 0x8000.

For more information on PE local memory please refer to the [documentation](https://github.com/esa-tu-darmstadt/tapasco/blob/master/documentation/pe-local-memories.md).

## Picolibc Support
For a better programming experience, you may use the [picolibc](https://github.com/picolibc/picolibc) which provides C standard library functions and standard input/output. The build of picolibc requires the meson build tool which you may install with:

```
apt install meson
```

To build the library, just use the built-in script by calling:

```
make picolibc
```

You can customize the build of picolibc and specify additional build options by providing the PICOLIBC_OPTS parameter, e.g.:

```
make PICOLIBC_OPTS="-Dio-long-long=true"
```

Detailed information about the available build options can be found [here](https://github.com/picolibc/picolibc/blob/main/doc/build.md), however, only the default configuration is tested.

Picolibc provides a specs-file for the GCC you need to specify when compiling software using the standard library.

### Stdin/stdout
If you would like to use functions like printf, scanf etc. you need to provide memory buffers using the TaPaSCo API, one buffer for stdin and one for stdout/stderr. We provide a header file which helps you with that, take a look at our [programming example](https://github.com/esa-tu-darmstadt/tapasco-riscv/tree/picolib_support/programming/examples/picolibc_example) to find out how to use it.

## Publications
Heinz, C., Lavan, Y., Hofmann, J., and Koch, A. (2019). A Catalog and In-Hardware Evaluation of Open-Source Drop-In Compatible RISC-V Softcore Processors. In *IEEE Proc. International Conference on ReConFigurable Computing and FPGAs (ReConFig)*. IEEE.
62 changes: 62 additions & 0 deletions picolibc_support/build_picolibc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/bin/bash

export REPO_ROOT=$(pwd)
cd picolibc_support
git clone https://github.com/picolibc/picolibc.git picolibc-git

## include own iob lib for printf support in picolibc meson build
cp -r tapasco_iob picolibc-git
sed -i "/subdir('semihost')/a subdir('tapasco_iob')" picolibc-git/meson.build

cd picolibc-git
mkdir -p build

## replace picolibc linker script with own adjusted linker script
## because data sections need to be place immediately to data memory (ram section)
for file in $(find . -name "picolibc.ld")
do
cp $REPO_ROOT/picolibc_support/linker_script/picolibc_adjusted.ld $file
done

## delete memcpy copying the data section from startup code and reference to __data_source since it is not necessary in our case
for file in $(find . -name "crt0.h")
do
sed -i '/data_source/d' $file
done

## add link forown iob library for printf support
for file in $(find . -name "picolibc.specs.in")
do
sed -i "s:--end-group:-ltapascoiob --end-group:" $file
done

## find out if riscv32 or riscv64 GCC must be used
if command -v riscv64-unknown-elf-gcc &> /dev/null
then
echo "Using RISC-V 64-bit GCC"
cd build
# disable tests to prevent failing build with self built compiler
../scripts/do-configure riscv64-unknown-elf -Dtests=false -Dprefix=$REPO_ROOT/picolibc_support -Dspecsdir=specs $1
ninja install
elif command -v riscv32-unknown-elf-gcc &> /dev/null
then
echo "Using RISC-V 32-bit GCC"
cd scripts
cp cross-riscv64-unknown-elf.txt cross-riscv32-unknown-elf.txt
sed -i 's/riscv64/riscv32/' cross-riscv32-unknown-elf.txt
cd ../build
../scripts/do-configure riscv32-unknown-elf -Dtests=false -Dprefix=$REPO_ROOT/picolibc_support -Dspecsdir=specs $1
ninja install
else
echo "No RISC-V compiler found...exiting"
exit
fi

## remove git folder
cd $REPO_ROOT/picolibc_support
rm -rf picolibc-git

exit



241 changes: 241 additions & 0 deletions picolibc_support/linker_script/picolibc_adjusted.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
/*
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright © 2019 Keith Packard
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/

ENTRY(_start)

/*
* These values should be provided by the application. We'll include
* some phony values here to make things link for testing
*/

MEMORY
{
flash (xai!rw) : ORIGIN = DEFINED(__flash) ? __flash : 0x10000000, LENGTH = DEFINED(__flash_size) ? __flash_size : 0x10000
ram (wari!x) : ORIGIN = DEFINED(__ram ) ? __ram : 0x20000000, LENGTH = DEFINED(__ram_size ) ? __ram_size : 0x08000
}

PHDRS
{
text PT_LOAD;
ram PT_LOAD;
ram_init PT_LOAD;
tls PT_TLS;
}

SECTIONS
{
PROVIDE(__stack = ORIGIN(ram) + LENGTH(ram));

.init : {
KEEP (*(.text.init.enter))
KEEP (*(SORT_BY_NAME(.init) SORT_BY_NAME(.init.*)))
} >flash AT>flash :text

.text : {
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
} >flash AT>flash :text

.fini : {
KEEP (*(.fini))
__text_end = .;
} >flash AT>flash :text

PROVIDE (__etext = __text_end);
PROVIDE (_etext = __text_end);
PROVIDE (etext = __text_end);

. = ALIGN(8);

/* --------------------------------------------------
* start of sections placed in data memory
* --------------------------------------------------
*/


/* the following sections contain function pointers instead of actual code!
* so that these function pointers can be read from memory by lw instructions
* they need to be placed in the data memory as well!
*/
.preinit_array : {
PROVIDE_HIDDEN ( __preinit_array_start = . );
KEEP (*(.preinit_array))
PROVIDE_HIDDEN ( __preinit_array_end = . );
} >ram AT>ram :ram

.init_array : {
PROVIDE_HIDDEN ( __init_array_start = . );
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN ( __init_array_end = . );
} >ram AT>ram :ram

.fini_array : {
PROVIDE_HIDDEN ( __fini_array_start = . );
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN ( __fini_array_end = . );
} >ram AT>ram :ram

.ctors : {
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.ctors))
} >ram AT>ram :ram

.dtors : {
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.dtors))
} >ram AT>ram :ram

.data.init.enter : {
KEEP (*(.data.init.enter))
} >ram AT>ram :ram

.rodata : {
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
*(.data.rel.ro .data.rel.ro.*)
*(.got .got.*)
} >ram AT>ram :ram

.data : ALIGN_WITH_INPUT {
PROVIDE(__data_start = .);
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.* .sdata2.*)
*(.gnu.linkonce.s.*)
} >ram AT>ram :ram

/* Thread local initialized data. This gets
* space allocated as it is expected to be placed
* in ram to be used as a template for TLS data blocks
* allocated at runtime. We're slightly abusing that
* by placing the data in flash where it will be copied
* into the allocate ram addresses by the existing
* data initialization code in crt0
*/
.tdata : ALIGN_WITH_INPUT {
PROVIDE( __tls_base = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
PROVIDE(__data_end = .);
} >ram AT>ram :tls :ram
PROVIDE( __tdata_size = SIZEOF(.tdata) );

PROVIDE( __edata = __data_end );
PROVIDE( _edata = __data_end );
PROVIDE( edata = __data_end );
PROVIDE( __data_size = __data_end - __data_start );

/*
* Data values which are preserved across reset
*/
.preserve (NOLOAD) : {
PROVIDE(__preserve_start__ = .);
KEEP(*(SORT_BY_NAME(.preserve.*)))
KEEP(*(.preserve))
PROVIDE(__preserve_end__ = .);
} >ram AT>ram :ram



.tbss (NOLOAD) : {
PROVIDE( __bss_start = . );
*(.tbss .tbss.* .gnu.linkonce.tb.*)
*(.tcommon)
PROVIDE( __tls_end = . );
} >ram AT>ram :tls :ram
PROVIDE( __tbss_size = SIZEOF(.tbss) );
PROVIDE( __tls_size = __tls_end - __tls_base );

/*
* The linker special cases .tbss segments which are
* identified as segments which are not loaded and are
* thread_local.
*
* For these segments, the linker does not advance 'dot'
* across them. We actually need memory allocated for tbss,
* so we create a special segment here just to make room
*/
.tbss_space (NOLOAD) : {
. = . + __tbss_size;
} >ram AT>ram :ram

.bss (NOLOAD) : {
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(8);
__bss_end = .;
} >ram AT>ram :ram
PROVIDE( __end = __bss_end );
PROVIDE( _end = __bss_end );
PROVIDE( end = __bss_end );
PROVIDE( __bss_size = __bss_end - __bss_start );

/* Make the rest of memory available for heap storage */
PROVIDE (__heap_start = __end);
PROVIDE (__heap_end = __stack - (DEFINED(__stack_size) ? __stack_size : 0x800));
PROVIDE (__heap_size = __heap_end - __heap_start);

/* Define a stack region to make sure it fits in memory */
.stack __heap_end (NOLOAD) : {
. += (DEFINED(__stack_size) ? __stack_size : 0x800);
} >ram :ram

/* Throw away C++ exception handling information */
/DISCARD/ : {
*(.eh_frame .eh_frame.*)
*(.note .note.*)
}
}
Loading