FPGA開発日記

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

RISC-Vについて改めて

f:id:msyksphinz:20160605215109p:plain

この記事は ハードウェア開発、CPUアーキテクチャ Advent Calendar 2016 - Qiita の1日目の記事です。

Advent-Calendarを埋めてくれるかた、今からでも募集中です!是非参加してください! 僕一人では、クオリティのある記事を続けられそうにありません。。。(弱音)

という訳で、私は今年一年で急激に注目を浴び始めたRISC-Vについて、あらためて纏めていこうと思う。

「改めて」と書いてあるとおり、私が一番最初に紹介したRISC-Vの記事は以下なので、こっちも参照してね。

msyksphinz.hatenablog.com

RISC-Vの生い立ち

今でこそ随分と知名度を得たRISC-Vだがが、私が一番最初に発見した日本語の記事は、以下と記憶している。

keisanki.at.webry.info

この記事を見て、「面白そう!」と思ったので、自分で調べながら記事を書き始めたのが最初。

さらに言うならば、2013年のHot-chipsにて以下のポスターセッションがあったようだ。

さらに、初期のRISC-Vの命令セットリファレンスマニュアルを見ていると、2011年という記述が出ており、ずいぶんと昔から検討されていたアーキテクチャなのだなということが分かる。

RISC-Vの目的

RISC-Vの目的とはいったい何なのだろうか?

まずはRISC-VのISA仕様書を読んでみよう。Introductionに(仕様書とは思えないような)設計者の思いが書いてある。

We developed RISC-V to support our own needs in research and education, where our group is particularly interested in actual hardware implementations of research ideas (we have completed eleven different silicon fabrications of RISC-V since the first edition of this specification), and in providing real implementations for students to explore in classes (RISC-V processor RTL designs have been used in multiple undergraduate and graduate classes at Berkeley).

まずは、RISC-Vの設計者とMIPSの設計者が同じ流れを組んでいることから分かる通り、過去の遺産を大量に抱えているMIPSアーキテクチャから決別した、新しいアーキテクチャが必要だったということだ。 プロセッサアーキテクチャを研究する人達は、自分の提案手法の効果を測定するためのリファレンスプロセッサモデルが必要だったのではないか?しかし、

  • リファレンスモデルとしてMIPSは過去の古い資産を含み過ぎている(遅延スロット、複雑な命令、複雑なレジスタ構成HI/LOなど)
  • 他のプロセッサアーキテクチャも、ライセンスなどの問題で自由に使えるものがあまり無い(ARMも大学の研究として使うのは難しく、またARM32のアーキテクチャRISCと呼ぶにはあまりにも複雑だった。ARM64は知らない)

ということから、誰もが自由に使用することができる、新しいデファクトスタンダードとしてのプロセッサアーキテクチャが必要だったという訳だ。最初は別に産業界に普及して欲しいとか、そういうことは考えていなかったのではなかろうか。

RISC-Vの特徴

上記のとおり、RISC-Vは過去のMIPSという古いアーキテクチャの問題点を解決するように設計されている。最初の目的がMIPSの改善ということもあり、MIPSの問題点を解決すべく設計されているような印象だ。

  • 遅延スロットは存在しない
  • 命令セットは単純
  • フラグは存在しない
  • HI/LOレジスタは存在しない
  • 命令セットはより単純に

アーキテクチャレベルについて

RISC-Vにはいくつかのアーキテクチャレベルが存在する。整数、浮動小数点のアーキテクチャセットの区別はもちろん(RV32I, RV32-Fみたいな)、 64ビット整数命令、64ビット倍精度浮動小数点命令、さらには128ビット整数命令まで定義されている。

RISC-V Spec 2.1を改めて読み直すと、いろいろアーキテクチャレベルが追記されている。

Specifications - RISC-V Foundation

