FPGA開発日記

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

MLIRについての勉強 (チュートリアルをベースとした自作言語作成)

MLIRはMulti Level Intermediate Representationの略で、LLVM IRよりも更にメタ化したような中間言語だ。LLVM IRでは吸収しきれないような各言語で定義される中間表現を、許容するために開発された。

これを使ってみたいので、まずはToyに似たような言語を使って自分でMLIRを生成できるようになりたい。いくつか試行をしている。

MYSVというVerilogに等価な言語を作って、まずはそれをParseしてDumpできるようにする。これまMLIRを生成する前段階だ。

 assign A = 0;
 assign Hoge = 2;

ASTは簡単なものを作って、AST.hを作成する。classofを作成しないと、クラスの動的な処理?が入るらしくコンパイルできない。

RTTI、つまり実行時型情報、の対応だな(よく分かっていない)。

llvm.org

 /// Base class for all expression nodes.                                                                                                                                                                                                                                                                        
 class ExprAST {
  public:
   enum ExprASTKind {
     Expr_Assign,
     Expr_Num,
   };

   ExprAST(ExprASTKind kind, Location location)
       : kind(kind), location(std::move(location)) {}
   virtual ~ExprAST() = default;

   ExprASTKind getKind() const { return kind; }

   const Location &loc() { return location; }

  private:
   const ExprASTKind kind;
   Location location;
 };


 /// Expression class for numeric literals like "1".                                                                                                                                                                                                                                                             
 class NumberExprAST : public ExprAST {
   uint64_t val;

  public:
   NumberExprAST(Location loc, uint64_t val)
       : ExprAST(Expr_Num, std::move(loc)), val(val) {}

   uint64_t getValue() { return val; }

   /// LLVM style RTTI                                                                                                                                                                                                                                                                                           
   static bool classof(const ExprAST *c) { return c->getKind() == Expr_Num; }
 };

とりあえず簡単なものなら、ファイルから読み込んで、ダンプできるようになった。

./bin/mysv ../mlir/examples/mysv/test/assign.sv -emit=ast                          
  Module:
    assign A @../mlir/examples/mysv/test/assign.sv:1:1
      0 @../mlir/examples/mysv/test/assign.sv:1:12
    assign Hoge @../mlir/examples/mysv/test/assign.sv:2:1
      2 @../mlir/examples/mysv/test/assign.sv:2:15

GShare分岐予測器で解決すべき問題設定

自作CPUにおいて、GShareb分岐予測器の実装をしようとしている。自分が実装しているものが本当に正しいのか検証したくて、いろいろモデルを作りながらまとめている。そのメモ。


実験

以下のプログラムを考える。要するに、両方の引数が偶数か奇数かで値を設定し、その結果に基づいて比較を行う。

このプログラムでは、3つの分岐命令が使用されている。

  • 引数0の偶数・奇数をチェック
  • 引数1の偶数・奇数をチェック
  • 上記2つの結果が異なっているかをチェック

つまり最後の比較は、上記の2つの比較に大きく依存する形式となっている。

.global branch_count

 branch_count:
     andi    a0, a0, 1
     beqz    a0, .cut_aa
     li      a0, 0
     j       .bb_check
 .cut_aa:
     li      a0, 1

     .bb_check:
     andi    a1, a1, 1
     beqz    a1, .cut_bb
     li      a1, 0
     j       .final_check
 .cut_bb:
     li      a1, 1

 .final_check:
     bne     a0, a1, .ret_true
     li      a0, 0
 .ret_true:
     li      a0, 1
     ret

このbranch_count()を引数のパタンでひたすら回していく。

 int result_count = 0;

 extern int branch_count(int aa, int bb);

 int main ()
 {
   for (int a = 0; a < 10; a++) {
     for (int b = 0; b < 10; b++) {
       if (branch_count (a, b)) {
         result_count ++;
       }
     }
   }

   return 0;
 }

これで、現状において分岐予測の結果をシミュレーションで取得する。

