2
Help us understand the problem. What are the problem?

posted at

updated at

[RgGen] 独自のビットフィールド型を扱えるようにする

[RgGen] 独自のビットフィールド型を扱えるようにする

はじめに

前回の記事では RgGen の紹介をしました。今回は、独自のビットフィールド型を扱えるようにするために、RgGen の拡張方法について説明します。

例題のビットフィールド型の仕様

例題のとして、カウント機能を持つ counter ビットフィールド型を追加してきます。仕様は以下の通りです。

  • 型名は counter
  • 入力 i_up がアサートされたら、カウント値を +1 する
  • 入力 i_down がアサートされたら、カウント値を -1 する
  • 入力 i_clear がアサートされたら、カウント値を初期化する
    • i_clear の代わりに、同一レジスタブロック内のビットフィールド(参照ビットフィールド)を用いることも出来る
  • 書き込みがあった場合、書き込みデータをカウント値に設定する
  • 現在のカウント値は、読み出しデータとして読み出すことが出来る

プラグインプロジェクトの作成

プラグインを作成し、読み込ませることで、RgGen に独自の拡張を追加すること出来ます。テンプレートが GitHub 上にあるので、テンプレートを元にプラグインプロジェクトを作成します。

テンプレート (https://github.com/rggen/rggen-plugin-template) を元にリポジトリを作成するか、ZIP でコピーするなどして、プロジェクトテンプレートをコピーします。

  • テンプレートを元にリポジトリを作成する
    project_template.png
  • ZIP としてコピーする
    copy_by_zip.png

本稿では、プラグインの名前を rggen-my-plugin とします。プラグイン名に合わせて、以下のファイルを変更します。

  • lib/rggen/plugin_template.rb
    • ファイル名を lib/rggen/my_plugin.rb に変更
    • 以下の置換を実施
      • PluginTemplate -> MyPlugin
      • rggen-plugin-template -> rggen-my-plugin
      • plugin_template -> my_plugin
  • lib/rggen/plugin_template
    • ディレクトリ名を lib/rggen/my_plugin に変更
  • lib/rggen/my_plugin/version.rb
    • 以下の置換を実施
      • PluginTemplate -> MyPlugin

変更したプラグインを RgGen に読み込ませられるか確認します。以下の方法で lib/rggen/my_plugin.rb へのパスを指定します。

  • 実行オプション --plugin で指定する
  • 環境変数 RGGEN_PLUGINS にパスを追加する

lib/rggen/my_plugin.rb へのパスの指定は、絶対パスで指定するか、相対パスの場合は、カレントディレクトリを含めるようにしてください。

実行オプション --verbose-version を付けて、プラグインも含めたバージョンの詳細情報を表示させてみます。

$ rggen --plugin ./lib/rggen/my_plugin.rb --verbose-version

または

$ export RGGEN_PLUGINS=`pwd`/lib/rggen/my_plugin.rb:${RGGEN_PLUGINS}
$ rggen --verbose-version

以下のように、バージョン情報に rggen-my-plugin の表示があれば、成功です。

$ rggen --verbose-version
RgGen 0.27
  - rggen-core 0.27.0
  - rggen-default-register-map 0.27.0
  - rggen-sv-rtl 0.27.0
  - rggen-sv-ral 0.27.0
  - rggen-c-header 0.2.0
  - rggen-markdown 0.23.0
  - rggen-spreadsheet-loader 0.22.0
  - rggen-my-plugin 0.1.0

実行時に --print-backtrace を追加すると、エラー発生時にバックトレースを表示させることできます(デフォルトは未表示)。エラーが出る場合は、バックトレースから問題箇所を特定し、エラーを修正しましょう。

$ rggen --verbose-version --plugin ./lib/rggen/my_plugin.rb --print-backtrace
[NameError] uninitialized constant RgGen::MyPlugIn

  plugin.version RgGen::MyPlugIn::VERSION
                      ^^^^^^^^^^
Did you mean?  RgGen::MyPlugin
backtrace:
    /home/taichi/workspace/rggen/rggen-sample-plugin-2/lib/rggen/my_plugin.rb:6:in `block in <top (required)>'
    /opt/rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rggen-core-0.27.0/lib/rggen/core/builder/plugin_spec.rb:12:in `initialize'
    /opt/rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rggen-core-0.27.0/lib/rggen/core/builder/plugin_manager.rb:87:in `new'
    /opt/rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rggen-core-0.27.0/lib/rggen/core/builder/plugin_manager.rb:87:in `setup_plugin'
    /opt/rbenv/versions/3.1.0/lib/ruby/3.1.0/forwardable.rb:238:in `setup_plugin'
    /opt/rbenv/versions/3.1.0/lib/ruby/3.1.0/forwardable.rb:238:in `setup_plugin'
    /home/taichi/workspace/rggen/rggen-sample-plugin-2/lib/rggen/my_plugin.rb:5:in `<top (required)>'
    <internal:/opt/rbenv/versions/3.1.0/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
    <internal:/opt/rbenv/versions/3.1.0/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
    /opt/rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rggen-core-0.27.0/lib/rggen/core/builder/plugin_manager.rb:109:in `read_plugin_file'
    /opt/rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rggen-core-0.27.0/lib/rggen/core/builder/plugin_manager.rb:76:in `load_plugin'
    /opt/rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rggen-core-0.27.0/lib/rggen/core/builder/plugin_manager.rb:82:in `block in load_plugins'
    /opt/rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rggen-core-0.27.0/lib/rggen/core/builder/plugin_manager.rb:82:in `each'
    /opt/rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rggen-core-0.27.0/lib/rggen/core/builder/plugin_manager.rb:82:in `load_plugins'
    /opt/rbenv/versions/3.1.0/lib/ruby/3.1.0/forwardable.rb:238:in `load_plugins'
    /opt/rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rggen-core-0.27.0/lib/rggen/core/printers.rb:30:in `load_plugins'
    /opt/rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rggen-core-0.27.0/lib/rggen/core/printers.rb:21:in `run'
    /opt/rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rggen-core-0.27.0/lib/rggen/core/cli.rb:16:in `run'
    /opt/rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rggen-core-0.27.0/exe/rggen:9:in `<top (required)>'
    /opt/rbenv/versions/3.1.0/bin/rggen:25:in `load'
    /opt/rbenv/versions/3.1.0/bin/rggen:25:in `<main>'

また、サンプルのレジスタマップも準備しておきます。以下のレジスタマップを、sample ディレクトリに置いておきます。

sample.yaml
- register_block:
  - name: sample
    byte_size:  256

########################################################################
  - register:
    - name: register_0
      offset_address: 0x00
      bit_fields:
      - { name: bit_field_0, bit_assignment: { lsb: 0, width: 4 }, type: counter, initial_value: 0 }
      - { name: bit_field_1, bit_assignment: { lsb: 8, width: 4 }, type: counter, initial_value: 0, reference: register_2.bit_field_0 }

########################################################################
  - register:
    - name: register_1
      offset_address: 0x04
      size: [2, 2]
      bit_fields:
      - { name: bit_field_0, bit_assignment: { lsb: 0, width: 4, sequence_size: 4, step: 8 }, type: counter, initial_value: 0 }

########################################################################
  - register:
    - name: register_2
      offset_address: 0x18
      bit_fields:
      - { name: bit_field_0, bit_assignment: { lsb: 0, width: 1 }, type: w1trg }

counter 型は未追加なので、読み込んでも、エラーになります。

$ rggen --plugin ./lib/rggen/my_plugin.rb --load-only ./sample/sample.yaml 
[RegisterMapError] unknown bit field type: "counter" -- ./sample/sample.yaml

ここまでの変更内容は、以下で確認できます。
https://github.com/rggen/rggen-sample-plugin/commit/497b3175f05a6faede0ed4174f0f244ce4fcff0c

counter 型の追加

ビットフィールド型を追加するには、RgGen.define_list_item_feature メソッドを使用します。メソッドに与えるブロック (do - end/{ - } で囲まれたコード片) 内に、追加するビットフィールドの特性や、コード生成論理を記述していきます。

lib/rggen/my_plugin/bit_field/type ディレクトリにサンプル (foo.rb) があるので、これを counter.rb に改名します。define_list_item_feature メソッドの末尾の引数が型名なので、:foo から :counter に変更します。

counter.rb(抜粋)
RgGen.define_list_item_feature(:bit_field, :type, :counter) do
  # 以下省略
end

lib/rggen/my_plugin.rb にある plugin.files にファイルのパス (my_plugin.rb がある場所からの相対パス) を追加します。これで追加した counter.rb が読み込まれます。

my_plugin.rb(抜粋)
RgGen.setup_plugin :'rggen-my-plugin' do |plugin|
  plugin.version RgGen::MyPlugin::VERSION
  plugin.files [
    'my_plugin/bit_field/type/counter'
  ]
end

ここで、サンプルのレジスタマップを読み込んでみます。--load-only を追加すれば、レジスタマップの読み込みのみを行います。couner 型が追加されたので、エラーなくレジスタマップを読み込むことが出来ます。

$ rggen --plugin ./lib/rggen/my_plugin.rb --load-only sample/sample.yaml

ここまでの変更内容は、以下で確認できます。
https://github.com/rggen/rggen-sample-plugin/commit/3866efcb21c8ce60d4a97af3b0be502744cda797

ビットフィードの特性を記述する

RgGen.define_list_item_feature 内の register_map 内に、ビットフィールド特性を記述してきます。記述するための API が定義されていて、これらを使ってビットフィールドの特性を記述します。定義されている API は以下のとおりです。

  • read_write/read_only/write_only
    • アクセス属性を指定します
  • volatile/non_volatile
    • ビットフィールドの揮発性を指定します
      • 外部から変更が加えられる可能性の有無を示します
      • RO 型のように、外部から変更される可能性があるものは揮発性 (volatile) です
      • RW 型のように、外部から変更される可能性がないものは不揮発性 (non volatile) です
    • 揮発性の場合は、volatile を、不揮発性の場合は non_volatile を使用します
    • 既定値は volatile です
    • UVM RAL モデルの生成時に使用されます
  • initial_value
    • 初期値を必要とするかを、指定します
    • 必要とする場合は、initial_value require: true を指定します
    • 不要な場合は、特に指定する必要はありません
  • reference
    • 参照ビットフィールドを使用するかどうかを指定します
    • 参照ビットフィールドを使う可能性がある場合は、reference use: true を指定します
    • 参照ビットフィールドの使用が必須の場合は、reference use: true, require: true を指定します
    • reference use: true, width: 2 の様に、参照ビットフィールドとして使用するビット幅を指定することが出来ます
      • 幅が未指定の場合は、ビットフィールド幅が、デフォルト値として使用されます
    • 参照ビットフィールドを使わない場合は、特に指定する必要はありません

今回追加する counter 型の場合、

  • 読み書き可能
  • i_up/i_down 等で現在値が変わる
  • 初期値の指定は必要
  • 参照ビットフィールドを i_clear として使用可で、幅は 1 ビット幅

なので、ビットフィールド特性の記述は、以下のようになります。

counter.rb(抜粋)
RgGen.define_list_item_feature(:bit_field, :type, :counter) do
  register_map do
    read_write
    volatile
    initial_value require: true
    reference use: true, width: 1
  end
end

一度、以下のように、サンプルのレジスタマップから初期値の指定を削除してみましょう。

sample.yaml(抜粋)
- name:           register_0
  offset_address: 0x00
  bit_fields:
    - { name: bit_field_0, bit_assignment: { lsb: 0, width: 4 }, type: counter }

初期値の指定が必須なので、以下のようにエラーが起こります。

$ rggen --plugin ./lib/rggen/my_plugin.rb --load-only sample/sample.yaml 
[RegisterMapError] no initial value is given

ここまでの変更内容は、以下で確認できます。
https://github.com/rggen/rggen-sample-plugin/commit/8c1b6eb17be93bb8ff522a2c25dd674867b25353

RTLの生成を実装する

RTLの生成には、

  • 入出力ポートの追加
  • ビットフィールド型を実装したモジュールをインスタンスするコード片の生成

を行う必要があります。RgGen.define_list_item_feature 内の sv_rtl に、これらを実装します。

入出力ポートの追加

生成する RTL に入出力ポートを追加するには、sv_rtl 内で build メソッドを呼び出します。この中に、追加するポートを記述していきます。使用する API は inputoutput で、以下のように使用します。

input :value_in, {
  name: "i_#{fll_name}_value_in", data_type: :logic, width: 1,
  array_size: array_size, array_format: array_port_format
}
  • 第一引数
    • 宣言したポートを RgGen 内で参照する際の名前を指定します。
  • 第二引数
    • 宣言するポートの属性を連想配列を使って記述します。
      • name
        • ポート名を指定します。
        • モジュール中でユニークなポート名を付けてください。
        • ポート名中に #{full_name} を挿入すると、レジスタ名とビットフィールド名を結合させた文字列が反映されます。これを使えばユニークなポート名をつけることが出来ます。
      • data_type
        • ポートのデータ型を指定します。
        • 生成した RTL のポート宣言に、そのまま反映されます。
      • width
        • ポートビット幅を指定します。
        • width: width とすると、ビットフィールドの幅が反映されます。
      • array_size/array_format
        • 配列の大きさと、フォーマットを指定します。
        • 上記の記述の通り残しておいてください。

counter 型のビットフィールドには、

  • i_clear: 1 ビット入力
  • i_up: 1 ビット入力
  • i_down: 1 ビット入力
  • o_count: width ビット出力

があるので、ポート宣言は以下のようになります。

counter.rb(抜粋)
sv_rtl do
  build do
    input :clear, {
      name: "i_#{full_name}_clear", data_type: :logic, width: 1,
      array_size: array_size, array_format: array_port_format
    }
    input :up, {
      name: "i_#{full_name}_up", data_type: :logic, width: 1,
      array_size: array_size, array_format: array_port_format
    }
    input :down, {
      name: "i_#{full_name}_down", data_type: :logic, width: 1,
      array_size: array_size, array_format: array_port_format
    }
    output :count, {
      name: "o_#{full_name}_count", data_type: :logic, width: width,
      array_size: array_size, array_format: array_port_format
    }
  end
end

ただし、

  • 参照ビットフィールドの指定がある場合は、i_clear として使用する

と言う仕様があります。上記の実装では、参照ビットフィールドの有無に関わらず、clear ポートが生成されてしまいます。なので、参照ビットフィールドの指定がある場合は、clear ポートを生成しないようにする必要があります。bit_field.reference? を使えば、参照ビットフィールドの指定の有無を取得できるので、clear ポートの宣言を if 文で囲ってやります。

という訳で、ポート宣言は以下のようになります。

counter.rb(抜粋)
sv_rtl do
  build do
    if !bit_field.reference?
      input :clear, {
        name: "i_#{full_name}_clear", data_type: :logic, width: 1,
        array_size: array_size, array_format: array_port_format
      }
    end
    input :up, {
      name: "i_#{full_name}_up", data_type: :logic, width: 1,
      array_size: array_size, array_format: array_port_format
    }
    input :down, {
      name: "i_#{full_name}_down", data_type: :logic, width: 1,
      array_size: array_size, array_format: array_port_format
    }
    output :count, {
      name: "o_#{full_name}_count", data_type: :logic, width: width,
      array_size: array_size, array_format: array_port_format
    }
  end
end

ビットフィールド型を実装したモジュールをインスタンスするコード片の生成

テンプレートの追加

RgGen では Ruby 標準のテンプレートエンジンである ERB をテンプレートエンジンとして使用しています。モジュールインスタンスを行うコード片を生成するために、ERB でテンプレートを作成します。

まずは、counter 型を実装するモジュールのモジュール名と、パラメータ・入出力の仕様を確認しておきます。

  • モジュール名
    • rggen_bit_field_counter とします。
  • パラメータ
    • WIDTH
      • int 型のパラメータで、カウンターの幅を指定します。
    • INITIAL_VALUE
      • 型が bit [WIDTH-1:0] のパラメータで、カウンターの初期値を指定します。
  • 入出力ポート
    • i_clk/i_rst_n
      • クロックとリセットです。
    • bit_field_if
      • rggen_bit_field_if 型のインターフェースポートです。
      • 書き込みデータ、マスク、読み出しデータなどが、このインターフェースを通じて、やり取りされます。
    • i_clear/i_up/i_down
      • カウンターの制御ポートです。
    • o_count
      • WIDTH 幅の出力ポートで、現在のカウント値を示します。

上記の仕様を元に、ERB を使ってテンプレートを作成します。lib/rggen/my_plugin/bit_field/typecounter.erb を作成します。現時点では、可変な部分 (パラメータ値の上書きやポート接続) は空白としておきます。

counter.erb
rggen_bit_field_counter #(
  .WIDTH          (),
  .INITIAL_VALUE  ()
) u_bit_field (
  .i_clk        (),
  .i_rst_n      (),
  .bit_field_if (),
  .i_clear      (),
  .i_up         (),
  .i_down       (),
  .o_count      ()
);

sv_rtl 中で main_code が呼ばれています。このメソッド呼び出しが、コード片生成を実現しています。from_templete: true が指定されていますが、これは、同一ディレクトリにある、同一ファイル名のテンプレートを処理することを指示しています。(今回の場合は、counter.rb から counter.erb が推定され、テンプレートとして処理される。) テンプレートを処理した結果が、コード片として、生成される RTL に埋め込まれます。

counter.rb(抜粋)
sv_rtl do
  main_code :bit_field, from_template: true
end

ここで、一度、RTL の生成を試行してみます。--enable sv_rtl を指定すると RTL の生成のみ実施します。また、--output DIRECTORY を指定することで、出力ディレクトリを変更することが出来ます。

$ rggen --plugin ./lib/rggen/my_plugin/setup.rb --enable sv_rtl --output out sample/sample.yml

上記を実行すると、out/sample.sv として、生成された RTL が出力されます。ポート接続等は未実装なので、当該箇所が空白のままになっている RTL が生成されます。生成された RTL は以下のリンクで確認できます。
https://github.com/rggen/rggen-sample-plugin/blob/9f990a46463a53438a1832d35b35087d203d63b0/out/sample.sv

ここまでの変更内容は、以下で確認できます。
https://github.com/rggen/rggen-sample-plugin/commit/9f990a46463a53438a1832d35b35087d203d63b0

テンプレートの実装

ERB では、<%=%> で囲まれた部分を、ruby のコード片として、テンプレート処理時に評価し、その結果をテンプレート中に埋め込むことが出来ます。以下の項目が API として準備されています。また、build 中で宣言したポートは、ハンドル名で参照できます。

  • width
    • ビットフィールドの幅を返します。
  • initial_value
    • 初期値を示す SystemVerilog の整数リテラルを返します。
  • clock
    • クロックのポート宣言を返します。
  • reset
    • リセットのポート宣言を返します。
  • bit_field_if
    • rggen_bit_field_if インターフェースのインスタンスを返します。
  • loop_variables
    • ビットフィールドが配列になっている場合、ループ変数 (genvar) の一覧を返します。
    • 配列として宣言したポートで、port[loop_variables] とすると、要素選択された状態の RTL コード片を取得できます。
  • reference_bit_field
    • 参照ビットフィールドが指定されている場合、参照ビットフィールドが持つ値への参照を返します。

これらを用いて、上記で空白に成っていた箇所を埋めていくと、テンプレートは以下のようになります。

counter.erb
rggen_bit_field_counter #(
  .WIDTH          (<%= width %>),
  .INITIAL_VALUE  (<%= initial_value %>)
) u_bit_field (
  .i_clk        (<%= clock %>),
  .i_rst_n      (<%= reset %>),
  .bit_field_if (<%= bit_field_if %>),
  .i_clear      (<%= clear[loop_variables] %>),
  .i_up         (<%= up[loop_variables] %>),
  .i_down       (<%= down[loop_variables] %>),
  .o_count      (<%= count[loop_variables] %>)
);

ここで、一度、RTL の生成を試行してみましょう。以下のように、NameError が出て、RTL の生成に失敗すると思います。

$ rggen --plugin ./lib/rggen/my_plugin.rb --enable sv_rtl --output out sample/sample.yaml 
[NameError] undefined local variable or method `clear' for type:counter(bit_field@sv_rtl):#<Class:0x00007fa3f957f108>
Did you mean?  caller

これは、ビットフィールド register_0.bit_field_1 が、クリア信号として参照ビットフィールドを用いているためです。ですので、clear の代わりに、参照ビットフィールドを i_clear に繋ぐ必要があります。

sv_rtl 内に、

  • 参照ビットフィールドが指定さている場合は、reference_bit_field
  • 参照ビットフィールドが指定されていない場合は、clear[loop_variables]

を返すメッソッド clear_signal を定義し、これをテンプレート内で使うようにします。

counter.rb(抜粋)
sv_rtl do
  def clear_signal
    if bit_field.reference?
      reference_bit_field
    else
      clear[loop_variables]
    end
  end
end
counter.erb
rggen_bit_field_counter #(
  .WIDTH          (<%= width %>),
  .INITIAL_VALUE  (<%= initial_value %>)
) u_bit_field (
  .i_clk        (<%= clock %>),
  .i_rst_n      (<%= reset %>),
  .bit_field_if (<%= bit_field_if %>),
  .i_clear      (<%= clear_signal %>),
  .i_up         (<%= up[loop_variables] %>),
  .i_down       (<%= down[loop_variables] %>),
  .o_count      (<%= count[loop_variables] %>)
);

