Skip to main content

Build, run, debug

This section is for how to build, run and debug project in ZStudio with ZCC, ZEMU and ZDB.

Build

ZStudio use project file .zsproj rather than makefile or cmake to organize each project. The project file contains all information and instructions that ZStudio needs to operate projects, including build configuration, run configuration, debug configuration and profile configuration.

In this section, we use the example solution in Quick Start. To build a project:

  1. Ensure the project you want to build is set to active

    To make the project active, choose the project in the Active Project dialogue in Project Controller.

    Set active project
  2. Choose build profile

    To use the Debug, Release, Min Size or Release with Debug information profiles, select them from the Configuration dialogue in Project Controller.

    • Debug: Used during development, includes extensive debugging information.

    • Release: Used for production, excludes debugging information.

    • Min Size: Focuses on minimizing the final file size.

    • Release with Debug Information: Retains some debugging information on top of the release build.

  3. Set build configuration

    By clicking the gear-button (Build Configuration) button, you can specify parameters to the current project and toolchain. You may also right-click the project node to trigger the pull-down menu and select Build Configuration:

    Build Configuration

    • Arch: Specify which CPU architecture the compiler will generate code for, such as "rv32imac". You can choose arch from dropdown list or input manually.

      For the lacked library of the architecture you specified, ZStudio will remind you of downloading from pack manager. The downloaded libraries would be added in toolchain and apply globally.

      Specify Arch and download library

      Specify Arch and download library

    • ABI: Specify binary interface of RISC-V application, such as"ilp32" indicates that in a 32-bit system, the integer,long, a nd pointer data types are all 32 bits.

    • CPU: The CPU option is used to enable specific optimizations, effectively specifying the Arch, ABI and scheduling model simultaneously, with the highest priority.

    • Compiler options allow you to set compilation flags, such as optimization level and debug level.

    • Linker options allow you to disable the default library and start file and specify linker scripts.

    • Assembler options allow you to set assembler flags.

    • NM/Readelf/Objdump/Objcopy/Size tool allows you to enable/disable output and control output content.

    For more details see the Configure build settings subsection.

  4. Build project

    To build a project, go to Build in the menu bar or clicking the build-button button in Project Controller view.

  5. Check build result

    Check the build result in the Build Console view, you can filter the build information in the drop-down box.

  6. Verify output file

    The executable files and object files are by default generated under output node in Project Navigator and {project_name}\output in File Navigator.

    Check build result

Configure build settings

To configure build settings for a project, go to Tool Settings page which list the available build options. Select and make the desired modifications.

Configure build settings
  • Compiler > Optimization

    This page allows you to configure optimization level, optimization options, and the code model for your project.

    • Optimization level: This option allows you to configure the level of optimization performed by compiler on the generated code. you can select from six optimization levels (from -o0 to -os) to control the trade-off between performance and code size according to your needs.

    • Code model: ZCC compiler supports the medany and medlow options, which are equivalent to the medium and small options in the GCC compiler for the RISC-V architecture, as shown in the table below.

      Supported code models of ZCC for RV32 and RV64
      Code ModelZCCGCCtext/data/rodata
      RISC-V architecturemedlowsmallFull 32-bit addressing space & The highest 2 GiB and the lowest 2 GiB in 64-bit addressing space
      RISC-V architecturemedanymediumFull 32-bit addressing space & PC ± 2 GiB in 64-bit addressing space
    • Loop Unroll: This option allow you to unroll all loops and turn on complete loop peeling (-funroll-loops) or turn off loop unroller (-fno-unroll-loops) . And the option "Pass no flags to compiler" means compiler defaults to partial loop unrolling.

    • Link Time Optimization : This option makes it possible to apply aggressive link time optimization to your projects. ZCC enable link time optimization by default , while some other toolchains do not have this feature. This option allows you to manually turn on (-flto) or turn off (-fno-lto) link time optimization or just use the default flag applicable to the compiler.

    • Remove unused function sections (-ffunction-sections) and unused data sections (-fdata-sections) : These options allow the removal of never referenced sections. When both options are selected, the compiler places each function/data item into its own section of the output file, whereupon the --gc-sections option is passes to the linker for the removal of never-referenced function/data. If ZCC(or other toolchain) is a linker, then the -wl, --gc-sections option is used instead.

      Compiler optimization option
    • Other optimization flags: This option allows you to manually add optimization flags or turn off default optimization options applicable to a particular optimization level.

  • Compiler > Debugging

    This page allows you to configure the degree or intensity of debugging information that is generated for your project.

    • None: No debugging information is generated or displayed.
    • Minimal: Basic debugging information, such as critical errors or checkpoints, is logged.
    • Default: More detailed information, including variable values or function call traces, is recorded.
    • Maximum: Highest level of detail, capturing extensive information for thorough debugging analysis.
  • Linker > General

    This page allows you to configure linker options, such as disable the default library and start file and specify linker scripts.

    Link script
    • Linker Script : Assign a linker script to your project. You have to specify a linker script here. ZCC linker does not support the DEFINED macro inside the link script. For link scripts that use DEFINED, you need to make some modifications as following example. For requirements and limitations pertaining to the link scripts, please refer to the ZCC User Guide.

      - __stack_size = DEFINED(__stack_size) ? __stack_size : 2K;
      + __stack_size = 2K;
  • Binutils

    When binutils (NM/Readelf/Objdump/Objcopy/Size) are enabled, the output is generated in project output node after the project is built.