grep 80002014 bru_detail.log                                        
               15778 : (09,2) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 0000000000000000, NotTaken, bim=1, Succ, DASM(0x00b51363)
               16014 : (11,1) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 0000000000000000, Taken   , bim=0, Miss, DASM(0x00b51363)
               16178 : (14,2) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=1, Succ, DASM(0x00b51363)
               16302 : (13,1) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=0, Miss, DASM(0x00b51363)
               16462 : (14,2) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=1, Succ, DASM(0x00b51363)
               16586 : (13,1) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=0, Miss, DASM(0x00b51363)
               16746 : (14,2) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=1, Succ, DASM(0x00b51363)
               16870 : (13,1) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=0, Miss, DASM(0x00b51363)
               17030 : (14,2) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=1, Succ, DASM(0x00b51363)
               17154 : (13,1) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=0, Miss, DASM(0x00b51363)
               17498 : (14,2) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=1, Miss, DASM(0x00b51363)
               17702 : (03,1) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=2, Miss, DASM(0x00b51363)
               17874 : (07,2) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=1, Miss, DASM(0x00b51363)
               18038 : (09,1) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=2, Miss, DASM(0x00b51363)
               18210 : (13,2) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=1, Miss, DASM(0x00b51363)
               18374 : (15,1) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=2, Miss, DASM(0x00b51363)
               18546 : (03,2) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=1, Miss, DASM(0x00b51363)
               18710 : (05,1) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=2, Miss, DASM(0x00b51363)
               18882 : (09,2) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=1, Miss, DASM(0x00b51363)
               19046 : (11,1) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=2, Miss, DASM(0x00b51363)
               19310 : (06,2) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=1, Succ, DASM(0x00b51363)
               19466 : (07,1) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=0, Miss, DASM(0x00b51363)
               19626 : (08,2) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=1, Succ, DASM(0x00b51363)
               19750 : (07,1) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=0, Miss, DASM(0x00b51363)
               19910 : (08,2) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=1, Succ, DASM(0x00b51363)
               20034 : (07,1) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=0, Miss, DASM(0x00b51363)
               20194 : (08,2) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=1, Succ, DASM(0x00b51363)
               20318 : (07,1) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=0, Miss, DASM(0x00b51363)
               20478 : (08,2) pc_vaddr = 0000000080002014, target_addr = 0000000080002018, pred_target_addr = 000000008000201a, NotTaken, bim=1, Succ, DASM(0x00b51363)
               20602 : (07,1) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=0, Miss, DASM(0x00b51363)
               20866 : (01,2) pc_vaddr = 0000000080002014, target_addr = 000000008000201a, pred_target_addr = 000000008000201a, Taken   , bim=1, Miss, DASM(0x00b51363)

TakenとNotTakenが連続で入れ替わるような結果になっている。これを改善していくことになる。

VirtIOのドキュメントを読む (2)

https://blogs.oracle.com/linux/post/introduction-to-virtio

SNS界隈で見つけて、面白そうなので読んでみることにした。

VHostについて

これまではVHostという言葉は登場しなかったが、ここで説明しておく必要がある。

パフォーマンスの問題が発生から出てきた機能。

  • ドライバがホストに物理ハードウェアで何らかの処理を実行するように要求するたびに、QEMUコンテキストスイッチが発生する。
  • データプレーンを別のホストユーザプロセスまたはそのカーネルにオフロードする。
    • これにより、QEMUのプロセスをバイパスし、レイテンシを削減してパフォーマンスを向上させる。
    • パフォーマンスが向上する代わりに、セキュリティ上の問題が発生する可能性がある。
    • 図を見る限り、QEMUを介さずに、ホストのユーザプロセスと直接通信をするということ?
      • VirtIOのバックエンドが不要となるということか。
https://blogs.oracle.com/content/published/api/v1.1/assets/CONT4FCF86F243514632B4117AD41E683DC4/Medium?cb=_cache_2f34&format=jpg&channelToken=3189ef66cf584820b5b19e6b10792d6f
https://blogs.oracle.com/content/published/api/v1.1/assets/CONTAFDE3146FCA448DCBFF0E83C24119D25/Medium?cb=_cache_2f34&format=jpg&channelToken=3189ef66cf584820b5b19e6b10792d6f

QEMUのVirtIO

  • VirtIOデバイスが大まかにどのように機能するかを確認する。
  • 標準のVirtIOデバイスでのVirtQueueとVRingsの機能を確認する。
  • virtio-SCSIが分割されたVirtQueueコンフィグレーションとVIRTIO_VRING_F_EVENT_IDX機能ビットが通信を行っている様子を観察する。

Virtio-SCSI

  • ハードディスクドライブなどの仮想論理ユニットをグループ化するために使用される。
