RISC-V RVV第9讲之搭建RVV开发环境

RISC-V RVV第9讲之搭建RVV开发环境

1 安装工具链(gcc与qemu)

为了方便后续的测试,我们需要安装RISC-V GCC编译器和qemu运行环境。

riscv gcc:

为了方便,riscv gcc这里我们下载已预编译好的riscv64-unknown-linux-gnu-gccriscv64-unknown-linux-gnu-gdb

https://github.com/riscv-collab/riscv-gnu-toolchain

下载:riscv64-glibc-ubuntu-22.04-gcc-nightly-2025.01.20-nightly.tar.xz

解压并配置工具链路径:

# 解压
$ tar -zxvf riscv64-glibc-ubuntu-22.04-gcc-nightly-2025.01.20-nightly.tar.xz

# 配置工具链路径
$ export PATH=/path/to/riscv/bin/:$PATH

# 测试
$ riscv64-unknown-linux-gnu-gcc -v
...
gcc version 14.2.0

$ riscv64-unknown-linux-gnu-gdb -v
GNU gdb (GDB) 15.1

riscv qemu:

qemu没有预编译好的版本,需要自己手动编译,为了方便,这里我们选择qemu-user模式。

$ sudo apt-get install -y build-essential pkg-config libglib2.0-dev zlib1g-dev libpixman-1-dev autoconf automake libtool bison flex texinfo gcc g++ git

$ git clone -b stable-9.0 https://github.com/qemu/qemu.git
$ cd qemu

$ mkdir build && cd build

$ ../configure --prefix=/path/to/qemu/build/linux_qemu --disable-pa --disable-linux-aio --disable-rbd --disable-vnc --disable-sdl --disable-sdl-image --target-list=riscv64-linux-user

$ make -j

# 在 qemu/build 路径下生成 qemu-riscv64  
# 配置工具链路径
$ export PATH=/path/to/qemu/build/:$PATH

# 测试
$ ./qemu-riscv64 --version
qemu-riscv64 version 9.0.4 (v9.0.4)
Copyright (c) 2003-2024 Fabrice Bellard and the QEMU Project developers

2 编译调试RVV intrinsics 的一个实例

编译一个简单的RVV intrinsics 代码,并在qemu环境中运行和调试。

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <riscv_vector.h>

#define DATALEN 16
int main(void)
{
  const int32_t vec1[DATALEN] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
  const int32_t vec2[DATALEN] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };

  int32_t res[DATALEN] = {0};

  const int32_t *pSrcA = vec1;
  const int32_t *pSrcB = vec2;
  int32_t *pDes = res;

  size_t avl = DATALEN;
  size_t vl;
  vint32m4_t op1, op2, rd;

  for (; (vl = __riscv_vsetvl_e32m4(avl)) > 0; avl -= vl) {
    // load数据
    op1 = __riscv_vle32_v_i32m4(pSrcA, vl);
    op2 = __riscv_vle32_v_i32m4(pSrcB, vl);
    pSrcA += vl;
    pSrcB += vl;

    // 向量加法
    rd = __riscv_vadd_vv_i32m4(op1, op2, vl);

    // store数据
    __riscv_vse32_v_i32m4 (pDes, rd, vl);
    pDes += vl;
  }

  // 数据打印
  for (int i = 0; i < DATALEN; i++) {
    printf("%d, ", res[i]);
  }
  printf("\r\n");

  return 0;
}

编译:

使用如下命令,或者进入part9文件夹,执行make即可

$ riscv64-unknown-linux-gnu-gcc -march=rv64imafdcv -mabi=lp64d *.c -o vadd_example.elf -lm -static -O2 -g

其中,-march=rv64imafdcv 中的v表示支持RVV

在qemu中运行:

qemu-riscv64 -cpu rv64,g=true,c=true,v=true,vlen=128,elen=64,vext_spec=v1.0 ./vadd_example.elf

打印日志如下,可见成功的实现了向量加法:

$ qemu-riscv64 -cpu rv64,g=true,c=true,v=true,vlen=128,elen=64,vext_spec=v1.0 ./vadd_example.elf
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,

单步调试RVV程序:

要学习RVV指令,一个单步调试指令的环境是不可或缺的,这里使用qemu以及riscv64-unknown-linux-gnu-gdb来单步调试RVV程序。

注意:在使用riscv64-unknown-linux-gnu-gcc编译代码时带上-g

step1:qemu启动gdb服务端

使用qemu-user启动你的程序,并通过-g参数指定GDB服务器监听的端口号,这里监听的端口号为1234。

$ qemu-riscv64 -cpu rv64,g=true,c=true,v=true,vlen=128,elen=64,vext_spec=v1.0 -g 1234 ./vadd_example.elf