Run

ZStudio provides several ways to run projects. You need to create necessary run configurations for each of the project and target that need to be launched.

Run on board

ZStudio supports running/debugging on board with OpenOCD, Please refer Start debugging on board and the Demo project Hello_with_dsp_and_nn_sdk_0.4.0.

Run on simulator

To run project on simulator:

  1. Ensure the run parameters

    You can change the run configuration by clicking the gear-button (Run Configuration) button and fill in the parameters you want to specify.

    Run Configuration

    run-project-simulator-1

    run-project-simulator-2

    • Program Argument: Pass arguments to program.

    • Connection Target: Choose where your project will be executed, physical board or simulator.

    • Choose Virtual Board:

    • Simulation Accuracy Level:

      • Emulation: Emulation mode offers faster execution speeds and is primarily used to verify program functionality. However, it provides limited performance data.
      • Simulation: Simulation mode operates at a lower speed but provides cycle information about the program which can be used for performance analysis.
    • Display Statistics: Choose whether to print performance statistics of the executable program. run-with-stat-arguments

    • Simulator Argument: Pass arguments to ZEMU. Use --stat to generates analytical data about the execution or performance of a program.

  2. Go to Run in the menu bar or clicking the run-button button in Project Controller view, ZStudio invoke ZEMU to run the compiled executable file of active project. The output is displayed in the Run Console in the bottom panel.

    Running output

Debug

ZStudio's built-in debugger ZDB help quickly find errors in the code and repair projects.

Start debugging on board

To start debugging on board, you need to build the project and flash it to the device.

  1. Connect the board to your PC and make sure it is really recognized by the PC.

    tip

    Please refer to the user guide of Development Board and check if the board need Driver.

  2. Create serial port connect

    From the main menu, select View > Serial Port Monitor to invoke the view. Click the + button to configure the port settings, the Serial Port box automatically detects any communication port connected to your computer. Click OK to build the connect.

    Create a serial port connect

    The status icon becomes green means Serial Port connect successfully. And the disconnect of board may cause serial port connect failure and the status icon will become red.

    Create serial port successfully

    See the following table to learn about the settings that the Serial Port Monitor provides.

    Configurable settings
    SettingsUsageAvailable options
    PortUse the Serial Port dropdown to select portsAutomatically detects serial port compatible devices connected to the device
    Baud RateUse the Baud Rate dropdown or write a custom rate in the text box to decide the frequency at which the monitor attempts to communicate with the connected device300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 250000, custom rate
    Data BitsUse the Data Bits dropdown to select how many data bits are used for the serial port connection5, 6, 7, 8
    ParityUse the Parity dropdown to select what parity is used for the serial port connectionNone, Odd, Even, Mark, Space
    Stop BitsUse the Stop Bits to select how many stop bits are used for the serial port connection1, 1, 5, 2
  3. Add OpenOCD configuration and start OpenOCD.

    From the main menu, select View > OpenOCD Explorer, click + to create an OpenOCD configuration. In the settings, you need to point ZStudio to the OpenOCD executable and configuration file in your PC file system.

    Add OpenOCD configuration
    tip

    Please refer to the user guide of Development Board to download OpenOCD executable and configuration file.

    Right-click the exist OpenOCD and select start or stop in context menu to control the OpenOCD process, the status icon becomes green means OpenOCD process is on.

    Start OpenOCD successfully
    tip

    Turn off or disconnect the board may cause the disconnection of OpenOCD and your board despite the OpenOCD process signal is green. Please check and restart OpenOCD.

  4. Specify debug configuration

    On the Project Controller, click the the gear-button (Debug Configuration) button to invoke configuration wizard. Set Board as run and debug target and select the OpenOCD configuration that matches the board you connected.

    Configure debug settings
  5. Add a breakpoint and start debug session. The debugger runs to the first breakpoint it encounters and stops. Click Step Over button and check the project output in Serial Port Monitor view.