-device virtio-scsi-pci
-device scsi-hd,drive=hd0,bootindex=0
-drive file=/home/qemu-imgs/test.img,if=none,id=hd0

hw/scsi/virtio-scsi.cがデバイスの動作に関する機能を実装している。

  • realizeという意味は、VirtIOデバイスの初期セットアップとコンフィグレーションを示すために使用される。
  • unrealizeという言葉はデバイスを破棄するために使用される。
  • virtio_scsi_common_realize()では、3つのVirtQueueを作成していることが見て取れる。
// In hw/scsi/virtio-scsi.c
void virtio_scsi_common_realize(DeviceState *dev,
                                VirtIOHandleOutput ctrl,
                                VirtIOHandleOutput evt,
                                VirtIOHandleOutput cmd,
                                Error **errp)
{
    ...
    s->ctrl_vq = virtio_add_queue(vdev, s->conf.virtqueue_size, ctrl);
    s->event_vq = virtio_add_queue(vdev, s->conf.virtqueue_size, evt);
    for (i = 0; i < s->conf.num_queues; i++) {
        s->cmd_vqs[i] = virtio_add_queue(vdev, s->conf.virtqueue_size, cmd);
    }
}
  • コントロールVirtQueue (ctrl_vq)
    • virtio-SCSIバイスの起動、シャットダウン、リセットなどのタスク管理機能(TMF)
    • 非同期通知のサブスクライブとクエリ
  • イベントVirtQueue (event_vq)
    • virtio-SCSIに接続されたホストからの情報(イベント)を報告するために使用される
  • コマンド・リクエストVirtQueue (cmd_vqs)
    • 一般的なSCSIトランスポートコマンドに使用される

コマンドVirtQueue

ファイルの読み取りや書き込みなどの一般的なSCSIトランスポートコマンドを扱うためのVirtQueueである。

  • コールバック関数を設定することができる(下記の例ではvirtio_scsi_handle_cmd)
// In hw/scsi/virtio-scsi.c
static void virtio_scsi_device_realize(DeviceState *dev,
                                       Error **errp)
{
    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
    VirtIOSCSI *s = VIRTIO_SCSI(dev);
    Error *err = NULL;

    virtio_scsi_common_realize(dev,
                               virtio_scsi_handle_ctrl,
                               virtio_scsi_handle_event,
                               virtio_scsi_handle_cmd, <----*
                               &err);
    ...
}

// In hw/virtio/virtio.c
VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
                            VirtIOHandleOutput handle_output)
{
    ...

    vdev->vq[i].vring.num = queue_size;
    vdev->vq[i].vring.num_default = queue_size;
    vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN;
    vdev->vq[i].handle_output = handle_output;  // ここの部分
    vdev->vq[i].used_elems = g_malloc0(sizeof(VirtQueueElement)
                                       * queue_size);
    return &vdev->vq[i];
}

virtio_scsi_handle_cmdvirtio_scsi_handle_cmd_vq()のラッパーとなっている。

// In hw/scsi/virtio-scsi.c
// virtio_scci_handle_cmd()の本体
bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
{
    VirtIOSCSIReq *req, *next;
    int ret = 0;
    bool suppress_notifications =
            virtio_queue_get_notification(vq);
    bool progress = false;

    QTAILQ_HEAD(, VirtIOSCSIReq) reqs =
            QTAILQ_HEAD_INITIALIZER(reqs);

    do {
        if (suppress_notifications) {
            virtio_queue_set_notification(vq, 0);
        }
        while ((req = virtio_scsi_pop_req(s, vq))) {
            progress = true;
            ret = virtio_scsi_handle_cmd_req_prepare(s, req);
            if (!ret) {
                QTAILQ_INSERT_TAIL(&reqs, req, next);
            } else if (ret == -EINVAL) {
                /* The device is broken and shouldn't
                   process any request */
                while (!QTAILQ_EMPTY(&reqs)) {
                    ...
                }
            }
        }
        if (suppress_notifications) {
            virtio_queue_set_notification(vq, 1);
        }
    } while (ret != -EINVAL && !virtio_queue_empty(vq));

    QTAILQ_FOREACH_SAFE(req, &reqs, next, next) {
        virtio_scsi_handle_cmd_req_submit(s, req);
    }
    return progress;
}

VirtIOのドキュメントを読む (1)

https://blogs.oracle.com/linux/post/introduction-to-virtio

SNS界隈で見つけて、面白そうなので読んでみることにした。