名称 内容 備考
RV32I base integer instruction set
RV32E base integer instruction set, which is a reduced version of RV32I designed for embedded systems
RV64I base integer instruction set, which builds upon the RV32I.
“M” Standard Extension standard integer multiplication and division instruction extension
“A” Standard Extension standard atomic instruction extension.
“F” Standard Extension standard instruction-set extension for single-precision floating-point.
“D” Standard Extension standard double-precision floating-point instruction-set extension.
“Q” Standard Extension standard extension for 128-bit binary floating-point instructions.
“L” Standard Extension support decimal floating-point arithmetic まだ詳細は定義されていないが。
“C” Standard Extension draft proposal for the RISC-V standard compressed instruction. RV32Eよりもより小さくした命令セットかな。
“V” Standard Extension vector instructions. まだ定義されていない。
“B” Standard Extension future standard extension to provide bit manipulation instructions まだ定義されていない。
“T” Standard Extension transactional memory operations. まだ定義されていない。
“P” Standard Extension standard packed-SIMD extension for RISC-V 命令セットの空間だけは予約してある?
RV128I variant of the RISC-V ISA supporting a flat 128-bit address space

ちなみに、システムレベル命令(システムコールとか、割り込み)などは別の仕様書に定義されている。

Draft Privileged ISA Specification v1.10 - RISC-V Foundation

備考: OpenRISCじゃ駄目なのかい?

これもアーキテクチャ仕様書に言及がある。OpenRISCにはOpenRISCの問題点が残っている訳だ。

  • OpenRISC has condition codes and branch delay slots, which complicate higher performance implementations.
  • OpenRISC uses a fixed 32-bit encoding and 16-bit immediates, which precludes a denser instruction encoding and limits space for later expansion of the ISA.
  • OpenRISC does not support the 2008 revision to the IEEE 754 floating-point standard.
  • The OpenRISC 64-bit design had not been completed when we began.

上記の資料を読めば分かるように、RISC-Vのアーキテクチャ仕様書を見て分かるとおり、命令エンコーディングについてはかなり工夫がされている。 最初にアーキ仕様書を読んだ人はびっくりするかもしれない。

f:id:msyksphinz:20161128010945p:plain

RISC-Vの即値生成は、他の命令の即値フィールドと合わせるためにこのようなビットフィールドになっている。これにより即値生成の回路を単純化するという目的がある。

手っ取り早くRISC-Vを試したい方へ

Zynq ZedBoard, Zybo, ZC702を持っている方は、RISC-Vの実装を手っ取り早く構築し、Linuxを起動させるデモがある。

ビルドの方法は、私の過去の記事を参照して欲しい。

msyksphinz.hatenablog.com

RISC-V Workshop

RISC-Vは定期的にワークショップを開催しており、徐々にその規模は拡大しているように感じる。

  • 2015/01/14-15 : RISC-V 1st Workshop at Marriott Hotel, Monterey
    • 最初のワークショップは殆どがUC Berkeleyの発表であり、かなりの部分をRISC-Vプラットフォームの説明、仕様書の説明に裂いてある。
  • 2015/06/29-30 : RISC-V 2nd Workshop at The International House, Berkeley
  • 2016/01/05-06 : RISC-V 3rd Workshop at Oracle Conference Center
  • 2016/06/12-13 : RISC-V 4th Workshop at MIT
  • 2016/11/29-30 : RISC-V 5th Workshop at Mountain View Google
  • 2017/05/08-11 : RISC-V 6th Workshop, co-hosted by NVIDIA and the Shanghai Jiao Tong University (SJTU) in Shanghai China

私の知っている限りのRISC-Vの学会発表

ちょっとフォローし切れていないけど。。。

  • 2013 Hot-chipsにてRISC-Vのポスター設置
  • 2014 ESSCIRC-2014 にてRISC-Vを用いたシステム発表
  • 2014 August, EETimesにRISC-Vの記事が登場
  • 2015 HPCA 2015にてRISC-Vのチュートリアル実施
  • 2015 Hot-chipsにてRISC-Vの実装Ravenの発表

次回

明日は、RISC-Vの様々な実装について紹介していきたい。

自作プロセッサの性能解析とその対策(7. コンパイラ最適化オプションの調整)

前回の記事で、-O3付きでコンパイルできないという問題が残っていたのだが、それを何とか回避できないか試行してみた。

