打印
[RISC-V MCU 应用开发]

基于 RISC-V 的 SoC 设计及其 RTOS 移植

[复制链接]
3854|21
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
沙发
wangjiahao88|  楼主 | 2021-7-28 09:29 | 只看该作者
主要通过对 RISC-V 官方提供的参考处理器实现项目 Rocket Chip 的
研究,构建了基于 RISC-V 的 SoC,首先对基于 Rocket Chip 的 SoC 的前端设计进
行了研究,基于 0.13μm 工艺,通过逻辑综合和后端物理设计完成了 SoC 的物理实
现,然后由 Rocket Chip 生成的软件模拟器初步对 SoC 的功能进行仿真,基于 Xilinx
ARTY A7 开发板,将构建得到的 SoC 用 FPGA 实现,并对其进行原型验证,最后
在基于 FPGA  的 RISC-V 平台上运行了 FreeRTOS,实现了 RISC-V  SoC 的操作系
统移植。

使用特权

评论回复
板凳
wangjiahao88|  楼主 | 2021-7-28 09:30 | 只看该作者

使用特权

评论回复
地板
wangjiahao88|  楼主 | 2021-7-28 09:31 | 只看该作者

使用特权

评论回复
5
wangjiahao88|  楼主 | 2021-7-28 09:32 | 只看该作者
RISC-V 为软件开发者提供了免费的指令集规范,硬件设计者根据规范去实现
满足所需的处理器,这种通过开放标准和开放源代码来让广大设计者参与处理器
创新的方式极大地降低了处理器设计的门槛,有望在新兴的 AI 与 IoT 领域中对
ARM 的统治地位形成挑战,也为中国在芯片设计领域打破国外技术垄断提供了很
好的机会。

使用特权

评论回复
6
wangjiahao88|  楼主 | 2021-7-28 09:35 | 只看该作者

使用特权

评论回复
7
wangjiahao88|  楼主 | 2021-7-28 09:36 | 只看该作者

使用特权

评论回复
8
wangjiahao88|  楼主 | 2021-7-28 09:37 | 只看该作者

使用特权

评论回复
9
wangjiahao88|  楼主 | 2021-7-28 09:38 | 只看该作者

使用特权

评论回复
10
wangjiahao88|  楼主 | 2021-7-28 09:44 | 只看该作者

使用特权

评论回复
11
wangjiahao88|  楼主 | 2021-7-28 09:44 | 只看该作者
RISC-V32I 整数指令子集的指令主要可分为以下几类:
1)  立即数赋值指令:它包括两条指令,分别是 LUI 和 AUIPC,两者的指令编
码格式都是 U 类,立即数可直接作为指令的操作数输入。LUI 用于构建 32 位常数,
将立即数放到目的寄存器 rd 的高 20 位,将 rd 的低 12 位填 0。AUIPC 用于构建 32
位偏移量,将 20 位立即数与 12 位的 0 组合起来,再将其加到 pc 上,得到的地址
放入 rd 中。
2)  控制转移指令:可分为两种类型,无条件跳转和条件跳转,两者都可以被
用于控制程序中的跳转,分支延迟槽(Branch Delay Slot)在体系结构中不可见。
无条件跳转指令的寻址方式全部都是采用 pc 相对寻址,这有助于执行与位置无关
的指令。所有条件跳转指令使用 SB 类指令格式,12 位二进制立即数对 2 字节倍
数的带符号偏移量进行了编码,并且被加到当前 pc 上以产生目标地址。
3)  访存指令:它包含三种比特宽度的加载(Load)和存储(Store)指令,分
别是:机器字(w)、半字(H)和字节(B),只有 Load 和 Store 指令能够对存储器进行
访问。Load 和 Store 的指令编码格式分别为 I 类和 S 类。Load 指令对存储器进行
访问,把存储器中的数据传输到寄存器 rd 中。Store 指令对存储器进行写入操作,
把寄存器 rs 中的值传输到存储器中。
4)  移位操作指令:移位操作包括算术右移(SRA)、逻辑右移(SRL)和逻辑
左移(SLL),被移位的操作数存储在寄存器 rs1 中,移位次数存放在寄存器 rs2 的
低 5 位中。
5)  逻辑操作指令:包含 AND、OR 和 XOR 指令,将两操作数按位进行 AND、
OR 和 XOR 操作,并且把结果写入至目的寄存器 rd 中。
6)  运算指令:ADD 和 SUB 分别执行加法和减法,SLT 执行有符号数比较,
SLTU 执行无符号数的比较。
7)  系统调用指令:系统指令用于访问那些可能需要特权访问的系统功能,以
I 类指令格式编码。系统指令可以分为两类:一类是原子性读-修改-写控制和状态
寄存器(CSR)的指令,另一类是其他特权指令。

