<<<
:sectnums:
== Software Framework

The NEORV32 project comes with a complete software ecosystem called the "software framework" which
is based on the C-language RISC-V GCC port and consists of the following parts:

* <<_compiler_toolchain>>
* <<_core_libraries>>
* <<_system_view_description_file_svd>>
* <<_application_makefile>>
* <<_default_compiler_flags>>
* <<_linker_script>>
* <<_c_standard_library>>
* <<_start_up_code_crt0>>
* <<_executable_image_formats>>
* <<_neorv32_runtime_environment>>
* <<_bootloader>>

.Software Documentation
[TIP]
All core libraries and example programs are documented _in-code_ using **Doxygen**.
The API documentation is automatically built and deployed to GitHub pages:
https://stnolting.github.io/neorv32/sw/files.html.

.Example Programs
[TIP]
A collection of annotated example programs illustrating how to use certain NEORV32 functions
and peripheral/IO modules can be found in `sw/example`.


// ####################################################################################################################
:sectnums:
=== Compiler Toolchain

The toolchain for this project is based on the free and open RISC-V GCC-port. You can find the compiler sources and
build instructions in the official RISC-V GNU toolchain GitHub repository: https://github.com/riscv-collab/riscv-gnu-toolchain.

.Toolchain Installation
[TIP]
More information regarding the toolchain (building from scratch or downloading prebuilt ones) can be found in the
user guide section https://stnolting.github.io/neorv32/ug/#_software_toolchain_setup[Software Toolchain Setup].


<<<
// ####################################################################################################################
:sectnums:
=== Core Libraries

The NEORV32 project provides a set of pre-defined C libraries that allow an easy integration of the processor/CPU features
(also called "HAL" - _hardware abstraction layer_). All driver and runtime-related files are located in
`sw/lib`. These library files are automatically included and linked by adding the following include statement:

[source,c]
----
#include <neorv32.h> // NEORV32 HAL, core and runtime libraries
----

The NEORV32 HAL consists of the following files.

.NEORV32 Hardware Abstraction Layer File List
[cols="<3,<3,<6"]
[options="header",grid="rows"]
|=======================
| C source file       | C header file          | Description
| -                   | `neorv32.h`            | Main NEORV32 library file
| `neorv32_aux.c`     | `neorv32_aux.h`        | General auxiliary/helper function
| `neorv32_cfs.c`     | `neorv32_cfs.h`        | <<_custom_functions_subsystem_cfs>> HAL
| `neorv32_clint.c`   | `neorv32_clint.h`      | <<_core_local_interruptor_clint>> HAL
| `neorv32_cpu.c`     | `neorv32_cpu.h`        | <<_neorv32_central_processing_unit_cpu>> HAL
|                     | `neorv32_csr.h`        | <<_control_and_status_registers_csrs>> definitions
| `neorv32_dma.c`     | `neorv32_dma.h`        | <<_direct_memory_access_controller_dma>> HAL
| `neorv32_gpio.c`    | `neorv32_gpio.h`       | <<_general_purpose_input_and_output_port_gpio>> HAL
| `neorv32_gptmr.c`   | `neorv32_gptmr.h`      | <<_general_purpose_timer_gptmr>> HAL
| -                   | `neorv32_intrinsics.h` | Macros for intrinsics and custom instructions*)
| `neorv32_neoled.c`  | `neorv32_neoled.h`     | <<_smart_led_interface_neoled>> HAL
| `neorv32_onewire.c` | `neorv32_onewire.h`    | <<_one_wire_serial_interface_controller_onewire>> HAL
| `neorv32_pwm.c`     | `neorv32_pwm.h`        | <<_pulse_width_modulation_controller_pwm>> HAL
| `neorv32_rte.c`     | `neorv32_rte.h`        | <<_neorv32_runtime_environment>>
| `neorv32_sdi.c`     | `neorv32_sdi.h`        | <<_serial_data_interface_controller_sdi>> HAL
| `neorv32_slink.c`   | `neorv32_slink.h`      | <<_stream_link_interface_slink>> HAL
| `neorv32_smp.c`     | `neorv32_smp.h`        | HAL for the SMP <<_dual_core_configuration>>
| `neorv32_spi.c`     | `neorv32_spi.h`        | <<_serial_peripheral_interface_controller_spi>> HAL
|                     | `neorv32_sysinfo.h`    | <<_system_configuration_information_memory_sysinfo>> HAL
| `neorv32_tracer.c`  | `neorv32_tracer.h`     | <<_execution_trace_buffer_tracer>> HAL
| `neorv32_trng.c`    | `neorv32_trng.h`       | <<_true_random_number_generator_trng>> HAL
| `neorv32_twd.c`     | `neorv32_twd.h`        | <<_two_wire_serial_device_controller_twd>> HAL
| `neorv32_twi.c`     | `neorv32_twi.h`        | <<_two_wire_serial_interface_controller_twi>> HAL
| `neorv32_uart.c`    | `neorv32_uart.h`       | <<_primary_universal_asynchronous_receiver_and_transmitter_uart0>> and UART1 HAL
| `neorv32_wdt.c`     | `neorv32_wdt.h`        | <<_watchdog_timer_wdt>> HAL
| `neorv32_newlib.c`  | -                      | Platform-specific system calls for _newlib_
|=======================

