有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

本帖最后由 sky 于 2020-9-16 10:15 编辑

移植01.jpg (131.33 KB, 下载次数: 0)

2020-9-16 10:14 上传

可以转载,但不准删改内容!

RISC-V,我喜欢缩写成 riscv,能少按一次 shift 和减号,是一个基于精简指令集(RISC)原则的开源指令集架构(ISA)。作为完全开源的指令集,天生自带开源的光环基因,纵使当今 x86 ARM 几乎绝对市场垄断,依然生机勃勃,持续发展着

如果要问我,为什么要把 ncnn 移植到 riscv 上面跑?那就是开源文化基因的力量,英文单词 meme 的魔法

其实移植过程中还是踩了一些坑的,感谢中科院软件所智能软件研究中心的大佬热心解答我的提问

一,编译工具链,pk,仿真器

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

其实第一次搭建环境,照着 README 的命令就足够了,首先是编译工具链,时间比较久,make 完会自动安装到 /opt/riscv,不需要 make install

$ export PATH=/opt/riscv/bin:$PATH

$ sudo apt-get install autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev

$ git clone https://github.com/riscv/riscv-gnu-toolchain.git

$ cd riscv-gnu-toolchain

$ git submodule update --init

$ ./configure --prefix=/opt/riscv

$ make -j4复制代码

https://github.com/riscv/riscv-pk

然后是 pk,proxy kernel

$ git clone https://github.com/riscv/riscv-pk.git

$ cd riscv-pk

$ mkdir build && cd build

$ ../configure --prefix=/opt/riscv --host=riscv64-unknown-elf

$ make -j4

$ make install复制代码

https://github.com/riscv/riscv-isa-sim

最后是仿真器,又名 spike

$ sudo apt-get install device-tree-compiler

$ git clone https://github.com/riscv/riscv-isa-sim.git

$ cd riscv-isa-sim

$ mkdir build && cd build

$ ../configure --prefix=/opt/riscv

$ make -j4

$ make install复制代码

正常情况下不会出错,/opt/riscv 在 install 的时候需要 root 权限

搭建完成就来编译个 hello。先写个 hello.c,用 riscv gcc 编译为 riscv 二进制,然后用 spike 仿真器在 Linux x86 跑 riscv 程序,成功了

#include

int main()

{

fprintf(stderr, "hello\n");

return 0;

}复制代码

$ riscv64-unknown-elf-gcc hello.c -o hello

$ spike /opt/riscv/riscv64-unknown-elf/bin/pk ./hello

bbl loader

hello复制代码

移植 ncnn

第一件事,安排个 riscv64-unknown-elf.toolchain.cmake

https://github.com/Tencent/ncnn/blob/master/toolchains/riscv64-unknown-elf.toolchain.cmake

第二件事,编译起来,已经预料到没有 protobuf opencv,newlib 也没有 openmp,那么禁用掉

$ cmake -DCMAKE_TOOLCHAIN_FILE=../riscv64-unknown-elf.toolchain.cmake -DNCNN_OPENMP=OFF -DNCNN_BUILD_TOOLS=OFF -DNCNN_BUILD_EXAMPLES=OFF ..

$ make -j4复制代码

platform.h 里的 Mutex ConditionVariable Thread 依赖 pthread,newlib 是没有的,新加一个 NCNN_THREADS 开关,彻底屏蔽一切和线程相关的代码

posix_memalign 和 sleep 属于 posix 函数,newlib 也是没有的,新加条件判断 defined(__unix__) || defined(__APPLE__) 绕过就改了这两个地方,似乎并没有什么困难嘛...

$ cmake -DCMAKE_TOOLCHAIN_FILE=../riscv64-unknown-elf.toolchain.cmake -DNCNN_THREADS=OFF -DNCNN_OPENMP=OFF -DNCNN_BUILD_TOOLS=OFF -DNCNN_BUILD_EXAMPLES=OFF ..

$ make -j4复制代码

编译通过了,但是跑 ctest 会因为 test_xxx 无法直接运行全部 Failed。riscv 的测试程序需要像 hello 一样,用 spike 仿真器跑,上网搜索一番找到这个方案,魔改一番,加上 spike 和 pk 参数

