FPGA開発日記

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

Rocket-Chipにおけるコンフィグレーション別の面積比較(各種構成での面積比較)

前回の続き。多少は面積比較できる程度に環境が構築できてきたので、いろんな構成でもってVivadoで合成して面積を比較してみた。

まず大前提の問題として、Vivadoの面積レポートはとても読みにくい。まあSynopsysのDesign Compilerのように、単純にゲート数で比較することができないから大変だろうけど、もう少しCSVとか、テキストで解析しやすいようにしてくれればありがたいのだが。。。

とりあえず現状で調査した構成は以下の通りだ。パラメータについては、ソースコードを読みながら調査しているので、間違いがあるかもしれない。

Rocket DefaultConfig Rocket DefaultSmallConfig Rocket TinyConfig boom-v1 BOOMConfig boom-v2 BOOMConfig Freedom E300 Arty
コア機能 ビット幅 64 64 32 64 64
VM 指定なし(あり) なし なし 指定なし(あり) 指定なし(あり) なし
演算器 mulUnroll 8 指定なし(なし) 8 8 不明 指定なし(なし)
mulEarlyOut あり 指定なし(なし) 指定なし(なし) あり 不明 指定なし(なし)
divEarlyOut あり 指定なし(なし) 指定なし(なし) あり 不明 指定なし(なし)
FPU 指定なし(あり) なし なし 指定なし(あり) あり なし
Dキャッシュ rowBits システムバスと同じサイズ システムバスと同じサイズ システムバスと同じサイズ 64 システムバスと同じサイズ
セット数 指定なし(64) 64 256 64 64 256
ウェイ数 4 1 1 4 8 1
TLBエントリ数 32 4 4 8 8 4
MSHR数 0 0 0 2 4 0
ブロックバイト数 CacheBlockBytes CacheBlockBytes CacheBlockBytes 不明 CacheBlockBytes
命令キャッシュ rowBits システムバスと同じサイズ システムバスと同じサイズ システムバスと同じサイズ 不明 システムバスと同じサイズ
セット数 64 64 64 64 64 64
ウェイ数 4 1 1 4 8 1
TLBエントリ数 32 4 4 8 8 4
ブロックバイト数 CacheBlockBytes CacheBlockBytes CacheBlockBytes 不明 不明
TotalLUT 28734 6318 4646 115043 93773 4803
TotalFF 13187 2657 2221 44852 26971 2241

面積を比較したものをGraphにすると以下のようになる。すべてVivado 2017.2 ZYNQをターゲットにして合成した。

f:id:msyksphinz:20171120235637p:plain

Rocket CoreのDefaultConfigを基準として、DefaultSmallConfigやTinyConfigはとことん小さくした構成だ。 一方でBOOMConfigは非常に大きなものとなっており、原因としてはやはりコア内の面積比率が大きく、リオーダバッファや分岐予測器などが面積を消費しているものと思われる。

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

「リーダブルコード」を読む (第3章「理解しやすいコード」第4章「美しさ」)

諸事情で週末はネットワークをあまり使えないので、RISC-Vに関連する調査は中止。 あまりやることが無いので例によって一人読書会をしている。 今回は「リーダブルコード」。名著と呼ばれており、私も一度さっくりと読んだ。 ただし忘れていることもあるし、体系的に学びたいので読み直す。

例によってJupyter Notebookに書いてまとめをブログに張っていくことにする。

今回は第3章「理解しやすいコード」第4章「美しさ」までをまとめた。

まとめるといっても、本書は言いたいことを非常に簡潔に要約しており、ほぼほぼそれを写経したようなものになっているが、まあ自分で手を動かさないと分からないということで。。。


リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

第3章 誤解されやすい名前

  • 鍵となる考え: 名前が「ほかの意味と間違われることは無いだろうか?」と何度も自問自答する。

3.1 例: filter()

filter()という言葉では、選択するのか、除外するのかがわからない。

resultls = Database.all_objects.filter("year <= 2011");
  • 選択するのであれば、 select() にした方が良い。
  • 除外するのであれば、 exclude() にした方が良い。

3.2 例: Clip(text, length)

# textの最後を切り落として、「...」をつける
def Clip(text, length):
    ...

