Skip to main content

Demo project

ZStudio contains a number of demos which can be imported conveniently. The following sections walk you through the demo projects and describe a set of ZStudio features along the way.

matrix_cmplx_mult

matrix_cmplx_mult demo is adopted as an example for step by step instructions on how to create custom extension with ZIGen, apply it on virtual SoC model, and identify bottlenecks and design optimization with ZProf.

Open matrix_cmplx_mult solution

Steps to open the demo in ZStudio:

  1. On the ZStudio main menu, click File > Import Example Solutions. Select matrix_cmplx_mult from pull-down box and click Open.

  2. Set the base project as active project, select the Release configuration and RISC-V platform, then click Build button and Check the build process in the Build Console view.

  3. Set the base project as active project, select Profiling > Configuration from main menu to set profile configuration before launching profiling session.

    • Choose Virtual Board : select Builtin from drop-down box
    • Simulator Virtual Board : select RocketChip from drop-down box
  4. Set the base project as active project, select Profiling > Start Profiling from main menu. Wait for the The profiling has finished! prompted from message window and avoid to executed again. When finished, the profiling result will open in a new editor.

In the following guidance, we will create custom instructions and use it to optimize base project and improve its performance on a RocketChip virtual boards.

Create custom extension

Select ZExplorer from the drop-down menu to enter into ZExplorer, then switch to ZIGen view through Activity Bar icon.

You can import custom extension that we prepared for this demo by clicking more-action-button (More Actions..) > import-extension-button (Import Extension) to evoke a dialog box. Then point ZStudio to dspmult.zsext which is under ~/ZStudio_Workspace/Solutions/matrix_cnmplx_mult/Extension in your PC file system.

Besides, you can also follow below steps to get familiar with instruction customization.

Click new-extension-button (New Extension) to create a new extension dspmult.

Add custom instruction zkmxda

  1. Right-click dspmult extension node and select New Instruction and specify the instruction name zkmxda to create a new instruction.

  2. Specify custom instruction configuration

    In instruction edit page, you need to specify all the configurable options to your custom instruction.

    • Function Unit : Select Simd function unit from pull-down box, please refer to Available Function Units Table.

    • Length: Select the 32bits length from pull-down box.

    • Architecture: Select the processor architecture of RV32&RV64 from pull-down box.

    • ASM: The assembly language (ASM) representation of your custom instruction, also known as instruction mnemonic, will be generated after defining custom instruction format automatically.

  3. Define the format of your custom instruction

    Click add-button (Add) to invoke the encoding field dialog and specify available encoding space in Encoding Field.

    • Base & Width: Control the encoding length and bit position.
    • Type & Value: Select the encoding type and enter its value.

    You can check it in in Encoding Preview Table and right-click the rows in Encoding Field to edit or delete them until you are happy with the corrections.

  4. Define instruction behavior

    Describe the execution flow of your custom instruction in Behavior code editor.

    Instruction behavior
    for (uint32_t i = 0; i < XLen / 32; ++i) {
    int16_t r1 = getHalf(rs1, 2 * i);
    int16_t r2 = getHalf(rs2, 2 * i);
    int32_t tmp = 0x80008000;
    if (getWord(rs1, i) != tmp || getWord(rs2, i) != tmp) {
    int32_t res = sext<16>(getHalf(rs1, 1 + 2 * i)) * sext<16>(r2) +
    sext<16>(r1) * sext<16>(getHalf(rs2, 1 + 2 * i));
    setWord(rd, i, res);
    } else {
    setWord(rd, i, 0x7fffffff);
    setVxsat(DI);
    }
    }

And your zkmxda instruction format will be like the below figure.