step2:使用gdb连接到qemu

新建一个终端,使用如下命令启动gdb

$ riscv64-unknown-linux-gnu-gdb
(gdb) target remote localhost:1234
warning: No executable has been specified and target does not support
determining executable automatically.  Try using the "file" command.
0x00000000000104d4 in ?? ()
(gdb) file vadd_example.elf
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Reading symbols from vadd_example.elf...
(gdb) b main
Breakpoint 1 at 0x10400: file main.c, line 9.
(gdb) c
Continuing.

Breakpoint 1, main () at main.c:9
9           const int32_t vec1[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };

接下来,单步调试这个RVV函数,并查看RVV的寄存器,可见v24 寄存器的内容符合预期。

(gdb) set disassemble-next-line on
# 经过多次单步
(gdb)
20          op1 = __riscv_vle32_v_i32m4(vec1, vl);
=> 0x000000000001047a <main+122>:       02016c07                vle32.v v24,(sp)
(gdb) info reg vl
vl             0x10     16
(gdb) info reg vtype
vtype          0xd2     210
(gdb) info reg v24
v24            {q = {0x4000000030000000200000001}, l = {0x200000001, 0x400000003}, w = {0x1, 0x2, 0x3, 0x4}, s = {0x1, 0x0,
    0x2, 0x0, 0x3, 0x0, 0x4, 0x0}, b = {0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0}}

注意:后续章节的RVV用例都是使用类似方法查看向量寄存器的。

3 rvv_spec_examples 用例的测试

本文档列出RVV intrinsic function的用例,仓库中也提供相同的用例,我们可以拉取下来,然后进行测试。

  1. 下载 rvv_spec_examples 用例

    git clone https://github.com/surez-ok/riscv-rvv-doc-zh.git
    
  2. 配置好工具链路径(上文提到的gcc路径与qemu路径)

  3. 进入文件夹,第9讲就进入part9,第10讲就进入part10..., 然后测试

    $ cd part9
    $ make all
    run ./vadd_test.elf
    2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
    

4 rvv-intrinsic-doc 仓库的使用

从哪里查询RVV intrinsic APIs?

官方参考:https://github.com/riscv-non-isa/rvv-intrinsic-doc/tree/main

在线查询API:https://dzaima.github.io/intrinsics-viewer/

这里讲述怎么测试rvv-intrinsic-doc仓库中提供的API

step1:下载rvv-intrinsic-doc 仓库

$ git clone https://github.com/riscv-non-isa/rvv-intrinsic-doc

RVV intrinsic API 可查询 rvv-intrinsic-doc/auto-generated/intrinsic_funcs.adoc

step2:测试 rvv intrinsic api

$ cd rvv-intrinsic-doc/rvv-intrinsic-generator
$ make run-api-testing COMPILER=riscv64-unknown-linux-gnu-gcc

测试结果:

-----------------------------------------------------------------
Total                                             :  468/ 468
-----------------------------------------------------------------
-----------------------------------------------------------------
API Test Summary:
-----------------------------------------------------------------
Vector Loads and Stores Intrinsics                :   29/  29
Vector Loads and Stores Segment Intrinsics        :  189/ 189
Vector Integer Arithmetic Intrinsics              :   63/  63
Vector Fixed-Point Arithmetic Intrinsics          :   13/  13
Vector Floating-Point Intrinsics                  :   46/  46
Vector Reduction Operations                       :   16/  16
Vector Mask Intrinsics                            :   18/  18
Vector Permutation Intrinsics                     :   10/  10
Miscellaneous Vector Utility Intrinsics           :    2/   2
BFloat16 Vector Loads and Stores Intrinsics       :    9/   9
BFloat16 Vector Loads and Stores Segment Intrinsics:   63/  63
BFloat16 Convert Intrinsics                       :    0/   0
BFloat16 Arithmetic Intrinsics                    :    2/   2
BFloat16 Miscellaneous Vector Utility Intrinsics  :    7/   7
Zvbb - Vector Bit-manipulation used in Cryptography:    1/   1
Zvbc - Vector Carryless Multiplication            :    0/   0
Zvkg - Vector GCM/GMAC                            :    0/   0
Zvkned - NIST Suite: Vector AES Block Cipher      :    0/   0
Zvknh - NIST Suite: Vector SHA-2 Secure Hash      :    0/   0
Zvksed - ShangMi Suite: SM4 Block Cipher          :    0/   0
Zvksh - ShangMi Suite: SM3 Secure Hash            :    0/   0
-----------------------------------------------------------------
Total                                             :  468/ 468
-----------------------------------------------------------------

表明编译器支持这些API。

posted @ 2025-04-12 16:19  sureZ_ok  阅读(219)  评论(0)    收藏  举报