ポイント

  • 仮想マシンとホストデバイスの抽象化を行うレイヤのこと
  • ホストマシンと仮想マシンでのデバイスの取り扱いには、2つの考え方がある?
  • エミュレーション
    • ソフトウェアによりハードウェアの動作を模倣する
    • ハードウェアが存在していなくても動かすことができる
    • パファーマンスに影響が出る。時間がかかる
  • 仮想化
    • ハードウェアを分割して、ゲストVMが使用できるようにする
    • 共有できるようにする、というイメージ
    • ゲストにとっては、任意のデバイスを使えるようにするわけではなく、仮想化デバイスを使えや、というように認識される、というイメージ
    • パフォーマンスに影響が出にくい。高速。
  • VirtIOのドライバはフロントエンドとバックエンドで構成されている
    • フロントエンド:ゲスト側
      • I/O要求の受け入れ、応答
    • バックエンド:ホスト側
      • ハイパーバイザにより動作する、というイメージ
      • フロントエンドからの要求を受け入れる。
      • 物理ハードウェアで動かす。
      • レスポンスをフロントエンドに返す。
  • 図の例だと、VirtQueueVRingsという機能でフロントエンドとバックエンドが接続されている。
    • これはQEMUの例だと思う。Linuxだとvirtqueueと書いてある。
    • VirtQueueはゲストとホストで共有メモリとなっている。こういうデータ構造。
    • VirtQueueはゲストOSに固有の情報が組まれている?
    • VRingsは転送される実際のデータ構造を含んでいるらしい。
      • 少なくともLinuxの持っているVirtQueueと若干機能が異なる。
      • Descriptor Ring (Descriptor Area)
        • ゲスト → ホストの領域?
        • 物理アドレス・データバッファの長さ・フラグ
        • ドライバのみがリングに追加可能
        • バイスはDescriptor Ringに書き込み可能
      • Available Ring (Driver Area)
        • Descriptor Ringの使用可能な領域の循環配列
      • Used Ring (Device Area)
        • すでに使用されたエントリへのポインタ
    • VRingについて
      • 間接Descriptors, Used Buffer Notification Supression, Packed VirtQueueなど
      • どのデータがゲストとホストで交換されたかを示している。

M1 MacにおけるMLIR向けLLVMビルド手順

以下は単なるメモ:MLIRをビルドするに当たりLLVMのビルドの方法。

M1 MacはARMなので、よく考えたらx86を指定しても意味ないのだった。何も考えずにドキュメントをコピペしていたらハマってしまった。

$ cmake -G Ninja ../llvm -DLLVM_ENABLE_PROJECTS=mlir -DLLVM_BUILD_EXAMPLES=ON -DLLVM_TARGETS_TO_BUILD="host;NVPTX;AMDGPU" -DCMAKE_BUILD_TYPE=Debug -DLLVM_ENABLE_ASSERTIONS=ON
$ ninja

IBM POWER7の論文を読む (5. Instruction Sequencing Unit)

マイクロアーキテクチャに関する論文を読んでいる。今回はIBM POWER7に関する論文。

ieeexplore.ieee.org

続いて命令シーケンスユニット。これはいわゆるフロントエンドから命令完了までを取り扱うユニットのことらしい。