Add another custom instruction zsmdrs

  1. Right-click dspmult extension to create another new instruction zsmdrs.

  2. Specify the configuration as same as zkmxda.

  3. Define the format of zsmdrs and describe the execution flow of zsmdrs in Behavior code editor.

    Instruction behavior
    for (uint32_t i = 0; i < XLen / 32; ++i) {
    int64_t Tmp = (int16_t)getHalf(rs1, 2 * i) * (int16_t)getHalf(rs2, 2 * i) -
    (int16_t)getHalf(rs1, 1 + 2 * i) * (int16_t)getHalf(rs2, 1 + 2 * i);
    setWord(rd, i, Tmp);
    }

And your zsmdrs instruction will be like the below figure.

Generate shared library

Right-click the extension dspmult and select Generate Shared Library. Check the state in bottom-right corner and wait for the Successfully generate shared library: dspmult message. You can find it under INCLUDE navigator.

The macro that needed be included as header file of your program will be saved under Home/{user_name}/ZStudio_Workspace/include in your file system.

The shared library that be used by compiler and simulator will be saved under Home/{user_name}/ZStudio_Workspace/lib in your file system.

Work with your custom extension

You can apply your custom extension in builtin virtual board and your project.

Use custom extension in programming

Select ZSolution from the drop-down menu to enter into ZSolution, then create a new project custom for using custom extension dspmult. Here we already prepared for you in matrix_cmplx_mult solution

  1. Use your custom extension in your project custom.

    • include header file of custom extension in custom_mat_cmplx_mult_q15.c.

    • Use the custom instructions in custom_mat_cmplx_mult_q15.c based on base_mat_cmplx_mult_q15.c.

      custom_mat_cmplx_mult_q15.c
      #include <stddef.h>
      #include <stdint.h>
      #include <stdio.h>
      #include <sys/_stdint.h>

      #include "input1_q15.h"
      #include "input2_q15.h"
      #include "xdspmult.h"

      #define TEST_M 10
      #define TEST_K 10
      #define TEST_N 10

      typedef int16_t q15_t;
      typedef int64_t q33_30_t;

      __attribute__((noinline)) static int32_t __SSAT(int32_t aValue, uint32_t aBits)
      {
      if (aBits >= 1U && aBits <= 32U)
      {
      int32_t max = (1 << (aBits - 1U)) - 1;
      int32_t min = -1 - max;

      if (aValue > max)
      return max;
      // aValue = max;
      else if (aValue < min)
      return min;
      // aValue = min;
      }

      return aValue;
      }

      __attribute__((noinline)) void tpt_mat_cmplx_mult_q15(q15_t *aOutMat, const q15_t *aInMatA,
      const q15_t *aInMatB, uint16_t aM, uint16_t aK,
      uint16_t aN)
      {
      for (uint16_t row = 0; row < aM; ++row)
      {
      for (uint16_t col = 0; col < aN; ++col)
      {
      q33_30_t sum_r = 0;
      q33_30_t sum_i = 0;
      const q15_t *p_in1 = &aInMatA[2 * ((uint32_t)row * aK)];
      const q15_t *p_in2 = &aInMatB[2 * col];

      for (uint16_t i = 0; i < aK; ++i)
      {
      int32_t a = ((int32_t *)p_in1)[0];
      int32_t b = ((int32_t *)p_in2)[0];
      int32_t tmp;

      _ZSMDRS(tmp, a, b);
      sum_r += tmp;
      _ZKMXDA(tmp, a, b);
      sum_i += tmp;

      p_in1 += 2;
      p_in2 += 2 * aN;
      }

      *aOutMat++ = __SSAT(sum_r >> 15U, 16);
      *aOutMat++ = __SSAT(sum_i >> 15U, 16);
      }
      }
      }

      #ifdef DUMP
      #define dump(data, n) \
      for (int i = 0; i < (n); ++i) \
      printf("%x \n", (data)[i]);
      #else
      #define dump(data, n) do {} while (0)
      #endif // DUMP

      static q15_t output_q15[TEST_M * TEST_N * 2];

      #define test_mat_cmplx_mult_q15(out, in1, in2, rows, k, cols) \
      tpt_mat_cmplx_mult_q15(out, in1, in2, rows, k, cols)

      int main(void)
      {
      test_mat_cmplx_mult_q15(output_q15, input1_q15, input2_q15, TEST_M, TEST_K,
      TEST_N);
      dump(output_q15, 20);
      return 0;
      }
  2. Set build configuration for custom

    Click the gear-button (Build Configuration) button and specify the Arch {standard_feature}_x{custom_extension} in build configuration. The prefix "x" is needed for custom extensions. And the supported {standard_feature} are listed in ZCC User Manual. As the picture below, you need specify rv32imafdc_xdspmult in this demo.

    When you specify Arch in build configuration, the header file will be included in your code and the shared library of custom extension will be linked in your ELF.

  3. Build custom project and check the build result

    Click the build-button button in Project Controller view and check the build result in the Build Console view.

  4. Disassemble custom project and check custom instruction.

    Right-click the executable file custom in File Navigator and select Disassemble and check your custom instructions.

  5. Run your project and check the run result.

    Click the run-button button in Project Controller view and check the result in the Run Console view.