そもそも-O3とはどのようなオプションなのだろうか?調査してみると、-O2に対して以下の最適化オプションを追加したものが-O3らしい。

gcc.gnu.org

Optimize yet more. -O3 turns on all optimizations specified by -O2 and also turns on the -finline-functions, -funswitch-loops, -fpredictive-commoning, -fgcse-after-reload, -ftree-loop-vectorize, -ftree-loop-distribute-patterns, -fsplit-paths -ftree-slp-vectorize, -fvect-cost-model, -ftree-partial-pre, -fpeel-loops and -fipa-cp-clone options.

なので、-O3は-O2に対して上記のオプションを追加すれば等価になるということか。じゃあ一つずつ追加していって、エラーが出るものは省けは、だいたい-O3になるんじゃないか。なんて卑怯な手動だ(笑)。

結果として、以下のようにオプションを変更すると、ほぼ-O3と同一のオプションで、コンパイルは成功することが分かった。

-PORT_CFLAGS = -O2 -g $(MACHINE_TARGET) -DITERATIONS=$(ITERATIONS)
+PORT_CFLAGS = -O2 -g $(MACHINE_TARGET) -DITERATIONS=$(ITERATIONS) -funroll-loops \
+              -finline-functions \
+              -funswitch-loops \
+              -fpredictive-commoning \
+              -fgcse-after-reload \
+              -ftree-loop-vectorize \
+              -fsplit-paths \
+              -ftree-slp-vectorize \
+              -fvect-cost-model \
+              -ftree-partial-pre \
+              -fpeel-loops \
+              -fipa-cp-clone
+

つまり、-ftree-loop-distribute-patternsを除去したということになる。これは、

Perform loop distribution of patterns that can be code generated with calls to a library. This flag is enabled by default at -O3.
This pass distributes the initialization loops and generates a call to memset zero. For example, the loop

          DO I = 1, N
            A(I) = 0
            B(I) = A(I) + I
          ENDDO
is transformed to

          DO I = 1, N
             A(I) = 0
          ENDDO
          DO I = 1, N
             B(I) = A(I) + I
          ENDDO
and the initialization loop is transformed into a call to memset zero. 

はーん。これでmemsetが呼ばれるということか。とりあえずこれを除去してみた。

2016/12/01 追記。最適化オプション-O2+Plusのサイクル数追加。

命令数 Rate サイクル数 Rate
最適化オプション追加前 308822 100% 433730 100%
最適化オプション-O2 264024 85.5% 396837 91.5%
最適化オプション-O2+Plus 290386 94.0% 398513 91.8%

あれま、実行命令数は増えてしまったな。実行命令数は増えても、サイクル数としてはほぼ変わっていない不思議。IPC経過を観察しても、コンパイルオプションを変更しただけで良い傾向になっている。

f:id:msyksphinz:20161201023738p:plain

そろそろ本当にFPGAに載せる準備をしなければならない。それが出来たらReturnStackPointerなどの実装かな。

自作プロセッサの性能解析とその対策(6. コンパイラの最適化オプション追加とそれによる性能変化)

だんだんネタも無くなってきたので、CoremarkをRISC-VのGCCコンパイルするにあたり、本当に最適なオプションになっていたのかを調査してみようと思う。

以前までのCoremarkは、以下のオプションでコンパイルしていた。

PORT_CFLAGS = -O2 -g $(MACHINE_TARGET) -DITERATIONS=$(ITERATIONS)

いくつか効果のありそうなコンパイルオプションを追加してみよう。まずは、現在の自作RISC-VプロセッサはLoad-Useが弱いため、ループアンローリングしてスケジュールを最適化させるため、-funroll-loopsを導入してみる。

gcc.gnu.org

Unroll loops whose number of iterations can be determined at compile time or upon entry to the loop. -funroll-loops implies -frerun-cse-after-loop. It also turns on complete loop peeling (i.e. complete removal of loops with small constant number of iterations). This option makes code larger, and may or may not make it run faster.

PORT_CFLAGS = -O2 -funroll-loops -g $(MACHINE_TARGET) -DITERATIONS=$(ITERATIONS)