命令シーケンスユニットの役割 (Instruction Sequence Unit)

  • Power7プロセッサはグループ単位で命令をディスパッチする。
  • グループをディスパッチする前に、すべてのグループ内の命令でリソースやリネームが完了している必要がある。
  • 同じスレッドから最大で2つの分岐命令と4つの非分岐命令を持つことができる。
    • 2番目の分岐命令がある場合、それはグループ内での最後の命令となる。
  • レジスタリネーム
  • ロードタグ(LTAG)・ストアタグ(STAG)
    • ロード命令とストア命令のフローを管理する。
    • LTAG
      • ロード命令に割り当てられたLRQ (Load-Reorder-Queue)エントリへのポインタに相当する。
    • STAG
      • ストア命令に割り当てられたSRQ(Store-Reorder-Queue)エントリへのポインタに相当する
    • ストアにおけるデータ命令とSRQのストアアドレス命令のマッチングにも使用される。
    • LRQの物理エントリが解放されると、仮想的なLTAGは、実LTAGに変換される。
    • SRQの物理エントリが解放されると、仮想STAGは実STAGに変換される。
    • 仮想STAG/LTAGは、その後発行キューにおいて実TAGであるとマークされるまで、LSUに発行されない。
  • Power7のエントリ
    • UQ(Unified Issue Queue): 48エントリ
    • BRQ(分岐発行キュー): 12エントリ
    • CRQ: 8エントリ
    • BRQとCRQは、ディスパッチされた命令がキューの先頭に置かれ、その後、キューの一番下に向かってトリクルダウンしていくシフトキューである(インオーダということ?)。
    • BRQ:分岐命令を含むキュー
      • 1サイクル当たり2つの分岐命令を受け取ることができる
    • CRQ: CR論理命令とSPRからの移動命令を含んでいる
      • 1サイクル当たり2命令を受け取り、1命令をIFUに発行する
    • UQ: 48エントリのキュー、24エントリずつ2つに分割されている
      • FXU, LSU, VSU, DFUで実行されるすべての命令が含まれる。
      • 上半分: VMX整数命令を含むFX0, LS0、VS0パイプライン用の命令が含まれる
      • 下半分: DFP, VMX PM, VSU, FX1, LS1, VS1パイプラインの命令が含まれる
      • UQは半分のキューにおいて1サイクル当たり最大で4つの命令を受け取ることができる
      • 64ビットVSUストア命令は、命令ディスパッチ時にアドレス生成(AGEN)とデータ操作に分割され、1サイクルで最大で8つの動作をUQに書き込むことができる。
    • ISUは、命令を追跡して完了させる責任を持っている。
      • ディスパッチ後のすべての命令をトレースするために、Global Completion Table(GCT)を持っている。
      • GCTは20エントリ、最大で120個の命令を管理することができる。
      • グループ内のすべての命令がFinishedとしてマークされ、そのグループが特定のスレッドで最も古い場合、そのグループは完了となる。
  • フラッシュについて
    • コアのフラッシュはISUによって処理される
    • 分岐予測ミス
    • LSアウトオブオーダ実行の失敗
    • コンテキスト同期命令の実行
    • 例外処理
    • 廃棄するグループについて20ビットのマスクにまとめ、フラッシュを管理する。

Linux on RISC-V 2022を読む (3)

SNSで見つけた、Linux on RISC-Vが現状のRISC-Vを非常に端的に説明していて勉強になると思ったので、読んでみることにした。 以下は読書メモ。といってもほぼ一対一に翻訳してしまっている。

前回の続き。最後はQEMUとか評価ボードとか。

kernel-recipes.org

mobile.twitter.com


QEMUによるRISC-Vのエミュレーション

  • RISC-VマシンはQEMUでサポートされている
  • 32ビットおよび64ビットのLinuxカーネルをブート可能
  • 複数のRISC-V開発ボードのマシンコンフィグレーションで、同一のバイナリをブート可能
  • ハイパーバイザとVector拡張をサポート済み

Linuxカーネル内でのRISC-Vサポート

  • Palmer Dabbeltによる最初の実装が2018年にLinux 4.15にマージされた
  • 「まだ小さなコミュニティだが、楽しく、フレンドリーだ」 - Bjorn Topel
  • Palmerはriscv_treeのメンテナンスを継続している
  • linux-riscvメーリングリストで開発が行われている
  • lore.kernel.orgでアーカイブを参照可能
  • IRC: libera.chat 上の#riscv

Linuxに最近追加された機能

  • KVM RISC-Vサポート (Anup Patel) Linux 5.16
    • ハイパーバイザ拡張のためのKVMサポート
  • SBI SRST拡張のサポート (Anup Patel) Linux 5.17
    • SBI SRST (System Reset)拡張をサポートし、システムリセットのためのLinux内の明確なドライバが不要になった。

Linux 5.18でサポートされた新たな機能

  • Sv57ページテーブルサポート (Qinglin Pan)
  • RISC-V Perfサポートの向上 (Atish Patra)
    • Perf on RISC-V: The Past, the Present and the Future
  • RISC-V CPU Idleサポート (Anup Patel)
    • cpuidleとssupendがSBI HSM拡張にてサポートされた
  • RISC-V ISA拡張のフレームワークサポート (Atish Patra)
    • 拡張名が単一文字ではなくなる場合、LinuxRISC-V ISAの文字列を正しくパースすることができなくなる。
    • 複数文字のISA拡張をサポートするための一般的なフレームワークを実装

