1. 向量寄存器初始化与数据搬运

向量寄存器初始化与数据搬运 学习卡片

任务目标

本案例演示RISC-V向量扩展(RVV)中向量寄存器的初始化与数据搬运操作。通过向量加载指令vle32.v将内存中的32位整型数据批量载入向量寄存器,再通过向量存储指令vse32.v将向量寄存器内容写回另一段内存区域,完成一次完整的数据搬运闭环。同时展示如何通过vsetvli配置向量长度与数据类型。

环境依赖

  • 支持RVV 1.0的RISC-V工具链(如GCC 12+,编译参数-march=rv64gcv)
  • 支持向量扩展的模拟器(如QEMU 7.0+,-cpu rv64,v=true)或真实硬件

关键完整代码

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

#define N 16  // 数据元素个数

int main() {
    // 源数据与目标缓冲区(均按16字节对齐以满足向量访问要求)
    int32_t src[N] __attribute__((aligned(16)));
    int32_t dst[N] __attribute__((aligned(16)));

    // 初始化源数据
    for (int i = 0; i < N; i++) {
        src[i] = i * 3 + 1;
        dst[i] = 0;
    }

    // 向量数据搬运:src → 向量寄存器 → dst
    size_t vl;
    int32_t *ps = src;
    int32_t *pd = dst;
    int32_t avl = N;  // 剩余元素数

    while (avl > 0) {
        // 设置向量长度:32位整型,每次处理min(avl, VLMAX)个元素
        vl = vsetvl_e32m1(avl);
        
        // 从内存加载avl个元素到向量寄存器v0
        vint32m1_t vec = vle32_v_i32m1(ps, vl);
        
        // 将向量寄存器v0的内容存储到目标内存
        vse32_v_i32m1(pd, vec, vl);
        
        // 更新指针与剩余计数
        ps += vl;
        pd += vl;
        avl -= vl;
    }

    // 验证搬运结果
    int err = 0;
    for (int i = 0; i < N; i++) {
        if (dst[i] != src[i]) {
            printf("Mismatch at [%d]: src=%d dst=%d\n", i, src[i], dst[i]);
            err = 1;
        }
    }
    if (!err) {
        printf("PASS: all %d elements copied correctly\n", N);
    }
    return err;
}

编译与运行

# 编译(需RVV工具链)
riscv64-unknown-elf-gcc -march=rv64gcv -mabi=lp64d -O2 -o vec_copy vec_copy.c

# QEMU模拟运行
qemu-riscv64 -cpu rv64,v=true ./vec_copy

验证方法与判定标准

程序执行后,通过逐元素比较dst与src内容完成自校验。若所有元素一致,输出PASS: all 16 elements copied correctly,退出码为0;否则打印首个不匹配位置并返回非零退出码。该验证覆盖了向量寄存器初始化(vle32.v载入)与数据搬运(vse32.v写出)的完整链路。

关键说明

  • vsetvl_e32m1将向量长度配置为32位整数、LMUL=1,返回实际处理的元素数vl,该值受硬件VLMAX约束。
  • 循环处理保证当N超过VLMAX时,代码仍能通过分段搬运正确处理全部数据。
  • 源与目标缓冲区均显式16字节对齐,避免非对齐访问异常。