0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

RISCV该如何开启和使用V扩展指令?

嵌入式IoT 来源:嵌入式IoT 作者:bigmagic 2021-06-18 16:28 次阅读

用哪吒D1开发板体验riscv向量底层编程

1.前言

2.机器模式处理器状态寄存器(MSTATUS)

3.编译选项支持V扩展

4.RISCV向量计算的原理

5.通过实例分析RISCV V扩展的运作机制

6.RVV使用体验

1.前言

RISCV V扩展即向量指令扩展(RVV),这部分作为研究AI加速计算领域有着非常关键的作用。既然的D1支持了rvv扩展(0.7.1,最新的版本已经0.10版本),那么就实际的从底层原理角度分析一下使用的流程。利用了多媒体加速指令集,可以让计算变得更加的高效,同时并行计算的特性使得同时多次计算一组数字成为可能,类似于arm的NEON等等,那么RISCV又该如何去开启和使用V扩展指令,让计算变得更加高效呢?

下面会通过一个裸机代码入手,结合实战去展示riscv rvv的使用。

https://github.com/bigmagic123/d1-nezha-baremeta/tree/main/src/2.vector_example

2.机器模式处理器状态寄存器(MSTATUS)

机器模式状态处理寄存器可以查看玄铁C910的用户手册,开启的V扩展的位是[23:24]位,如果不设置这两位,那么使用V扩展指令的时候,会出现指令未定义的异常。

这里需要注意的是,RISCV的各家的VS标志并不是一定是这两位,比如sifive会定义在

但是无论怎么说,都需要设置机器状态控制器去开启v扩展指令的支持。

/* Enable FPU and accelerator if present */

li t0, MSTATUS_FS | MSTATUS_XS | (0x01800000)

csrs mstatus, t0

在启动代码中,通过0x01800000设置mstatus开启V扩展支持。

3.编译选项支持V扩展

默认情况下,平头哥提供的交叉编译工具链已支持了V扩展的编译。只需要在编译选项中开启即可。

从传递给riscv 的gcc的选项来看,带有v扩展即可。

-march是指定了riscv的模块化的指令集选项,可以通过选项指定目标RISC-V支持的模块化的指令集的组合。比如下面几种组合。

rv32i[m][a][f[d]][c]

rv32g[c]

rv64i[m][a][f[d]][c]

rv64g[c]

往往也会结合-mabi进行使用。-mabi决定了RISCV目标支持的ABI函数调用的规程。

4.RISCV向量计算的原理

在riscv的V扩展中,一共定义了32个寄存器,v0~v31,这32个寄存器,每个长度都是VLEN长度。在玄铁C906定义长度为128位。

而在V扩展的操作中,需要扩展下面的寄存器组。

下面来具体分析一些每个寄存器的作用。

vstart

矢量起始位置寄存器指定了执行矢量指令时起始元素位置,每条矢量指令执行后 VSTART 会被清零。

该寄存器只有在处理器进入陷阱或者中断状态时,才会被硬件写入。

所以的向量指令都会从vstart中给定的元素编号开始执行,支持完成后,自动变为0。

为什么会有这个寄存器,原因是在V扩展指令中,每个寄存器是可以分割与合并的,并不是单独操作。

vxsat

这个是向量定点的饱和标志位,该位指示定点指令是否必须使输出值饱和,以此适应目标格式。

vxrm

向量定点舍入模式寄存器,指定了定点指令采用的舍入模式。

vl

矢量长度寄存器指定了矢量指令更新目的寄存器的范围,矢量指令更新目的寄存器中元素序号小于 VL 的元素,清零目的寄存器中元素序号大于等于 VL 的元素。特别的,当 VSTART》=VL 或 VL 为 0 时,目的寄存器的所有元素不 被更新。该寄存器是任意模式下的只读寄存器,但是 vsetvli、vsetvl 以及 fault-only-first 指令能够更新该寄存器的值。

该寄存器的值是通过vsetvli/vsetvl指令自动设置的。

vtype

VTYPE 寄存器指定了矢量寄存器组的数据类型以及矢量寄存器的元素组成。

通过C910的数据手册,可看出

向量长度寄存器VLENB

该寄存器用于表示矢量寄存器的数据位宽,以实际位宽除以 8 得到的字节数体现。C906 矢量寄存器为 128 位,因此 VLENB 值固定为 16。该寄存器位长是 64 位,用户模式只读。

5.通过实例分析RISCV V扩展的运作机制

下面一个rvv实际的函数

void test_v(void)