Apply custom extension in virtual SoC model

Back to ZExplorer mode from the drop-down menu, then switch to ZVB view through Activity Bar icon.

Duplicate the builtin RocketChip and save as CusRocketChip. Enter into CPU layer of CusRocketChip to define which types of instruction operations are allowed to be performed on Execute type component from pull-down menu.

  1. Right-click the CPU type component CusRocketChip and select Open. Click the EXU component to invoke property edit panel.

  2. In the Property region, click to add-button to add Op List 1.

  3. Select Op Desc from pull-down box and specify Builtin function unit for EXU component.

    Builtin means specify all function unit except for Cus0/1/2/3/4. Please refer to Available Function Units.

    tip

    If you specify Cus0/Cus1/Cus2/Cus3/Cus4 function unit for your custom instructions, you need to repeat above steps to add Op List and specify Cus0/Cus1/Cus2/Cus3/Cus4 function unit uniquely for EXU component to ensure they are coincident.

  4. Run ELF on CusRocketChip

    To return to board layer, just right-click blank area and select Close. Right-click the CusRocketChip in navigator and select Run ELF.

    In the invoked dialog, point ZStudio to the directory of executable file custom which is /ZStudio_Workspace/Solutions/matrix_cmplx_mult/custom/output/zcc/risc-v/release/build-output/custom and pass shared library path --zigen-plugin-path=/home/{user_name}/ZStudio_Workspace/lib in your pc file system to zemu.

    Check the run output in Run Console.

Performance comparison

You can compare results to see how changes that you've made to instructions and source code affect program performance on RocketChip virtual boards.

Launch profiling sessions for custom

  1. Set the custom project as active project, select Profiling > Configuration from main menu to set profile configuration before launching profiling session.

    • Choose Virtual Board: select custom from drop-down box
    • Board Configuration File: point to the CusRocketChip.zvb file which can be found under home\ ZStudio_Workspace\VirtualBoards directory.
  2. Set the custom project as active project, select Profiling > Start Profiling from main menu. Wait for the The profiling has finished! prompted from message window and avoid to executed again.

Profiling comparison

To compare results:

  1. On the main menu, select View > Profiling Comparison to invoke the comparison tool.

  2. In the profiling comparison side bar, you need to specify base project profiling result as the reference benchmark. Right-click and select Select as Base.

  3. Click the comparison-configuration-button button to invoke the configuration window. And click "Ok" when you are happy with the configuration.

    • Select the data visualization of the Program Performance Comparison: select at least one form between chart and table.
    • Select items to compare. The default items are Instruction Count, Cycle Count and Instruction Per Cycle. You can select by yourself.
  4. Use Shift or Ctrl to select two profiling results, right click on one, and select Compare to achieve quick compare.

  5. The profiling comparison view will be opened in editor.