Clip()の動作は2つ考えられる。

  • 最後から length文字を削除する (remove)
  • 最大length文字までを切り詰める (truncate)

3.3 限界地を含めるときはminとmaxを使う

ショッピングカートには商品が10点までしか入らないとする。

CART_TOO_BIG_LIMIT = 10

if shopping_cart.num_items() >= CART_TOO_BIG_LIMIT:
    Error("カートにある商品数が多すぎます。");

根本的な問題は、CART_TOO_BIG_LIMITという名前があいまいなことだ。

  • アドバイス: 限界値を明確にするには、名前の前に max_min_ を付けよう。
MAX_ITEMS_IN_CART= 10

if shopping_cart.num_items() >= MAX_ITEMS_IN_CART:
    Error("カートにある商品数が多すぎます。");

3.4 範囲を指定するときはfirstとlastを使う

包含の意味を含むのであれば、範囲を指定するときはfirstlastを使用した方が良い。

set.PrintKeys(first="Bart", last="Maggie");

3.5 包含/排他的範囲には begin と end を使う

包含・排他的範囲 (最初を含むが、最後の要素は含まない)の場合は beginendを使うのが良い。

3.6 ブール値の名前

ブール地の変数やブール地を返す関数の名前を選ぶときは、truefalseの意味を明確にしなければならない。

bool read_password = true;

上記のプログラムは2つの意味に読み取ることができる。

  • パスワードをこれから読み取る必要がある。
  • パスワードをすでに読み取っている。

need_passworduser_is_authenticatedなどが適切。

3.7 ユーザの期待に合わせる

例: get*()

getで始まるメソッドはメンバの値を返すだけの「軽量アクセサ」の意味を持っている。以下は、getMean()が非常に重たいため良くない例。

public class StatisticsColllector {
    public void addSample(double x) { ... }
    public double getMean() {
        // すべてのサンプルをイテレートして、total/num_samplesを返す。
    }
    ...
}

例: list::size()

list.size()の計算量がO(n)のため、下記のコードは [tex:O(n2)] になっている。

void ShrinkList(list<Node>& list, int max_size) {
    while (list.size() > max_size) {
        FreeNode (list.back());
        list.pop_back();
    }
}

sizeメソッドは一定時間で終了するようにすべきだ。最新のC++標準では、size()の計算量をO(1)にすることが求められている。

3.8 例: 複数の名前を検討する

名前を決めるときは複数の候補を検討する。

experiment_id: 100
description: "フォントサイズを14ptに上げる"
traffic_fraction: 5%

同じような実験をするときは設定ファイルの大部分をコピペしなければならない。 既存の設定ファイルをほかの実験でも使えるようにしたい場合、以下のように書くことができる。

expriment_id: 101
the_other_experiment_id_I_want_to_reuse: 100
[ 以下、変更が必要な情報だけ書き換える ]
  • template
experimnet_id: 101
template: 100

「これはテンプレートなのか」「このテンプレートを使っている」のかが分かりにくい。 - reuse

experiment_id: 101
reuse: 100

「この実験は100回再利用できる可能性がある」と誤解されるのを防ぐために、"reuse_id"とした方が良い。ただし、reuse_id=100でぼ、この実験の再利用idは100だ、と誤解する人が現れるかもしれない。 - copy :

experiment_id: 101
copy:100

「この実験を100回コピーする」とか「これは100回目のコピーだ」などと思われる可能性がある。

  • inherint
experimnt_id: 101
inherint: 100

継承するという意味は適切に思える。 したがって、最善の名前はcopy_experimnetinherit_from_experiment_idということになった。

3.9 まとめ

英語の単語は、 filter, length, limitのように、プログラミングに使うには意味があいまいなものが多い。 名前を決める前に、誤解される可能性について考慮する。

第4章「美しさ」

優れたソースコードは「目に優しい」ものでなければならない。本章では、コードを読みやすくするための余白・配置・順序について説明する。

  • 読み手が慣れているパターンと一貫性のあるレイアウトを使う。
  • 似ているコードは似ているように見せる。
  • 関連するコードをまとめてブロックにする。

なぜ美しさが大切なのか?