.Doxygen API Documentation
[TIP]
The Doxygen-based documentation of all core libraries is available online at
https://stnolting.github.io/neorv32/sw/files.html.


<<<
// ####################################################################################################################
:sectnums:
=== System View Description File (SVD)

A CMSIS-SVD-compatible **System View Description (SVD)** file including all peripherals is available in `sw/svd`.


<<<
// ####################################################################################################################
:sectnums:
=== Application Makefile

Application compilation is based on a centralized GNU makefile (`sw/common/common.mk`). Each software project
(for example the ones in `sw/example` folder) should provide a local makefile that just includes the central makefile:

[source,makefile]
----
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk
----

Thus, the functionality of the central makefile (including all targets) becomes available for the project.
A project-local makefile should be used to define all setup-relevant configuration options instead of changing the
central makefile to keep the code base clean. Setting variables in the project-local makefile will override the default
configuration. Most example projects already provide a makefile that list all relevant configuration options.

The following example shows the configuration of a local Makefile:

[source,makefile]
----
# Override the default CPU ISA
MARCH = rv32imc_zicsr_zifencei

# Override the default RISC-V GCC prefix
RISCV_PREFIX ?= riscv-none-elf-

# Override default optimization goal
EFFORT = -Os

# Add extended debug symbols for Eclipse
USER_FLAGS += -ggdb -gdwarf-3

