最近在研究riscv的底层,包括riscv的bkpv扩展,riscv工具链,riscv的qemu,看到D1的硬件性能还不错,结合自己的研究方向,在实际的芯片上做实验更加有效果。加上平头哥的C906已经开源了,这确实是一个选择底层研究riscv不错的硬件平台。
之前研究过一段时间的树莓派baremeta,觉得d1-nezha也是完全可以研究baremetal的
https://github.com/bigmagic123/d1-nezha-baremeta
实验基于全志的soc,目前已经实现了clint,plint等中断系统,还有riscv system timer, soft interrupt等实验,拿到MangoPi-MQ后,也进行led的点灯实验。后期也会逐渐完善i2c,spi, sdio 等等,还有精力的话实现更加高级的外设。
1.startup
2.vector_example
3.uart
4.soft_intrrupt
5.timer
6.plint
7.led
8.input
另外,也适配了rt-thread系统,当前rt-thread是系统运行在riscv machine mode下,因为是实验平台,实现最新版本的rt-thread的适配,后期会结合baremetal做更多有趣的应用。
离线
离线
期待补上些针对MQ的实验记录,然后私信我有惊喜。
RTT-smart那边说本月会释放个新版本适配了MQ。
歪朵拉开源硬件: https://widora.cn
淘宝: https://widora.taobao.com/
离线
D1s跑rtt就强大了,64M内存完全够用
离线
离线
芒果派-D1S怎么搭建RTT平台-点灯,大佬出个教程呗
离线
当前d1s的gpio驱动已经对接到rt-thread的驱动框架上了。
现在描述一下在麻雀派上的点灯操作以及原理分析。
LED对应的引脚是PD22
这时对接rt-thread的pin框架,可以按照下面的方式进行
首先需要实现rt-thread pin 框架的ops
static const struct rt_pin_ops ops =
{
d1s_pin_mode,
d1s_pin_write,
d1s_pin_read,
d1s_pin_attach_irq,
d1s_pin_detach_irq,
d1s_pin_irq_enable,
d1s_pin_get,
};
实现上述的几个函数的功能,然后将上述的结构体注册进去
rt_device_pin_register("gpio", &ops, RT_NULL);
当前只实现了读,写操作,关于中断的操作目前还没有实现。
在操作的代码中,可以通过下面的操作进行
int main(void)
{
printf("Hello RISC-V!\n");
int led_pin = rt_pin_get("PD.22");
rt_pin_mode(led_pin, PIN_MODE_OUTPUT);
while(1)
{
rt_pin_write(led_pin, 1);
rt_thread_mdelay(500);
rt_pin_write(led_pin, 0);
rt_thread_mdelay(500);
}
return 0;
}
最后就可以实现点灯操作。
离线
关键点在于设置VS标志位
VS位于MSTATUS寄存器的23到24位。但是需要注意的是,当使用RVV时,需要开启浮点寄存器(FS),不然会报错。
同时在编译选项中添加
-march=rv64gcvxtheadc -mabi=lp64d -mtune=c906
关于测试的例子,可以参考
https://github.com/T-head-Semi/csi-nn2
这是平头哥开源的神经网络库,里面又有一些操作函数,只简单测试一下性能
测试结果可以看出,浮点加法,乘法性能还是可以的,但是memcpy还是newlib中优化的较好。
代码可以参考
https://github.com/bigmagic123/d1-nezha-rtthread/blob/main/bsp/d1-nezha/applications/vector.c
离线
完成了麻雀riscv d1s上的rt-thread 适配lvgl功能
刷新率还算可以,通过demo上测试的平均帧率在38fps,当然这个不是很可信,基本还算流畅吧。应该还有优化空间,现在开源,起到抛砖引玉的作用。
开源代码
https://github.com/bigmagic123/d1-nezha-rtthread
打开env功能
输入
C:\work\work\d1\d1-nezha-rtthread\bsp\d1-nezha
> pkgs --update
==============================> LVGL update done
==============================> lv_music_demo update done
Operation completed successfully.
然后输入scons开始编译
最后通过fex工具下载固件到d1s的板子上就可以看到了。
当前gt911触摸驱动已经ok,还没完全适配到lvgl上
离线
d1s 上的运行rt-thread 上的lvgl 触摸功能也正常了,现在实现的gt911触摸驱动比较粗糙,没有按下移动事件,这里基本对接到lvgl的indev设备,后续有需求再完善功能。
离线
关于平头哥开源的DSP RVV intrinsic
似乎很久没有维护了,其自带的编译器中是,就拿官网上下载的riscv gcc来看
riscv64-elf-mingw\lib\gcc\riscv64-unknown-elf\8.4.0\include
其gcc的版本为8.4.0,平头哥开源出来的gcc版本为10.2.
https://github.com/T-head-Semi/xuantie-gnu-toolchain
其版本号不一样,而且riscv-vector.h和riscv-dsp.h的intrinsic也不一样。这样就有可能平头哥内部维护一个版本的gcc,而开源的又是另外一个版本。
这两个版本的intrinsic应该都不会被gcc上游接纳,所以编译模型也会非常奇怪,感觉这部分不会被启用了。
不过这个也没办法,做芯片相关gcc都会这样搞,就像当年苹果维护gcc一样。后续感觉平头哥对维护自己的开源的xuantie-gnu-toolchain,也会显得有心无力啊。
离线
d1上的向量自动化
由于d1支持rvv扩展,如果写汇编比较麻烦,用intrinsic比较简单,但是问题是也需要查手册,而且平头哥rvv0.71版本并不在上游支持的范围了。
如果直接写c函数,编译器能够自动优化并且自动向量化,这样才是最智能的方式。
首先需要开启rvv的扩展,并且在gcc编译器中使能rvv支持。这部分可以看我移植的rtt的代码实现。
直接看效果。
#include <riscv-vector.h>
vuint8m8_t test_auto_vand(vuint8m8_t a, vuint8m8_t b)
{
return a & b;
}
int main(void)
{
vuint8m8_t aa = {0};
vuint8m8_t bb = {0};
test_auto_vand(aa,bb);
}
通过反汇编可以看到已经自动向量化了
一次性可以将一个数组的变量进行and操作。
这是一个很好的优化特性,如果做代码优化和速度优化,将会很实用。但是需要注意的是,硬件也应该开启rvv支持,否则编译器做了优化,而应该没有开启,会导致系统崩溃。
离线
@bigmagic
大佬能否研究一下f133的mpu,现在我有个问题解决不了,在跑lvgl或者awtk的时候,特别是动画的时候,比如指针旋转,那么指针会无规律的出现毛刺,应该是dcache引起的,我把dcache关闭就正常了,但是帧率惨不忍睹,开了dcache就发现这个毛刺问题,理论上我也没有用到dma,不知道为什么会导致dcache不一致的,能否指点一下该怎么去操作
在线
@smiletiger
如果是cache问题,那么就flush fb那一块的cache,帧率上不去,就用双缓冲buffer。cache一致性问题不一定是使用了dma。经过研究,在c906中,特别开启了O2优化,很多函数写法都会引起编译器自动优化调用thead自定义指令,虽然可以提高系统性能和速度,但是最好还是注意一下cache问题,另外就是内存不经过分配直接使用,可能会多出ebreak的指令操作。O0优化基本没这个问题,但是性能有所下降,你自己做取舍。
最近编辑记录 bigmagic (2022-01-27 10:07:56)
离线
riscv编译器中,不同的选项组合对于系统性能的影响非常严重。我们往往会通过优化来进行code size和性能的提升,这里不仅仅涉及到内存访问速度,更多是底层算数或者逻辑操作的优化,这一点点优化空间对于系统的影响是非常大的。下面列出几个例子。以下测试都是基于开启O2优化后进行的测试。
https://github.com/bigmagic123/d1-nezha-rtthread/blob/main/bsp/d1-nezha/rtconfig.py
DEVICE = ' -march=rv64gcvxtheadc -mabi=lp64d -mtune=c906 -fno-omit-frame-pointer '
CFLAGS = DEVICE + ' -ffreestanding -fno-common -ffunction-sections -fdata-sections -fstrict-volatile-bitfields '
-fno-omit-frame-pointer
开启这个选项,可以增加fp的功能,也就具备栈回溯的功能。
https://pdos.csail.mit.edu/6.828/2019/lec/l-riscv.txt
其栈的分布如下:
Stack
.
.
+-> .
| +-----------------+ |
| | return address | |
| | previous fp ------+
| | saved registers |
| | local variables |
| | ... | <-+
| +-----------------+ |
| | return address | |
+------ previous fp | |
| saved registers | |
| local variables | |
+-> | ... | |
| +-----------------+ |
| | return address | |
| | previous fp ------+
| | saved registers |
| | local variables |
| | ... | <-+
| +-----------------+ |
| | return address | |
+------ previous fp | |
| saved registers | |
| local variables | |
$fp --> | ... | |
+-----------------+ |
| return address | |
| previous fp ------+
| saved registers |
$sp --> | local variables |
+-----------------+
同样写一个函数
unsigned long test_addsl(unsigned long b,unsigned long c)
{
unsigned long a;
a = b + (c << 2);
return a;
}
当带有fno-omit-frame-pointer时,其生成的汇编如下:
00000000400000f0 <test_addsl>:
400000f0: 1141 addi sp,sp,-16
400000f2: e422 sd s0,8(sp)
400000f4: 0800 addi s0,sp,16
400000f6: 6422 ld s0,8(sp)
400000f8: 04b5150b addsl a0,a0,a1,2
400000fc: 0141 addi sp,sp,16
400000fe: 8082 ret
...
如果不需要栈回溯,则不添加该指令
00000000400000d0 <test_addsl>:
400000d0: 04b5150b addsl a0,a0,a1,2
400000d4: 8082 ret
...
可以看到优化很多,条指令,减少了内存读写次数。可见其优化的力度还是很大的。有时候费尽心力的去优化驱动提高性能,而再编译器层面,却一个选项就可以让性能提高非常大。
-ffunction-sections -fdata-sections
减少code size的选项,如果gcc选项中添加这个,将会让代码函数进行调用优化,如果没使用到的函数则不会被链接进去。并且函数的链接形式也会发生一些改变。
也就是说可能通过objdump再也通过函数名字找到某些函数的反汇编代码了。
离线
想要发挥出riscv极致的性能特性,少不了对riscv指令的扩展,这里除了通用的bkpv指令的扩展外,c906也自己定义了自己的指令实现。这部分可以参考《玄铁C906_R1S0用户手册》,但是这部分的优化,要想使用的好,必须对gcc有一定的了解,由于平头哥、全志对这部分的资料如何使用,放出来的并不多,完全没法将其性能发挥到极致。作为gcc的开发者和研究者,对这部分可以做一个简单的说明。
文档说扩展指令必须在mxstatus.theadisaee==1时才能够执行,半精度指令在mstatus.fs!=2'00时才能正常执行,否则会产生非法指令的异常。这是硬件的限制,下面来看一下算数运算指令。
在编译器选项的优化中,需要开启O2优化,此时才能让编译器去优化特定的操作,例如
ADDSL
寄存器位移
rd <- rs1+rs2 << imm2
unsigned long test_addsl(unsigned long b,unsigned long c)
{
unsigned long a;
a = b + (c << 2);
return a;
}
这个是一个很典型的位移后再加的操作。
如果不开启O2优化,采用O0优化,则生成汇编代码如下
000000004000c5a0 <test_addsl>:
4000c5a0: 7179 addi sp,sp,-48
4000c5a2: f422 sd s0,40(sp)
4000c5a4: 1800 addi s0,sp,48
4000c5a6: fca43c23 sd a0,-40(s0)
4000c5aa: fcb43823 sd a1,-48(s0)
4000c5ae: fd043783 ld a5,-48(s0)
4000c5b2: 078a slli a5,a5,0x2
4000c5b4: fd843703 ld a4,-40(s0)
4000c5b8: 97ba add a5,a5,a4
4000c5ba: fef43423 sd a5,-24(s0)
4000c5be: fe843783 ld a5,-24(s0)
4000c5c2: 853e mv a0,a5
4000c5c4: 7422 ld s0,40(sp)
4000c5c6: 6145 addi sp,sp,48
4000c5c8: 8082 ret
开启O2优化后,则gcc会对指令进行优化,采用平头哥自定义指令。
0000000040000500 <test_addsl>:
40000500: 04b5150b addsl a0,a0,a1,2
40000504: 8082 ret
...
肉眼可见其优化力度了,这个目前在标准的riscv指令中就是B扩展,相信随着B扩展的稳定,在性能和code size上一定可以超过arm指令。
类似的还有
MULA
乘法累加
MULS
乘法累减
左移右移操作,FF快速查找等等。
这些并不需要使用者去写汇编指令,只需要开启编译选项,编译器会自动优化,这对于程序的执行效率将会非常大的影响。
需要注意的是,想要使用平头哥自定义的扩展指令,必须开启MXSTATUS的THEADISAEE位。
离线
@bigmagic
f133跑rtt经常会出现这报错
Unhandled Exception 1:Instruction Access Fault
mcause:0x0000000000000001,mtval:0x000000004002fb1c,mepc:0x000000004002fb1c
--------------Dump Registers-----------------
Function Registers:
ra(x1) = 0xb16411401d4de880()
)
gp(x3) = 0x1c0c1d1609056001()
tp(x4) = 0xa0a01b0458959944()
Temporary Registers:
t0(x5) = 0xc99409841cb40d84()
t1(x6) = 0x2811084e1d836415()
t2(x7) = 0x0cc50cc545445525()
t3(x28) = 0x186652b424602c04()
t4(x29) = 0x178059000044cbd5()
t5(x30) = 0xa08009f10d111d83()
t6(x31) = 0x4d0111251891050f()
Saved Registers:
s0/fp(x8) = 0x352819511da41060()
s1(x9) = 0x94141d4501140380()
s2(x18) = 0x14521c57bd3d0b81()
s3(x19) = 0x0581828d1d111d01()
s4(x20) = 0x18b5050121a419b5()
s5(x21) = 0x5c1589ccb0915961()
s6(x22) = 0x0507154311050020()
s7(x23) = 0x9dae00191f100410()
s8(x24) = 0x09959cb008eccd35()
s9(x25) = 0x1c859d2110801085()
s10(x26) = 0x0905d40019538d87()
s11(x27) = 0x511d051890d513e7()
Function Arguments Registers:
a0(x10) = 0x1dc6450144144980()
a
1(x11) = 0x1d91093038315db3()
a2(x12) = 0x90a41e3d808b4c96()
a3(x13) = 0x0d28148c99e02c85()
a4(x14) = 0x0590238b0f1401b9()
a5(x15) = 0x7d091d155b0c4100()
a6(x16) = 0x0c87182739a51a11()
a7(x17) = 0x2d03208419851495()
sstatus = 0x0000000a00b00080
Supervisor Interrupt Disabled
Last Time Supervisor Interrupt Disabled
Last Privilege is User Mode
Not Permit to Access User Page
Not Permit to Read Executable-only Page
satp = 0x0000000000000000
Mode = No Address Translation/Protection Mode
-----------------Dump OK---------------------
可能是哪里有问题哦用的o3优化
在线
@smiletiger
开启优化选项,并且使能了平头哥的扩展指令集或者V扩展指令,就要注意代码的规范了,说不定就优化过度了(插入了一些特殊操作),目前平头哥的riscv gcc目前仍然在编程模型上有着一定的限制,并不会如arm编译器一样稳定,特别是开启优化后,就要十分注意了。可以通过empc地址跟踪一下函数的报错地方,看看反汇编是否正常。
离线
最近研究平头哥开源的gcc编译器,发现其针对MCU系列,也有硬件自动压栈指令
自动生成ipush和ipop的方式也有意思
匹配条件
-march=*xtheade*,开启O2优化
#include <string.h>
#include <stdio.h>
__attribute__((interrupt)) void func(void)
{
}
void main(void)
{
func();
}
然后编译
riscv64-unknown-elf-gcc -march=rv64gcxtheade -mabi=lp64d -ffreestanding -fno-common applications\test\test_thead.c -o aaa
反汇编该文件
000000000001018e <func>:
1018e: 0040000b ipush
10192: 1141 addi sp,sp,-16
10194: e422 sd s0,8(sp)
10196: 1100 addi s0,sp,160
10198: 0001 nop
1019a: 6422 ld s0,8(sp)
1019c: 0141 addi sp,sp,16
1019e: 0050000b ipop
这就意味着,在MCU层面,使用向量中断,不用考虑中断的压栈和出栈问题,大大提高MCU的实时性。该机制非常重要,但是对于D1这种高性能的MPU,并没有这种特性,更多的灵活性在编程者手中。
离线
玄铁C900系列工具链更新了
https://occ.t-head.cn/community/download?id=3996672928124047360
终于更新到10.2版本了
Thread model: single
Supported LTO compression algorithms: zlib zstd
gcc version 10.2.0 (Xuantie-900 elf newlib gcc Toolchain V2.2.4 B-20211227)
很显然,平头哥内部还在积极的向上游的riscv gcc保持统一的,这对riscv发展来说是件好事。通过对其关注,发现平头哥确实在riscv gcc的上游rvv上提供了不少的patch。但是并非开放在xuantie gcc中,社区和内部还是有所保留。
https://github.com/riscv-collab/riscv-gcc/issues/320
There is a guy at rivai.ai who claims to be working on gcc rvv 1.0 support for mainline FSF gcc, so maybe in a few months we will have something usable. Rivai is in Shenzhen.
如果可能,是不是能够在今年见的完整的商业可用的riscv rvv指令支持呢?期待完成向量支持,这样riscv将会在桌面,AI,高性能上大有可为
离线
嗯 我测试mangopi-mq 可以运行成功 但是屏幕没有显示 屏幕是4.3寸 800x480
ps
thread pri status sp stack size max used left tick error
-------------------- --- ------- ---------- ---------- ------ ---------- ---
gt911 25 ready 0x00000830 0x00001000 51% 0x00000005 000
tshell 20 running 0x000002f8 0x00002800 19% 0x00000009 000
LVGL 21 ready 0x000002d8 0x00002000 44% 0x00000006 4294967294
sys_work 23 suspend 0x00000288 0x00001000 15% 0x0000000a 000
mmcsd_detect 22 suspend 0x000002e8 0x00002800 07% 0x00000014 000
tidle0 31 ready 0x00000570 0x00004000 08% 0x0000001a 000
timer 4 suspend 0x00000278 0x00004000 04% 0x00000009 000
main 10 suspend 0x000002f8 0x00004000 10% 0x0000000f 000
msh />
msh />
貌似有点问题,CPU 是F133-A,运行linux 可以亮屏
最近编辑记录 9844201@qq.com (2022-02-06 23:25:39)
离线
@bigmagic
大佬怎么不来更新了,也不去github更新啦 ,想死你了
在线
D1s跑rtt,在配个LVGL应该很溜,正在学习中
离线
scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
scons: building associated VariantDir targets: build
LINK rtthread.elf
riscv64-unknown-elf-objcopy -O binary rtthread.elf rtthread.bin
Error in calling command:riscv64-unknown-elf-objcopy
Exception: Exec format error
scons: *** [rtthread.elf] Error 8
scons: building terminated because of errors.
你好请问这个怎么解决啊
7 | #include <riscv-vector.h>
| ^~~~~~~~~~~~~~~~
compilation terminated.
scons: *** [build\applications\test\auto_rvv.o] Error 1
scons: building terminated because of errors.
离线
@zhong
编译器需要支持V扩展,另外编译器选项-march=rv64gcvxtheadc -mabi=lp64d,其中的v表示告诉编译器开启v扩展指令
离线
你好,博主,请问这个怎么处理啊
ZWH@DESKTOP-AQD2LI1 G:\cenge\D1S_CODE\d1-nezha-rtthread-main\bsp\d1-nezha
> set RTT_EXEC_PATH=G:\cenge\D1S_CODE\gcc\riscv64-elf-mingw-20210618\riscv64-elf-mingw\bin
ZWH@DESKTOP-AQD2LI1 G:\cenge\D1S_CODE\d1-nezha-rtthread-main\bsp\d1-nezha
>
ZWH@DESKTOP-AQD2LI1 G:\cenge\D1S_CODE\d1-nezha-rtthread-main\bsp\d1-nezha
> scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
scons: building associated VariantDir targets: build
CC build\applications\lvgl\lv_demo.o
riscv64-unknown-elf-gcc: error: CreateProcess: No such file or directory
scons: *** [build\applications\lvgl\lv_demo.o] Error 1
scons: building terminated because of errors.
ZWH@DESKTOP-AQD2LI1 G:\cenge\D1S_CODE\d1-nezha-rtthread-main\bsp\d1-nezha
> scons -c
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed cconfig.h
scons: done cleaning targets.
ZWH@DESKTOP-AQD2LI1 G:\cenge\D1S_CODE\d1-nezha-rtthread-main\bsp\d1-nezha
> scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
scons: building associated VariantDir targets: build
CC build\applications\lvgl\lv_demo.o
riscv64-unknown-elf-gcc: error: CreateProcess: No such file or directory
scons: *** [build\applications\lvgl\lv_demo.o] Error 1
scons: building terminated because of errors.
离线
ZWH@DESKTOP-AQD2LI1 G:\cenge\D1S_CODE\d1-nezha-rtthread-main\bsp\d1-nezha
> set RTT_EXEC_PATH=G:\cenge\D1S_CODE\gcc\riscv64-elf-mingw-20210618\riscv64-elf-mingw\bin
ZWH@DESKTOP-AQD2LI1 G:\cenge\D1S_CODE\d1-nezha-rtthread-main\bsp\d1-nezha
> set EXEC_PATH=G:\cenge\D1S_CODE\gcc\riscv64-elf-mingw-20210618\riscv64-elf-mingw\bin
ZWH@DESKTOP-AQD2LI1 G:\cenge\D1S_CODE\d1-nezha-rtthread-main\bsp\d1-nezha
> set PATH=G:\cenge\D1S_CODE\gcc\riscv64-elf-mingw-20210618\riscv64-elf-mingw\bin;%PATH%
你好,是这样吗
离线
@bigmagic
可以研究一下怎么烧入flash开机运行吗,现在这个裸机只能在ddr上面调试
在线
超级爱,正想学习准备用D1S呢,又不想上Linux,启动太慢,
离线
@bigmagic
您好,请问RT中的C906文件夹的内容是哪里来的啊?我在RT官网没找到啊
最近编辑记录 March (2022-03-22 20:24:56)
离线
@bigmagic
您好,请问RT中的C906文件夹的内容是哪里来的啊?我在RT官网没找到啊
大哥你也来了啊,哈哈,freertos 177秒宕机问题找到了吗,我这里测试也是177秒死机....一直在研究
在线
D1S:从机器模式切换到用户模式,怎么执行到mret之后的第一条指令,就报异常1的?mtval,mepc都是mret后的第一条指令地址。是还有哪些寄存器要配置吗?
csrr t1, mstatus
li t0, ~0x00001800
and t1, t1, t0
csrw mstatus, t1
la t0, 1f
csrw mepc, t0
mret
1:
最近编辑记录 dick2945 (2022-06-08 10:26:56)
离线
March 说:@bigmagic
您好,请问RT中的C906文件夹的内容是哪里来的啊?我在RT官网没找到啊大哥你也来了啊,哈哈,freertos 177秒宕机问题找到了吗,我这里测试也是177秒死机....一直在研究
CLINT计时器中断比较值寄存器 只能用32位指针读写,用64位指针写时高32位是写不进去的。32位无符号整数最大值4294967295/晶振频率24000000=178.957秒。所以到了178.956秒的中断后,会一直进入中断直至0x10000000000000000/24000000=8895999天后才正常。
*(uint32_t*)CLINT_MTIMECMPL(0) = tick_l;
*(uint32_t*)CLINT_MTIMECMPH(0) = tick_h;
最近编辑记录 dick2945 (2022-06-14 13:52:52)
离线
兄弟继续啊, 点个屏, 要啥接口的我都可以送你
RGB/LVDS/MIPI
我前阵子想从xboot里面学学, 可是干点别的就放下了
离线
这个板子哪里买的
离线
@dick2945
应该是没有配置PMP物理内存保护,切换到用户模式后没权限访问内存,导致取指令错误
离线