LoginSignup
1
0

[UVM] PLI なしで Backdoor アクセスを実現する

Last updated at Posted at 2023-12-02

PLI なしで Backdoor アクセスを実現する

石谷 @ PEZY Computing です。 Hardware Description Language Advent Calendar 2023 の3日目と言うことで、今年は、RgGen が生成する UVM RAL モデルのとある機能の解説という誰得な投稿をしようと思います。

はじめに

UVM RAL は CSR への読み書きを抽象化するための仕組みで、アドレスやプロトコルを意識せずに、CSR への読み書きを実行できます。

uart_ral_model.dll.write(status, 'haa);
uart_ral_model.dlm.read(status, value);

UVM RAL には backdoor アクセス と言って、バスアクセスを起こさずに、対象レジスタに値を設定したり、読んだりる機能があります。

uart_ral_model.dll.poke(status, 'haa);  // write に相当
uart_ral_model.dlm.peek(status, value); // read に相当

対象レジスタを直接操作するので、バスアクセスを起こすより、シミュレーション時間を短縮することができます。ただ、既存の実装では、PLI を使った C のプログラムを介して実装されており、PLI の使用は実行時間の増加につながります。

拙作の RgGen が出力する RAL モデルでは、PLI を使わない backdoor アクセスを実現させています。本稿では、どのように実現したかを解説したいと思います。

なぜ PLI を使っているか?

なぜ、既存の実装では、実行時間の悪化を許容してまで、PLI を使って backdoor アクセスを実現させているのでしょうか?
それは、package 内で定義された class からは、以下のように、

tb.dut.u_csr_block.u_dll.value_reg = 'haa;

階層アクセスを用いる事が出来ないためです。そのため、対象レジスタへの階層パスを文字列で指定し、PLI を使って実装された C の関数を SystemVerilog のコー上から呼び出すことで、backdoor アクセスを実現させています。

RgGen での実現方法

方針

module (回路) の世界と class (検証環境) の世界を繋ぐ方法は、

  1. module 中に interface をインスタンスする
  2. interface のインスタンスを virtual interface として、class に渡す
  3. vittual interface を介して、interface 中の信号を操作する

が王道パターンです。RgGen でもこの方法を採用します。RgGen では、RTL も自動生成なので、生成した RTL に、内部信号を制御するための interface を事前にインスタンスしておきます。

RgGen が生成する RTL の構造は、

image.png

のようになっています。
u_register は register 階層の機能を実装していて、

  • CSR バスから来たリクエストをデコードし、配下の bit field に分配する
    • 書き込みマスク、読み出しマスクを生成
  • 配下の bit field が保持する値を纏めて、読み出しデータを作る

を行っています。
u_bit_field は bit field 階層の機能を実現していて、CSR の記憶素子の役割を担っています。

つまり、u_register を乗っ取って、

  • 書き込みデータ、書き込みマスク、読み出しマスクを上書き
  • 纏めた読み出しデータを参照

するための interface をインスタンスし、それの virtual interface を検証環境の世界に渡すことができれば、PLI なしに backdoor アクセスを実現できます。

RTL 側の準備

対象となる CSR ブロックの RTL も自動生成されるので、上記の仕組みを予め仕込んでおくことができます。

register 階層には、rggen_register_common がインスタンスされています。このモジュール中に、rggen_backdoor および rggen_backdoor_if がインスタンスされています。

rggen_backdoor_if には、レジスタアクセスを乗っ取る用の

  • 書き込みデータ
  • 書き込みマスク
  • 読み出しマスク

が宣言されています。これらが有効の際は、バスからのアクセスに代わり、配下の bit_field を更新します。

image.png

また、rggen_backdoor_if に宣言されている読み出しデータには、各 bit field からの読み出しデータが接続されています。

image.png

rggen_backdoor_if には、以下のメソッドが定義されていて、

これらのメソッドを用いて、レジスタアクセスを起こしたり、リードデータを取得したりします。
rggen_backdoor_if は、RTL 中で BFM (Bus Function Model) として機能するようになっています。

検証環境との接続

class からのmodule への階層アクセスは使えないので、rggen_backdoor_if の virtual interface を直接取得することは不可能です。package 中に virtual interface を保持するための変数を宣言し、この変数を介して、module の世界から virtual interface を取り出します。

また、

  • $sformatf("%m") で、これが呼び出された module の階層パスを取得できる
  • 生成された RAL モデルには、すでに階層パスが設定されている

ことから、階層パスの文字列をキーとすることで、virtual interface の受け渡しを簡単に行うことができます。

rggen_backdoor_pkg がそのための package です。この package には、rggen_backdoor_if の virtual interface の連想配列が宣言されています。
RTL 側で $sformatf("%m") をキーにして、この連想配列に rggen_backdoor_if の virtual interface を設定します。

image.png

検証環境側の対応

uvm_reg は register 階層のモデリングを行う class です。この class に、write/read などのレジスタアクセスを行うメソッドが定義されています。また、この class には、以下の backdoor アクセスを行うメソッドが定義されており、

これらのメソッドをオーバーラードして、対応します。

これらのメソッドが呼ばれたら、

  • 設定されている階層パスをキーにして、rggen_backdoor_if の virtual interface を取り出す
  • rggen_backdoor_if 内に定義されているメソッドを呼び出し、レジスタアクセスを起こす

ようになっています。

image.png

image.png

アクセスにもう一階層経由していたり、各シミュレータや言語の差分を吸収するための記述があったりしますが、今回は割愛します。
詳細は、rggen_backdoor_pkgrggen_ral_backdoor_pkg の実装を参照ください。

まとめ

このように、RgGen では、BFM として機能する interface を RTL 中にインスタンスすることで、PLI なしの backdoor アクセスを実現してします。PLI 未使用なので、シミュレーション実行時間への影響が少ない事が利点の1つですが、他ににも利点があります。

まずは、副作用 (write 1 clear/read clear など) も再現できる、と言う点です。bit field から見ると、backdoor アクセスも通常のアクセスも何ら変わりがないからです。 PLI を使った backdoor アクセスでは、値を強制的に上書きしているだけなので、副作用の再現まではできません。

次に、UVM 未使用でも backdoor アクセスを使える、と言う点です。backdoor アクセスを実現している rggen_backdoor_if や rggen_backdoor_pkg は、UVM を使っていません。従来の module ベースの検証環境などからも、backdoor アクセスを行うことができます。

ただ、PLI を使った実装に比べて、以下の欠点があります。

まずは、RTL を検証用に変更している、と言う点です。合成の際は rggen_backdoor_if のインスタンスを作らないようにしているので、検証時と合成時とでは、記述に差分があることになります。なので、これを良しとするかは、使用時に検討が必要になるでしょう。

image.png

次に、書き込みに 1 サイクル分の時間がかかる、と言う点です。副作用の再現を重視して、通常のアクセスと同じようにレジスタアクセスを起こすようになっています。そのため、PLI を使った backdoor アクセスでは 0 時間でアクセスを実行できますが、本実装では 1 サイクル分の時間を要してしまいます (バスモデルからバスアクセスを起こすことに比べれば、短時間ですが。)。アクセスするレジスタの数が多く、シーケンシャルにアクセスを実行する場合に、問題になるかもしれません。

そして、合成後のネットリストに対しては適用できない、と言う点です。PLI を使った場合では、階層パスを適切に設定すれば、合成後のネットリストに対しても backdoor アクセスを実行できます。本実装の場合は、ネットリストは合成ツールが生成する Verilog なので、rggen_backdoor_if をインスタンスしようがありません。

最後に

宣伝です。社内で使っているツールや、共通モジュールなどを公開しています。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0