FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

RISC-VのArduino(HiFive)が我が家にやってきたよ

マルツオンラインが、RISC-VのArduinoボード、HiFive1を取り扱い始めた。

www.marutsu.co.jp

これまで海外で購入可能だったが、海外サイトでわざわざ購入するのが億劫で買っていなかったのだが、マルツだと安心。 購入して即日で届く速さだった。

まだ開封しただけで、ソフトウェアの環境などは用意していないが、ボチボチ構築していこう。

さて、これで何して遊ぼうかな(買ったは良いが何をするか決めていない)。

f:id:msyksphinz:20170307010142p:plain

f:id:msyksphinz:20170307010200p:plain

OpenSPARC T1の調査(7. S1coreでDhrystoneを動作させたい)

S1coreとOpenSPARC T1純正環境との差分は引き続き調査中だ。 とりあえず、S1coreを使いこなせるようになりたい。 まずはベンチマークプログラムを動作させられるようにしたい。Coremarkが動けば面白いのだが、まずはDhrystoneかな。

Dhrystoneは、CPUの基本性能を知るための最も基礎的なベンチマークプログラムだ。

Dhrystone - Wikipedia

S1coreでプログラムを動作させるためには

前回少し解説したが、S1coreでベンチマークプログラムを動作させるためには、以下の2つのファイルを用意する必要がある。

  • rom_harness.hex : リセット後のブート動作を行うためのプログラム。main()に入る直前まで。
  • ram_harness.hex : main()以降のプログラムを格納している。

まずは、S1coreのリリース群に入っているスクリプトを確認して、何をしなければならないのかを確認しよう。

$ less ./tools/bin/compile_test
...
# Compile the boot code
sparc64-linux-gnu-as -ah -am -o boot/boot.bin boot/boot.s
sparc64-linux-gnu-objdump -d -EB -w -z boot/boot.bin > boot/boot.dump
grep "  " boot/boot.dump | egrep -v "elf64-sparc" | dump2hex.bin > boot/rom_harness.hex

# Compile the C test
sparc64-linux-gnu-gcc -c -O0 $1.c
sparc64-linux-gnu-ld -Ur --script=$S1_ROOT/tools/src/linker.map -EB -o $1.bin $1.o
sparc64-linux-gnu-objdump -d -EB -w -z $1.bin > $1.dump
grep "  " $1.dump | egrep -v "elf64-sparc" | dump2hex.bin > ram_harness.hex

基本的にsparcgccを使ってコンパイルし、リンカはlinker.mapを使っている。これはDhrystoneも同じものを使えばよかろう。 このコンパイル手順をDhrystoneにも適用すれば良いと思われる。

Dhrystoneのコードは以下からダウンロードした。

fossies.org

Makefileの編集を行う。

CC=      sparc64-linux-gnu-gcc           # C compiler name goes here (UNIX)
GCC=        sparc64-linux-gnu-gcc
...

CFLAGS= $(OPTIMIZE) $(TIME_FUNC) -DHZ=$(HZ) $(ENUMS) $(STRUCTASSIGN) $(CFL) -Ur -Xlinker --script=/home/masayuki/work/s1_core_opensparc_t1/s1_core/tools/src/linker.map -Xlinker -EB -lc
GCCFLAGS= $(GCCOPTIM) $(TIME_FUNC) -DHZ=$(HZ) $(ENUMS) $(STRUCTASSIGN) $(CFL) -Ur -Xlinker --script=/home/masayuki/work/s1_core_opensparc_t1/s1_core/tools/src/linker.map -Xlinker -EB -lc

さらに、cc_dhryを作成した後に、hexファイルを生成する手順も追加した。

cc_dry2:     $(SRC) $(HDR)
        $(CC) $(CFLAGS) $(SRC) $(LFLAGS) -o $@
        sparc64-linux-gnu-objdump -d -EB -w -z $@ > $@.dump
        grep "  " $@.dump | egrep -v "elf64-sparc" | dump2hex.bin > ram_harness.hex

これで、Dhrystoneのディレクトリにram_harness.hexが生成される。これを既存のs1_core/test/ram_harness.hex (hello.cから生成したもの)と置き換えてシミュレーションを走らせて見ればよい。

OpenSPARC T1の調査(7. OpenSPARC T1の外部ポート制約)

S1coreの動作方法が分かってきたのだが、S1coreとOpenSPARC T1のコアは分離されているが、SPARCコアの部分は共通のものを利用しているので、使いようがあるはずだ。

