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

[sw] add support for newlib's system calls #275

Merged
merged 11 commits into from
Feb 11, 2022
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,20 @@ The version number is globally defined by the `hw_version_c` constant in the mai

* :bug: = bug-fix
* :sparkles: = new feature
* :test_tube: = new (experimental) feature
* :warning: = (major) change that might impact compatibility with previous versions
* :lock: = security issue
* :rocket: = release


| Date (*dd.mm.yyyy*) | Version | Comment |
|:----------:|:-------:|:--------|
| 11.02.2022 | 1.6.7.8 | :test_tube: added newlib's system calls (stubs) and linker script symbols for heap memory to support **dynamic memory allocation** (e.g. `malloc`) and even **standard IO functions** like `printf`; see [PR #275](https://github.com/stnolting/neorv32/pull/275) |
| 10.02.2022 | 1.6.7.7 | :sparkles: added **RISC-V hardware trigger module** to CPU - allows to set _hardware breakpoints_ (via gdb's `hb`/`hbreak` command) to debug code from ROM; see [PR #274](https://github.com/stnolting/neorv32/pull/274); :bug: minor bug fix in `ebreak` instruction's `dcsr.cause` value (was 0b010 but has to be 0b001) |
| 08.02.2022 | 1.6.7.6 | :warning: renamed default branch of repository to `main` |
| 07.02.2022 | 1.6.7.5 | removed default values for bi-directional top entity ports `twi_sda_io` and `twi_scl_io` |
| 05.02.2022 | 1.6.7.4 | added `err_o` signal to **IMEM** module; if the IMEM is implemented as true ROM any write attempt will raise a _store access fault_ exception (with a `[DEVICE_ERR]` error); see [PR #273](https://github.com/stnolting/neorv32/pull/273) |
| 03.02.2022 | 1.6.7.3 | using `LTO` (link-time-optimization) option for **bootloader**; improved bootloader user console; see [PR #268](https://github.com/stnolting/neorv32/pull/268) |
| 03.02.2022 | 1.6.7.3 | :test_tube: using `LTO` (link-time-optimization) option for **bootloader**; improved bootloader user console; see [PR #268](https://github.com/stnolting/neorv32/pull/268) |
| 31.01.2022 | 1.6.7.2 | :bug: fixed minor bug in **bootloader's MTIME handling** (bootloader crashed if `Zicntr` ISA extension not enabled), fixed minor issues in MTIME and `time` CSRs handling; added MTIME example program; see [PR #267](https://github.com/stnolting/neorv32/pull/267) |
| 30.01.2022 | 1.6.7.1 | :sparkles: added **`Zxcfu` ISA extension for user-defined custom RISC-V instructions**; see [PR #264](https://github.com/stnolting/neorv32/pull/264) |
| 28.01.2022 |[**:rocket:1.6.7**](https://github.com/stnolting/neorv32/releases/tag/v1.6.7) | **New release** |
Expand Down
5 changes: 5 additions & 0 deletions docs/datasheet/soc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,11 @@ internal _bootloader memory_ (BOOTLDROM).
.NEORV32 processor - address space (default configuration)
image::address_space.png[900]

.RAM Layout - Usage of the Data Address Space
[TIP]
The actual usage of the data address space by the software/executables (stack, heap, ...) is
illustrated in section <<_ram_layout>>.


:sectnums:
==== CPU Data and Instruction Access
Expand Down
56 changes: 43 additions & 13 deletions docs/datasheet/software.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ The documentation is automatically built and deployed to GitHub pages by the CI




<<<
// ####################################################################################################################
:sectnums:
Expand Down Expand Up @@ -282,19 +281,16 @@ MEMORY
----

Each memory section provides a _base address_ `ORIGIN` and a _size_ `LENGTH`. The base address and size of the `iodev` section is
fixed and must not be altered. The base addresses and sizes of the `ram` and `rom` regions correspond to the total available instruction
and data memory address space (see section <<_address_space_layout>>).
fixed and should not be altered. The base addresses and sizes of the `ram` and `rom` regions correspond to the total available instruction
and data memory address space (see section <<_address_space_layout>>) as defined in `rtl/core/neorv32_package.vhd`.

[IMPORTANT]
`ORIGIN` of the `ram` section has to be always identical to the processor's `dspace_base_c` hardware configuration. Additionally,
`ORIGIN` of the `ram` section has to be always identical to the processor's `dspace_base_c` hardware configuration. +
+
`ORIGIN` of the `rom` section has to be always identical to the processor's `ispace_base_c` hardware configuration.

The sizes of `ram` section has to be equal to the size of the **physical available data instruction memory**. For example, if the processor
setup only uses processor-internal DMEM (<<_mem_int_dmem_en>> = _true_ and no external data memory attached) the `LENGTH` parameter of
this memory section has to be equal to the size configured by the <<_mem_int_dmem_size>> generic.

The sizes of `rom` section is a little bit more complicated. The default linker script configuration assumes a _maximum_ of 2GB _logical_
memory space, which is also the default configuration of the processor's hardware instruction memory address space. This size _does not_ have
memory space, which is also the default configuration of the processor's hardware instruction memory address space. This size does not have
to reflect the _actual_ physical size of the instruction memory (internal IMEM and/or processor-external memory). It just provides a maximum
limit. When uploading new executable via the bootloader, the bootloader itself checks if sufficient _physical_ instruction memory is available.
If a new executable is embedded right into the internal-IMEM the synthesis tool will check, if the configured instruction memory size
Expand All @@ -308,8 +304,8 @@ The `ram` region also uses a conditional assignment (via the `make_bootloader` s
(`make_bootloader` symbol is set) the generated bootloader will only use the _first_ 512 bytes of the data address space. This is
a fall-back to ensure the bootloader can operate independently of the actual _physical_ data memory size.

The linker maps all the regions from the compiled object files into four final sections: `.text`, `.rodata`, `.data` and `.bss`.
These four regions contain everything required for the application to run:
The linker maps all the regions from the compiled object files into five final sections: `.text`, `.rodata`, `.data`, `.bss` and `.heap`.
These regions contain everything required for the application to run:

.Linker memory regions
[cols="<1,<9"]
Expand All @@ -320,13 +316,45 @@ These four regions contain everything required for the application to run:
| `.rodata` | Constants (like strings) from the application; also the initial data for initialized variables.
| `.data` | This section is required for the address generation of fixed (= global) variables only.
| `.bss` | This section is required for the address generation of dynamic memory constructs only.
| `.heap` | This section is required for the address generation of dynamic memory constructs only.
|=======================

The `.text` and `.rodata` sections are mapped to processor's instruction memory space and the `.data` and
`.bss` sections are mapped to the processor's data memory space. Finally, the `.text`, `.rodata` and `.data`
The `.text` and `.rodata` sections are mapped to processor's instruction memory space and the `.data`,
`.bss` and `heap` sections are mapped to the processor's data memory space. Finally, the `.text`, `.rodata` and `.data`
sections are extracted and concatenated into a single file `main.bin`.


:sectnums:
==== RAM Layout

The default NEORV32 linker script uses all of the defined RAM (linker script memory section `ram`) to create four areas.
Note that depending on the application some areas might not be existent at all.

.Default RAM Layout
image::ram_layout.png[400]

[start=1]
. **Constant data (`.data`)**: The constant data section is placed right at the beginning of the RAM. For example, this section
contains _explicitly initialized_ global variables. This section is initialized by the executable.
. **Dynamic data (`.bss`)**: The constant data section is followed by the dynamic data section, which contains _uninitialized_ data
like global variables without explicit initialization. This section is cleared by the start-up code `crt0.S`.
. **Heap (`.heap`)**: The heap is used for dynamic memory that is managed by functions like `malloc()` and `free()`. The heap
grows upwards. This section is not initialized at all.
. **Stack**: The stack starts at the very end of the RAM at address `ORIGIN(ram) + LENGTH(ram) - 4`. The stack grows downwards.

There is _no explicit limit_ for the maximum stack size as this is hard to check. However, a physical memory protection rule could
be used to configure a maximum size by adding a "protection area" between stack and heap (a PMP region without any access rights).

The maximum size of the heap is defined by the linker script's `__heap_size` symbol. This symbol can be overridden at any time.
By default, the maximum heap size is 1/4 of the total RAM size.

.Heap-Stack Collisions
[WARNING]
Take care when using dynamic memory to avoid collision of the heap and stack memory areas. There is no compile-time protection
mechanism available as the actual heap and stack size are defined by _runtime_ data. Also beware of fragmentation when
using dynamic memory allocation.


:sectnums:
==== Executable Image Generator

Expand Down Expand Up @@ -409,12 +437,14 @@ int __neorv32_crt0_after_main(int32_t return_code) {
----



<<<
// ####################################################################################################################

include::software_bootloader.adoc[]



<<<
// ####################################################################################################################

Expand Down
Binary file added docs/figures/ram_layout.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ package neorv32_package is
-- Architecture Constants (do not modify!) ------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant data_width_c : natural := 32; -- native data path width - do not change!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01060707"; -- no touchy!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01060708"; -- no touchy!
constant archid_c : natural := 19; -- official NEORV32 architecture ID - hands off!

-- Check if we're inside the Matrix -------------------------------------------------------
Expand Down
29 changes: 22 additions & 7 deletions sw/common/neorv32.ld
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/* # ********************************************************************************************* # */
/* # BSD 3-Clause License # */
/* # # */
/* # Copyright (c) 2021, Stephan Nolting. All rights reserved. # */
/* # Copyright (c) 2022, Stephan Nolting. All rights reserved. # */
/* # # */
/* # Redistribution and use in source and binary forms, with or without modification, are # */
/* # permitted provided that the following conditions are met: # */
Expand Down Expand Up @@ -75,6 +75,10 @@ SECTIONS
/* start section on WORD boundary */
. = ALIGN(4);

/* default heap size: we can use up to 1/4 of available data memory (RAM) by default */
/* WARNING! the heap will collide with the stack if allocating too much memory! */
__heap_size = DEFINED(__heap_size) ? __heap_size : LENGTH(ram) / 4;


/* Actual instructions */
.text :
Expand Down Expand Up @@ -178,23 +182,26 @@ SECTIONS
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
*(.sdata .sdata.* .gnu.linkonce.s.*)

PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)


/* finish section on WORD boundary */
. = ALIGN(4);

_edata = .; PROVIDE (edata = .);
. = .;
__DATA_END__ = .;
__global_pointer$ = __DATA_END__ + 0x800;

} > ram AT > rom


/* zero/non-initialized read/write data placed in RAM */
.bss (NOLOAD):
{
__bss_start = .;
. = ALIGN(4);
__BSS_START__ = .;
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
Expand All @@ -215,13 +222,21 @@ SECTIONS
pad the .data section. */
. = ALIGN(. != 0 ? 32 / 8 : 1);

. = ALIGN(32 / 8);
. = ALIGN(4);
__BSS_END__ = .;
__global_pointer$ = MIN(__SDATA_BEGIN__ + 0x800, MAX(__DATA_BEGIN__ + 0x800, __BSS_END__ - 0x800));
_end = .; PROVIDE (end = .);
} > ram


/* heap for dynamic memory allocation (use carefully!) */
.heap :
{
PROVIDE(__heap_start = .);
. = __heap_size;
PROVIDE(__heap_end = .);
} > ram


/* Yet unused */
.jcr : { KEEP (*(.jcr)) }
.got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } .interp : { *(.interp) }
Expand Down Expand Up @@ -299,7 +314,7 @@ SECTIONS
PROVIDE(__ctr0_imem_begin = ORIGIN(rom));
PROVIDE(__ctr0_dmem_begin = ORIGIN(ram));
PROVIDE(__crt0_stack_begin = (ORIGIN(ram) + LENGTH(ram)) - 4);
PROVIDE(__crt0_bss_start = __bss_start);
PROVIDE(__crt0_bss_start = __BSS_START__);
PROVIDE(__crt0_bss_end = __BSS_END__);
PROVIDE(__crt0_copy_data_src_begin = __etext + SIZEOF(.rodata));
PROVIDE(__crt0_copy_data_dst_begin = __DATA_BEGIN__);
Expand Down
Loading