これにより、ISSによる実行では命令数は 308822命令から264024に減少していることが確認できた。 では、これでRTLシミュレーションを実行してみよう。

命令数 Rate サイクル数 Rate
最適化オプション追加前 308822 100% 433730 100%
最適化オプション追加後 264024 85.5% 396837 91.5%

うーん、IPCとしては何故か下がってしまった。命令数としては15%程度削減できているのだが、サイクル数としては8%弱の削減数だ。どこか効率の悪いところがあるらしい。

IPC経過

緑色が最適化コンパイルオプション追加後だ。やはりIPCとしては悪くなっている。

f:id:msyksphinz:20161129024940p:plain

-O3コンパイルすると

-O3コンパイルすると、コンパイルエラーになることは分かっている。memsetが足りないということだ。これは自分で実装して、どうにか-O3を使えるようにするしか無いかなあ。

自作プロセッサの性能解析とその対策(5. タグフォワーディング)

リザベーションステーションを実装していると、連続して同じレジスタを使うような命令が連続する場合、通常の実装ではどうしてもストールが1サイクル入ってしまう問題があった。

f:id:msyksphinz:20161127125835p:plain

上記のような演算器の実装をしていると、どうしても演算器の結果の直後にFFが入っておりリザベーションステーションへの書き込みが1サイクル遅れてしまう。これにより、 リザベーションステーションから命令が発行されるタイミングが1サイクル遅れ、依存関係のある連続する命令に1サイクルの空きが発生してしまう。

OP0   r3, r2, r1  // r3=op0(r2, r1)
OP1   r4, r3, r5  // r4=op1(r3, r5)

このr3のレジスタ依存のフォワーディングを解決するために1サイクル待たなければならないという訳だ。これは性能に重大な影響を及ぼしそうなので、以下の資料を参考に、1サイクル早く命令を発行できるような機構を実装する。

github.com

Chip Architect: Detailed Architecture of AMD's Opteron

リザベーションステーションは、ALUが演算結果を生成する1サイクル前に、演算命令のタグをバスに流すようにしている。これを受け取ったリザベーションステーションは、 「1サイクル後に欲しいデータが入手できるはず」という情報のもと投機的に命令をリザベーションステーションから発行してしまう。 これは、リザベーションステーション内で「データのフォワーディング」をする必要が無く、「タグ比較」のみで命令を発行してよいかを判断できるため、回路的に大きな負荷にならないという利点がある。

f:id:msyksphinz:20161127130949p:plain

本当はALUだけでなく、LSUにも同様の機構を実装すると効果がありそうだが、とりあえず現状の自作プロセッサに対して、以下のタグフォワーディングパスを実装して性能向上を観測した。

  • ALU0 --> ALU1
  • ALU1 --> ALU0

これにより、全てのALU同士の演算結果はストールすることなく実行することが出来るようになる。

サイクル数

前回の分岐予測改善時と比較して、サイクル数がどの程度改善しているのか計測した。

Cycle Rate
2-state Branch Prediction 49889 100%
4-state Branch Prediction 45528 91.2%
Branch + Tag Forwarding 43373 86.9%

タグフォワーディングにより、性能は約4%改善した。

IPC経過

f:id:msyksphinz:20161127141436p:plain

ちょっと分かりにくくなってきたなあ。前半のIPCが改善されてきた気がする。ただし後半はあまり伸びがない。 要改善。

CUIからVivadoを立ち上げて論理合成するためのスクリプト

自作RISC-Vプロセッサの設計もおおよそ完了してきたので、FPGA向けに論理合成する環境を構築している。

GUIを立ち上げてボタンをポチポチ押すのはあまり好きではないので、VivadoをCUIで立ち上げて動作させる環境を構築した。

VivadoのtclはDesign Compilerなどの一般の論理合成ツールのtclと非常に似ているが、フローは全く異なるので注意が必要だ。 正しく構築するためには、まずはGUIのVivadoの操作が記録されたVivadoのLogを採取し、それをtclに落としておくのが良いと思う。

Vivadoでの論理合成用tcl