https://stackoverflow.com/questions/28812533/how-to-pass-command-line-arguments-in-ctest-at-runtime

$ TESTS_EXECUTABLE_LOADER=spike TESTS_EXECUTABLE_LOADER_ARGUMENTS=/opt/riscv/riscv64-unknown-elf/bin/pk ctest复制代码

单元测试通过了,感觉速度比 qemu 这类的快

开启 RISC-V V 扩展(SIMD)

前面编译的三大件,默认架构 rv64imafdc,也就是 rv64gc,也就是 k210 上面用的架构,是没有 SIMD 指令的。 ncnn 的优化代码中使用大量的 SIMD 指令实现 cpu 加速,打开 riscv SIMD 扩展指令相当必要。

riscv 的 V 扩展就是 riscv 的 SIMD 标准,目前最新版本是 0.9,下一个版本 1.0 很可能就是正式版。1.0 和 0.9 看起来是完全兼容的,没有重大改动,并且 riscv-gnu-toolchain git 只有 rvv-0.9 分支,spike 也声明支持 0.9 版本 V 扩展,那么就用 0.9

$ cd riscv-gnu-toolchain

# rvv-0.9.x = 5842fde8ee5bb3371643b60ed34906eff7a5fa31

$ git checkout 5842fde8ee5bb3371643b60ed34906eff7a5fa31

$ git submodule update --init复制代码

riscv-gnu-toolchain 和 riscv-pk 编译时 ./configure 添加 --with-arch=rv64gcv 参数启用 V 扩展

riscv-isa-sim 编译时 ./configure 添加 --with-isa=rv64gcv 参数设置默认启用 V 扩展编译 ncnn 链接时出错,报错 undefined reference to 'math_oflowf',经过寻找发现,这个math_oflowf 函数实现在 newlib 中,并且被 __OBSOLETE_MATH 条件屏蔽了,代码里用到 exp() 会报这个错。一行 sed 把这个条件删掉,重新编译一遍,通过

# rvv-0.9.x fix undefined reference to '__math_oflowf'

sed -i '/__OBSOLETE_MATH/d' riscv-newlib/newlib/libm/common/math_errf.c复制代码

简单优化一个 riscv op

有了支持 V 扩展的 gcc 和 spike,当然要试试看效果,就简单优化个 riscv clip

SIMD 指令优化有三种方式,intrinsic/inline assembly/assembly,嫌弃 assembly 麻烦,ncnn 一直是用前两种实现方式。正常的话,clip这种形式简单不怎么耗寄存器的 op,适合用 intrinsic,简单方便效果好。可是找了一圈工具链文件夹没找到 intrinsic 头文件,原来 riscv-gnu-toolchain 并没有实现 V 扩展 intrinsic,我看 isrc-cas/rvv-llvm 正在开发相关的 intrinsic,不清楚是怎样的状态,暂时退而求其次 inline assembly 实现一下

https://github.com/isrc-cas/rvv-llvm

asm volatile("vle8.v  v0, (a1)");复制代码

直接这么写一行 riscv v 指令,能通过编译,运行会报错 Illegal Instruction,我以为是工具链或 spike 编译的问题,倒腾了好久,幸亏大佬解答了一番

https://github.com/isrc-cas/plct-spike/issues/3

如果是 x86 sse/avx 或 arm neon 优化,循环通常会写成这个样子,一次取8个数或4个数,最后剩余的用一个 naive 循环处理

int i = 0;

#if __AVX___

for (; i + 7 < N; i += 8)

{

}

#endif // __AVX___

#if __SSE___

for (; i + 3 < N; i += 4)

{

}

#endif // __SSE___

for (; i < N; i++)

{

}复制代码

riscv v 是全新的变长 SIMD 设计,据说是沿袭 arm sve,最大能支持 8192bit。这样的好处就是代码可以只写一个循环,里面到底是展开8个数还是4个数,是自动的!再看看 riscv v 的其他指令,好些运算指令支持 mask 寄存器,这设计也是相当 modern 的,大概是从 avx512 学来的,可以用这个 mask 实现很多原先要多条指令才能实现的骚操作,真的很 flexible