では、再度、RTL の生成を試行してみましょう。今度は、エラーなく生成できると思います。生成された RTL は以下のリンクから確認できます。
https://github.com/rggen/rggen-sample-plugin/blob/7995b8de694e1c328ebbe1c76390605e3a5396e7/out/sample.sv

ここまでの変更内容は、以下で確認できます。
https://github.com/rggen/rggen-sample-plugin/commit/7995b8de694e1c328ebbe1c76390605e3a5396e7

シミュレーション用モデルの生成を実装する

UVM RAL は、検証フレームワークである UVM の一部で、CSR のシミュレーション用モデルを作るためのクラス郡が提供されています。RgGen では UVM RAL を使ったシミュレーション用モデルを生成することが出来ます。

シミュレーション用モデル生成は RgGen.define_list_item_feature 内の sv_ral に実装してきます。以下に示すメソッドを用いることで、シミュレーション用モデル生成を実装します。

  • access
    • 既存のビットフィールド型で代替する場合に使用します。
    • 代替する型を引数に指定します。
      • access 'RW'
    • UVM で実装されている型は、こちらを参照ください。
  • model_name
    • ビットフィールドを表すクラスを、自身で定義する場合に使用します。
    • 定義したクラス名を引数で指定します。
      • 例: model_name 'rggen_ral_foo_field'