以下のような論理合成用tclを作成した。先頭のPROJ_NAMETOP_NAMERTL_ROOT_DIRなどは好きに変更して欲しい。

set PROJ_NAME project_synth
set PROJ_DIR .
set RTL_ROOT_DIR ../../rtl
set TOP_NAME project

set dump 1
set checkpoint 1

create_project -in_memory -part xc7z020clg484-1

set_property parent.project_path ${PROJ_DIR}/${PROJ_NAME}.xpr [current_project]
set_property default_lib xil_defaultlib [current_project]
set_property target_language Verilog [current_project]
set_property board_part em.avnet.com:zed:part0:1.3 [current_project]
set_property vhdl_version vhdl_2k [current_fileset]

source filelist.tcl

read_xdc ${TOP_NAME}.xdc

synth_design -top ${TOP_NAME} -part xc7z020clg484-1 -verilog_define PP_BUSWIDTH_64=1 -include_dirs {../../../common/include} -fanout_limit 10000 -flatten_hierarchy rebuilt
write_checkpoint -force ${TOP_NAME}.dcp
report_utilization -file ${TOP_NAME}_utilization_synth.rpt -pb ${TOP_NAME}_utilization_synth.pb

if {$checkpoint} {write_checkpoint -force ${TOP_NAME}.synth.dcp}
if {$checkpoint} {write_verilog -force ${TOP_NAME}.synth.v}

if {$dump} {report_io -file ${TOP_NAME}.io.rpt}
if {$dump} {report_timing_summary -file ${TOP_NAME}.timing_summary.rpt}
if {$dump} {report_timing -delay_type min_max -sort_by group -max_paths 10 -path_type full -input_pins -file ${TOP_NAME}.timing_detail.rpt}
if {$dump} {report_route_status -show_all -file ${TOP_NAME}.route.rpt}
if {$dump} {report_utilization -file ${TOP_NAME}.util.rpt}

Vivado起動用CMakeLists.txt

別にcmakeで無くても良いのだが、cmakeが好きなので。filelist.fは自動生成するか、自分で作成する必要があるのだが、ここでは非公開。

project (mag_top)

set(CMAKE_VERBOSE_MAKEFILE true)


add_custom_target (mag_top ALL
  vivado -m64 -mode batch -source vivado_synth.tcl
  DEPENDS filelist.f)

自作RISC-Vプロセッサを論理合成した時のタイミング結果

自作RISC-Vプロセッサを論理合成した場合、50MHzのクロックを当てると以下のようなtiming_summaryがレポートされた。

------------------------------------------------------------------------------------------------
| Design Timing Summary
| ---------------------
------------------------------------------------------------------------------------------------

    WNS(ns)      TNS(ns)  TNS Failing Endpoints  TNS Total Endpoints      WHS(ns)      THS(ns)  THS Failing Endpoints  THS Total Endpoints     WPWS(ns)     TPWS(ns)  TPWS Failing Endpoints  TPWS Total Endpoints
    -------      -------  ---------------------  -------------------      -------      -------  ---------------------  -------------------     --------     --------  ----------------------  --------------------
      6.648        0.000                      0               100940        0.245        0.000                      0               100940        8.750        0.000                       0                 36712

Metした。調子になって100MHzにクロック周波数を上げてみる。

create_clock -period 10.0 [get_ports CPU_CLK]
set_input_jitter [get_clocks -of_objects [get_ports CPU_CLK]] 0.05

結果はViolatedとなってしまった。

------------------------------------------------------------------------------------------------
| Design Timing Summary
| ---------------------
------------------------------------------------------------------------------------------------

    WNS(ns)      TNS(ns)  TNS Failing Endpoints  TNS Total Endpoints      WHS(ns)      THS(ns)  THS Failing Endpoints  THS Total Endpoints     WPWS(ns)     TPWS(ns)  TPWS Failing Endpoints  TPWS Total Endpoints
    -------      -------  ---------------------  -------------------      -------      -------  ---------------------  -------------------     --------     --------  ----------------------  --------------------
     -3.352     -878.515                    508               100940        0.245        0.000                      0               100940        3.750        0.000                       0                 36712