見た目が美しいコードの方が読みやすいのは明らかだ さっと流し読みができれば、だれにとっても使いやすいコードだといえるだろう。

4.1 一貫性のある簡潔な改行位置

適切な改行を入れることにより、「似ているコードは似ているように見える」という原則を守る。

public class PerformanceTester {
    public static final TcpConnectionSimulator wifi = new TcpConnectionSimulator (
        500, /* Kbps */
        80, /* millisecs latency */
        200, /* jitter */
        1 /* packet loss % */);

ソースコードを整形する。

public class PerformanceTester {
    public static final TcpConnectionSimulator tb_fiber = 
        new TcpConnectionSimulator (
            500,   /* Kbps */
            80,    /* millisecs latency */
            200,   /* jitter */
            1      /* packet loss % */);

より簡潔にするように、コメントを上位に書いて下位の引数を並べるようにする。

public class PerformanceTester {
   // TcpConnectionSimulator (throughtput, latency, jitter, packet_loss)
   //                            [Kbps]     [ms]     [ms]   [percent]
   public static final TcpConnectionSimulator wifi = 
       new TcpConnectionSimulator (500,   80,  200, 1);
   public static final TcpConnectionSimulator t3_fiber =
       new TcpConnectionSimulator (45000, 10,  0,   0);
   public static final TcpConnectionSimulator cell = 
       new TcpConnectionSimulator (100,   400, 250, 5);
}

4.3 メソッドを使った整列

見た目が美しくないコードや、同じことを何度も書いているコードは、ヘルパーメソッドを使って改善する。

CheckFullName("Doug Adams", "Mr. Douglas Adams", "");
CheckFullName(" Jake Brown,", "Mr. Jake Bron III", "");
CheckFullName("No Such Guy", "", "no match found");
CheckFullName("John", "", "more than one result");
  • 重複を排除することデコードが簡潔になった。
  • テストケースの大切な部分 (名前やエラー文字列)が見やすくなった。
  • テストの追加が簡単になった。

4.4 縦の線をまっすぐにする

縦の線をまっすぐにし、列を「整列」させれば、コードが読みやすくなることがある。

CheckFullName("Doug Adams"  , "Mr. Douglas Adams", "");
CheckFullName(" Jake Brown,", "Mr. Jake Bron III", "");
CheckFullName("No Such Guy" , ""                 , "no match found");
CheckFullName("John"        , ""                 , "more than one result");

wgetのコードでは、利用可能なコマンドラインオプション(100個以上ある)が、以下のように並べられている。

commands[] = {
    ...
    { "timeout",    NULL,              cmd_spec_timeout },
    { "timestamp",  &opt.timestamping, cmd_boolean },
    { "tries",      &opt.ntry,         cmd_number_inf },
    { "useproxy",   &opt.use_proxy,    cmd_boolean },
    { "useragent",  NULL,              cmd_spec_useragent },
    ...
};

整列すべきなのか?

整列することにより、1行変更するだけですべての行を変更しなければならない、差分が増えるという意見があるが、実際にはそこまで手間はかからないはずだ。

4.5 一貫性と意味のある並び

ランダムに並べるのではなく、意味のある順番に並べるのが良い。例えば、

  • 対応するHTMLフォームの\<input>フィールドと同じ並び順にする。
  • 「最重要」なものから重要度順に並べる。
  • アルファベット順に並べる。

4.6 宣言をブロックにまとめる

コードの概要を素早く把握するには、単位を作成する。

メソッドを1つの大きなグループにまとめるのではなく、論理的なグループに分けてあげるのが適切だと思われる。

4.7 コードを「段落」に分割する

文章と同様に、コードも段落に分けるべきである。

# ユーザのメール帳をインポートして、システムのユーザと照合する。
# そして、まだ友達になっていないユーザの一覧を表示する。
def suggest_new_friends (user, email_password):
   friends = user.friends()
   friend_emals = set(f.email for f in friends)
   contacts = import_contacts(user.email, email_password);
   contact_emals = set(c.email for c in contacts)
   non_friend_emails = contact_emals - friend_emails
   suggested_friends = USer.objects.select(email__in=non_friend_emails)
   display['user'] = user
   display['friends'] = friends
   display['suggested_friends'] = suggested_friends
   return render("suggested_friends.html", display)

コードを分割する。

# ユーザのメール帳をインポートして、システムのユーザと照合する。
# そして、まだ友達になっていないユーザの一覧を表示する。
def suggest_new_friends (user, email_password):
   # ユーザの友達のメールアドレスを取得する。
   friends = user.friends()
   friend_emals = set(f.email for f in friends)
   