S1coreの起動方法をトレースすると、OpenSPARC T1も動作させることが出来るに違いないと思い、S1Coreの動作方法について調査を行った。

S1coreは以下のような階層構成を取っている。

f:id:msyksphinz:20170307005317p:plain

ここでsparc_0と表記されているのがOpenSPARCのコア1つ分で、それを包んでいるのがs1_top_0という階層になる。

ここでは、以下の外部ポートが制約されており、駆動しないようになっている。

  • s1_top.v
  /*
   * Continuous assignments
   */

  assign const_cpuid = 4'h0;
  assign const_maskid = 8'h20;

  // sscan
  assign ctu_tck = 1'b0;
  assign ctu_sscan_se = 1'b0;
  assign ctu_sscan_snap = 1'b0;
  assign ctu_sscan_tid = 4'h1;

  // bist
  assign ctu_tst_mbist_enable = 1'b0;

  // efuse
  assign efc_spc_fuse_clk1 = 1'b0;     // Activity
  assign efc_spc_fuse_clk2 = 1'b0;     // Activity
  assign efc_spc_ifuse_ashift = 1'b0;
  assign efc_spc_ifuse_dshift = 1'b0;
  assign efc_spc_ifuse_data = 1'b0;    // Activity
  assign efc_spc_dfuse_ashift = 1'b0;
  assign efc_spc_dfuse_dshift = 1'b0;
  assign efc_spc_dfuse_data = 1'b0;    // Activity

  // scan and macro test
  assign ctu_tst_macrotest = 1'b0;
  assign ctu_tst_scan_disable = 1'b0;
  assign ctu_tst_short_chain = 1'b0;
  assign global_shift_enable = 1'b0;
  assign ctu_tst_scanmode = 1'b0;
  assign spc_scanin0 = 1'b0;
  assign spc_scanin1 = 1'b0;

これをOpenSPARC側にも移植すれば良いのではないか?ということで移植して際シミュレーションしてみたのだが、どうやらそれだけではSPCパケットはまだ発行されない。

まだリセット解除に問題があるようだ。

OpenSPARC T1の調査(6. S1coreのSPC⇔WishBoneの構成)

OpenSPARC T1のインタフェースは、どうやらSPARC固有のパケットを使って通信しているらしい。 このパケットを分解して、S1Coreに搭載されているWishBoneに載せ変えているのがSPC2WBMユニットだ。

インタフェースは以下のようになっており、SPARCのパケットを受信してWishBoneへの変換ステートマシンが搭載されている。

インタフェース名 接続信号
Top-level system inputs sys_clock_i sys_clock_i
sys_reset_i sys_reset_final
sys_interrupt_source_i sys_interrupt_source
Bridge inputs connected to SPARC Core outputs spc_req_i spc_pcx_req_pq
spc_atom_i spc_pcx_atom_pq
spc_packetout_i spc_pcx_data_pa
Bridge outputs connected to SPARC Core inputs spc_grant_o pcx_spc_grant_px
spc_ready_o cpx_spc_data_rdy_cx2
spc_packetin_o cpx_spc_data_cx2
spc_stall_o wbm_spc_stall
spc_resume_o wbm_spc_resume
Top-level Wishbone Interconnect inputs wbm_ack_i wbm_ack_i
wbm_data_i wbm_data_i
Top-level Wishbone Interconnect outputs wbm_cycle_o wbm_cycle_o
wbm_strobe_o wbm_strobe_o
wbm_we_o wbm_we_o
wbm_addr_o wbm_addr_o
wbm_data_o wbm_data_o
wbm_sel_o wbm_sel_o

SPARCの命令フェッチパケットの構成

  • spc_pcx_req_pq[4:0] : processor to pcx request
  • spc_pcx_atom_pq : processor to pcx atomic request
  • spc_pcx_data_pa[123:0] : processor to pcx packet

ちなみに、T1のパケットは以下のような124ビットの構成であり、図に起こすとさらに以下のような図になる。

