359 lines
16 KiB
Markdown
359 lines
16 KiB
Markdown
# Rocket Chip在ZYNQ上的实现
|
||
|
||
该仓库包含在Vivado 2016.2上的各种Zynq FPGA开发板(Zybo,Zedboard,ZC706,PYNQ-z2)上运行RISC-V rocket chip所需的文件。 (注:因为Vivado版本问题,推荐使用Ubuntu16.04操作系统)
|
||
|
||
### 如何使用该README:
|
||
|
||
该README主要包含4部分:
|
||
|
||
[0 - 前言](#foreword):简单介绍该工程的原理。
|
||
|
||
[1 - 快速开始](#quickinst):使用编译好的文件极速上手,无需下载各种工具,在windows操作系统上即可完成。如果您只是想用该系统测试RISC-V程序或者验证该系统的功能,就不必进行以下步骤。如果您需要修改rocket-chip RISC-V核、修改FPGA电路结构或者修改ARM linux内核配置等等,那么以下步骤有助于熟悉一整套工作流程。
|
||
|
||
[2 - RISC-V工具链(riscv-tools)编译](#toolchain):安装RISC-V工具链,用于编译rocket chip生成RISC-V核。
|
||
|
||
[3 - 工程编译的详细步骤](#compile):从头开始一步步编译整个工程。
|
||
|
||
[附录](#appendices):主机和开发板传输文件的方法。
|
||
|
||
注:以下的`$REPO`均代表`fpga-pynq`仓库所在的本地目录,建议执行以下命令将REPO加入环境变量(替换仓库在本地的目录):
|
||
|
||
```
|
||
$ export REPO=仓库在本地的目录
|
||
```
|
||
|
||
## 目录
|
||
|
||
+ [0 - 前言](#foreword)
|
||
+ [1 - 快速开始](#quickinst)
|
||
+ [2 - RISCV工具链(riscv-tools)编译](#toolchain)
|
||
+ [3 - 工程编译的详细步骤](#compile)
|
||
+ [创建工程](#setup)
|
||
+ [生成比特流文件](#bitstream)
|
||
+ [编译FSBL](#fsbl)
|
||
+ [编译u-boot](#u-boot)
|
||
+ [Building u-boot for the Zynq ARM Core](#u-boot)
|
||
+ [创建boot.bin](#boot.bin)
|
||
+ [编译zynq ARM的linux内核](#arm-linux)
|
||
+ [生成设备树文件](#arm-dtb)
|
||
+ [启动](#booting)
|
||
+ [附录](#appendices)
|
||
+ [说明](#note)
|
||
|
||
## 0)<a name="foreword"></a> 前言
|
||
|
||
#### 1)Zynq相关的基础知识:
|
||
|
||
Zynq-7000系列基于赛灵思SoC架构,在一个芯片上集成了双核或单核ARM Cortex A9的处理系统(PS)和赛灵思可编程逻辑(PL)。
|
||
|
||
##### 1.1)Zynq的一般启动流程(此处仅介绍非安全模式、不用JTAG的启动方式):
|
||
|
||
1.1.1)由于刚刚上电,Zynq的PL部分没有被初始化,所以首先要启动PS端的ARM核,执行BootROM代码。ARM核内部的BootROM存储第0阶段启动代码,这段代码的功能是配置一个ARM核并从其中一个启动设备(NAND、NOR、SD flash)中加载FSBL(First Stage Bootloader)到片上内存(OCM:on-chip memory),加载到片上内存的FSBL的大小在192KB以内。
|
||
|
||
1.1.2)然后执行FSBL。FSBL的功能是:对PS的外设初始化;如果提供了PL部分的bitstream,会用它初始化PL部分;加载第二阶段BootLoader或者裸机应用程序到DDR内存中;然后跳转到DDR内存中执行。(在该工程中,FSBL烧写bitstream、加载u-boot、跳转到u-boot执行)
|
||
|
||
1.1.3)然后执行u-boot代码,将linux内核、文件系统、设备树加载到内存中,启动linux操作系统。
|
||
|
||
##### 1.2)Zynq bitstream的本地烧写方法:
|
||
|
||
1.2.1)通过FSBL烧写bitstream,前面已经介绍。(该工程采用此种方式)
|
||
|
||
1.2.2)通过u-boot烧写bitstream,将bitstream加载到内存中,然后使用fpga loadb对PL进行编程,例如:
|
||
|
||
```
|
||
U-Boot> fatload mmc 0 0x4000000 bitstream.bit
|
||
U-Boot> fpga loadb 0 0x4000000 <bitstream file size>
|
||
```
|
||
|
||
1.2.3)通过linux烧写bitstream,启动Linux后,将bitstream文件写入devcfg设备即可对PL进行编程,例如:
|
||
|
||
```
|
||
$cat bitstream.bit > /dev/xdevcfg
|
||
```
|
||
|
||
#### 2)Rocket chip
|
||
|
||
Rocket Chip是基于Chisel开发的一款开源SoC生成器,它包含了由RISC-V core,cache以及互连(interconnect)等构成的模块库,以此为基础构成一个完整的SoC,并可以生成可综合的RTL代码。
|
||
|
||
#### 3)前端服务器(FESVR : Front-End Server):
|
||
|
||
FESVR是一个C ++库,用于管理主机和rocket chip之间的通信。为了调试,它提供了一个简单的API来复位,发送数据以及在rocket chip上加载、运行程序。 具体来说,FESVR使用主机目标接口(HTIF)(一种通信协议)与rocket chip通信。HTIF是一种非标准的伯克利协议,它使用FIFO非阻塞接口进行通信。可以使用HTIF协议读、写rocket chip的内存,加载、启动、停止程序等等。
|
||
|
||
#### 4)RISCV代理内核(RISCV-PK):
|
||
|
||
RISC-V代理内核是一个运行在RISC-V端的轻量级应用程序执行环境,可以运行静态链接的RISC-V ELF二进制文件。它将与IO相关的系统调用代理到主机(在本工程中指的是ARM端的linux系统)来处理。
|
||
|
||
#### 5)该工程执行RISC-V程序的原理:
|
||
|
||
内存分配:pynq-z2开发板有512MB DDR3内存,其中一半(256MB)分配给ARM的linux使用,一半分配给rocket chip使用。
|
||
|
||
启动ARM linux之后,通过运行在linux上的前端服务器加载代理内核(pk)和可执行程序(hello)到rocket chip的内存中,加载完后前端服务器发送复位信号给rocket chip,启动代理内核,然后代理内核执行hello程序,将hello程序与IO相关的系统调用(主要是终端打印)代理到主机处理,hello程序执行完后,代理内核发送信号通知前端服务器结束执行。
|
||
|
||
1)<a name="quickinst"></a> 快速开始
|
||
------------------
|
||
|
||
*用预先编译好的镜像,运行hello world程序在rocket chip上 (注:此环节无需安装任何工具)*
|
||
|
||
1)点击[fpga-pynq](https://gitee.com/huozf123/fpga-pynq)打开该仓库主页,然后依次点击*克隆/下载 -> 下载ZIP*,将该仓库文件(不带子模块)下载到本地,然后解压该文件。
|
||
|
||
2)格式化SD卡,文件系统格式为FAT32,将`$REPO/pynq-z2/fpga-images-pynq`目录下的四个文件拷贝至SD卡。
|
||
3)弹出SD卡,将其插入开发板,将开发板的启动跳线设置为“SD”,然后打开开发板的电源。 使用网线连接电脑和开发板,打开电脑终端用SSH登录ARM端的linux系统(用户名密码均为*root*),并在rocket chip上运行hello程序:
|
||
|
||
$ ssh root@192.168.1.5
|
||
root@zynq:~# ./fesvr-zynq pk hello
|
||
hello!
|
||
|
||
注:这一步需要提前将电脑有线网卡IP地址设置为192.168.1.*(0<\*<256且不为5),即和192.168.1.5同一网段且不为192.168.1.5,子网掩码设置为255.255.255.0。
|
||
|
||
## 2)<a name="toolchain"></a> RISCV工具链(riscv-tools)编译
|
||
|
||
1)克隆整个工程到本地:
|
||
|
||
为了方便大家快速获取源码,已将全部源码(包括子模块)打包上传到百度网盘,可以直接下载。(注:网盘中的工程版本不是最新版本,少量最新的改动可能没有包含进来,可以直接从gitee手动下载zip然后把新文件放进去即可)
|
||
|
||
```
|
||
链接:https://pan.baidu.com/s/1mTCcKG0EiFdxq4C5HTey3w
|
||
提取码:1234
|
||
```
|
||
|
||
```
|
||
$ cat fpga-pynq.0* > fpga-pynq.tar.gz #组装文件
|
||
$ md5sum fpga-pynq.tar.gz > md5 #计算MD5校验码
|
||
$ cmp md5 md5sum #比对校验码,如果此处没有任何输出,则为正确
|
||
$ tar -zxvf fpga-pynq.tar.gz #解压文件
|
||
```
|
||
|
||
或者从github获取源码:
|
||
|
||
```
|
||
$ git clone https://github.com/huozf123/fpga-pynq.git
|
||
$ cd fpga-pynq
|
||
$ git submodule update --init --recursive #快速开始不需要执行该指令,自己编译工程才需要
|
||
```
|
||
|
||
(注:如果机器上已经有编译好的工具链,则只需将其加入环境变量即可,这一步可以跳过)
|
||
|
||
2)安装依赖:
|
||
|
||
```
|
||
$ sudo apt-get install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev libusb-1.0-0-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev device-tree-compiler pkg-config libexpat-dev
|
||
```
|
||
|
||
3)编译工具链,此处需要指定工具链要安装的目标路径(绝对路径):
|
||
|
||
(注:此处需要GCC版本>=4.8,详情请参照[README](https://github.com/riscv/riscv-tools#readme)。)
|
||
|
||
```
|
||
$ export RISCV=工具链要安装的目的路径
|
||
$ export PATH=${RISCV}/bin:$PATH
|
||
$ cd $REPO/rocket-chip/riscv-tools/
|
||
$ ./build.sh
|
||
```
|
||
|
||
3)<a name="compile"></a> 工程编译的详细步骤
|
||
-------------------------
|
||
|
||
*前提:安装好的Vivado 2016.2 ,一个可以运行scala代码的JVM(注:测试使用的java版本为1.8.0_271,如果编译rocket chip过程中遇到java错误,可能是java版本的原因)*
|
||
|
||
首先添加Vivado相关的环境变量,执行(替换掉“你的vivado安装目录”):
|
||
|
||
```
|
||
$ source 你的vivado安装目录/Vivado/2016.2/settings64.sh
|
||
$ source 你的vivado安装目录/SDK/2016.2/settings64.sh
|
||
```
|
||
|
||
因为Vivado、SDK存在bug,所以需要执行以下命令(替换“你的vivado安装目录”):
|
||
|
||
```
|
||
$ sudo apt-get install libgoogle-perftools-dev
|
||
$ export SWT_GTK3=0
|
||
$ sudo sed -i "11,15s/^/#/" 你的vivado安装目录/Vivado/2016.2/.settings64-Vivado.sh #注释该文件第11-15行
|
||
```
|
||
|
||
然后初始化子模块,执行:
|
||
|
||
$ cd $REPO/pynq-z2/
|
||
$ make init-submodules
|
||
|
||
### 3.1) <a name="setup"></a> 创建工程
|
||
|
||
首先,执行如下命令生成工程。 (注:运行期间请保持网络畅通)
|
||
|
||
$ cd $REPO/pynq-z2/
|
||
$ make project
|
||
|
||
### 3.2) <a name="bitstream"></a> 生成比特流文件
|
||
|
||
然后,我们通过如下命令打开vivado:
|
||
|
||
$ make vivado
|
||
|
||
然后点击左下角的*Generate Bitstream*按钮, Vivado将自动生成比特流文件。该文件位置为:
|
||
|
||
`$REPO/pynq-z2/pynq_rocketchip_ZynqFPGAConfig/pynq_rocketchip_ZynqFPGAConfig.runs/impl_1/rocketchip_wrapper.bit`
|
||
|
||
下一步,点击*File -> Export -> Export Hardware*。这将创建以下目录:
|
||
|
||
`$REPO/pynq-z2/pynq_rocketchip_ZynqFPGAConfig/pynq_rocketchip_ZynqFPGAConfig.sdk`
|
||
|
||
该目录包含的各种文件向SDK提供有关硬件的信息。
|
||
|
||
|
||
### 3.3) <a name="fsbl"></a> 编译FSBL
|
||
|
||
在Vivado界面点击*File -> Launch SDK* 打开SDK:
|
||
|
||
1) 点击 *File -> New -> Application Project*
|
||
|
||
2) 在弹出的新窗口中,输入FSBL作为Project name,其他项保持默认:
|
||
|
||
3) 点击*Next*,然后依次点击*Zynq FSBL* 和*Finish*。然后SDK将继续自动编译FSBL。
|
||
|
||
4) 编译完成后,继续下一步。
|
||
|
||
### 3.4) <a name="u-boot"></a> 编译u-boot
|
||
|
||
打开一个新的终端,进入目标开发板的目录,执行如下命令:
|
||
|
||
$ source 你的vivado安装目录/Vivado/2016.2/settings64.sh
|
||
$ source 你的vivado安装目录/SDK/2016.2/settings64.sh
|
||
$ export REPO=repo在本地的目录
|
||
$ cd $REPO/pynq-z2/
|
||
$ make arm-uboot
|
||
|
||
编译好的u-boot所在位置为:`$REPO/pynq-z2/soft_build/u-boot.elf`。
|
||
|
||
### 3.5) <a name="boot.bin"></a> 创建boot.bin
|
||
|
||
回到SDK界面,点击 *Xilinx Tools -> Create Zynq Boot Image*。
|
||
|
||
1) 点击*Output BIF file path*后面的*Browse..*,然后找到并选择`$REPO/pynq-z2/deliver_output`。
|
||
|
||
2) 点击右下角的*Add*,并在弹出的对话框中点击*Browse*,找到如下文件(First Stage BootLoader):
|
||
|
||
`$REPO/pynq-z2/pynq_rocketchip_ZynqFPGAConfig/pynq_rocketchip_ZynqFPGAConfig.sdk/FSBL/Debug/FSBL.elf`
|
||
|
||
*Partition type*选择bootloader,然后点击*OK*。
|
||
|
||
3) 再一次点击 *Add*,并在弹出的对话框中点击*Browse*,找到如下文件(bitstream):
|
||
|
||
`$REPO/pynq-z2/pynq_rocketchip_ZynqFPGAConfig/pynq_rocketchip_ZynqFPGAConfig.runs/impl_1/rocketchip_wrapper.bit`
|
||
|
||
*Partition type* 选择datafile,然后点击*OK*。
|
||
|
||
4) 再一次点击 *Add*,并在弹出的对话框中点击*Browse*,找到如下文件(uboot):
|
||
|
||
`$REPO/pynq-z2/soft_build/u-boot.elf`
|
||
|
||
*Partition type* 选择datafile,然后点击*OK*。
|
||
|
||
5) 点*Create Image*。这将产生 `BOOT.bin` 文件在 `$REPO/pynq-z2/deliver_output` 目录下。
|
||
|
||
进行完以上5个步骤之后,如果再次修改其中的文件,通过如下命令快速生成boot.bin文件(注:最终写入到SD卡中的boot.bin文件名不区分大小写)。
|
||
|
||
$ cd $REPO/pynq-z2/
|
||
$ make deliver_output/boot.bin
|
||
|
||
### 3.6) <a name="arm-linux"></a> 编译zynq ARM的linux内核
|
||
|
||
然后编译linux内核:
|
||
|
||
$ cd $REPO/pynq-z2/
|
||
$ make arm-linux
|
||
|
||
### 3.7) <a name="arm-dtb"></a> 生成设备树文件
|
||
|
||
生成linux的dtb:
|
||
|
||
$ make arm-dtb
|
||
|
||
### 3.8) <a name="booting"></a> 启动
|
||
|
||
此时,`$REPO/pynq-z2/deliver_output` 目录下包含如下文件:
|
||
|
||
* `BOOT.bin` - 包含FSBL、bitstream、u-boot。
|
||
* `uImage` - zynq ARM端的Linux内核。
|
||
* `devicetree.dtb` - Linux需要的设备树文件。
|
||
* `uramdisk.image.gz` - ARM linux的文件系统。
|
||
|
||
最终只需将linux根文件系统复制到该目录下即可完成SD卡内所有文件的准备工作,进入目标开发板的目录,执行:
|
||
|
||
$ cd $REPO/pynq-z2/
|
||
$ cp fpga-images-pynq/uramdisk.image.gz ./deliver_output/
|
||
|
||
现在将`deliver_output/`中的如下四个文件拷贝到SD卡中,然后将SD卡插入到pynq-z2开发板中,将开发板右上角跳线帽调整到SD端(即从SD卡启动)。SD卡内的目录结构如下:
|
||
|
||
SD_ROOT/
|
||
|-> boot.bin
|
||
|-> devicetree.dtb
|
||
|-> uImage
|
||
|-> uramdisk.image.gz
|
||
|
||
此时已经完成了所有工作,打开开发板电源,使用网线(用户名密码均为*root*)连接至开发板并运行hello程序:
|
||
|
||
$ ssh root@192.168.1.5
|
||
root@zynq:~# ./fesvr-zynq pk hello
|
||
hello!
|
||
|
||
<a name="appendices"></a> 附录
|
||
------------
|
||
|
||
|
||
### 主机与开发板传输文件
|
||
|
||
#### 通过以太网传输文件
|
||
最简单的方法,使用scp在线传输文件:
|
||
|
||
$ scp file root@192.168.1.5:~/
|
||
|
||
注意:上电期间对文件系统的修改不会自动写入`uramdisk.image.gz`文件中,如需永久修改文件系统参见如下:
|
||
|
||
#### 修改linux文件系统
|
||
1)首先需要安装uboot tools:
|
||
|
||
```
|
||
sudo apt-get install u-boot-tools -y
|
||
```
|
||
|
||
2)将SD卡通过读卡器插入主机。
|
||
|
||
3)解压文件系统:
|
||
|
||
$ cd $REPO/pynq-z2
|
||
$ make ramdisk-open
|
||
|
||
解压后的文件系统位置为:`$REPO/pynq-z2/ramdisk`,可以在此处修改文件系统中的文件。
|
||
(注:如果执行时出现`make: *** [fpga-images-pynq/boot.bif] Error 128`错误,请执行`cp ../zedboard/fpga-images-zedboard/boot.bif ./fpga-images-pynq/`命令)
|
||
|
||
4)修改完成后压缩文件系统,覆盖旧的文件系统:
|
||
|
||
$ cd $REPO/pynq-z2/
|
||
$ make ramdisk-close
|
||
|
||
(注:文件系统的位置为:`$REPO/pynq-z2/fpga-images-pynq/uramdisk.image.gz`,该文件大小不能超过10MB,否则无法启动!)
|
||
|
||
5)将文件系统`$REPO/pynq-z2/fpga-images-pynq/uramdisk.image.gz`拷贝到SD卡。
|
||
|
||
#### 通过给sd卡分区并自动挂载到arm linux文件系统中实现永久存储(掉电不丢失)
|
||
|
||
如果本地仓库没有$REPO/sd-partition这个目录,则需要进入[这里](https://gitee.com/hustos/fpga-pynq/raw/master/sd-partition/get-files.png),点击“下载zip”
|
||
|
||
![](https://gitee.com/hustos/fpga-pynq/raw/master/sd-partition/get-files.png)
|
||
|
||
下载好后将文件传到ubuntu系统中并解压,并将该目录复制到本地仓库中。
|
||
|
||
1)先给sd卡分区,可以在windows下分成两个区或在ubuntu系统下使用fdisk工具分区,为了方便起见,特地制作了sd卡分区脚本,只需要把sd卡接到ubuntu系统,执行以下命令即可:
|
||
*注意:第二行命令的"/dev/sd?"要改为自己sd卡所在的路径,我的路径为"/dev/sdc",分区后sd卡内容会全部丢失,请提前做好备份,一定要检查无误后再执行!!!*
|
||
|
||
```
|
||
$ cd $REPO/sd-partition
|
||
$ ./make-fs.sh /dev/sd?
|
||
```
|
||
|
||
2)此时sd卡有两个分区,第一个分区不到100M,另一个分区是剩下的空间,第一个分区里面要放置四个文件*boot.bin devicetree.dtb uImage uramdisk.image.gz*,第二个比较大的分区放置自己要挂载到arm linux系统上的文件。
|
||
*说明:arm linux的根文件系统做了少许改动(自动挂载sd第二个分区,添加软连接在`/home/root/sd-card`以快速访问该分区),改动后文件位于[$REPO/sd-partition/uramdisk.image.gz](https://gitee.com/hustos/fpga-pynq/blob/master/sd-partition/uramdisk.image.gz)*
|
||
|
||
## <a name="note"></a> 说明
|
||
|
||
此工程基于[fpga-zynq](https://github.com/ucb-bar/fpga-zynq),如果需要更加深入的了解,请参考[fpga-zynq](https://github.com/ucb-bar/fpga-zynq)。
|