sky 发表于 2020-9-25 00:10:15

RISC-V的“Demo”级项目——Rocket-chip

本帖最后由 sky 于 2020-9-25 00:13 编辑


本专栏早前的两篇文章介绍了Chisel的好处,并展示了使用Chisel快速搭建FFT电路的方法,充分证明了Chisel在敏捷开发方面的优势。 本文将继续延伸Chisel的脉络,为大家进一步介绍一下基于Chisel开发的“Demo”级RISC-V开源项目Rocket-chip,它是由RISC-V架构的创始单位——UC Berkeley开发的。
一,Rocket-chip是一个SoC生成器
在很多场景下我们常用Rocket指代Rocket“处理器”,而实际上Rocket-chip是一个SoC生成器(Generator),它用来根据不同的配置参数产生不同处理器的RTL代码,而后者才是一个真正的“处理器”。 下图为Rocket-chip的一种示例。
一种典型的Rocket-Chip结构
从图中可以看出,Rocket-Chip项目有六个组成部分:

[*]A为Core Generator,用于生成处理器核,支持Rocket-core和BOOM两种


[*]B为Cache,包括L1 Cache和L2 Cache


[*]C为RoCC,即Rocket的用户自定义加速器接口,用户可以使用Chisel自行编写加速器挂载到Rocket-chip中


[*]D为Tile,一个处理器核和一个L1 Cache(包括指令Cache和数据Cache)构成一个Tile,在Rocket-chip中通过复用各种Tile构建一个多核(同构或异构)的体系


[*]E为TileLink,为UC Berkeley自行开发的片上总线,用于连接处理器、缓存和外设


[*]F为Peripheral,包括AMBA兼容总线(AXI,AHB-Lite和APB)的发生器以及各种转换器和控制器。


