: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 documentation is automatically built and deployed to GitHub pages and is available online
at https://stnolting.github.io/neorv32/sw/files.html.

.Example Programs
[TIP]
A collection of annotated example programs illustrating how to use certain CPU 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/riscv-gnutoolchain.

.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_crc.c`     | `neorv32_crc.h`        | <<_cyclic_redundancy_check_crc>> HAL
| `neorv32_cpu.c`     | `neorv32_cpu.h`        | <<_neorv32_central_processing_unit_cpu>> HAL
| `neorv32_cpu_amo.c` | `neorv32_cpu_amo.h`    | Emulation functions for the read-modify-write  <<_zalrsc_isa_extension>> / `A` instructions
|                     | `neorv32_cpu_csr.h`    | <<_control_and_status_registers_csrs>> definitions
| `neorv32_cpu_cfu.c` | `neorv32_cpu_cfu.h`    | <<_custom_functions_unit_cfu>> HAL
| `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_legacy.h`     | Legacy compatibility layer / wrappers (**do not use for new designs**)
| `neorv32_mtime.c`   | `neorv32_mtime.h`      | <<_machine_system_timer_mtime>> HAL
| `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_spi.c`     | `neorv32_spi.h`        | <<_serial_peripheral_interface_controller_spi>> HAL
| `neorv32_sysinfo.c` | `neorv32_sysinfo.h`    | <<_system_configuration_information_memory_sysinfo>> HAL
| `neorv32_trng.c`    | `neorv32_trng.h`       | <<_true_random_number_generator_trng>> 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_xip.c`     | `neorv32_xip.h`        | <<_execute_in_place_module_xip>> HAL
| `neorv32_xirq.c`    | `neorv32_xirq.h`       | <<_external_interrupt_controller_xirq>> HAL
| `neorv32_newlib.c`  | -                      | Platform-specific system calls for _newlib_
|=======================

.Core Library Documentation
[TIP]
The Doxygen-based documentation of the software framework including 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:

```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.
The 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 all relevant configuration variables:

```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
USER_FLAGS += -ggdb -gdwarf-3

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

# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k

# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k

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

# Additional compiler flags (append to this variable)
#USER_FLAGS += ...

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

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

.New Project
[TIP]
When creating a new project, copy an existing project folder or at least the makefile to the new project folder.
It is recommended to create new projects also in `sw/example` to keep the file dependencies. However, these
dependencies can be manually configured via makefile variables if the new project is located somewhere else.


: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,makefile]
----
neorv32/sw/example/hello_world$ make
NEORV32 Software Makefile
Find more information at https://github.com/stnolting/neorv32

Targets:

  help         - show this text
  check        - check toolchain
  info         - show makefile/toolchain configuration
  gdb          - start GNU debugging session
  asm          - compile and generate <main.asm> assembly listing file for manual debugging
  elf          - compile and generate <main.elf> ELF file
  exe          - compile and generate <neorv32_exe.bin> executable image file for bootloader upload (includes a HEADER!)
  bin          - compile and generate <neorv32_raw_exe.bin> executable memory image
  hex          - compile and generate <neorv32_raw_exe.hex> executable memory image
  coe          - compile and generate <neorv32_raw_exe.coe> executable memory image
  mem          - compile and generate <neorv32_raw_exe.mem> executable memory image
  mif          - compile and generate <neorv32_raw_exe.mif> executable memory image
  image        - compile and generate VHDL IMEM application boot image <neorv32_application_image.vhd> in local folder
  install      - compile, generate and install VHDL IMEM application boot image <neorv32_application_image.vhd>
  sim          - in-console simulation using default/simple testbench and GHDL
  hdl_lists    - regenerate HDL file-lists (*.f) in NEORV32_HOME/rtl
  all          - exe + install + hex + bin + asm
  elf_info     - show ELF layout info
  elf_sections - show ELF sections
  clean        - clean up project home folder
  clean_all    - clean up whole project, core libraries and image generator
  bl_image     - compile and generate VHDL BOOTROM bootloader boot image <neorv32_bootloader_image.vhd> in local folder
  bootloader   - compile, generate and install VHDL BOOTROM bootloader boot image <neorv32_bootloader_image.vhd>

Variables:

  USER_FLAGS     - Custom toolchain flags [append only]: "-ggdb -gdwarf-3 -Wl,--defsym,__neorv32_rom_size=16k -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   "
  ASM_INC        - ASM include folder(s) [append only]: "-I ."
  RISCV_PREFIX   - Toolchain prefix: "riscv32-unknown-elf-"
  NEORV32_HOME   - NEORV32 home folder: "../../.."
  GDB_ARGS       - GDB (connection) arguments: "-ex target extended-remote localhost:3333"
  GHDL_RUN_FLAGS - GHDL simulation run arguments: ""