counter 型の場合、ビットフィールドの属性として volatile を指定しているので、既存のビットフィールド型である RW で代替可能です。なので、シミュレーション用モデルの実装は、以下のようになります。

counter.rb(抜粋)
RgGen.define_list_item_feature(:bit_field, :type, :counter) do
  sv_ral do
    access 'RW'
  end
end

シミュレーション用モデルの生成を試行してみます。--enable オプションに sv_ral を追加すると、シミュレーション用モデルも生成することができます。

$ rggen --plugin ./lib/rggen/my_plugin.rb --enable sv_rtl,sv_ral --output out sample/sample.yaml 

シミュレーション用モデルが out/sample_ral_pkg.sv として出力されます。生成されてシミュレーション用モデルは、以下のリンクで確認できます。
https://github.com/rggen/rggen-sample-plugin/blob/22d49b6f9bc604f25b46b2aaae9eae8bd4f8ff2c/out/sample_ral_pkg.sv

RgGen の ruby 側の実装は以上です。ここまでの変更内容は、以下で確認できます。
https://github.com/rggen/rggen-sample-plugin/commit/22d49b6f9bc604f25b46b2aaae9eae8bd4f8ff2c

ビットフィールドモジュールの作成

生成される RTL 中にインスタンスされる、ビットフィールドモジュールを作成していきます。