About the Demo of debugging on board, please refer to Hello_with_dsp_and_nn_sdk_0.4.0.

Start debugging on simulator

  1. Select the Debug build profile for the project you want to debug and rebuild.
  2. If necessary, modify the debug configuration or create the detailed parameters by clicking the gear-button (Debug Configuration) button.
  3. Set breakpoint in the source code and click the debug-button button to start debug session.
tip

Check if Windows Defender Firewall allow zemu.exe to create port listening.

Once a debug session starts, the Debug toolbar will be available to help you debug your projects more quickly:

Debug toolbar
  • Pause/Continue F5
  • Step Over F10 : Steps over the current line and takes you to the next line even if the current line includes function calls. The calls are skipped, and you move straight to the next line of the caller.
  • Step Into F11 : Advance the debugger into each function. Steps inside the code of a called function.
  • Step Out Shift+F11: Steps out of the current function and takes you to the code of the caller.
  • Restart Control+Shift+F5
  • Stop Shift+F5

You can check information related to debug include:

Debug related information
  • THREADS: examine and work with threads in the code that you are debugging.
  • CALL STACK: the call stack shows the order in which methods and functions are called.
  • REGISTERS: you can inspect registers variables here.
  • VARIABLES: you can inspect local, global variables here.
  • WATCH: keep track of some variable or the result of a complex expression.
  • BREAKPOINTS: add, remove, edit or disable and enable breakpoints.

The status bar will change to orange once debugging session has started. The user can change the debug configuration by clicking Configuration Active Project and the target by clicking Debug on Simulator/board in the status bar.

Debugging status bar

Set breakpoint

You can set one or more breakpoints to suspend your running code in order to take a look at variables' values, or see whether or not a block of code is getting executed.

Once you have set a breakpoint, you can remove it, edit it, or disable and enable it again from the BREAKPOINTS list. The buttons are:

Breakpoints list
  • Add Function Breakpoints
  • Activate/Deactivate Breakpoints
  • Remove All Breakpoints

Besides, you can also right-click the breakpoint and select Remove Breakpoint, Edit Breakpoint, Disable Breakpoint or Enable Breakpoint.

Line Breakpoint

To set a breakpoint, click in the margin to the left of a line of code in the editor. A red dot is displayed. In the example sum.c below, debugger runs to the first breakpoint it encounters and stops:

Set a line breakpoint

Exception Breakpoint

Exception breakpoint suspends the project when the specified exception is thrown. When a project throws an exception (throw) or catches an exception (catch), the debugger interrupts the project's execution. Exception breakpoints can help users quickly locate and solve exception issues in the project, such as accessing null pointers and dividing by zero. In the example below, you can set exception breakpoints through the following steps.

Exception breakpoint
  1. Click BREAKPOINTS section in the left part of the Debug View
  2. Check the box next to C++ Catch and C++ Throw
  3. Start debugging

C++ Throw can capture the exception that project throws. In this case, the division function throws an exception.

C++ Throw

C++ Catch is used to catch thrown exceptions. When an exception occurs, the project jumps to the specified catch statement to handle the exception and stops executing the subsequent code. In this case, the division function catches an exception.

C++ Catch

Function Breakpoint

It is useful to set function breakpoint when you know the function name but not its location. With function breakpoint, you can break execution when a function is called. To set a function breakpoint:

Click the Add-Function-Breakpoint button
  1. Unfold the BREAKPOINT list in debug view.
  2. Click the Add Function Breakpoint button, the dialog box opens.
  3. Type the name of function you are looking for and click OK.

The execution break when debugger runs to the function breakpoint you set.

Set a function breakpoint

Conditional Breakpoint

Conditional breakpoints allow you to break inside a code block when a defined condition is met. You can set two types of conditions.

  • Expressions: The debugger pauses when the expression you defined is true.
  • Hit Count: The debugger pauses after a specified number of hits, called a hit count. If you suspect that a loop in your code starts misbehaving after a certain number of iterations, you can set a breakpoint to stop execution after that number of hits.

As the example below, you can set a expression as conditional breakpoint:

Set a expression as condition
  1. Right-click in the margin to the left of a line of code in the editor and select Add Conditional Breakpoint....

    If you already have a breakpoint defined, you can also right-click the breakpoint and select Edit Breakpoint....

  2. In the drop-down list that is displayed, select Expression or Hit Count and set a condition as follows:

    • Expression: Can be any valid expression that the debugger recognizes. The debugger pauses when the expression is satisfied.

      Expression condition
    • Hit Count: Specify the number of iterations (hits) after which execution will stop.

      Hit count condition
  3. Press Enter.

In the editor, conditional breakpoints are indicated by a breakpoint symbol that has a equals sign inside of it. You can place the cursor over a conditional breakpoint to show its condition. The debugger will evaluate the condition when it hit the breakpoint. When the expression of i==3 is satisfied, the debugger paused.

The debugger paused When expression satisfied

Inspect memory

In some cases, for example, when debugging data processing problems, you may need to view raw memory of the running process. For this, ZStudio provides Memory View which is default displayed in right side bar. You can click the memory icon to unfold it and check raw memory when you need.

Memory view

To inspect memory:

  1. Get the required address: you can input `p &variable_name command in REPL to get required address of the variables.
  2. Jump to the address: Input the hex address and click Go; the memory view initially shows a 256-byte region that starts from the chosen address, with higher memory address at the bottom of the window. You can check more data by setting LENGTH.

As the example below, you can trace the change of the array in the memory view. When you click step over, the memory data will be highlighted.

Inspect memory

Format settings

you can change the memory data format by clicking settings button. For example, you can set byte size as 8, bytes per groups as 4, groups per row as 1 to control how much data you see at once,and how it's grouped for you preferences. Regardless, Changing the view does not change the actual data in memory --- it simply changes how you're looking at it.

Change memory data format

Inspect registers

The Debug view provides functionality to inspect register values. Register values can be modified with the Set Value action from the register's context menu. For example, to set value of register while debugging:

Set value of register
  1. Wait for your project to stop at a breakpoint.
  2. Unfold REGISTERS section in the Debug view and find the target register
  3. Double-click the register or right -click the register and select Set Value, type the new value and click OK.

Inspect variables

All Local, Global variables are shown in the VARIABLES section. When the debugger is paused, hover over an object with the mouse, and you will see its current property value. You can also inspect variable values in the VARIABLES section. you can use the Step Over debug command, you can observe how the variables change as each step is executed.

Inspect variables

If there is a need to test how the project would behave in certain conditions or fix its current behavior at runtime, you can do that by setting/changing the variable values.

  1. Right-click a variable on the VARIABLES section and select Set Value, or double-click the variable name.
  2. Enter the value for the variable and click OK.

When the debugger is paused, several options are available when you right-click a variable from the VARIABLES section:

  • Copy Value: Allows you to copy the value of a variable.
  • Copy As Expression: Allows you to copy the name of a variable.

Set watch expressions

If you want to keep track of some variable or the result of a more complex expression, you can set up a watch for this variable or expression.

  1. Click the + button in the WATCH section to open Edit Watch Expression dialog box.
  2. Type the name of a variable or expression and click OK.

The project will pause at the line where the breakpoint is set and display the value of the variable. You can step over as needed to observe whether the value of the variable sum is computing as expected.

Set a watch expression <code>sum</code>

More options are available from the WATCH section:

  • Collapse All
  • Remove All Expressions

Debug console

Debug Console view is used to output debugging results and information. To open the Debug Console, click the View > Debug Console in menu bar or press Control+Shift+Y. When starting debugging, the Debug Console panel will show debug output.

REPL

The Debug Console REPL (Read-Eval-Print Loop) feature is on the bottom of the view and can be used to calculate the return value of a variable or function. Click the REPL-button button in the up right corner of Debug view to open REPL input box.

In this example below, typing i+count in the REPL window and then pressing Enter to send it, the Debug Console output the return value of i+count.

Debug console REPL

If you are an advanced user, you can use the REPL to interact with the debugger through frequently used ZDB/GDB commands. When entering a command, it needs to start with `. It provides functionality the UI does not expose, including:

  • bt
  • p <expression>

For the example below, enter `p &i in the REPL window at the bottom, and then press Enter to send it, the Debug Console will output the address of the current variable.

Use REPL to interact with debugger through command

::: tip

You must be in a running debug session to use the Debug Console REPL. When use the REPL to interact with the debugger , it is necessary to consider the potential risks of calling functions or changing variable values. :::

Disassembly view

The disassembly view is provided in debugging to display high-level source code with its associated assembler code for use in identifying instruction issues during debugging. You can switch to the disassembly view by following these steps.

  1. Make sure the debug session is on;
  2. Open the disassembly view from view's pull-down menu.
Open disassembly view