这段代码里的 vsetvli 控制循环步进,t0 就是 cpu 告诉我他想一次性处理 fp32 的个数。remain 是我告诉 cpu 还有多少个数需要处理,你不准搞多了。m8 是我建议 cpu 一次性处理8个数,cpu 可以不听,返回4也是可以的

asm volatile(

"L0:                        \n"

"vsetvli    t0, %1, e32, m8 \n"// t0 = vsetvli(remain, 32bit x 8)

"vle32.v    v0, (%0)        \n"// load ptr to v0

"vfmax.vf   v0, v0, %4      \n"

"vfmin.vf   v0, v0, %5      \n"

"vse32.v    v0, (%0)        \n"// store v0 to ptr

"slli       t1, t0, 2       \n"

"add        %0, %0, t1      \n"// ptr += t0 * sizeof(float)

"sub        %1, %1, t0      \n"// remain -= t0

"bnez       %1, L0          \n"

: "=r"(ptr),   // %0

"=r"(remain) // %1

: "0"(ptr),

"1"(remain),

"f"(min), // %4

"f"(max)  // %5

: "cc", "memory", "t0", "t1"

);复制代码

https://github.com/Tencent/ncnn/blob/master/src/layer/riscv/clip_riscv.cpp

也许 V 扩展太 flexible,标准也没有正式定稿,目前还没有看到完整实现 V 扩展的内核,这些优化代码只能在 spike/qemu 上面运行

期待将来有真实的硬件产品实现,latyas 说 k510 没有 V ... qwq

增加 RISC-V 32位 编译

去年参加 riscv 的开源活动,NXP 送了我一块 vega-lite 开发板,CPU 是 rv32imc,NXP 真是太棒了 QvQ

移植02.jpg (130.01 KB, 下载次数: 0)

2020-9-16 10:14 上传趁热打铁,也编译一套 riscv 32位 ncnn,方法和前面 V 扩展基本一致,区别就是 rv64gcv 换成 rv32imc。rv32imc 缺少 A 扩展,ncnn 代码里用到 __atomic_fetch_add 导致链接报错,添加一份无 atomic 实现就行

最后,整理出 rv64gv rv64gcv rv32imc 三种架构,放到 github action ci,自动编译测试。rv32imc 缺少 F 扩展,没有浮点计算能力,跑起来慢得出乎想象,隔壁 rv64gc 几分钟跑完全部测试,这边 rv32imc 跑一个 test_convolution 就跑了一个多小时,算了,ci 有编译就行了,测试就放弃治疗了