使用特权

评论回复
12
wangjiahao88|  楼主 | 2021-7-28 09:47 | 只看该作者
RISC-V32M 乘除法指令子集主要包括乘法、除法和取余指令[10,33]:
1)  乘法指令:MUL 指令执行一个 XLEN 位数乘 XLEN 位数的乘法,并将结
果的低 XLEN 位写入 rd 中。MULH 执行有符号数乘有符号数的乘法,MULHU 执
行无符号数乘无符号数的乘法,MULHSU 执行有符号数乘无符号数的乘法,都是
将运算结果的高 XLEN 位返回。
2)  除法指令:DIV 执行有符号的 XLEN 位整数除以 XLEN 位整数的除法运算
操作,DIVU 执行无符号的 XLEN 位整数除以 XLEN 位整数的除法运算操作。

使用特权

评论回复
13
wangjiahao88|  楼主 | 2021-7-28 09:48 | 只看该作者
3)  取余指令:REM 执行有符号的 XLEN 位整数除以 XLEN 位整数的取余操
作,REMU 指令执行无符号的 XLEN 位整数除以 XLEN 位整数的取余操作。
Rocket 标量内核还支持一些可选的 A、F、B 指令集扩展。
指令流水线由所有细化的操作阶段串联而成,通常将流水线中细化的操作阶
段称为段[34]。Rocket 是一个拥有 5 级流水线的标量单发射顺序处理器内核,指令
执行过程可划分为指令读取、指令解码、执行、访问内存和写回等不同阶段[33]:
1)  指令读取(Instruction Fetch):从存储器中读取指令的这一过程叫做指令读
取。Rocket 处理器内核的指令读取阶段主要由 ibuf 部件来实现,Scala 源码具体的
实现在 ibuf.scala 中。
2)  指令解码(Instruction Decode):翻译从存储器中取出的指令的这一过程称
为指令解码。经指令解码阶段后可得到指令所需要的寄存器索引以及操作数,能
够使用寄存器索引从通用寄存器堆(Register File,Regfile)中将所需操作数读出。
指令解码阶段主要对文件 ibuf.scala 中提供的指令进行解码,即可解析出控制线的
信息和一些其他的信息,存放到 id_ctrl(控制寄存器)中。Decode 的解码逻辑在
decode.scala 中,映射关系在 idecode.scala 中。解码阶段还能够读取寄存器中的值,
供执行阶段使用,但这个值并不一定正确,需要经过旁路等逻辑才是正确的值。
3)  指令执行(Instruction Execute):指令经解码阶段之后,已得知所需要进行
的计算类型,而且也已经从通用寄存器堆中读取出了要完成指令所需的操作数,
随后便开始进入指令执行阶段。指令的执行阶段是真正对指令进行运算操作的过
程,不同的指令会有不同的需求,最终决定需要使用的部件类型。在执行阶段中,
最常见的是作为实施具体运算操作的硬件功能单元——算术逻辑运算部件
(Arithmetic Logical Unit,ALU),该部件的源码在 alu.scala 中。访存指令会在执
行阶段准备好 Cache 的 request 值。
4)  访问内存(MEM):访存阶段是指对存储器进行访问从而将数据读出,或
者写回的过程。访存部件是 dmem(连接一级数据缓存),Scala 源码包含在
DCache.scala 文件中。访存阶段还会计算分支指令和跳转指令的目的地址。
5)  写回(Write-Back):把指令执行完的运算结果写入寄存器堆的这一过程称
为写回阶段。若指令为普通的运算指令,那么计算结果的值源于执行阶段的计算
结果;若指令为存储器读指令,那么计算结果源于访存阶段对存储器进行访问从
而读出的数据。在 Rocket 处理器内核中,写回阶段执行包含加法器、乘法器、访
存和 ROCC 等需要写回的操作,每个周期只能写回一个寄存器,存在优先级问题。
ROCC 的指令发送阶段也在写回阶段,因为写回阶段才能确定好发送给 ROCC 的
寄存器值。