#define PCX_VLD         123  //PCX packet valid
#define PCX_RQ_HI       122  //PCX request type field
#define PCX_RQ_LO       118
#define PCX_NC          117  //PCX non-cacheable bit
#define PCX_R           117  //PCX read/!write bit
#define PCX_CP_HI       116  //PCX cpu_id field
#define PCX_CP_LO       114
#define PCX_TH_HI       113  //PCX Thread field
#define PCX_TH_LO       112
#define PCX_BF_HI       111  //PCX buffer id field
#define PCX_INVALL      111
#define PCX_BF_LO       109
#define PCX_WY_HI       108  //PCX replaced L1 way field
#define PCX_WY_LO       107
#define PCX_P_HI        108  //PCX packet ID, 1st STQ - 10, 2nd - 01
#define PCX_P_LO        107
#define PCX_SZ_HI       106  //PCX load/store size field
#define PCX_SZ_LO       104
#define PCX_ERR_HI      106  //PCX error field
#define PCX_ERR_LO      104
#define PCX_AD_HI       103  //PCX address field
#define PCX_AD_LO        64
#define PCX_DA_HI        63  //PCX Store data
#define PCX_DA_LO         0

f:id:msyksphinz:20170304115954p:plain

詳細は省略するが、内部にステートマシンが組まれており、SPARCのパケットをWishBoneに変換している。

OpenSPARC T1の調査(5. S1coreをModelSimで動かす環境の構築)

OpenSPARC T1のラッパーであるS1Coreは、デフォルトではVcsもしくはIcarus Verilogで動作するようになっているが、これらで動作するのだったらModelsim Starter Editionでも動作するはずだ。 デバッグにあたり、やはりModelSimの方が簡単なので、Modelsimへの環境を以降しておこう。

まずは、S1Coreのためのリポジトリを作成した。

github.com

環境変数の設定

S1Coreの環境変数では、S1CoreそのものとOpenSPARC T1の場所を設定する必要がある。 これに加えて、ModelSim用のファイルリストを作成する記述を追加した。

  • s1_core/sourceme
diff --git a/s1_core/sourceme b/s1_core/sourceme
index 8f8d03b..01112cb 100755
--- a/s1_core/sourceme
+++ b/s1_core/sourceme
@@ -6,6 +6,7 @@ export PATH=.:$S1_ROOT/tools/bin:$PATH

 # Filelist names
 export FILELIST_ICARUS=$S1_ROOT/hdl/filelist.icarus
+export FILELIST_QUESTA=$S1_ROOT/hdl/filelist.questa
 export FILELIST_VCS=$S1_ROOT/hdl/filelist.vcs
 export FILELIST_FPGA=$S1_ROOT/hdl/filelist.fpga
 export FILELIST_DC=$S1_ROOT/hdl/filelist.dc

さらに、build_questa および run_questaを作成した。

  • build_questa
#!/bin/bash

if [ -z "$S1_ROOT" ]; then echo "***ERROR***: S1_ROOT variable is undefined, please set it and run 'source sourceme'."; exit 1; fi
if ! [ -d "$S1_ROOT" ]; then echo "***ERROR***: directory '$S1_ROOT' does not exist, please check it and run 'source sourceme' again."; exit 1; fi

echo "Building testbench using QuestaSim simulator..."
mkdir -p $S1_ROOT/run/sim/questa
cd $S1_ROOT/run/sim/questa
# rm -rf *
vlib worklib
vlog -work worklib -f $FILELIST_QUESTA
echo -e "Done!"
  • run_questa
#!/bin/bash

if [ -z "$S1_ROOT" ]; then echo "***ERROR***: S1_ROOT variable is undefined, please set it and run 'source sourceme'."; exit 1; fi
if ! [ -d "$S1_ROOT" ]; then echo "***ERROR***: directory '$S1_ROOT' does not exist, please check it and run 'source sourceme' again."; exit 1; fi

cd $S1_ROOT/run/sim/questa
ln -f -s $S1_ROOT/tests/boot/rom_harness.hex .
ln -f -s $S1_ROOT/tests/ram_harness.hex .

vsim -c worklib.testbench -voptargs="+acc" -l sim.log -do "run -all; quit"
echo "Simulation completed!"
echo "To see the output:"
echo "        less $S1_ROOT/run/sim/questa/sim.log"
echo "Too watch the waveforms:"
echo "        gtkwave $S1_ROOT/run/sim/questa/trace.vcd"

動作させるプログラムをコンパイル

S1Coreのリポジトリにはhello.cというサンプルプログラムが用意されているが、これを動作させるためにはもちろんSparcコンパイラコンパイルしなければならない。

  • tests/hello.c
// Sample program that writes two words at a predefined address

