Project settings

Important

This documentation is not recommended for new RISC-V projects. New RISC-V projects should reference the newest version of the documentation. Users targeting Arm devices can still use this documentation as their reference.

The newest version of the documentation can be found here: https://mi-v-ecosystem.github.io/SoftConsole-Documentation/

Program image is too large

If the program image size is too large, then check the list and map files for details of what application and library code is contributing to the total size. Note that the ELF file size on disk is not indicative of the program image size when running on the embedded hardware target. Some useful common tips for reducing the program image size:

  1. Tell the compiler to optimize:

    digraph { graph [rankdir="LR", ranksep=.01, bgcolor=transparent]; node [fontname="Verdana", style=filled, fillcolor=white, fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01"]; edge [arrowsize=.7]; "Project Properties" -> "C/C++ Build" -> "Settings" -> "Tool Settings" -> "Optimization"; }

    Level = Optimize for size -Os (this will negatively affect debugging capabilities)

  2. Use newlib-nano.

    Multiple things can be configured in the Linker, go into its setting by:

    digraph { graph [rankdir="LR", ranksep=.01, bgcolor=transparent]; node [fontname="Verdana", style=filled, fillcolor=white, fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01"]; edge [arrowsize=.7]; "Project Properties" -> "C/C++ Build" -> "Settings" -> "Tool Settings" -> "GNU Arm/RISC-V Cross C/C++ Linker"; }

    Then check to use the nano.spec:

    digraph { graph [rankdir="LR", ranksep=.01, bgcolor=transparent]; node [fontname="Verdana", style=filled, fillcolor=white, fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01"]; edge [arrowsize=.7]; "GNU Arm/RISC-V Cross C/C++ Linker" -> "Miscellaneous" -> "Use newlib-nano (--spec=nano.specs)"; }

    Uncheck the nodefaultlibs:

    digraph { graph [rankdir="LR", ranksep=.01, bgcolor=transparent]; node [fontname="Verdana", style=filled, fillcolor=white, fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01"]; edge [arrowsize=.7]; "GNU Arm/RISC-V Cross C/C++ Linker" -> "General" -> "Do not use default libraries (-nodefaultlibs)"; }

    And unchek nostdlib:

    digraph { graph [rankdir="LR", ranksep=.01, bgcolor=transparent]; node [fontname="Verdana", style=filled, fillcolor=white, fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01"]; edge [arrowsize=.7]; "GNU Arm/RISC-V Cross C/C++ Linker" -> "General" -> "No use startup or default libs (-nostdlib)"; }
  3. Note the newlib doesn’t have fully ported floating point support for RISC-V and is not utilizing some floating point instructions even if they are supported by the hardware (fmin/fmax/fsqrt…) and some functions might accidentally include soft double support. This can lead to the application footprint growing unexpectedly. If really needed, it’s possible to avoid these newlib functions and replace them with own implementations using inline assembly.

  4. If printf() style functions are being used and the program is still too large even when using newlib-nano then it may be possible to use a standalone small printf() implementation instead. Most such implementations may have limitations compared to a “full” standard library printf() implementation but often these limitations are acceptable in an embedded context. Examples of such “small” printf() implementations include:

    Then disable the use of the compiler standard libraries inside the linker:

    digraph { graph [rankdir="LR", ranksep=.01, bgcolor=transparent]; node [fontname="Verdana", style=filled, fillcolor=white, fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01"]; edge [arrowsize=.7]; "GNU Arm/RISC-V Cross C/C++ Linker" -> "General" -> "Do not use default libraries (-nodefaultlibs)"; }

    Better still consider rewriting the relevant code to avoid the use of printf() functions which are generally not recommended on embedded platforms because they are often large and often use the heap.

  5. Wrap code that is not always required (e.g. verbose logging code used for debugging/diagnostics only) in blocks such as below:

    #ifdef <symbol> 
    
    // Debuging code, logging feature, auxaliary feature
    
    #endif 
    

    The blocks can be quickly and conditionally compiled out when not needed (in essence enabled/disabled). Adding addition extra auxiliary features into the ifdef blocks could produce further code shrinking as it’s less frequent that all the features have to be used on the target all the time. Custom (or existing) configurations can be used to have different defines and the Debug configuration having different set of features enabled then Release configuration (debugging/troubleshooting log features on a production code will not just make it bigger, but often are considered as a security risk as well).

  6. Check if the floating point is using hardware and not software implementation. Not enabling hardware properly and using floating point will emulate every instruction in software and enlarge the codebase significantly. Do not use RVF or RVD floating point without setting the corresponding floating point ABI in :

    digraph { graph [rankdir="LR", ranksep=.01, bgcolor=transparent]; node [fontname="Verdana", style=filled, fillcolor=white, fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01"]; edge [arrowsize=.7]; "Project Properties" -> "C/C++ Build" -> "Settings" -> "Target processor"; }

    With RISC-V cores implementing the F and/or D extensions the Floating-point divide/sqrt instructions (-mfdiv) can also be enabled.

  7. Check what function or blocks of project code should be prioritized for optimization. Create a size analysis post build step under:

    digraph { graph [rankdir="LR", ranksep=.01, bgcolor=transparent]; node [fontname="Verdana", style=filled, fillcolor=white, fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01"]; edge [arrowsize=.7]; "Project Properties" -> "C/C++ Build" -> "Settings" -> "Build Steps" -> "Post-build steps"; }

    and put the following in the Command field:

    ${cross_prefix}nm${cross_suffix} --print-size --size-sort ${BuildArtifactFileName}
    

    Optionally a Description can be given to it, for example: ------- Size analysis -------.

    After the build all symbols with their sizes will be displayed and ordered by the size. This can point to functions which will benefit from optimizations the most. It can reveal design/code issues as when a large library could have been linked into a project by mistake or other unnecessary code compiled in.

  8. Enable hardware features if the core is capable – e.g. use the RISC-V M extension fully if present. Under:

    digraph { graph [rankdir="LR", ranksep=.01, bgcolor=transparent]; node [fontname="Verdana", style=filled, fillcolor=white, fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01"]; edge [arrowsize=.7]; "Project Properties" -> "C/C++ Build" -> "Settings" -> "Tool Settings" -> "Target processor"; }

    Enable/check the Multiply extension (RVM) and the Integer divide instructions (-mdiv) options if appropriate. If the target implements the Compressed extension (RVC) then enable/check that too.

  9. See the miv-rv32imaf-raytracer-uart-cpp as an example when making a C++ project. C++ is a large language with an overhead which is very significant from an embedded perspective. Disable as much as is viable in the Optimization tab settings:

    • Do not use exceptions

    • Do not use RTTI

    • Do not use _cxa_atexit()

    • Do not use thread-safe statics

Size optimizations cause trap exception: Load/Store address misaligned (mcause 4/6)

Can be caused when using default HAL without any modifications and allowing unaligned accesses in the project settings.

Can be fixed by making the project to use aligned addresses only:

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "Project" -> "Properties" -> "C/C++ Build" -> "Settings" -> "Tool Settings" -> "Align Strict (-mstrict-align)"
     }

Note

Our HAL is not supporting unaligned accesses. Howerver it’s not recommended for the user to implement the unaligned acesses to the trap handler because it significantly affects the performance.

See: Use strict alignment

Program file does not exist

Possibly caused by build finishing successfully and the ELF file existing, but a misconfigured debug launch configuration cannot see it. Then a likely cause is the use of the wrong slash in the program path name. It is advisable to use the forward slash / in such paths for Windows and Linux cross OS compatibility. If the backslash \ is used then it will only work on Windows but the forward slash works on both. Unfortunately the debug launch configuration editor on Windows defaults to using the backslash.

Change the slash in launcher configuration from “Debug\blinky.elf” to “Debug/blinky.elf”:

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "SoftConsole Menu toolbar" -> "Run" -> "Debug Configurations..." -> "<YOUR_LAUNCHER>" -> "Main" -> "C/C++ Application"
     }

Another cause of this problem is building one configuration (for example Release) and having launcher hard-coded for different configuration (for example Debug). Good and generic launchers (such as launchers bundled in the workspace.examples) always use the macro approach:

${config_name:<YOUR_PROJECT_NAME>}/<YOUR_PROJECT_NAME>.elf

Where <YOUR_PROJECT_NAME> is replaced with the name of the project, for example:

${config_name:miv-rv32imaf-mandelbrot-uart}/miv-rv32imaf-mandelbrot-uart.elf

Together with build configuration set to Use Active:

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "SoftConsole Menu toolbar" -> "Run" -> "Debug Configurations..." -> "<YOUR_LAUNCHER>" -> "Main" -> "Build Configuration" -> "Use Active"
     }

It will allow the launcher to work with any configuration seemingly such as Debug/Release (or many more).

Redirect printf() output to UART

To route printf() output to UART:

  1. Set up CoreUART in such way that UART_polled_tx_string() output works

  2. Add the following include file:

    #include <stdio.h>
    
  3. Go to the C/C++ Compiler settings:

    digraph { graph [rankdir="LR", ranksep=.01, bgcolor=transparent]; node [fontname="Verdana", style=filled, fillcolor=white, fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01"]; edge [arrowsize=.7]; "Project Properties" -> "C/C++ Build" -> "Settings" -> "Tool Settings" -> "GNU RISC-V Cross C/C++ Compiler"; }

    And add the define symbol MSCC_STDIO_THRU_CORE_UART_APB to the:

    digraph { graph [rankdir="LR", ranksep=.01, bgcolor=transparent]; node [fontname="Verdana", style=filled, fillcolor=white, fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01"]; edge [arrowsize=.7]; "GNU RISC-V Cross C/C++ Compiler" -> "Preprocessor" -> "Defined Symbols"; }

Undefined reference to printf/puts/write/strlen etc.

When one of these errors appears:

undefined reference to 'printf'
undefined reference to 'puts'
undefined reference to 'write'
undefined reference to 'strlen'

Then possibly no libraries are present to implement these calls, go to the linker settings:

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "Project Properties" -> "C/C++ Build" -> "Settings" -> "Tool Settings" -> "GNU RISC-V Cross C/C++ Linker"
     }

And uncheck the nodefaultlibs:

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "GNU RISC-V Cross C/C++ Linker" -> "General" -> "Do not use default libraries (-nodefaultlibs)"
     }

And the nostdlib:

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "GNU RISC-V Cross C/C++ Linker" -> "General" -> "No startup or default libs (-nostdlib)"
     }

Build fails when using “Print removed sections (-Xlinker –print-gc-sections)”

When the option to print removed unused sections is selected, then CDT may report that the build has failed even though it was completed correctly. This is because of a bug in CDT whereby the --print-gc-sections option prints removed sections to stderr and CDT incorrectly interprets any output on stderr as a build error. This bug has been reported to the CDT project and for now it is safe to ignore such build failure false positives.

Alternatively disable the --print-gc-sections option resolve the issue. First go to the Tool settings :

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "Project Properties" -> "C/C++ Build" -> "Settings" -> "Tool Settings" 
     }

For RISC-V targets uncheck the --print-gc-sections inside the Tool settings:

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "GNU RISC-V Cross C/C++ Linker" -> "General" -> "Print removed sections (-Xlinker --print-gc-sections)"
     }

For Arm targets uncheck the --print-gc-sections inside the Tool settings:

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "Cross Arm GNU C/C++ Linker" -> "General" -> "Print removed sections (-Xlinker --print-gc-sections)"
     }

When the –print-gc-sections option is enabled then the following false positive build failure may occur:

riscv64-unknown-elf/bin/ld.exe: Removing unused section '.text.__disable_irq' in file
'./riscv_hal/riscv_hal.o'
riscv64-unknown-elf/bin/ld.exe: Removing unused section '.text.handle_m_ext_interrupt' in
file './riscv_hal/riscv_hal_stubs.o'
riscv64-unknown-elf/bin/ld.exe: Removing unused section '.text.SysTick_Handler' in file
'./riscv_hal/riscv_hal_stubs.o'
riscv64-unknown-elf/bin/ld.exe: Removing unused section '.sbss.__env' in file
'./riscv_hal/syscall.o'
...
riscv64-unknown-elf/bin/ld.exe: Removing unused section '.text.isatty' in file
'lib/rv32im/ilp32\libg_nano.a(lib_a-sysisatty.o)'
riscv64-unknown-elf/bin/ld.exe: Removing unused section '.debug_frame' in file
'lib/rv32im/ilp32\libg_nano.a(lib_a-sysisatty.o)'
riscv64-unknown-elf/bin/ld.exe: Removing unused section '.sdata._global_impure_ptr' in file
'lib/rv32im/ilp32\libg_nano.a(lib_a-impure.o)'
Finished building target: miv-rv32im-systick-blinky.elf
12:35:47 Build Failed. 71 errors, 0 warnings. (took 2s.428ms)

Debugger Console View is not working or GDB is misbehaving

SoftConsole v2021.3 debugger version detection can fail and not show Debugger Console. The Debugger Console will work when macros are not used in the debug launcher, copy content of the

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "Debug Configuration" -> "Debugger" -> "GDB Client Setup" -> "Actual name"
     }

It should be riscv64-unknown-elf-gdb or arm-none-eabi-gdb, if the actual name doesn’t match expected value then workaround the issue, change the Executable:

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "Debug Configuration" -> "Debugger" -> "GDB Client Setup" -> "Executable"
     }

To use explicitly riscv64-unknown-elf-gdb or arm-none-eabi-gdb instead of the \({cross_prefix}gdb\){cross_suffix} macro.

sprintf() prints empty characters instead of floating point numbers

Possible cause is that the support in the libraries is not enabled by default when newlib-nano is used. Verify if the newlib-nano is used in the project settings:

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "C/C++ Build" -> "Settings" -> "Tool Settings" -> "GNU RISC-V Cross C/C++ Linker" -> "Miscellaneous" ->  "Use newlib-nano (--specs=nano.specs)"
     }

If newlib-nano is used, then the the %f feature can be enabled by checking the following in the project settings:

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "C/C++ Build" -> "Settings" -> "Tool Settings" -> "GNU RISC-V Cross C/C++ Linker" -> "Miscellaneous" ->  "-u_printf_float"
     }

and/or (when scanf is used):

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "C/C++ Build" -> "Settings" -> "Tool Settings" -> "GNU RISC-V Cross C/C++ Linker" -> "Miscellaneous" ->  "-u_scanf_float"
     }

Note

Enabling the floating feature of printf will increase the footprint. If that is a problem, see the size shrinking section.

If newlib-nano is not in use but this problem occurs then it may be caused by the GNU or a third party standard library used instead of newlib.

Invalid project path: Duplicate path entries found Warnings

Using macros in include files can cause these warnings, use relative paths on all included folders instead. RISC-V projects:

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "Project Properties" -> "C/C++ Build" -> "Settings" -> "Tool Settings" -> "GNU RISC-V Cross C/C++ Compiler" -> "Includes"
     }

For example replace "${workspace_loc:/${ProjName}/drivers/CoreUARTapb}" with "../drivers/CoreUARTapb"

undefined reference to `__stack_top’ etc.

Or one of the following errors:

undefined reference to `__sdata_start'
undefined reference to `__data_start'
undefined reference to `__sbss_start'
undefined reference to `_heap_end'
undefined reference to `__dso_handle'
hidden symbol `__dso_handle' isn't defined

Possibly caused because of old/wrong/no linker script.

Ensure that the appropriate linker script is configured under:

digraph {
         graph [rankdir="LR", ranksep=.01, bgcolor=transparent];
         node [fontname="Verdana", fontsize="9", shape="rectangle", width=.1, height=.2, margin=".04,.01", style=filled, fillcolor=white];
         edge [arrowsize=.7];
         "Project" -> "Properties" -> "C/C++ Build" -> "Settings" -> "Tool Settings" -> " GNU Arm/RISC-V Cross C/C++ Linker" -> "Add linker script"
     }