rggen_bit_field_if の仕様

書き込みデータ、読み出しデータなど、読み書きに必要な情報は、rggen_bit_field_if を通じて、やり取りされます。このインターフェースには、以下の信号が定義されています。

  • valid
    • 所属するレジスタへのアクセスの有無を示します。
    • アクセス1回に付き、1クロック間アサートされます。
    • アクセスが連続する場合は、連続でアサートされます。
  • read_mask
    • 読み出しが行われるビットを示します。
    • アサートされているビットが、読み出されるビットです。
    • valid がアサートされている期間で有効です。
  • write_mask
    • 書き込みが行われるビットを示します。
    • アサートされているビットが、書き込みされるビットです。
    • valid がアサートされている期間で有効です。
  • write_data
    • 書き込みデータです。
    • valid がアサートされている期間で有効です。
  • read_data
    • 読み出しデータです。
    • この値が読み出しデータのセレクタに伝搬します。
  • value
    • 参照ビットフィールドとして、他のビットフィールドから参照されます。
    • 通常は read_data をドライブします。
    • read_data がマスクされていて、生のデータを参照したい場合などは、所望の値をドライブします。

ビットフィールドから見た、入出力は以下の通りです。

Name In/Out
valid in
read_mask in
write_mask in
write_data in
read_data out
value out