Program Performance Table provides change of indicators according to the base project data; The color differs the change direction, green means decrease while red means increase compared to base project.

The decrease of Instruction Count and Cycle Count as well as the increase of IPC of custom project demonstrate that custom instructions improves overall performance and efficiency.

add

add demo is adopted as an example for step by step instructions on how to create custom extension in ZExplorer and work with your custom extension in ZSolution.

Create custom extension

Steps to create custom extension in ZExplorer:

Select ZExplorer from the drop-down menu to enter into ZExplorer, then switch to ZIGen view through Activity Bar icon.

You can import custom extension that we prepared for this demo by clicking more-action-button (More Actions..) > import-extension-button (Import Extension) to evoke a dialog box. Then point ZStudio to singularadd.zsext which is under /home/{user_name}/ZStudio_Workspace/Solutions/add/Extension in your PC file system.

Besides, you can also follow below steps to get familiar with instruction customization.

  1. Click new-extension-button (New Extension) to create a new extension singularadd.

  2. Right-click singularadd extension node and select New Instruction. Specify the instruction name as singular_add.

  3. Specify custom instruction configuration

    In instruction edit page, you need to specify all the configurable options to your custom instruction.

    • Function Unit : Select IntAlu function unit unit from pull-down box.
    • Length: Select the 32bits length from pull-down box.
    • Architecture: Select the processor architecture of RV32&RV64 from pull-down box
    • ASM: The assembly language (ASM) representation of your custom instruction, will be generated after defining custom instruction format automatically.
  4. Define the format of your custom instruction

    Click add-button (Add) to invoke the encoding field dialog and specify available encoding space in Encoding Field.

    • Base & Width: Control the encoding length and bit position.
    • Type & Value: Select the encoding type and input its value.

    And your singular_add instruction format will be like the below figure. You can check it in in Encoding Preview Table and right-click the rows in Encoding Field to edit or delete them until you are happy with the corrections.

  5. Define instruction behavior

    Describe the execution flow of your custom instruction in C Code editor.

    Instruction behavior
    rd = rs1 + rs2;

Generate shared library

Right-click the extension singularadd and select Generate Shared Library. Check the state in bottom-right corner and wait for the "Successfully generate shared library: singularadd." message. You can find it under INCLUDE navigator.

The macro that needed be included as header file of your program will be saved under Home/{user_name}/ZStudio_Workspace/include in your file system.

The shared library that be used by compiler and simulator will be saved under Home/{user_name}/ZStudio_Workspace/lib in your file system.

Work with your custom extension

Select ZSolution from the drop-down menu to enter into ZSolution, then create a new project for using custom extension singularadd. You can import example solution that we prepared for this demo by clicking File > Import Example Solutions. Select add from pull-down box and click Open.

Besides, you can also follow below steps to create a project by yourself.

  1. Use your custom extension in your solution and project.

    • Include header file of custom extension in main.c.
    • Use the custom instructions in main.c.
    main.c
    #include "xsingularadd.h"

    #include <stdio.h>

    int main() {
    int Num0 = 2;
    int Num1 = 5;
    int Res;

    _SINGULAR_ADD(Res, Num0, Num1);
    printf("singular_add res: %d\n", Res);

    return 0;
    }
  2. Set build configuration

    Click the gear-button (Build Configuration) button and specify the Arch {standard_feature}_x{custom_extension} in build configuration. The prefix "x" is needed for custom extensions. And the supported {standard_feature} are listed in ZCC user manual. As the picture below, you need specify rv64imafdc_xsingularadd in this demo.

    When you specify Arch in build configuration, the header file will be included in your code and the shared library of custom extension will be linked in your ELF.

  3. Build your project and check the build result.

    Click the build-button button in Project Controller view and check the build result in the Build Console view.

  4. Run your project and check the run result.

    Click the run-button button in Project Controller view and check the result in the Run Console view.