一番辛いのは、ALUとALU用のReservation Stationとの間にあるReadyとValidの信号か。。。

    Location             Delay type                Incr(ns)  Path(ns)    Netlist Resource(s)
  -------------------------------------------------------------------    -------------------
                         (clock CPU_CLK rise edge)    0.000     0.000 r
                                                      0.000     0.000 r  CPU_CLK (IN)
                         net (fo=0)                   0.000     0.000    CPU_CLK
                         IBUF (Prop_ibuf_I_O)         0.921     0.921 r  CPU_CLK_IBUF_inst/O
                         net (fo=1, unplaced)         0.800     1.721    CPU_CLK_IBUF
                         BUFG (Prop_bufg_I_O)         0.101     1.822 r  CPU_CLK_IBUF_BUFG_inst/O
                         net (fo=36711, unplaced)     0.800     2.622    u_mag_exu_1/ex_latch_0/CPU_CLK_IBUF_BUFG
                         FDRE                                         r  u_mag_exu_1/ex_latch_0/alu_inst_vld_r_reg/C
  -------------------------------------------------------------------    -------------------
                         FDRE (Prop_fdre_C_Q)         0.478     3.100 f  u_mag_exu_1/ex_latch_0/alu_inst_vld_r_reg/Q
                         net (fo=61, unplaced)        0.828     3.928    u_mag_exu_1/int_mult_unit_0/alu_inst_vld_r
                         LUT4 (Prop_lut4_I1_O)        0.295     4.223 r  u_mag_exu_1/int_mult_unit_0/inst_en_i_4__0/O
                         net (fo=4, unplaced)         0.473     4.696    u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_3/RS_EX_INST_READY_1
                         LUT5 (Prop_lut5_I0_O)        0.116     4.812 r  u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_3/inst_en_i_3__1/O
                         net (fo=2, unplaced)         0.460     5.272    u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/p_10_in
                         LUT6 (Prop_lut6_I5_O)        0.124     5.396 r  u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/inst_en_i_2/O
                         net (fo=119, unplaced)       0.553     5.949    u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/rs_entry_bottom_idx_vld[0]
                         LUT4 (Prop_lut4_I3_O)        0.124     6.073 r  u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf[31]_i_14/O
                         net (fo=3, unplaced)         0.467     6.540    u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf[31]_i_14_n_5
                         LUT5 (Prop_lut5_I4_O)        0.124     6.664 r  u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf[31]_i_6/O
                         net (fo=156, unplaced)       1.013     7.677    u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf[31]_i_6_n_5
                         LUT4 (Prop_lut4_I1_O)        0.124     7.801 r  u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf[3]_i_7/O
                         net (fo=1, unplaced)         0.000     7.801    u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf[3]_i_7_n_5
                         CARRY4 (Prop_carry4_S[1]_CO[3])
                                                      0.533     8.334 r  u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf_reg[3]_i_2/CO[3]
                         net (fo=1, unplaced)         0.009     8.343    u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf_reg[3]_i_2_n_5
                         CARRY4 (Prop_carry4_CI_CO[3])
                                                      0.117     8.460 r  u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf_reg[7]_i_2/CO[3]
                         net (fo=1, unplaced)         0.000     8.460    u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf_reg[7]_i_2_n_5
                         CARRY4 (Prop_carry4_CI_CO[3])
                                                      0.117     8.577 r  u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf_reg[11]_i_2/CO[3]
                         net (fo=1, unplaced)         0.000     8.577    u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf_reg[11]_i_2_n_5
                         CARRY4 (Prop_carry4_CI_O[3])
                                                      0.331     8.908 r  u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf_reg[15]_i_2/O[3]
                         net (fo=1, unplaced)         0.618     9.526    u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/u_mag_exu_1/unsign_op1_data0[15]
                         LUT6 (Prop_lut6_I0_O)        0.307     9.833 r  u_mag_rsu/u_rs_ex_unit_1/rs_alu_entry_0/alu_op1_data_buf[15]_i_1/O
                         net (fo=2, unplaced)         0.460    10.293    u_mag_exu_1/int_mult_unit_0/imm_reg[31][15]
                         LUT5 (Prop_lut5_I3_O)        0.124    10.417 r  u_mag_exu_1/int_mult_unit_0/p_0_out_i_17/O
                         net (fo=1, unplaced)         0.800    11.217    u_mag_exu_1/int_mult_unit_0/A[15]
                         DSP48E1 (Prop_dsp48e1_A[15]_P[0])
                                                      3.841    15.058 r  u_mag_exu_1/int_mult_unit_0/p_0_out/P[0]
                         net (fo=3, unplaced)         0.800    15.858    u_mag_exu_1/int_mult_unit_0/p_0_out__0[0]
                         FDRE                                         r  u_mag_exu_1/int_mult_unit_0/part_mult0_buf_reg[0]/D
  -------------------------------------------------------------------    -------------------