アクセス例

rggen_bit_field_if.png

  1. read_datarm0 が、write_mask に 0 がドライブされているので、読み出しアクセスです。
  2. read_data に 0 が、write_maskwm0 がドライブされているので、読み出しアクセスです。
  3. 読み出しと、書き込みが連続で行われています。

counter モジュールの実装

counter 型用のビットフィールドモジュールを実装していきます。モジュール名は rggen_bit_field_counter とし、パラメータや、入出力などの仕様は以下のとおりです。

  • パラメータ
    • WIDTH
      • カウンターの幅を示します。
      • 型は int とします。
    • INITIAL_VALUE
      • カウンターの初期値です。
      • 型は bit [WIDTH-1:0] です。
  • 入出力ポート
    • i_clk
      • クロックです。
    • i_rst_n
      • リセットです。
      • 0 でリセットがかかります。
    • bit_field_if
      • rggen_bit_field_if が接続されます。
    • i_clear
      • アサートで、カウント値が初期値 (INITIAL_VALUE) に戻ります。
    • i_up
      • アサートで、カウント値が +1 されます。
    • i_down
      • アサートで、カウント値が -1 されます。
    • o_count
      • 現在の、カウント値を示します。

本モジュールでは、read_data にマスクをかけるなどの操作は特にしないので、value には、カウント値をそのままドライブします。また、書き込みアクセスがあった場合は、書き込みデータをカウント値とするので、rggen_bit_field_counter の実装は以下のようになります。
https://github.com/rggen/rggen-sample-plugin/blob/dc6a453ceb49b52feda270e9002d756c1be5a99d/sv_rtl/rggen_bit_field_counter.sv

最後に

デフォルトの実装も、上述する方法で実装されているので、独自ビットフィールドを追加する際の参考になると思います。

質問などありましたら、コメントやメールなど、お気軽にご連絡ください :smile:

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
2
Help us understand the problem. What are the problem?