使用特权

评论回复
14
wangjiahao88|  楼主 | 2021-7-28 09:50 | 只看该作者
我们一般使用高级语言,如 C 语言,在计算机上编写代码,要使我们编写的
代码能被计算机所识别,一般需要经历四个环节:预处理、编译、汇编和链接。
我们编写的 C 程序经过预处理过程,头文件中的内容会被添加到预处理后的文件
中,宏定义会替换掉程序中的相应内容,根据标识符,条件编译中不必要的指令
会被删去,程序中的注释的内容也会被删去。编译过程则是对预处理后的文件做
语法的检查和分析,再将其转换成汇编代码。相对于高级语言,汇编语言是更底
层的面向硬件的语言,利用助记符对硬件进行操作,但对计算机来说,它其实只
能识别和执行机器指令,也就是数字“1”和“0”组成的二进制代码,所以我们
还需要通过汇编过程将汇编代码转换成机器码。链接过程将程序中调用的各个函
数和汇编后的文件链接到一起,生成一个可执行文件,去在计算机上执行。这个
过程中的每个环节都有对应的工具软件,也就是所谓的工具链。将 C 程序转换为
可执行文件的这个过程,称为本地编译。

使用特权

评论回复
15
wangjiahao88|  楼主 | 2021-7-28 09:51 | 只看该作者
Rocket  Chip 项目就可以借由参数的传递去自定义我们想要的处理器配置并生
成相应的 RTL。比如,在 rocket-chip/src/main/scala/system/Configs.scala 文件中,定
义了多组配置,基于 Configs.scala 中的配置,来生成 ExampleRocketSystem.scala
中所定义的 SoC。由于 Rocket Chip 将处理器的每一种功能都进行了参数化,我们
可以在 Configs.scala 文件中定义新的 config 类,参考已有的 config 类,修改其中
的参数,构成我们需要的功能,再将我们需要的功能组合起来,形成我们想要的
配置,比如,Configs.scala 文件中提供的基本配置 BaseConfig 中包含一个 16KB 的
2 路组相连 L1 指令缓存,而我们想要得到一个 32KB 的 4 路组相连 L1 指令缓存,
我们就需要将 L1ICacheWays 中的 nWays 参数改为 4。我们也可以直接就已有的配
置 更 改 其 功 能 的 组 合 , 比 如 , Configs.scala 文 件 中 提 供 的 可 选 配 置
DefaultSmallConfig 通过 extends 关键字继承了基本配置 BaseConfig 的所有参数,
只是增加了一个 WithNSmallCores 的调用。

使用特权

评论回复
16
wangjiahao88|  楼主 | 2021-7-28 09:51 | 只看该作者

使用特权

评论回复
17
wangjiahao88|  楼主 | 2021-7-28 09:52 | 只看该作者

使用特权

评论回复
18
wangjiahao88|  楼主 | 2021-7-28 09:52 | 只看该作者

使用特权

评论回复
19
wangjiahao88|  楼主 | 2021-7-28 09:53 | 只看该作者

使用特权

评论回复
20
wangjiahao88|  楼主 | 2021-7-28 09:54 | 只看该作者

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

474

主题

7520

帖子

30

粉丝