# Additional sources
APP_SRC += $(wildcard ./*.c)
APP_INC += -I .

# Adjust processor IMEM size and base address
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
USER_FLAGS += -Wl,--defsym,__neorv32_rom_base=0x00000000

# Adjust processor DMEM size and base address
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
USER_FLAGS += -Wl,--defsym,__neorv32_ram_base=0x80000000

# Adjust maximum heap size
USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=2k

# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..

# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk
----

:sectnums:
==== Makefile Targets

Invoking a project-local makefile (executing `make` or `make help`) will show the help menu that lists all
available targets as well as all variable including their _current_ setting.

[source,bash]
----
neorv32/sw/example/hello_world$ make
NEORV32 Software Makefile
Find more information at https://github.com/stnolting/neorv32
Use 'make V=1' or set BUILD_VERBOSE to increase build verbosity

Targets:

  help       show this text
  check      check toolchain and list supported ISA extensions
  info       show project/makefile configuration
  gdb        start GNU debugging session
  asm        build and generate <main.asm> assembly listing file
  elf        build and generate <main.elf> ELF file
  exe        build and generate <neorv32_exe.bin> executable file for bootloader upload
  bin        build and generate <neorv32_raw_exe.bin> executable memory image
  hex        build and generate <neorv32_raw_exe.hex> executable memory image
  coe        build and generate <neorv32_raw_exe.coe> executable memory image
  mem        build and generate <neorv32_raw_exe.mem> executable memory image
  mif        build and generate <neorv32_raw_exe.mif> executable memory image
  image      build and generate VHDL IMEM application memory image <neorv32_imem_image.vhd> in local folder
  install    build, generate and install VHDL IMEM application memory image <neorv32_imem_image.vhd>
  clean      clean up project home folder
  clean_all  clean up project home folder and image generator
  all        elf + asm + exe + bin + coe + mem + mif + image + install

Additional targets:

  sim           in-console simulation using default testbench (sim folder) and GHDL
  hdl_list      regenerate HDL file-list (*.f) in NEORV32_HOME/rtl
  upload        upload executable to bootloader via UART (/dev/ttyUSB1)
  elf_info      show ELF information
  elf_sections  show ELF sections
  bl_image      build and generate VHDL BOOTROM bootloader memory image <neorv32_bootrom_image.vhd> in local folder
  bootloader    build, generate and install VHDL BOOTROM bootloader memory image <neorv32_bootrom_image.vhd>

Variables:

  BUILD_VERBOSE   Set to increase build verbosity: "0"
  USER_FLAGS      Custom toolchain flags [append only]: "-ggdb -gdwarf-3 -Wl,--defsym,__neorv32_rom_size=16k -Wl,--defsym,__neorv32_rom_base=0x00002000 -Wl,--defsym,__neorv32_ram_size=8k"
  USER_LIBS       Custom libraries [append only]: ""
  EFFORT          Optimization level: "-Os"
  MARCH           Machine architecture: "rv32i_zicsr_zifencei"
  MABI            Machine binary interface: "ilp32"
  APP_INC         C include folder(s) [append only]: "-I ."
  APP_SRC         C source folder(s) [append only]: "./main.c   "
  APP_OBJ         Object file(s) [append only]: ""
  ASM_INC         ASM include folder(s) [append only]: "-I ."
  RISCV_PREFIX    Toolchain prefix: "riscv-none-elf-"
  NEORV32_HOME    NEORV32 home folder: "../../.."
  GDB_ARGS        GDB arguments: "-ex target extended-remote localhost:3333"
  UART_TTY        Serial port for upload to bootloader: "/dev/ttyUSB1"
  GHDL_RUN_FLAGS  GHDL simulation run arguments: ""
----

.Build Artifacts
[NOTE]
All _intermediate_ build artifacts (like object files and binaries) will be places into a (new) project-local
folder named `build`. The _resulting_ build artifacts (like executable, the main ELF and all memory
initialization/image files) will be placed in the root project folder.

.Increase Verbosity
[TIP]
Use `make V=1` or set `BUILD_VERBOSE` in your environment to increase build verbosity.

.Compile Flags as C-String
[TIP]
The makefile defines a C string `CC_FLAGS_STR` that contains all flags passed to the compiler.
This string can be processed at runtime: `printf("CC_FLAGS: %s\n", CC_FLAGS_STR);`


:sectnums:
==== Default Compiler Flags

The central makefile uses specific compiler flags to tune the code to the NEORV32 hardware. Hence, these flags should not
be altered. However, experienced users can modify them to further tune compilation.

.Compiler Options (`CC_OPTS`)
[cols="<3,<9"]
[grid="none"]
|=======================
| `-Wall`, `-Wextra`    | Enable all/extra compiler warnings.
| `-ffunction-sections` | Put functions in independent sections. This allows a code optimization as dead code can be easily removed.
| `-fdata-sections`     | Put data segment in independent sections. This allows a code optimization as unused data can be easily removed.
| `-mno-fdiv`           | Use built-in software functions for floating-point divisions and square roots (since the according instructions are not supported yet).
| `-mstrict-align`      | Unaligned memory accesses cannot be resolved by the hardware and require emulation.
| `-mbranch-cost=10`    | Branching is expensive.
| `-ffp-contract=off`   | Disable floating-point expression contraction (fused multiply-add/sub; not supported by the NEORV32 FPU).
| `-g`                  | Add (simple) debug information.
|=======================

.Linker Libraries (`LD_LIBS`)
[cols="<3,<9"]
[grid="none"]
|=======================
| `-lm`               | Include/link with `math.h`.
| `-lc`               | Search for the standard C library when linking.
| `-lgcc`             | Make sure we have no unresolved references to internal GCC library subroutines.
| `-nostartfiles`     | Do not use the default start code. Instead, the NEORV32-specific start-up code (`sw/common/crt0.S`) is used (pulled-in by the linker script).
| `-Wl,--gc-sections` | Make the linker perform dead code elimination.
|=======================

.Advanced Debug Symbols
[IMPORTANT]
By default, only "simple" symbols are added to the ELF (`-g`). Extended debug flags (e.g. for Eclipse) can be added
using the `USER_FLAGS` variable (e.g. `USER_FLAGS += -ggdb -gdwarf-3`). Note that other debug flags may be required
depending of the GCC/GDB version


<<<
// ####################################################################################################################
:sectnums:
=== Linker Script

The NEORV32-specific linker script (`sw/common/neorv32.ld`) is used to link the compiled sources according to the
processor's <<_address_space>>). For the final executable, only two memory segments are required:

.Linker script - Memory Segments
[cols="<2,<8"]
[options="header",grid="rows"]
|=======================
| Memory section  | Description
| `rom`           | Instruction memory address space (processor-internal <<_instruction_memory_imem>> and/or external memory)
| `ram`           | Data memory address space (processor-internal <<_data_memory_dmem>> and/or external memory)
|=======================

These two sections are configured by several variables defined in the linker script and exposed to the build
framework (aka the makefile). Those variable allow to customized the RAM/ROM sizes and base addresses. Additionally,
a certain amount of the RAM can be reserved for the software-managed heap (see <<_ram_layout>>).

.Linker script - Configuration
[cols="<2,<7,^1"]
[options="header",grid="rows"]
|=======================
| Memory section        | Description                                    | Default
| `__neorv32_rom_size`  | "ROM" size (instruction memory / IMEM)         | 16kB
| `__neorv32_ram_size`  | "RAM" size (data memory / DMEM)                | 8kB
| `__neorv32_rom_base`  | "ROM" base address (instruction memory / IMEM) | `0x00000000`
| `__neorv32_ram_base`  | "RAM" base address (data memory / DMEM)        | `0x80000000`
| `__neorv32_heap_size` | Maximum heap size; part of the "RAM"           | 0kB
|=======================

Each variable provides a default value (e.g. "16K" for the instruction memory /ROM /IMEM size). These defaults can
be overridden by setup-specific values to take the user-defined processor configuration into account (e.g. a different IMEM
size). The `USER_FLAGS` variable provided by the <<_application_makefile>> can also be used to customize the memory
configuration. For example, the following line can be added to a project-specific local makefile to adjust the memory
sizes:

.Overriding Default Memory Sizes (configuring 64kB IMEM and 32kB DMEM)
[source, makefile]
----
USER_FLAGS += "-Wl,--defsym,__neorv32_rom_size=64k -Wl,--defsym,__neorv32_ram_size=32k"
----

.Memory Configuration Constraints
[IMPORTANT]
Memory sizes have to be a multiple of 4 bytes. Memory base addresses have to be 32-bit-aligned.


:sectnums:
==== RAM Layout

The default NEORV32 linker script uses the defined RAM (**DMEM**) size to map several sections.
Note that depending on the application some sections might have zero size.

.Default RAM Layout
[source]
----
<End of RAM>
+------------------------------+
|             Stack            |
+------------------------------+
.     stack grows downwards    .
.                              .
.                              .
.      heap grows upwards      .
+------------------------------+
|   Dynamic memory (".heap")   |
+------------------------------+
| Uninitialized data (".bss")  |
+------------------------------+
|  Initialized data (".data")  |
+------------------------------+
<Start of RAM>
----

[start=1]
. **Initialized data (`.data`)**: The data section is placed right at the beginning of the RAM. For example, this
contains _explicitly initialized_ global variables which are initialized by the <<_start_up_code_crt0>>.
. **Non-initialized data (`.bss`)**: This dynamic data section contains data like global variables
_without explicit initialization_. This memory section is cleared by the <<_start_up_code_crt0>>.
. **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 end of the RAM at the last 16-byte aligned address. According to the RISC-V ABI / calling
convention the stack is 128-bit-aligned before procedure entry. The stack grows downwards.

.Heap Size
[IMPORTANT]
The maximum size of the heap is defined by the `__neorv32_heap_size` variable. This variable has to be
**explicitly defined** in order to define a heap size (and to use dynamic memory allocation at all).

.Heap-Stack Collision
[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.
The <<_smpmp_isa_extension,physical memory protection>> extension can be used to implement a guarding mechanism.


:sectnums:
==== ROM Layout

The default NEORV32 linker script uses the defined ROM (**IMEM**) size to map several sections into
an executable layout. Note that depending on the application some sections might have zero size.

.Default ROM Layout
[source]
----
<End of ROM>
+-----------------------------+
|  Initial data for ".data"   |
+-----------------------------+
|  Read-only data ".rodata"   |
+-----------------------------+
|    Program code ".text"     |
+-----------------------------+
<Start of ROM>
----

[start=1]
. **Program code (`.text`)**: This section contains the actual instructions of the program.
. **Read-only data (`.rodata`)**: Read-only data, for example for constants and strings.
. **Heap (`.heap`)**: Initialization data that is copied at runtime to the RAM's `data` section by by the <<_start_up_code_crt0>>.

.Binary Executable Image
[NOTE]
The above sections are concatenated by the <<_application_makefile>> to create a standalone and portable executable.
This can be exported in various <<_executable_image_formats>>, e.g. for transfer via the <<_bootloader>> or to initialize
read-only memory.


<<<
// ####################################################################################################################
:sectnums:
=== C Standard Library

The default software framework relies on **newlib** as default C standard library. Newlib provides hooks for common
"system calls" (like file handling and standard input/output) that are used by other C libraries like `stdio`.
These hooks are available in `sw/lib/source/newlib.c` and were adapted for the NEORV32 processor.

.Standard Input/Output Streams / Consoles
[NOTE]
The <<_primary_universal_asynchronous_receiver_and_transmitter_uart0, UART0>>
is used to implement all the standard input, output and error consoles (`STDIN` = file number 0, `STDOUT` = file
number 1, `STDERR` = file number 2). All other input/output streams (other file number than 0,1,2) are redirected
to <<_secondary_universal_asynchronous_receiver_and_transmitter_uart1, UART1>>.

.Constructors and Destructors
[NOTE]
Constructors and destructors for plain C code or for C++ applications are supported by the software framework.
See `sw/example/hello_cpp` for a minimal example. Note that constructor and destructors are only executed
by core 0 (primary core) in the SMP <<_dual_core_configuration>>.

.Newlib Test/Demo Program
[TIP]
A simple test and demo program that uses some of newlib's system functions (like `malloc`/`free` and `read`/`write`)
is available in `sw/example/demo_newlib`.

.Executing System Functions on a Host Computer
[TIP]
The NEORV32 on-chip debugger supports <<_semihosting>> which allow to use the input/output facilities on a host computer.


<<<
// ####################################################################################################################
:sectnums:
=== Start-Up Code (crt0)

The CPU and also the processor require a minimal start-up and initialization code to bring the hardware into an
operational state. Furthermore, the C runtime requires an initialization before compiled code can be executed.
This setup is done by the start-up code (`sw/common/crt0.S`) which is automatically linked with _every_ application
program and gets mapped before the actual application code so it gets executed right after boot.
The `crt0.S` start-up performs the following operations:

.CTR0 operations executed by each CPU core
[cols="^5,^5"]
[frame=ends]
|=======================
| **CPU 0 (primary core)** | **CPU 1 (secondary core)**
2+^| setup the stack pointer (`sp`) and the global pointer (`gp`) according to the <<_ram_layout>>
2+^| initialize <<_mstatus>> disabling machine-level interrupts
2+^| install an endless loop as trap handler ("crt0 panic") to <<_mtvec>>: the core will halt if any trap occurs
2+^| clear <<_mie>> disabling all interrupt sources
2+^| initialize all integer register `x1..x31` (only `x1..x15` if `E` ISA extension is enabled)
| initialize `.data` section | wait in SMP sleep mode for <<_dual_core_boot>>.
| clear `.bss` section |
| call constructors |
| call core0's `main` function | call core1's `main` function
2+^| _execute application_
2+^| `main` returns
2+^| clear <<_mie>> disabling all interrupt sources
2+^| reinstall an endless loop as trap handler ("crt0 panic") to <<_mtvec>>.
2+^| `main` return value is copied to <<_mscratch>> for inspection by a debugger
| call destructors |
| execute `ebreak` instruction to notify external debugger |
2+^| halt: CPU enters sleep mode executing `wfi` in an endless loop
| **CPU 0 (primary core)** | **CPU 1 (secondary core)**
|=======================


<<<
// ####################################################################################################################
:sectnums:
=== Executable Image Formats

The <<_application_makefile>> generates a flattened binrary from the final ELF file, which is further processed
by the NEORV32 executable image generator (`sw/image_gen`). This utility tool can generate various types of standalone
and portable executable file formats, which are used, for example, for uploading via the <<_bootloader>> or for
initializing SoC ROM modules.

.Invoking the Image Generator
[source,bash]
----
neorv32/sw/image_gen$ ./image_gen
NEORV32 executable image generator

Usage:    image_gen [options]
Example:  image_gen -i elf.bin -o main_exe.bin -b A0000000 -t exe

Options:
  -h            Show this help text and exit
  -i file_name  Flattened binary input file
  -o file_name  Image output file
  -t format     Image output format
  -b address    Bootloader exe base address (hex; for "-t exe" only)

Image formats (using little-Endian byte ordering):
  exe  Executable for bootloader upload (binary file with header)
  vhd  VHDL memory image (raw executable)
  bin  Binary file (raw executable)
  hex  Plain hexdump file (raw executable)
  coe  COE file (8x hex per line, ASCII, raw executable)
  mem  MEM file (8x hex per line, ASCII, raw executable)
  mif  MIF file (8x hex per line, ASCII, raw executable)
----

The image generator can be used as a stand-alone program, but it is also integrated into the application makefile.
This provides corresponding <<_makefile_targets>>) for the different image types:

.Image Generation Targets
[cols="<1,<10"]
[grid="none"]
|=======================
| `exe` | Generates an executable binary file (including a header; see <<_bootloader_image_format>>) for upload via the <<_bootloader>>.
| `vhd` | Generates a raw VHDL memory image (package file, package name is the same as the output file name).
| `bin` | Generates a raw binary file for custom purpose.
| `hex` | Generates a raw HEX file for custom purpose (like memory initialization via `$readmemh()` / `hread()`).
| `coe` | Generates a raw COE file for FPGA memory initialization.
| `mem` | Generates a raw MEM file for FPGA memory initialization.
| `mif` | Generates a raw MIF file for FPGA memory initialization.
|=======================

.Image Generator Compilation
[NOTE]
The sources of the image generator are automatically compiled when invoking the according makefile targets.
Note that compiling the image generator requires a _native_ C compiler.

.VHDL Memory Initialization Files
[NOTE]
The generated VHDL images are plain VHDL packages providing program data as constant array.
Note that this array is always extended to a power of 2. Unused elements are set to zero.


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

include::software_bootloader.adoc[]


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

include::software_rte.adoc[]