int main() {
  unsigned long* address;
  address = (unsigned long*)0x0000CAC0;
  (*address) = 0xC1A0C1A0;  // First store
  address = (unsigned long*)0x0000CAC0;
  (*address) = 0xFABA1210;  // Second store
  return 0;
}

このためにUbuntuのパッケージとしてgcc-sparc64-linux-gnuをインストールした。

sudo aptitude install -y gcc-sparc64-linux-gnu

そしてcompile_testコマンドをいくつか改造する必要がある。 と言っても、sparc64-linux-sparc64-linux-gnu-に変更しただけだ。

  • compile_test
diff --git a/s1_core/tools/bin/compile_test b/s1_core/tools/bin/compile_test
index 5684c25..060ab69 100755
--- a/s1_core/tools/bin/compile_test
+++ b/s1_core/tools/bin/compile_test
@@ -6,7 +6,7 @@
 # Parameter is test name without extension (e.g. to compile
 # $S1_ROOT/tests/hello.c) just run "compile_test hello".
 #
-# Note: requires sparc64-linux-gcc (see Download section on
+# Note: requires sparc64-linux-gnu-gcc (see Download section on
 # http://www.srisc.com).

 if [ -z "$S1_ROOT" ]; then echo "***ERROR***: S1_ROOT variable is undefined, please set it and run 'source sourceme'."; exit 1; fi
@@ -32,15 +32,14 @@ fi
 gcc -o $S1_ROOT/tools/bin/dump2hex.bin $S1_ROOT/tools/src/dump2hex.c

 # Compile the boot code
-sparc64-linux-as -ah -am -o boot/boot.bin boot/boot.s
-sparc64-linux-objdump -d -EB -w -z boot/boot.bin > boot/boot.dump
-grep "  " boot/boot.dump | egrep -v "file format" | dump2hex.bin > boot/rom_harness.hex
+sparc64-linux-gnu-as -ah -am -o boot/boot.bin boot/boot.s
+sparc64-linux-gnu-objdump -d -EB -w -z boot/boot.bin > boot/boot.dump
+grep "  " boot/boot.dump | egrep -v "elf64-sparc" | dump2hex.bin > boot/rom_harness.hex

 # Compile the C test
-sparc64-linux-gcc -c -O0 $1.c
-sparc64-linux-ld -Ur --script=$S1_ROOT/tools/src/linker.map -EB -o $1.bin $1.o
-sparc64-linux-objdump -d -EB -w -z $1.bin > $1.dump
-grep "  " $1.dump | egrep -v "file format" | dump2hex.bin > ram_harness.hex
+sparc64-linux-gnu-gcc -c -O0 $1.c
+sparc64-linux-gnu-ld -Ur --script=$S1_ROOT/tools/src/linker.map -EB -o $1.bin $1.o
+sparc64-linux-gnu-objdump -d -EB -w -z $1.bin > $1.dump
+grep "  " $1.dump | egrep -v "elf64-sparc" | dump2hex.bin > ram_harness.hex

 #rm -f *.o *~ *.bin *.dump           # Make clean
-

最初は何のことだか分からなかったのだが、以下のfile formatを除去するのは、dumpファイルの先頭行を除去したいようなのだが、環境変数が日本語だと違う文字列になってしまうので、共通のelf64-sparcに変更した。

-grep "  " $1.dump | egrep -v "file format" | dump2hex.bin > ram_harness.hex
+grep "  " $1.dump | egrep -v "elf64-sparc" | dump2hex.bin > ram_harness.hex

これで、build_questa && run_questarun/sim/questa/にシミュレーションログが出力された。 正しく動作しているようだ。

cd run/sim/questa
less sim.log

...
# INFO: MEMH testbench.ram_harness: R @             35410000 ns, AD=0800000000040018 SEL=ff DAT=8410a1a0c4704000
# INFO: WBM2SPC: *** RETURN PACKET TO SPARC CORE ***
# INFO: WBM2SPC: Valid bit is 1
# INFO: WBM2SPC: Return Packet of Type IFILL_RET
# INFO: WBM2SPC: L2 Miss is 0
# INFO: WBM2SPC: Error is 0
# INFO: WBM2SPC: Non-Cacheable bit is 1
# INFO: WBM2SPC: Thread is 0
# INFO: WBM2SPC: Way Valid is 0
# INFO: WBM2SPC: Replaced L2 Way is 0
# INFO: WBM2SPC: Fetch for Boot is 0
# INFO: WBM2SPC: Atomic LD/ST or 2nd IFill Packet is 1
# INFO: WBM2SPC: PFL is 0
# INFO: WBM2SPC: Data is c25fa7f7053068308410a1a0c4704000
# INFO: TBENCH: Completed Simply RISC S1 Core simulation!
# ** Note: $finish    : /home/masayuki/work/s1_core_opensparc_t1/s1_core/hdl/behav/testbench/testbench.v(94)
#    Time: 50 us  Iteration: 0  Instance: /testbench
# End time: 01:15:23 on Mar 04,2017, Elapsed time: 0:09:38
# Errors: 0, Warnings: 43