上图的具体示例包括了两个Tile,这些Tile连接到一个4-bank L2 Cache,该缓存本身通过AXI互连连接到外部I/O和存储系统。 Tile 1内是一个乱序的BOOM内核,它具有FPU,L1指令和数据缓存以及实现RoCC接口的加速器。 Tile 2和Tile 1类似,但是它使用的是顺序执行的Rocket-core内核,并且具有不同的L1数据缓存参数。
二,Rocket-core和BOOM微架构简介通过上一节的介绍你应该已经知道了Rocket-chip和Rocket-core以及BOOM的关系。 本节介绍Rocket-core和BOOM的微架构,了解微架构对于体系结构工程师来说可以学习其设计思想,提升处理器设计的能力; 而对于处理器的用户而言也可以根据自己的需要选择合适的处理器来使用。
1).Rocket的微架构
Rocket-core是一个标准的五级流水处理器(下图1为其流水线示意图),它支持开源RV64GC RISC-V指令集,并使用Chisel硬件构造语言编写。 Rocket-core具有一个MMU,该MMU支持基于页面的虚拟内存,无阻塞数据缓存,同时支持分支预测功能。分支预测是可配置的,并由分支目标缓冲区(BTB),分支历史表(BHT)和返回地址堆栈(RAS)提供。 对于浮点运算,Rocket利用Berkeley的Chisel浮点运算单元实现。 Rocket还支持RISC-V的内核、管理员和用户三种特权等级,可以启动Linux操作系统。
Rocket-Core的流水线
2).BOOM的微架构
BOOM的全称是Berkeley Out-of-Order Machine,顾名思义它是乱序执行的处理器(不过严格来讲,BOOM和上述的Rocket一样,也是一个处理器生成器,它可以根据配置生成一系列不同的BOOM Core)。BOOM的流水线如下图2所示。
BOOM的流水线
从上图中不难看出,BOOM的流水线分为10个阶段,分别是取指(Fetch),译码(Decode),寄存器重命名(Register Rename),派遣(Dispatch),发射(Issue),读寄存器(Register Read),执行(Execute),访存(Memory),写回(Writeback)和提交(Commit)。
但是在实际实现过程中,重命名逻辑被分成两部分,分别与译码和派遣合并在一起;发射和读寄存器两个阶段也被合并在一起;而提交由于是异步行为,不算做在流水线中。因此10个阶段实际上被压缩在图中所示的7级流水线中。
接下来分别介绍一下每个阶段的大致行为,对于乱序处理器不够熟悉的读者看过以后应该也能对一个典型的乱序处理器有一个直观的认识了。
取指(Fetch)
处理器将指令从指令存储器(一般是L1指令缓存)中取出来放到一个叫做Fetch Buffer的队列中,同时进行分支预测,必要时对取来的指令进行重定向。
译码(Decode)
在译码阶段处理器将指令从Fetch Buffer中取出,通过译码逻辑得到适当的微操作(UOP)用于放进流水线中。
寄存器重命名(Register Rename)
将RISC-V ISA规定的逻辑上的寄存器(即x1-x31)重命名为(即映射到)片上的物理寄存器中。
派遣(Dispatch)
将UOP写入到一组发射队列中。
发射(Issue)
处在发射队列中的指令等待其所有依赖的寄存器都可用(即前面的指令已经算出它们的值)之后,就可以进行发射。 从这个阶段起,指令开始乱序执行。
读寄存器(Register Read)
被发射的指令首先从寄存器堆或者从旁路逻辑中读取所需的寄存器。
执行(Execute)
指令的计算在这个阶段完成,访存指令也在这个阶段完成目标地址的计算。
访存(Memory)
加载/存储单元(Load/Store Unit)有三个队列,分别是加载地址队列(LAQ),存储地址队列(SAQ)和存储数据队列(SDQ)。 当地址进入LAQ时加载指令被发送到存储器中;而存储指令则要等到指令提交(Commit)阶段才能被发送到存储器。
写回(Writeback)
ALU操作和加载操作的结果写回到目标寄存器中。
提交(Commit)
重排序缓冲区(ROB)跟踪着流水线中每条指令的状态。当ROB的Header处于空闲状态时,ROB提交指令。 对于存储指令来说,ROB向位于存储队列(SAQ / SDQ)头的存储指令发出信号,它现在可以将其数据写入存储器中。
三、使用Rocket-Chip进行实验

本文接下来为大家演示一下如何使用Rocket-Chip(包括Rocket和BOOM)进行实验。 虽然Rocket-Chip的项目直接可以用来进行EDA仿真、FPGA(官方仅支持使用Firesim在AWS F1云FPGA上运行)和ASIC流程,但笔者还是建议大家使用chipyard项目开展实验。
Chipyard是用于敏捷开发基于Chisel的SoC的开源框架。 它让用户能够利用Chisel HDL,Rocket-Chip SoC生成器和其他Berkeley项目来生产RISC-V SoC,它具有从MMIO映射的外设到定制加速器的所有功能。 Chipyard项目包含处理器内核(Rocket,BOOM,Ariane),加速器(Hwacha),存储器系统以及其他外围设备和工具,以帮助用户快速创建功能齐全的SoC。 Chipyard支持多种敏捷硬件开发流程,包括软件RTL仿真,FPGA加速仿真(FireSim),自动化VLSI流程(Hammer)以及针对裸机和基于Linux的系统的软件开发。
本节接下来为大家演示在Chipyard项目中分别使用Rocket和BOOM运行典型的处理器跑分程序Dhrystone。 (本实验使用的环境为Ubuntu 16.04)

四、部署Chipyard