鸿蒙系统移植到 FPGA,我把 ncnn 移植到 RISC-V 啦!相关推荐

  1. 鸿蒙系统可以安装当贝市场吗,华为智慧屏V系列怎么样?怎么安装当贝市场?...

    2021年4月8日晚上8点,华为将举行全屋智能及智慧屏新品发布会.时隔半年,华为的新品智慧屏将与大家见面.据悉此次智慧屏的型号有V85.V75和V65三个版本. "打着电话,边看边聊&quo ...

  2. 第三批升级鸿蒙系统名单时间表,华为可升级鸿蒙系统名单已确认!将分批进行,这些手机将被淘汰...

    原标题:华为可升级鸿蒙系统名单已确认!将分批进行,这些手机将被淘汰 今年对于华为品牌来说,可谓是非常的艰难,在这一年当中美国对华为品牌进行了多次的打压,并且还限制了华为品牌芯片的代工以及外购的措施.这 ...

  3. 如何在鸿蒙系统中移植 Paho-MQTT 实现MQTT协议

    MQTT 是当前最主流的物联网通信协议,需要物联网云平台,例如华为云.阿里云.移动OneNET都支持mqtt.而Hi3861则是一款专为IoT应用场景打造的芯片.本节主要讲如何在鸿蒙系统中通过移植第3 ...

  4. 鸿蒙系统移植imx6dl,韦东山鸿蒙系统移植课程:在IMX6ULL上体验鸿蒙系统

    请先下载以下文件,里面含有烧写软件: 鸿蒙内核Liteos-a的官方代码目前只支持海思的芯片,我作为首批开发者入驻华为一个多月,成功在100ASK_imx6ULL上移植了Liteos-a. 本文先让大 ...

  5. 麒麟810鸿蒙内核移植,麒麟810实体芯片首曝光 鸿蒙系统或8月重磅发布

    原标题:麒麟810实体芯片首曝光 鸿蒙系统或8月重磅发布 昨日(7月8日)荣耀9X在北京提前举办了一场技术沟通会,荣耀产品副总裁熊军民首次向公众展示麒麟810实体芯片,并表示这款获全球AI评分最高的芯 ...

  6. 鸿蒙系统全面解析,诞生背景、技术细节生态圈一文看懂

    编辑:智东西内参 华为6月2日正式发布的鸿蒙系统无疑占据了最近热点话题的C位,虽然不全是赞美的声音,但这种努力打破美国垄断,挑战谷歌.苹果在移动操作系统上垄断地位的尝试必将成为中国科技史上的里程碑事件 ...

  7. 央视谈鸿蒙系统的优点,央视解释为什么华为鸿蒙系统不卡顿,本质上和iOS一样流畅...

    华为鸿蒙系统已经正式发布三天了,昨天还发布了首款鸿蒙设备荣耀智慧屏,但是关于鸿蒙系统的原理及特性官方尚未有比较接地气的解释,说白了不少人都还是不够了解鸿蒙系统,那么它相比安卓和iOS到底有何差异呢? ...

  8. 鸿蒙系统是单任务还是多任务,在鸿蒙系统上使用MQTT编程

    我们使用的是paho mqtt软件包,这里介绍一下怎么使用mqtt协议编程.关于鸿蒙系统的mqtt移植好的软件包,相关github链接如下: https://gitee.com/qidiyun/har ...

  9. 馀承东发布鸿蒙,鸿蒙系统一无是处?鸿蒙有何优势?

    华为方面官宣,将于6月2日晚8点,举行鸿蒙操作系统及华为全场景新品发布会,届时,大家期待已久的鸿蒙操作系统也将正式亮相. 鸿蒙OS有别于传统OS,具有四大技术特性,这也是鸿蒙的四大优越之处. 首先,鸿 ...

最新文章

  1. sonar的次要问题_次要GC,主要GC与完整GC
  2. Java程序员从笨鸟到菜鸟之(一百零六)java操作office和pdf文件(四)页面列表导出cvs,excel、pdf报表.
  3. java form表单传参_表单Form传参数
  4. Java使用独立数据库连接池(DBCP为例)
  5. 心痛!你的快递可能已经被烧毁,13吨快递“无一生还”
  6. 关于jq easyui 刷新tabs的问题
  7. 如何使用Movavi Video Editor Plus在Mac上制作旁白配音视频
  8. 如何在 Mac 上创建自动填充的智能文件夹?
  9. java c 引用类型_C++引用类型详解
  10. u盘装linux fail load,安装ubuntu18.04报:failed to load ldlinux.c32的问题及解决步骤
  11. RedHat红帽RHEL7安装与使用,VMware Workstation16 Pro虚拟机的安装与使用
  12. python UI自动化图片断言
  13. SI 9000 及阻抗匹配学习笔记(二)
  14. 目标检测的图像特征提取之LBP特征
  15. 无缘晶振匹配电容计算方法
  16. Molecular Contrastive Learning of Representations via Graph Neural Networks
  17. matlab求矩阵的非,matlab矩阵非零个数 Matlab如何提取非零元素
  18. 车辆网相关政策和法律法规
  19. 清算(清分)与结算的区别
  20. Unity 脚本中的几种等待方法

热门文章

  1. 大砍广告投放,还威胁要下架Twitter,马斯克怒向苹果开炮:宁可开战也不付30%“过路费”
  2. Https与TCP协议的三次握手、四次挥手
  3. 怎样把界址点文本转为面状地块?
  4. STM32F1与STM32CubeIDE编程实例-热敏传感器驱动
  5. 信号集中监测网站服务器,信号集中监测系统
  6. FPGA基础知识极简教程(7)详解亚稳态与跨时钟域传输
  7. 设置tablayout选中文字颜色和背景图片
  8. 上决╇ф的精确打击问题
  9. 华为鸿蒙系统清单,【AVW分享】华为鸿蒙操作系统2.0版支持的设备清单流出!
  10. 更改安装IDEA文件夹名称,快捷方式图标不显示,双击打不开