RISC-V 初探

在現在的世界,如果要講到指令集架構(ISA),腦海中第一個想到的不是 x86 就是 ARM 或 者 MIPS,然而如果想要自己製作一個 CPU 來玩,如果不透過現有的指令集的話,要從 CPU 打造到編譯器的撰寫、Linux 的移植又會花費大量的時間,有沒有一個現成且不需要商業授 權的指令集可以直接套用呢?有,那就是 RISC-V

RISC-V (發音為: risk-five) 是由 UC Berkeley 所發展的開源 ISA,具有大約 100 個 指令,並且提供 16、32、64、128 等多種記憶體定址方式,更酷的事情是,RISC-V 已經具 有 Linux、GCC、LLVM、Yocto 等軟體支援,也就是說,任何人都可以基於 RISC-V 製作屬 於自己的 CPU,並且可以快速移植 Linux 上去。

聽起來很棒,那麼效能如何呢? 為了確認 RISC-V 的效能,UC Berkeley 設計出了一顆名為 Rocket 的 CPU,並選用了和 ARM Cortex-A5 相同的製成,由官方 資訊 來看,RISC-V 除 了晶片面積較小以外,運算速度也比較快,更重要的事情是,功耗更低,由此可見 RISC-V 有挑戰行動領域的王者 ARM 的淺力。

下表為 RISC-V 官網上針對 Rocket 與 ARM Cortex-A5 進行的對照表:

ISA Implementation ARM Cortex-A5 RISC-V Rocket R/A
ISA Register Width 32 bits 64 bits 2
Frequency >1 GHz >1 GHz 1
Dhrystone Performance 1.57 DMIPS/MHz 1.72 DMIPS/MHz 1.1
Area excluding caches 0.27 mm² 0.14 mm² 0.5
Area with 16KB caches 0.53 mm² 0.39 mm² 0.7
Area Efficiency 2.96 DMIPS/MHz/mm² 4.41 DMIPS/MHz/mm² 1.5
Dynamic Power <0.08 mW/MHz 0.034 mW/MHz >= 0.4

聽起來很棒對不對,本文將簡單介紹如何初步認識 RISC-V 的軟體與環境。

環境建立與 toolchain 編譯

為了可以執行 RISC-V 環境,我們首先要安裝 riscv-tools 套件,裡面包含了開發用的 toolchain 以及模擬器等 repo,我們可以使用以下命令取得 riscv-tool 並編譯

git clone https://github.com/riscv/riscv-tools.git
cd riscv-tools
git submodule update --init --recursive
export RISCV=/path/to/install/riscv/toolchain
./build.sh

在我的 Gentoo Linux 這個編譯是非常愉快的,如果你編譯失敗的話請參考 riscv-tools 的 README.md 文件。 而在 Mac OSX 下則是有已經預先編譯好的套件可以安裝,我們可以使用 homebrew 來安裝 riscv-tools

coldnew@osx ~ $ brew tap ucb-bar/riscv && brew install riscv-tools

安裝完成後,我們系統會大致上增加以下這些命令

coldnew@osx ~ $ ls ${RISCV}/bin
elf2hex                            riscv64-unknown-elf-gconv
fesvr-eth                          riscv64-unknown-elf-gprof
fesvr-rs232                        riscv64-unknown-elf-ld
fesvr-zenboard                     riscv64-unknown-elf-ld.bfd
riscv64-unknown-elf-addr2line      riscv64-unknown-elf-nm
riscv64-unknown-elf-ar             riscv64-unknown-elf-nm
riscv64-unknown-elf-as             riscv64-unknown-elf-objcopy
riscv64-unknown-elf-c++            riscv64-unknown-elf-objdump
riscv64-unknown-elf-c++filt        riscv64-unknown-elf-ranlib
riscv64-unknown-elf-cpp            riscv64-unknown-elf-readelf
riscv64-unknown-elf-elfedit        riscv64-unknown-elf-size
riscv64-unknown-elf-g++            riscv64-unknown-elf-strings
riscv64-unknown-elf-gcc            riscv64-unknown-elf-strip
riscv64-unknown-elf-gcc-4.9.2      spike
riscv64-unknown-elf-gcc-ar         spike-dasm
riscv64-unknown-elf-gcc-nm         termios-xspike
riscv64-unknown-elf-gcc-ranlib     xspike

使用 Spike 來模擬編譯出來的程式

當你的 toolchain 編譯/安裝完成後,就讓我們先從 Hello World 來開始玩吧,首先建立 名為 hello.c 的檔案

#include <stdio.h>

int main(int argc, char *argv[])
{
        printf("Hello RISC-V\n");
        return 0;
}

接著使用 riscv64-unknown-elf-gcc 對其進行編譯成 hello 這個執行檔

coldnew@osx ~ $ riscv64-unknown-elf-gcc -O2 -o hello hello.c