首先获取Chipyard项目,并进行初始化。
git clone https://github.com/ucb-bar/chipyard.git
cd chipyard
./scripts/init-submodules-no-riscv-tools.sh
上述步骤会clone Chipyard及其子模块,接下来的步骤是安装RISC-V Tools。 有些同学可能以前装过RISC-V tools,但这里最好使用它的脚本重新安装一下,因为版本不匹配后续可能会出现意外问题。 下面这个步骤就是安装RISC-V Tools,这一部分编译需要较长时间,可以开启并行选项export MAKEFLAGS=-j8以加快速度。
./scripts/build-toolchains.sh
上述脚本成功执行后会在当前目录下生成env.sh,以后每次新开启终端需要执行该脚本以设置环境变量:source ./env.sh

五、仿真工具的选择

Chipyard(包括Rocket-Chip)项目支持使用Verilator或Synopsys VCS进行精确到时钟周期的仿真。前者是可免费使用的开源软件,本文接下来介绍一下如何使用开源的Verilator进行仿真。
请读者在进行下面操作之前先按照此文档以源码方式安装verilator(通过apt安装会有问题)。
六、使用Rocket进行Dhrystone测试

使用Verilator仿真,先进入sims/verilator目录
cd sims/verilator
Chipyard的仿真分成两个步骤,第一步是使用Chisel代码生成Verilog代码,然后用Verilator编译生成可执行文件; 第二步是执行可执行文件,这一步处理器就会仿真执行用户指定的软件代码。
# 先选择RocketConfig进行编译
make CONFIG=RocketConfig
# 然后运行dhrystone程序
./simulator-chipyard-RocketConfig $RISCV/riscv64-unknown-elf/share/riscv-tests/benchmarks/dhrystone.riscv
执行结果如下图所示(读者如果自行操作,显示的内容可能与图中不同,这是因为我修改了Dhrystone的代码,让它能显示周期数与CPI):

可以看到Dhrystones per Second为1952(程序中假定频率为60MHz)。
有些同学可能会比较疑惑上面的CONFIG=RocketConfig是什么意思,其实这是Chisel灵活配置的一个体现。 打开文件generators/chipyard/src/main/scala/config/RocketConfig.scala可以发现有一个类名字叫做RocketConfig,如下图。
RocketConig配置
从这段代码中可以看到我们使用的RocketConfig配置了1个大Rocket核,带有L2Cache; 还有许多其他信息,读者可以从名称和注释上理解,这里就不一一解释了。
读者也可以将make CONFIG=RocketConfig后面的内容换掉,换成这个文件里的其它配置,甚至可以自己编写配置,生成自己需要的配置。
六、使用BOOM进行Dhrystone测试

使用BOOM的方式和Rocket几乎一样,还是在sims/verilator目录中,这次我们将Config换一下,换成BOOM的默认配置。
# 选择LargeBoomConfig进行编译
make CONFIG=LargeBoomConfig
# 然后运行dhrystone程序
./simulator-chipyard-LargeBoomConfig $RISCV/riscv64-unknown-elf/share/riscv-tests/benchmarks/dhrystone.riscv
执行结果如下图所示(仿真所需时间可能较长):

可以看到Dhrystones per Second为2735(程序中假定频率为60MHz),和顺序执行的Rocket相比还是有很大进步。
BOOM的配置文件在generators/chipyard/src/main/scala/config/BoomConfig.scala中,读者也可以自行编写Boom的其它配置项。
七、总结

本文介绍了笔者认为RISC-V开源处理器中最有代表性的Rocket和BOOM的微架构, 介绍了Chipyard项目的在EDA仿真流程中的使用方法,有了Chipyard,用户可以方便地使用UC Berkeley的众多项目(除了上述Rocket和BOOM外,还包括Hwacha RoCC、IceNet网络接口等项目),基于自己的需要构建自己的整个SoC平台。 通过这篇文章希望读者能学会快速上手使用Rocket和BOOM处理器,并对其大致情况与性能有了一个直接的认识。如果读者想了解更多有关Chipyard的信息,可查阅Chipyard官方文档。
参考文献- Rocket-chip Technical Report- RISC-BOOM Document

页: [1]
查看完整版本: RISC-V的“Demo”级项目——Rocket-chip