f:id:msyksphinz:20170304014111p:plain

OpenSPARC T1の調査(5. S1coreの調査)

OpenSPARC T1のコア部分のみを切り出したものとして、S-RISC (Simply-RISC)というものをコメントで紹介してもらった。

どうやら、コアの部分をOpenSPARC-T1として利用し、それ以外の外側を独自に囲むことによってOpenSPARCを動作させるものらしい。 概要図を当該HPから引用する。

www.srisc.com

http://www.srisc.com/images/dmitry_diagram1.jpg

上記のとおり、OpenSPARC-T1のコアはそのまま利用し、外部へのWishboneバスおよびペリフェラルを追加することによって動作させる仕組みだ。

With this new system, now Linux boots correctly as single-thread! And even using PROM file 1c4t_obp_prom.bin, i.e. the four-threads version of the OpenBoot code, Linux starts booting.

どうやらシングルコアでもLinuxのブートに成功しているらしい。すごいな!

という訳で早速チャレンジしてみることにする。

S1 Coreのダウンロードとインストール

以下からS1 Coreのダウンロードを行う。解答するとsourcemeというファイルが見えるので、これを編集する。

www.srisc.com

# General paths settings
export S1_ROOT=~/work/s1_core
export T1_ROOT=~/work/opensparc/t1
export PATH=.:$S1_ROOT/tools/bin:$PATH

まず、OpenSPARC T1のソースコードはダウンロードしていること(http://www.oracle.com/technetwork/systems/opensparc/opensparc-t1-page-1444609.html)が必要である。 コア部分はOpenSPARCそのものを利用しているということになる (これはT1_ROOT変数にて指定されている)。 そして、ダウンロードしたS1 Coreの場所を指定している (これはS1_ROOT変数にて指定されている)。

sourcemeを読み込んで、update_filelistによりファイルリストが更新される。

source sourceme
update_filelist

Icarus Verilogによるシミュレーション環境構築

シェル一覧を見ていると、どうやらVcs, Icarus Verilogでの動作をサポートしているらしい。Vcsなんて持っていないので、Icarus Verilogでシミュレーションしてみよう。

build_icarus
run_icarus

しばらくするとシミュレーションが完了する。vcdファイルが生成されたようだ。

$ run_icarus

Simulation completed!
To see the output:
        less /home/xxx/work/s1_core/run/sim/icarus/sim.log
Too watch the waveforms:
        gtkwave /home/xxx/work/s1_core/run/sim/icarus/trace.vcd

vcdを眺めるのは面倒だし、ちょうどModelSimをインストールしているのでwlf形式に変換した。

vcd2wlf trace.vcd trace.wlf

ModelSimで波形を開いてみた。構造としてはS1コアの横に命令ROM、データROMが接続されているような状態だ。 命令ROMの波形を出してみると、ちゃんとフェッチが効いているようなので、これは動作しているのかな?もうちょっと掘り下げてみよう。

f:id:msyksphinz:20170303081121p:plain

f:id:msyksphinz:20170303081135p:plain

6th RISC-V Workshop の Registration および Call for Papers が始まりました

f:id:msyksphinz:20170304095136p:plain

2017/05/8 - 2017/05/11にかけて、6th RISC-V Workshopが開催されるようだ。RegistrationおよびCall for Papersが開始されている。

riscv.org

場所は上海の上海交通大学、情報系の学会に行くと、必ずと言っていいほど聞いたことのある中国では有名な大学だ。

ホストは今回はGoogleではなくnVIDIAnVIDIARISC-V系の発表をして来るのだろうか。期待だ。

上海なのでこれまでのアメリカよりは行きやすいはず。興味のある方はぜひ聴講を!