如果你想更深入的理解編譯出來的 hello 這個靜態編譯 (static-linked) 的執行檔內容是 什麼,你可以透過 readelf 或是 objdump 來觀察他:

coldnew@osx ~ $ riscv64-unknown-elf-readelf -a hello | less
coldnew@osx ~ $ riscv64-unknown-elf-objdump -d hello | less

在目前的版本中,RISC-V 尚未支援 qemu-user 的功能,那我們要怎樣執行剛剛編譯出來的 hello 執行檔呢? 我們可以使用 Spkie - ISA Simulator 搭配 riscv-pk 來作為 qemu-user 的替代,執行方式如下

coldnew@osx ~ $ spike pk hello
Hello RISC-V

使用 ANGEL 來測試 RSIC-V

ANGEL 是一款 RISC-V 基於 javascript 線上模擬器,類似 jslinux 那樣,只是模擬的平 台為 RISC-V 架構而已,你可以點擊以下連結去測試 ANGEL

http://riscv.org/angel/

如果你對 ANGEL 有興趣,可以到這裡去看看他的原始碼: https://github.com/riscv/riscv-angel

使用 Yocto 來編譯 RISC-V Linux 系統

目前 RISC-V 雖然尚未被併入 Yocto 當中,但是 RISC-V 官方有提供 riscv-poky 好方便 我們測試 RISC-V 在 Linux 下的狀況,我們可以使用以下命令取得:

coldnew@osx ~ $ git clone https://github.com/riscv/riscv-poky.git

接著進入該資料夾

coldnew@osx ~ $ cd riscv-poky

再接下來則是和 Yocto 一樣的使用方式,首先先取得編譯環境用的環境變數

coldnew@osx ~/riscv-poky $ source oe-init-build-env

接著修改一下目標平台,預設是 qemuriscv64 ,但是在本文撰寫時似乎執行 QEMU 會有 問題,因此請將 MACHINE 改為 riscv64 ,我們將使用 spike 來進行 riscv 的模擬

coldnew@osx ~/riscv-poky/build $ vim conf/local.conf

MACHINE="riscv64"

接下來就是編譯我們想要的目標: core-image-riscv ,這邊由於包含下載程式碼以及編譯,會耗費許多時間

coldnew@osx ~/riscv-poky/build $ bitbake core-image-riscv

在本篇文章撰寫的時候,riscv-poky 有 bug 會造成執行 spike 時不正常,因此最好不要在 conf/local.conf 加上 INHERIT += "rm_work" ,不然在執行 runspike 命令時他會 抱怨說找不到 riscv-pk 編譯出來的檔案 bbl (Berkeley Boot Loader)。


針對這個問題我已經發了 patch 來修正,請參閱: https://github.com/riscv/riscv-poky/pull/5

編譯完成後,我們就可以使用 runspike 來執行我們的 RISC-V Linux 環境

coldnew@osx ~/riscv-poky/build $ runspike riscv64

Continuing with the following parameters:
KERNEL: [/Yocto/riscv-poky/build/tmp/deploy/images/riscv64/vmlinux-riscv64.bin]
ROOTFS: [/Yocto/riscv-poky/build/tmp/deploy/images/riscv64/core-image-riscv-riscv64-20150914130848.rootfs.ext2]
FSTYPE: [ext2]
SPIKE_BIN: [/Yocto/riscv-poky/build/tmp/sysroots/x86_64-linux/usr/bin/spike]
BBL_PATH: [/Yocto/riscv-poky/build/tmp/work/riscv64-poky-linux/riscv-pk/1.0-r0/bbl]

              vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
                  vvvvvvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrr       vvvvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrr      vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrrrr    vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrrrr    vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrrrr    vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrr      vvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrr       vvvvvvvvvvvvvvvvvvvvvv
rr                vvvvvvvvvvvvvvvvvvvvvv
rr            vvvvvvvvvvvvvvvvvvvvvvvv      rr
rrrr      vvvvvvvvvvvvvvvvvvvvvvvvvv      rrrr
rrrrrr      vvvvvvvvvvvvvvvvvvvvvv      rrrrrr
rrrrrrrr      vvvvvvvvvvvvvvvvvv      rrrrrrrr
rrrrrrrrrr      vvvvvvvvvvvvvv      rrrrrrrrrr
rrrrrrrrrrrr      vvvvvvvvvv      rrrrrrrrrrrr
rrrrrrrrrrrrrr      vvvvvv      rrrrrrrrrrrrrr
rrrrrrrrrrrrrrrr      vv      rrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrr          rrrrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrrrr      rrrrrrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrrrrrr  rrrrrrrrrrrrrrrrrrrrrr

.....

Poky (Yocto Project Reference Distro) 1.8+snapshot-20150914 riscv64 /dev/ttyHTIF0

riscv64 login: root
root@riscv64:~# cat /proc/cpuinfo
hart  : 0
isa : RV64G