1. RISC-V向量扩展环境搭建与首个向量程序

RISC-V向量扩展环境搭建与首个向量程序 学习卡片

任务目标

本案例使用RISC-V向量扩展指令(V扩展)实现两个整数向量的逐元素加法。通过内联汇编方式,在支持V扩展的RISC-V环境中完成向量加载、向量加法和向量存储操作,并与标量计算结果比对以验证正确性。

环境要求

  • 支持RISC-V V扩展(向量扩展)的编译器:GCC 12+(需启用 -march=rv64gcv)
  • 支持V扩展的模拟器或硬件环境(如QEMU 7.0+,或RISC-V FPGA平台)
  • Linux环境(用于编译和运行测试程序)

核心实现

以下代码定义了两个长度为8的整数向量,使用向量指令完成逐元素加法,并通过标量循环验证结果。向量长度固定为8,对应vlen=128位时SEW=32可容纳8个元素;若硬件向量长度不同,代码通过vsetvli动态获取实际处理元素数,并循环处理剩余元素,保证可移植性。

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

#define N 8

int main() {
    int32_t a[N] = {1, 2, 3, 4, 5, 6, 7, 8};
    int32_t b[N] = {10, 20, 30, 40, 50, 60, 70, 80};
    int32_t result[N] = {0};
    int32_t expected[N];

    // 标量计算期望结果
    for (int i = 0; i < N; i++) {
        expected[i] = a[i] + b[i];
    }

    // 向量加法:处理长度为N的数组
    size_t len = N;
    int32_t *pa = a, *pb = b, *pr = result;

    while (len > 0) {
        size_t vl;
        asm volatile(
            "vsetvli %0, %1, e32, m1\n"   // 设置向量长度(按32位元素)
            "vle32.v v1, (%2)\n"          // 加载a[i..i+vl-1]
            "vle32.v v2, (%3)\n"          // 加载b[i..i+vl-1]
            "vadd.vv v3, v1, v2\n"        // 向量加法
            "vse32.v v3, (%4)\n"          // 存储结果
            : "=&r"(vl)                    // 输出:实际处理的元素数
            : "r"(len), "r"(pa), "r"(pb), "r"(pr)
            : "v1", "v2", "v3", "memory");

        pa += vl;
        pb += vl;
        pr += vl;
        len -= vl;
    }

    // 验证结果
    int ok = 1;
    for (int i = 0; i < N; i++) {
        if (result[i] != expected[i]) {
            printf("Mismatch at index %d: got %d, expected %d\n",
                   i, result[i], expected[i]);
            ok = 0;
        }
    }

    if (ok) {
        printf("Vector add test PASSED\n");
    } else {
        printf("Vector add test FAILED\n");
    }

    return ok ? 0 : 1;
}

编译与运行

# 编译(需RISC-V GCC工具链)
riscv64-unknown-linux-gnu-gcc -march=rv64gcv -mabi=lp64d -static -O2 -o vec_add vec_add.c

# 在QEMU中运行(需支持V扩展)
qemu-riscv64 -cpu rv64,v=true,vlen=128 ./vec_add

验证方法

程序运行后,若输出Vector add test PASSED且退出码为0,则说明向量加法结果与标量计算结果完全一致,验证通过。若输出FAILED并显示不匹配的索引和值,则说明向量指令执行结果有误,需检查编译参数或模拟器V扩展支持情况。

预期输出(当向量指令正确执行时):

Vector add test PASSED

关键说明

  • vsetvli指令根据硬件向量长度(VLEN)和元素宽度(SEW=32)自动计算本次循环可处理的元素数,保证代码在不同VLEN的硬件上均可正确运行。
  • 内联汇编中"memory"clobber确保编译器不会将数组访问重排到向量指令之前或之后,维持正确的内存访问顺序。
  • 本案例使用m1寄存器组策略(单向量寄存器组),适用于元素数不超过VLEN/32的场景;对于更长数组,循环机制会自动分段处理。