自作プロセッサの性能解析とその対策(4. 分岐予測アルゴリズムの改善)

自作RISC-Vプロセッサの性能向上対策その4。分岐予測アルゴリズムを、4ステートの分岐予測方式に切り替える。

これまでは、単純な2ステートの分岐予測アルゴリズムを利用していた。

  • 当該命令で分岐すると、次に同じ命令では分岐と予測する
  • 当該命令で分岐しないと、次に同じ命令では分岐しないと予測する

f:id:msyksphinz:20161123162108p:plain

これを、4ステートの分岐予測アルゴリズムに切り替える。4ステートの分岐予測アルゴリズムでは、「Strong Through」「Weak Through」「Weak Jump」「Strong Jump」の4ステートである。

  • Strong Throughステートの場合、当該命令で分岐すると、Weak Throughステートに移行する
  • Weak Throughステートの場合、当該命令で分岐すると、Weak Jumpに移行、分岐しない場合はStrong Throughに移行する。
  • Weak Jumpステートの場合、当該命令で分岐すると、Strong Jumpに移行、分岐しない場合はWeak Throughに移行する。
  • Strong Jumpステートの場合、当該命令で分岐しない場合、Weak Jumpステートに移行する。

f:id:msyksphinz:20161123162611p:plain

この2つを比較して、性能向上比率を測定した。

Cycle Rate
2-state Branch Prediction 49889 100%
4-state Branch Prediction 45528 91.2%

おおよそ9%の性能向上となった。IPCの経過グラフを作成すると、以下のようになった。

青のグラフが、前回のロードレイテンシ+1のグラフ、赤が前回のロードレイテンシ+0のグラフ、さらに黄色のグラフが分岐予測のアルゴリズムを4-stateに変更したものだ。

f:id:msyksphinz:20161123163231p:plain:w800

過去の性能向上対策と解析

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

RISC-VのFreeBSD実装をZedBoardで動作させたい(解決したがFPGAで動作不良)

結局、いろいろ調べたところFreeBSDカーネルを作るのにはもう一段階くらい必要で、

riscv - FreeBSD Wiki

WikiFreeBSDをビルドする際、

make TARGET_ARCH=riscv64 buildworld

の次に、

make TARGET_ARCH=riscv64 KERNCONF=ROCKET buildkernel

を追加した。上記のコマンドにより、

/home/vagrant/obj/riscv.riscv64/home/vagrant/freebsd-riscv/sys/ROCKET/kernel

が作られたので、これを使ってBBLをビルドすることにした。

RISC-VのBBLのビルドの所で、../configureを実行している行にて、

../configure --prefix=$PREFIX --host=riscv64-unknown-freebsd11.0 --with-payload=/home/vagrant/obj/riscv.riscv64/home/vagrant/freebsd-riscv/sys/ROCKET/kernel

とすると、BBLが生成された!これをSDカードにコピーし、ZedBoardを起動させてみたのだが、

f:id:msyksphinz:20161125002159p:plain

やった!成功だ!と思ったら...

f:id:msyksphinz:20161125002251p:plain

ありゃー、カーネルパニックのような状態になってしまった...

いろんなBBLを作って試してみるか...