Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
Kernel
在picorv32上面对 rt-thread nano的移植
发布于 2020-07-01 20:08:35 浏览:2480
订阅该版
[tocm] * 本帖最后由 Stupid_bird 于 2020-7-1 20:20 编辑 * PicoRV32 是使用verilog实现一个简单的RISC-V CPU 只需要很少的资源消耗便可以移植到FPGA中运行起来。 几个月之前忽然想尝试将RT-Thread 内核移植到 PicoRV32 CPU上运行起来的想法,于是有了目前这个帖子。 第一次写帖子如有问题望大家见谅 ,记录一下移植的方法 欢迎大家交流。 PicoRV32 内核的github地址 : [https://github.com/cliffordwolf/picorv32](https://github.com/cliffordwolf/picorv32) 目前情况 已经基本完成RT-Thread的移植工作。工程连接:[https://github.com/flyfishR/rtthread-nano](https://github.com/flyfishR/rtthread-nano)FPGA工程 :https://gitee.com/Stupid_bird/picorv32_EG4S20.git 移植方法 1、使用的工具链是 gcc 在picorv32 GitHub上有安装方法 2、调试的时候使用的是modelsim (:L 好麻烦。。。。)移植主要需要实现下面几个函数 1、启动代码 start.s 2、上下文切换函数 rt_hw_context_switch_to rt_hw_context_switch rt_hw_context_switch_interrupt 3、全局中断开关 rt_hw_interrupt_disable rt_hw_interrupt_enable 4、中断管理函数 rt_hw_interrupt_init rt_hw_interrupt_mask rt_hw_interrupt_umask rt_hw_interrupt_install 启动代码1、主要完成了CPU寄存器、数据段和BSS段的初始化工作 提供好C语言的运行环境 ```_pvstart: /* zero-initialize all registers */ addi x1, zero, 0 addi x2, zero, 0 addi x3, zero, 0 addi x4, zero, 0 addi x5, zero, 0 addi x6, zero, 0 addi x7, zero, 0 addi x8, zero, 0 addi x9, zero, 0 addi x10, zero, 0 addi x11, zero, 0 addi x12, zero, 0 addi x13, zero, 0 addi x14, zero, 0 addi x15, zero, 0 addi x16, zero, 0 addi x17, zero, 0 addi x18, zero, 0 addi x19, zero, 0 addi x20, zero, 0 addi x21, zero, 0 addi x22, zero, 0 addi x23, zero, 0 addi x24, zero, 0 addi x25, zero, 0 addi x26, zero, 0 addi x27, zero, 0 addi x28, zero, 0 addi x29, zero, 0 addi x30, zero, 0 addi x31, zero, 0 /* set stack pointer */ lui sp, %hi(_riscv_sp) addi sp, sp, %lo(_riscv_sp) addi sp,sp,-16 sw zero,0(sp) sw zero,4(sp) sw zero,8(sp) sw zero,12(sp) // picorv32_waitirq_insn(zero) picorv32_maskirq_insn(zero, zero) j _start ebreak _start: # Initialize global pointer 1: auipc gp, %pcrel_hi(__global_pointer$) addi gp, gp, %pcrel_lo(1b) # Clear the bss segment la a0, _edata la a1, _end _bss_init: addi a0,a0,4 sw zero,-4(a0) bgeu a1,a0,_bss_init # Init the data segment la a0, _data la a1, _edata la a2, _data_lma _data_init: addi a2,a2,4 lw a5,-4(a2) addi a0,a0,4 sw a5,-4(a0) bgeu a1,a0,_data_init # call entry li a0, 0 call entry ebreak riscv_maskirq: picorv32_maskirq_insn(a0, a0) ret riscv_timer: picorv32_timer_insn(a0, a0) ret riscv_getirq: picorv32_getq_insn(a0, q1) ret ``` 2、进程切换 rt_hw_context_switch_interrupt ```void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to) { if (rt_thread_switch_interrupt_flag == 0) rt_interrupt_from_thread = from; rt_interrupt_to_thread = to; rt_thread_switch_interrupt_flag = 1; return ; }``` rt_hw_context_switch 这个函数要说明一下 我这边使用的触发中断的方式来实现进程切换的 使用的rt_thread_switch_interrupt_flag 这个变量来标记 是否要进入中断状态 ,实际进入中断是在 rt_hw_interrupt_enable函数中后面会看到实现方法。 ```void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to) { if (rt_thread_switch_interrupt_flag == 0) rt_interrupt_from_thread = from; rt_interrupt_to_thread = to; rt_thread_switch_interrupt_flag = 1; rt_hw_context_switch_flag=1 ; return ; }```rt_hw_context_switch_to加载第一个线程的时候使用。 ```/* * void rt_hw_context_switch_to(rt_ubase_t to); * a0 --> to */ .globl rt_hw_context_switch_to rt_hw_context_switch_to: LOAD sp, (a0) /* resw ra to mepc */ LOAD tp, 0 * 4(sp) // 加载PC指针 到线程指针中 待用 LOAD x1, 1 * REGBYTES(sp) /* x1 - ra - return address for jumps */ LOAD x5, 5 * REGBYTES(sp) LOAD x6, 6 * REGBYTES(sp) LOAD x7, 7 * REGBYTES(sp) LOAD x8, 8 * REGBYTES(sp) LOAD x9, 9 * REGBYTES(sp) LOAD x10, 10 * REGBYTES(sp) LOAD x11, 11 * REGBYTES(sp) LOAD x12, 12 * REGBYTES(sp) LOAD x13, 13 * REGBYTES(sp) LOAD x14, 14 * REGBYTES(sp) LOAD x15, 15 * REGBYTES(sp) LOAD x16, 16 * REGBYTES(sp) LOAD x17, 17 * REGBYTES(sp) LOAD x18, 18 * REGBYTES(sp) LOAD x19, 19 * REGBYTES(sp) LOAD x20, 20 * REGBYTES(sp) LOAD x21, 21 * REGBYTES(sp) LOAD x22, 22 * REGBYTES(sp) LOAD x23, 23 * REGBYTES(sp) LOAD x24, 24 * REGBYTES(sp) LOAD x25, 25 * REGBYTES(sp) LOAD x26, 26 * REGBYTES(sp) LOAD x27, 27 * REGBYTES(sp) LOAD x28, 28 * REGBYTES(sp) LOAD x29, 29 * REGBYTES(sp) LOAD x30, 30 * REGBYTES(sp) LOAD x31, 31 * REGBYTES(sp) addi sp, sp, 32 * REGBYTES jr tp // 跳转至线程指针```3、中断开关 ```rt_base_t rt_hw_interrupt_disable(void) { return riscv_maskirq(0xffffffff); } void rt_hw_interrupt_enable(rt_base_t level) { riscv_maskirq(level); if(rt_hw_context_switch_flag) { rt_hw_context_switch_flag =0; if((level & 0x0002)==0) { /* 判断是否要触发系统中断*/ if(rt_thread_switch_interrupt_flag) { __asm("ecall"); } } } return; } ``` 中断入口 实际进行线程切换的地方 ```irq_entry: /* save registers */ addi sp, sp, -32 * REGBYTES picorv32_setq_insn(q2, x1) picorv32_getq_insn(x1, q0) sw x1, 0*REGBYTES(sp) // 保存 epc 指针 picorv32_getq_insn(x1, q2) // 保存 return address sw x1, 1 * REGBYTES(sp) sw x5, 5 * REGBYTES(sp) sw x6, 6 * REGBYTES(sp) sw x7, 7 * REGBYTES(sp) sw x8, 8 * REGBYTES(sp) sw x9, 9 * REGBYTES(sp) sw x10, 10 * REGBYTES(sp) sw x11, 11 * REGBYTES(sp) sw x12, 12 * REGBYTES(sp) sw x13, 13 * REGBYTES(sp) sw x14, 14 * REGBYTES(sp) sw x15, 15 * REGBYTES(sp) sw x16, 16 * REGBYTES(sp) sw x17, 17 * REGBYTES(sp) sw x18, 18 * REGBYTES(sp) sw x19, 19 * REGBYTES(sp) sw x20, 20 * REGBYTES(sp) sw x21, 21 * REGBYTES(sp) sw x22, 22 * REGBYTES(sp) sw x23, 23 * REGBYTES(sp) sw x24, 24 * REGBYTES(sp) sw x25, 25 * REGBYTES(sp) sw x26, 26 * REGBYTES(sp) sw x27, 27 * REGBYTES(sp) sw x28, 28 * REGBYTES(sp) sw x29, 29 * REGBYTES(sp) sw x30, 30 * REGBYTES(sp) sw x31, 31 * REGBYTES(sp) picorv32_setq_insn(q3, x2) // 保存sp 至q3 寄存器 /* switch to interrupt stack */ la sp , irq_stack // 加载 irq 堆栈 /* interrupt handle */ call rt_interrupt_enter /* call interrupt handler C function */ picorv32_getq_insn(a1, q1) // call to C function jal ra, irq call rt_interrupt_leave /* switch to from thread stack */ picorv32_getq_insn(sp, q3) /* need to switch new thread */ la s0, rt_thread_switch_interrupt_flag lw s2, 0(s0) beqz s2, rt_hw_context_switch_interrupt_exit /* clear switch interrupt flag */ sw zero, 0(s0) la s0, rt_interrupt_from_thread lw s1, 0(s0) sw sp, 0(s1) la s0, rt_interrupt_to_thread lw s1, 0(s0) lw sp, 0(s1) lw a0, 0 * REGBYTES(sp) picorv32_setq_insn(q0, a0) /* restore registers */ rt_hw_context_switch_interrupt_exit: lw x1, 0 * REGBYTES(sp) picorv32_setq_insn(q0, x1) lw x1, 1 * REGBYTES(sp) picorv32_setq_insn(q2, x1) lw x5, 5 * REGBYTES(sp) lw x6, 6 * REGBYTES(sp) lw x7, 7 * REGBYTES(sp) lw x8, 8 * REGBYTES(sp) lw x9, 9 * REGBYTES(sp) lw x10, 10 * REGBYTES(sp) lw x11, 11 * REGBYTES(sp) lw x12, 12 * REGBYTES(sp) lw x13, 13 * REGBYTES(sp) lw x14, 14 * REGBYTES(sp) lw x15, 15 * REGBYTES(sp) lw x16, 16 * REGBYTES(sp) lw x17, 17 * REGBYTES(sp) lw x18, 18 * REGBYTES(sp) lw x19, 19 * REGBYTES(sp) lw x20, 20 * REGBYTES(sp) lw x21, 21 * REGBYTES(sp) lw x22, 22 * REGBYTES(sp) lw x23, 23 * REGBYTES(sp) lw x24, 24 * REGBYTES(sp) lw x25, 25 * REGBYTES(sp) lw x26, 26 * REGBYTES(sp) lw x27, 27 * REGBYTES(sp) lw x28, 28 * REGBYTES(sp) lw x29, 29 * REGBYTES(sp) lw x30, 30 * REGBYTES(sp) lw x31, 31 * REGBYTES(sp) picorv32_getq_insn(x1, q2) addi sp, sp, 32 * REGBYTES picorv32_retirq_insn() ```运行效果 安路FPGA上运行效果 ![QQ截图20200701200411.png](https://oss-club.rt-thread.org/uploads/202007/01/200525eegk18boe87i1zbr.png)
查看更多
5
个回答
默认排序
按发布时间排序
bernard
2020-07-01
这家伙很懒,什么也没写!
挺赞的,可以把msh也跑起来,有msh更有手感些 :D
jerry2cool
2020-07-01
这家伙很懒,什么也没写!
高手。。。。佩服
whj467467222
认证专家
2020-07-02
开源,分享,交流,共同进步
给大佬点赞!!! PR! PR!! PR!!!
lsx
2021-05-13
这家伙很懒,什么也没写!
你好,我现在想要参考这个例子把RT-Thread Nano移植到一个类似risc v的架构上,有个问题想请教下题主。 在main里分配的task1_stack空间应该是作为中断时保存当前线程寄存器堆的内存地址,在_rt_thread_init中只是将这个栈顶地址给了thread->sp。 而在中断入口的地方,第一步就是用addi将sp向前压栈,但是此时的sp寄存器保存的应该是中断前用户task程序执行时的栈底地址?中断发生的时候,在哪一个步骤有将分配的栈顶地址赋值给sp寄存器的操作?
Stupid_bird
2021-05-18
这家伙很懒,什么也没写!
是的 ,picorv32 是通过私有寄存器保存的sp指针 ( picorv32_setq_insn(q3, x2) // 保存sp 至q3 寄存器),保存现场后 会判断rt_thread_switch_interrupt_flag 标志位来判断是否进行进程切换,当判断需要进行进程切换后 ,会切换线程的 SP 指针 ,来实现线程切换工作
撰写答案
登录
注册新账号
关注者
0
被浏览
2.5k
关于作者
Stupid_bird
这家伙很懒,什么也没写!
提问
1
回答
1
被采纳
0
关注TA
发私信
相关问题
1
请教cpu使用率分析
2
选择FreeRTOS, 还是RT-Thread。
3
thread heap stack overflow ?
4
rtt消息队列delay问题
5
释放被删除线程的内存地方在哪里啊
6
请教:各线程结束后,释放其中的内存的连续性问题
7
STM32F103中断关于信号量、邮箱问题
8
RTT中的线程栈大小如何控制
9
关于线程由执行态变为挂起态的代码实现,,,
10
rt_malloc(rt_size_t size)内存分配函数最小分配尺寸问题
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
a1012112796
13
个答案
1
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
6
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部