{

float a[]={1.0,2.0,3.0,4.0};

float b[]={1.0,2.0,3.0,4.0};

float c[]={0.0,0.0,0.0,0.0};

int len=4;

int i=0;

//inline assembly for RVV 0.7.1

//for(i=0; i《len; i++){c[i]=a[i]+b[i];}

asm volatile(

“mv t4, %[LEN]

“mv t1, %[PA]

“mv t2, %[PB]

“mv t3, %[PC]

“LOOP1:

“vsetvli t0, t4, e32,m1

sub t4, t4, t0

“slli t0, t0, 2

” //Multiply number done by 4 bytes

“vle.v v0, (t1)

add t1, t1, t0

“vle.v v1, (t2)

“add t2, t2, t0

“vfadd.vv v2, v0, v1

“vse.v v2, (t3)

“add t3, t3, t0

“bnez t4, LOOP1

:[LEN]“r”(len), [PA]“r”(a),[PB]“r”(b),[PC]“r”(c)

:“cc”,“memory”, “t0”, “t1”, “t2”, “t3”, “t4”,

“v0”, “v1”, “v2”

);

for(i=0; i《len; i++){

printf(“

”);

printf(“%f

”,c[i]);

printf(“

”);

}

}

这里采用的是内联汇编,可以更加深入的分析RVV的运作机制和底层原理。

在riscv中,内联汇编的写法

asm volatile(“nop”);

这样编译器在编译后会生成可以执行的汇编代码。

该函数的功能

for(i=0; i《len; i++){c[i]=a[i]+b[i];}

通过上述分析,通过向量计算,可以一次性计算出上面四次循环加法。

vsetvli t0, t4, e32,m1

vsetvli表示设置每个向量的长度,t4的值表示的是len,也就是4。

e32表示每个元素为32位,m1表示使用1倍数量的向量寄存器。

该条指令相当于把一个向量寄存器(128位)分成四等分,这是一条设置指令,设置vl寄存器。返回值为t0,这里由于是刚好装下4条32位的数字,所以返回值为4。

sub t4, t4, t0

通过查看数组是否计算完成,来进行循环计算,这里t4为0了。

slli t0, t0, 2

往左移动两位,也就是将t0乘以4。这里计算的目的是如果存在很长的数组,可以偏移t0个字节从而指向数组的下个地址。

vle.v v0, (t1)

填充向量寄存器(t1)为a数组,一条指令将数据放到向量寄存器v0中。

add t1, t1, t0

将a数组的起始元素加上16字节(4个元素)的偏移。

vle.v v1, (t2)

填充b数组的数组到向量寄存器v1中。

add t2, t2, t0

将数组b的元素的起始地址偏移16字节,也就是4个元素。

vfadd.vv v2, v0, v1

执行向量加法,将向量的结果保存到向量寄存器v2中。

vse.v v2, (t3)

将向量寄存器中值写回到c数组中。

add t3, t3, t0

将数组c的元素指针偏移4个元素。

bnez t4, LOOP1

直到计算的len长度为0,此时跳出循环计算。

由于此时计算只有4字节,所以一次循环就计算完成了,不用多次计算。

采用向量寄存器的计算,可以把四次循环计算用一次计算就完成。当然这种如果大量计算时,才能体现出更大的优势。

最后的结果如下:

通过对数组的计算

float a[]={1.0,2.0,3.0,4.0};

float b[]={1.0,2.0,3.0,4.0};

float c[]={0.0,0.0,0.0,0.0};

最后c数组的结果

float c[]={2.0,4.0,6.0,8.0};

其理论数据和实际数据一样。

6.RVV使用体验

刚接触到riscv 的 V扩展编程时,很多概念都理解的很模糊,感觉十分的困难,通过一段时间梳理之后,发现和以前mips上接触的mxu或者arm的neno使用上大多数是一样的,就需要去设置使用寄存器的长度,当然这些底层函数如果进行一层封装后,再给用户使用,那才是比较方便的,但是本文只是介绍底层实现的原理,并不多介绍使用的细节。

RVV还有一个特性就是寄存器的扩充,比如D1采用的玄铁C906的核,支持的是32个128位的向量寄存器,也可以将两个或多个向量寄存器拼成一个来使用。这样寄存器的长度更加长,能够同时做到并行计算也就更多。这取决于如何做向量的优化设计。

原文标题:用哪吒D1开发板体验riscv向量底层编程

文章出处:【微信公众号:嵌入式IoT】欢迎添加关注!文章转载请注明出处。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    30

    文章

    4995

    浏览量

    117422
  • 开发板
    +关注

    关注

    25

    文章

    4370

    浏览量

    93439

原文标题:用哪吒D1开发板体验riscv向量底层编程