   # ユーザのメールアカウントからすべてのメールアドレスをインポートする。
   contacts = import_contacts(user.email, email_password);
   contact_emals = set(c.email for c in contacts)
   
   # まだ友達になっていないユーザを探す。
   non_friend_emails = contact_emals - friend_emails
   suggested_friends = USer.objects.select(email__in=non_friend_emails)

   # それをページに表示する
   display['user'] = user
   display['friends'] = friends
   display['suggested_friends'] = suggested_friends
   return render("suggested_friends.html", display)

4.8 個人的な好みと一貫性

クラスと定義のカッコの位置など、個人的な好みはどちらでもよい。ただし、それを混ぜてしまうと、すごく読みに組み物になってしまう。

プロジェクトの規約に従い、一貫性があった方がプログラムとしては読みやすいものになる。

「リーダブルコード」を読む (「第1章: 理解しやすいコード」「第2章: 名前に情報を埋め込む」)

諸事情で週末はネットワークをあまり使えないので、RISC-Vに関連する調査は中止。 あまりやることが無いので例によって一人読書会をしている。 今回は「リーダブルコード」。名著と呼ばれており、私も一度さっくりと読んだ。 ただし忘れていることもあるし、体系的に学びたいので読み直す。

例によってJupyter Notebookに書いて、スクリーンショットをキャプチャする形で公開していく。

今回は「第1章: 理解しやすいコード」「第2章: 名前に情報を埋め込む」までをまとめた。

まとめるといっても、本書は言いたいことを非常に簡潔に要約しており、ほぼほぼそれを写経したようなものになっているが、まあ自分で手を動かさないと分からないということで。。。

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

https://zrhudq.bn1304.livefilestore.com/y4m8bAtmXdGSh0VXsFlgf80nuyh4YYYHkzzx8LpGsQWB4TNXPHcbnl8b3sf4UWFHTiuVdkUdl3wYahmFNdlNqWMTtH6D450O4gHDzMngTW09GMQiUGVsjRs1oza_bdM4Uuj-Hd-GxXTzgMCDILBqRyiFzA1Wnzp-9mUXooKtO6R0H6WQR4bJK2ofLdXK_q4gfKSVd6c7dLTMrz4HB4ITITcjg?width=1670&height=5053&cropmode=none

Rocket-Chipにおけるコンフィグレーション別の面積比較 (BOOMConfigで同様の合成調査)

前回のRocket Chipの面積比較に続いて、BOOMでも同様のことを実施した。

BOOMはVersion 1とVersion 2があり、それぞれでVerilogを生成してVivadoで合成してみる。

まだ集計できていないが、だいたいの面積の概要は以下のようになっている。BOOM v1の方が少し大きいかなあ。階層構成が違うので少しわかりにくい。