----


: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`               | Enable all 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.
| `-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).
| `-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 costs a lot of cycles.
| `-Wl,--gc-sections`   | Make the linker perform dead code elimination.
| `-ffp-contract=off`   | Disable floating-point expression contraction.
| `-g`                  | Add (simple) debug information.
|=======================

.Checking Compiler Flags from a Compiled Program
[TIP]
The makefile's `CC_OPTS` is exported as **define** to be available within a C program; for example
`neorv32_uart0_printf("%s\n", CC_OPTS);`.

.Linker Libraries (`LD_LIBS`)
[cols="<2,<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.
|=======================

.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 size to map several sections.
Note that depending on the application some sections might have zero size.

.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 <<_start_up_code_crt0>>.
. **Dynamic data (`.bss`)**: The constant data section is followed by the dynamic data section that contains _uninitialized_
data like global variables without explicit initialization. This 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) other than zero.

.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.


<<<
// ####################################################################################################################
: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 Consoles
[NOTE]
The <<_primary_universal_asynchronous_receiver_and_transmitter_uart0, UART0>>
is used to implement all the standard input, output and error consoles (`STDIN`, `STDOUT` and `STDERR`).
Note that `\n` (newline) is automatically converted to `\r\n` (carriage-return and newline).

.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.

.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`.


<<<
// ####################################################################################################################
: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:

[start=1]
. Clear <<_mstatus>> CSR.
. Clear <<_mie>> CSR disabling all interrupt sources.
. Install an <<_early_trap_handler>> to <<_mtvec>> CSR.
. Initialize the global pointer `gp` and the stack pointer `sp` according to the <<_ram_layout>> provided by the linker script.
. Initialize all integer register `x1` - `x31` (only `x1` - `x15` if the `E` CPU extension is enabled).
. Setup `.data` section to configure initialized variables.
. Clear the `.bss` section.
. Call all _constructors_ (if there are any).
. Call the application's `main()` function (with no arguments; `argc` = `argv` = 0).
. If `main()` returns:
** All interrupt sources are disabled by clearing <<_mie>> CSR.
** The return value of `main()` is copied to the <<_mscratch>> CSR to allow inspection by the debugger.
** Call all _destructors_ (if there are any).
** Re-install an <<_early_trap_handler>> to <<_mtvec>> CSR. If any destructor causes an exception the <<_early_trap_handler>> is used for handling.
** The CPU enters sleep mode executing the `wfi` instruction in an endless loop.


:sectnums:
==== Early Trap Handler

The start-up code provides a very basic trap handler for the early boot phase. This handler does nothing but
trying to move on to the next linear instruction whenever an interrupt or synchronous exception is encountered.
This simple trap handler does not interact with the stack at all as it just uses a single register that is backup-ed
using the <<_mscratch>> CSR.


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

The compiled and linked executable (ELF file) is further processed by the NEORV32 image generator (`sw/image_gen`) to
generate the final executable file. The image generator can generate several types of executable file formats selected
by a flag when calling the generator.
**Note that all these options are managed by the makefile (see <<_makefile_targets>>).**

[cols="<2,<8"]
[grid="none"]
|=======================
| `-app_bin` | Generates an executable binary file (including a bootloader header) for upload via the bootloader.
| `-app_vhd` | Generates an executable VHDL memory initialization image for the processor-internal IMEM.
| `-bld_vhd` | Generates an executable VHDL memory initialization image for the processor-internal BOOT ROM.
| `-raw_hex` | Generates a raw 8x ASCII hex-char file for custom purpose.
| `-raw_bin` | Generates a raw binary file `for custom purpose.
| `-raw_coe` | Generates a raw COE file for FPGA memory initialization.
| `-raw_mem` | Generates a raw MEM file for FPGA memory initialization.
| `-raw_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 makefile
(requiring a _native_ GCC installation).

.Executable Header
[NOTE]
for the `app_bin` option the image generator adds a small header to the executable. This header is required by the
<<_bootloader>> to identify and manage the executable. The header consists of three 32-bit words located right
at the beginning of the file. The first word of the executable is the signature word and is always `0x4788cafe`.
Based on this word the bootloader can identify a valid image file. The next word represents the size in bytes of the
actual program image in bytes. A simple complement checksum of the actual program image is given by the third word.
This provides a simple protection against data transmission or storage errors.
**Note that this executable format cannot be used for _direct_ execution (e.g. via XIP or direct memory access).**


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

include::software_bootloader.adoc[]


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

include::software_rte.adoc[]