Linux 5.19に向けて

  • Linux 5.19マージに向けてRISC-Vのパッチのマージウィンドウ
    • ページベースのメモリ属性 (以降で少し説明する)
    • rv32バイナリをrv64システムで動作させる (compat subsystem)
    • kexec_file()のサポート
    • チケットベースのスピンロックをサポートし、qrwlockをサポートする
    • アトミックとXIPのためのクリーンアップと修正

作業中

  • Add vector ISA support (Greentime Hu)
    • Vector 1.0拡張に基づく
    • __riscv_v_stateをサポートし、ベクトルに関連するレジスタをセーブ・リストアできるようにする。
  • RISC-V IPIの拡張 (Anup Patel)
    • RISC-V S-modeソフトウェアはM-modeのランタイムを呼び出してOpenSBIのIPIを呼び出す
    • AIA (advanced interrupt architecture) により、S-modeでもIPIを投げれるようになる。
  • Sstc拡張のサポート (Atish Patra)
    • SBIの呼び出しにはS-modeのタイマ割り込みが必要であり、M-modeのタイマ比較レジスタは不要だった。
    • この結果、カーネルがタイマ割り込みをかけるのに非常に大きなレイテンシが必要であった。
    • 仮想化された環境では、KVMがSBI呼び出しを制御することにより状況は悪化する
    • Sstc拡張では、カーネルがスーパバイザ実行環境(M-mode/HS-mode)を使うことなくプログラムにタイマおよび割り込みの受信ができるようになる。

Linuxディストリビューション: Fedra

  • RISC-Vにおける完全なFedraの体験を提供する
  • Wei Fuによるトーク
  • QEMUおよびRISC-V開発ボードにおけるインストール手順書が提供されている

Linuxディストリビューション: Debian

  • riscv64がDebianにポートされている
  • 95%のパッケージがRISC-Vでビルド済み

Linuxディストリビューション: Ubuntu

  • riscv64がUbuntu 20.04 LTSでサポートされている
  • Ubuntu 22.04がプリインストールされたSD-CardがSiFiveの開発ボードおよびQEMU向けに配布されている
  • Ubuntu 22.04より、サーバインストールイメージがSiFive UnmatchedボードのNVMe向けに配布されている。

その他のLinuxディストリビューション

  • OpenSuSE
    • RISC-VサポートはTumbleweedイメージにていくつかのボードサポートとして開発中
  • Arch Linux
    • RISC-V向けにコアパッケージの95%はビルド済み
  • Gentoo
    • riscv64ステージはGentooダウンロードページにおいてダウンロード可能

OpenEmbeddedとYocto

  • meta-riscv: 一般的なハードウェア向けのBSPによりRISC-Vデバイスをオーバレイする

Buildroot

  • RISC-Vの移植により、BuldRootプロジェクトでRISC-Vがサポートされている
  • “Embedded Linux from Scratch in 45 minutes (on RISC-V)”
    • Michael Opdenacker at FOSDEM 2021
    • ビルドブートを使用してOpenSBI, U-Boot, Linux, Busyboxをビルドする
    • QEMU上でブートする

SiFive Freedom Unleashed

  • 2018年に立ち上がった、最初のLinux起動可能なRISC-V開発ボード
  • Fedra GNOMEデスクトップがRISC-V上で立ち上がった

Microchip PolarFire SoC

  • RISC-VコアはSiFive FU540 SoCを使用している

Kendryte K210

  • RV64GCをサポートした400MHzのコア
  • 8MBのSRAMを持っているが、DRAMはない
  • 14ドルから入手可能
  • Linuxとu-bootがサポートされている
  • Buildrootがサポートされている

Sifive Unmatched

  • SiFive Freedom FU740 SoC
    • 4x U74 RV64GCアプリケーションコア

T-Head Xuantie C910

  • T-Head
  • 高性能RV64GC、最大16コア

AndroidRISC-Vに移植する

T-HeadのRVB-ICE開発ボード

  • ICE SoC 2コアのC910、1.2GHz
  • 4GB LPDDR4, 16GB eMMC

RISC-V Android SIG (Special Interest Group)

  • GitHub organizationである riscv-android-srcに変更が含まれている

T-Head Xuantie C906

  • シングルコア RV64GC, 1.0GHz, 5ステージパイプライン

Allwinner D1 SoC

  • T-HeadのC906コアが使用されている

Allwinner Nezha D1開発ボード