  • BOOM v1
|   RocketTile                        |                     RocketTile |     115065 |     110560 |    4478 |   27 | 43418 |      9 |      8 |           40 |
|     core                            |                       BoomCore |     108816 |     104369 |    4422 |   25 | 38958 |      0 |      0 |           40 |
|     dcache                          |       NonBlockingDCache_dcache |       2723 |       2674 |      48 |    1 |  1460 |      5 |      4 |            0 |
|     dcacheArb                       |              HellaCacheArbiter |          0 |          0 |       0 |    0 |     2 |      0 |      0 |            0 |
|     frontend                        |              Frontend_frontend |       3002 |       2993 |       8 |    1 |  2526 |      4 |      4 |            0 |
|     ptwOpt                          |                            PTW |        524 |        524 |       0 |    0 |   472 |      0 |      0 |            0 |
  • BOOM v2
+----------------------------------------------+------------------------------------+------------+------------+---------+------+-------+--------+--------+--------------+
|                   Instance                   |               Module               | Total LUTs | Logic LUTs | LUTRAMs | SRLs |  FFs  | RAMB36 | RAMB18 | DSP48 Blocks |
+----------------------------------------------+------------------------------------+------------+------------+---------+------+-------+--------+--------+--------------+
|   (Top)                                      |                              (top) |          0 |          0 |       0 |    0 |     0 |      0 |      0 |            0 |
|   tileList_0                                 |                           BOOMTile |     113074 |      99582 |   13470 |   22 | 32276 |      0 |      0 |           40 |
|     PTW_1                                    |                                PTW |        286 |        286 |       0 |    0 |   471 |      0 |      0 |            0 |
|     core                                     |                           BOOMCore |      93773 |      91919 |    1834 |   20 | 26971 |      0 |      0 |           40 |
|     dcArb                                    |                  HellaCacheArbiter |          1 |          1 |       0 |    0 |     2 |      0 |      0 |            0 |
|     dc_shim                                  |                         DCacheShim |        554 |        554 |       0 |    0 |   737 |      0 |      0 |            0 |
|     dcache                                   |                         HellaCache |       9987 |       4086 |    5900 |    1 |  2120 |      0 |      0 |            0 |
|     icache                                   |                           Frontend |       8473 |       2736 |    5736 |    1 |  1975 |      0 |      0 |            0 |
|   uncore                                     |                             Uncore |     196636 |      91747 |  104888 |    1 |  5443 |    128 |      0 |            0 |
|     (uncore)                                 |                             Uncore |          6 |          6 |       0 |    0 |     7 |      0 |      0 |            0 |
|     DebugModule_1                            |                        DebugModule |        300 |        236 |      64 |    0 |   138 |      0 |      0 |            0 |
|     LevelGateway_1_1                         |                       LevelGateway |          0 |          0 |       0 |    0 |     1 |      0 |      0 |            0 |
|     LevelGateway_2                           |                     LevelGateway_0 |          0 |          0 |       0 |    0 |     1 |      0 |      0 |            0 |
|     PLIC_1                                   |                               PLIC |         38 |         38 |       0 |    0 |    42 |      0 |      0 |            0 |
|     PRCI_1                                   |                               PRCI |        205 |        205 |       0 |    0 |   210 |      0 |      0 |            0 |
|     ROMSlave_1                               |                           ROMSlave |        169 |        169 |       0 |    0 |    14 |      0 |      0 |            0 |
|     TileLinkRecursiveInterconnect_2          |      TileLinkRecursiveInterconnect |         52 |         52 |       0 |    0 |     7 |      0 |      0 |            0 |
|     outmemsys                                |                  OuterMemorySystem |     195866 |      91041 |  104824 |    1 |  5023 |    128 |      0 |            0 |

BOOM v2の合成結果の階層表示。

f:id:msyksphinz:20171117025701p:plain

Rocket-Chipにおけるコンフィグレーション別の面積比較 (BlockRAMを推論させる方法調査)

前回のRocket Chipの標準論理合成では、FPGA向けにVivadoで合成してもBlockRAMが正常に推論されず、Dcacheが面積のほとんどを消費してしまう構成になってしまっていた。

msyksphinz.hatenablog.com

どうにかしてBlockRAMを使うように変更することはできないだろうか。 そもそも、なぜSRAMの部分がLUTで作られてしまうかというと、Rocket Chipの標準フローで合成すると、ASIC用にSRAMは外部定義に変更される。 rocket-chip/emulator/freechips.rocketchip.system.DefaultConfig.behav_srams.v というのがそれだ。 ASICを作る場合は、このモジュールを各プロセスに対応するSRAMに置き換える。 ただしこれは標準的なSRAMのように、WMEMのようなビット単位のWrite Maskが付いているSRAMを前提としており、BlockRAMを推論するのには不向きな構成になっている。

module data_arrays_0_ext(
  input RW0_clk,
  input [8:0] RW0_addr,
  input RW0_en,
  input RW0_wmode,
  input [31:0] RW0_wmask,
  input [255:0] RW0_wdata,
  output [255:0] RW0_rdata
);