文章出处:【微信号:Embeded_IoT,微信公众号:嵌入式IoT】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    RISCV soft JTAG调试_v1.1

    因为目前软件的限制,RISCV的逻辑不能同时共用JTAG,所以如果想要同时去调试逻辑和RISCV的话,可以通过RISCV的soft Jtag来实现。soft Jtag就是通过GPIO来实现的软件
    的头像 发表于 02-23 16:16 140次阅读
    <b class='flag-5'>RISCV</b> soft JTAG调试_v1.1

    【RISC-V开放架构设计之道|阅读体验】汇编语言和扩展指令

    【RISC-V开放架构设计之道|阅读体验】汇编语言和扩展指令集 汇编语言 将C语言翻译成可执行的机器语言的重要步骤包括编译过程,汇编过程,链接过程。 函数调用约定过程分为六个阶段: 1)将参数存放
    发表于 02-03 13:29

    【RISC-V开放架构设计之道|阅读体验】RISC-V基础整数指令

    分支的B型,用于长立即数的U型和用于无条件跳转的J型。 下面是本章的思维导图: RV32I是RISC-V的基础指令集,后续会继续拓展RISC-V的其它指令
    发表于 01-31 21:10

    risc-v标准指令集如何扩展

    想问问具体要怎么实现标准指令集的扩展呢?需要修改哪些硬件啊? 每一种指令扩展是相似的吗?还是需要不一样的步骤呢(比如V
    发表于 01-21 22:19

    riscv开发板推荐

    、灵活和可扩展指令集,使得各种芯片设计人员可以根据自己的需求来自定义处理器设计,而无需受到专有指令集的限制。因此,越来越多的开发者开始使用RISC-V进行各种应用的开发和研究。 在选择RISC-V开发板时,你需要考虑以下几个方
    的头像 发表于 01-07 16:43 742次阅读

    RISCV如何去开启和使用V扩展指令

    原理角度分析一下使用的流程。利用了多媒体加速指令集,可以让计算变得更加的高效,同时并行计算的特性使得同时多次计算一组数字成为可能,类似于arm的NEON等等,那么RISCV又该如何去开启和使用
    发表于 08-16 08:15

    如何在蜂鸟处理器核的基础上扩展第三方指令

    想咨询一下如何在蜂鸟处理器核的基础上扩展第三方指令,使用户自定义指令,并如何构建机器码等内容? 我看了胡老师的RISC-V处理器设计的书里面讲的使用custom1-4来进行
    发表于 08-16 07:36

    riscv实现自定义指令并用qemu运行的过程

    1.说明 riscv支持指令集自定义扩展,这大大增加了riscv的可性,同时对于一些实际应用中,自己通过一条指令来实现特定的功能,效率非常高
    发表于 08-16 07:27

    全志D1开发板RISCV64开箱评测

    支持RVV 这个也较为关键,在RISCV中对于多媒体加速指令上,采用的是V扩展,也就是RISCV V
    发表于 08-16 07:05

    RISCV自定义指令编译生成.verilog文件后如何修改其中的地址?

    各位老师好,本人最近在自学riscv,在使用蜂鸟e203自定义指令拓展时,遇到了一些问题,我在 Linux中通过修改gnu工具链加入了新的dot指令,并成功生成了可执行文件,通过objcopy转换
    发表于 08-12 07:43

    RISCV自定义指令编译报错怎么解决?

    各位老师好,本人在学习riscv指令时,在指令编译过程中遇到如下问题,希望老师能够不吝赐教,非常感谢!
    发表于 08-12 07:40

    Ubuntu20.04对benchmark编译出不带压缩指令的汇编代码,缺少 -lstdc++是为什么?

    压缩指令的汇编代码,但链接时报错,说缺少 -lstdc++。 我尝试过把makefile的-lstdc++给去掉,然后报了一大堆错误,看来这个库是sdk必不可少的。 官方工具链是否支持非压缩编译呢,请问如何解决呢? 谢谢!
    发表于 08-11 13:01

    AG32VF407环境搭建(FPGA+RISCV

    AG32VF407环境搭建(FPGA+RISCV
    的头像 发表于 07-17 09:21 4539次阅读
    AG32VF407环境搭建(FPGA+<b class='flag-5'>RISCV</b>)

    BLUFI命令开启后,不能再重复使用哪些AT指令

    当使用 AT+BLUFI=1 命令时,如果刚发送完 AT+RESTORE 或 AT+RST 命令,则开启 BLUFI 成功,若期间发送了一些蓝牙广播开启等命令后,则会失败。请问 BLUFI 命令开启后,不能再重复使用哪些 AT
    发表于 04-24 06:28

    riscv和arm性能对比

      riscv和arm性能对比  RISC-V 和 ARM 的相似之处  RISC-V与ARM最大的不同就在于其推崇的大道至简的技术风格和彻底开放的模式。由于ARM是一种封闭的指令集架
    发表于 03-30 16:43