  reg reg_RW0_ren;
  reg [8:0] reg_RW0_addr;
  reg [255:0] ram [511:0];
  `ifdef RANDOMIZE_MEM_INIT
    integer initvar;
    initial begin
...
  always @(posedge RW0_clk)
    if (RW0_en && RW0_wmode) begin
      if (RW0_wmask[0]) ram[RW0_addr][7:0] <= RW0_wdata[7:0];
      if (RW0_wmask[1]) ram[RW0_addr][15:8] <= RW0_wdata[15:8];
      if (RW0_wmask[2]) ram[RW0_addr][23:16] <= RW0_wdata[23:16];
      if (RW0_wmask[3]) ram[RW0_addr][31:24] <= RW0_wdata[31:24];
      if (RW0_wmask[4]) ram[RW0_addr][39:32] <= RW0_wdata[39:32];
      if (RW0_wmask[5]) ram[RW0_addr][47:40] <= RW0_wdata[47:40];
      if (RW0_wmask[6]) ram[RW0_addr][55:48] <= RW0_wdata[55:48];

そこでどうにかしてこの外部SRAM向けのWrapperが生成されるのを防がなければならないのだが、SiFive社の提供するFreedom環境ではSRAM Wrapperは生成されていない。どうやっているんだろう。

いろいろ調査した結果、SRAM Wrapperを作らない方法としては、FIRRTLでのVerilogファイルを生成する際、--repl-seq-mem を付加しないことがポイントなのではないかと思えてきた。

  • rocket-chip/emulator/Makefrag-verilator の抜粋
%.v: %.fir $(FIRRTL_JAR)
    echo $(FIRRTL)
    mkdir -p $(dir $@)
    $(FIRRTL) $(patsubst %,-i %,$(filter %.fir,$^)) -o $*.v -X verilog --infer-rw $(MODEL) --repl-seq-mem -c:$(MODEL):-o:$*.conf -faf $*.anno -ffaaf
  • freedom/common.mk の抜粋
$(verilog): $(firrtl) $(FIRRTL_JAR)
    $(FIRRTL) -i $(firrtl) -o $@ -X verilog

したがって、Rocket-Chipのリポジトリ内の Makefrag-verilatorを以下のように改造した。これでfreechips.rocketchip.system.DefaultConfig.vを再生成すると、外部SRAM Wrapperを生成しなくなっていた。成功だ!

diff --git a/emulator/Makefrag-verilator b/emulator/Makefrag-verilator
index 021e131..86fdea6 100644
--- a/emulator/Makefrag-verilator
+++ b/emulator/Makefrag-verilator
@@ -3,8 +3,9 @@
 #--------------------------------------------------------------------
 firrtl = $(generated_dir)/$(long_name).fir
 verilog = \
-  $(generated_dir)/$(long_name).v \
-  $(generated_dir)/$(long_name).behav_srams.v \
+  $(generated_dir)/$(long_name).v
+
+# $(generated_dir)/$(long_name).behav_srams.v \

 .SECONDARY: $(firrtl) $(verilog)

@@ -12,9 +13,12 @@ $(generated_dir)/%.fir $(generated_dir)/%.d: $(FIRRTL_JAR) $(chisel_srcs) $(boot
        mkdir -p $(dir $@)
        cd $(base_dir) && $(SBT) "run-main $(PROJECT).Generator $(generated_dir) $(PROJECT) $(MODEL) $(CFG_PROJECT) $(CONFIG)"

-%.v %.conf: %.fir $(FIRRTL_JAR)
+%.v: %.fir $(FIRRTL_JAR)
+       echo $(FIRRTL)
        mkdir -p $(dir $@)
-       $(FIRRTL) $(patsubst %,-i %,$(filter %.fir,$^)) -o $*.v -X verilog --infer-rw $(MODEL) --repl-seq-mem -c:$(MODEL):-o:$*.conf -faf $*.anno -ffaaf
+       $(FIRRTL) $(patsubst %,-i %,$(filter %.fir,$^)) -o $*.v -X verilog
+
+#   $(FIRRTL) $(patsubst %,-i %,$(filter %.fir,$^)) -o $*.v -X verilog --infer-rw $(MODEL) --repl-seq-mem -c:$(MODEL):-o:$*.conf -faf $*.anno -ffaaf

freechips.rocketchip.system.DefaultConfig.v をVivadoで合成し、Utilizationを出力させてみた。よっしゃ!しっかりBlockRAMが使われている!

+---------------------------------------+----------------------------+------------+------------+---------+------+-------+--------+--------+--------------+
|                Instance               |           Module           | Total LUTs | Logic LUTs | LUTRAMs | SRLs |  FFs  | RAMB36 | RAMB18 | DSP48 Blocks |
+---------------------------------------+----------------------------+------------+------------+---------+------+-------+--------+--------+--------------+
|     dcache                            |              DCache_dcache |       2585 |       2584 |       0 |    1 |  2577 |      0 |     36 |            0 |
|       (dcache)                        |              DCache_dcache |        898 |        897 |       0 |    1 |   536 |      0 |      4 |            0 |
|       data                            |            DCacheDataArray |        324 |        324 |       0 |    0 |     0 |      0 |     32 |            0 |
|       tlb                             |                        TLB |       1363 |       1363 |       0 |    0 |  2041 |      0 |      0 |            0 |

合成結果の効果は見ての通りだ。BlockRAMを活用したことで、しっかり面積が削減できている。

これで、公平な評価が取れそうだな。

f:id:msyksphinz:20171116023808p:plain

「GPUを支える技術」を読了

Hisa Ando氏の「GPUを支える技術」を、とりあえず読了した。最後の方はだいぶ適当に省略してしまったが、メインの部分はかなりちゃんと読み込んだと思う。

GPUの基礎を分かっていない私にとって、一から解説してくれる良い本だった。詳細までは触れることはないが、全般的な技術の概要をイラストや写真を使って分かりやすく解説してくれる。

これ以降、GPUのニュース記事やネット上の解説記事を読んで、「???この用語の意味が分からない」となっても、この本を読み直せばきちんと理解できる気がする。 そんな感じの、GPUの辞典として使うことが出来るのではないか。とりあえず、良本として保管。

次は何の本を読もうかな。

GPUを支える技術 ――超並列ハードウェアの快進撃[技術基礎] (WEB+DB PRESS plus)

GPUを支える技術 ――超並列ハードウェアの快進撃[技術基礎] (WEB+DB PRESS plus)

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

Verilog-HDLで記述されたオープンソースのハードウェアライブラリ"BaseJump"

HotChips29 で発表された、学生が開発したRISC-V SoC ”Celerity”について資料を読んだ。

news.mynavi.jp

Celerityは学生の作ったRISC-Vのメニーコアチップで、4大学が共同して9か月で作成したチップとなっている。

9か月という短期間で作るための秘訣として、

  • 再利用
  • モジュール化設計
    • 部品レベルで設計を最適化し、ツールの処理時間を短くするため階層化設計を行った。
    • 詳細な中身を知らなくても利用できるブラックボックス設計を行った。
  • 自動化設計
    • 実装とテストのフローを抽象化して、色々な設計に適用できるようにした。
    • 確認済みのIPコンポーネントを利用し、インテグレーションのテストだけで済むようにした。
    • ハイレベル合成ツールを使用した。
    • アナログ設計が行われていた部分についてもディジタル設計のフローを使うようにした。

ということらしい。

BaseJump: Components for Open Source Hardware

この中で注目したのは、”BaseJump”とよばれるオープンソースのハードウェア部品を使ったということ。

BaseJumpは、オープンソースなハードウェアコンポーネントで誰でも使用することが出来る。 また、ホームページを見てみるとBGAパッケージも開発されており、これらもコンポーネント化されているのだろうか。

System Verilog のハードウェアコンポーネントは、BaseJump STLとして以下のBitbucketのページにまとめられている。

bitbucket.org

中身を見てみると、NoCのようなネットワークルータの部品から、標準的なMuxや非同期FIFOなど、一通りの部品はそろっている。かなり有用そうだ。

オープンソースのハードウェアコンポーネントというと、ParallelaのOH!が有名だが、こちらよりも部品点数は多いのではないだろうか?

github.com