[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 でコピーするなどして、プロジェクトテンプレートをコピーします。
本稿では、プラグインの名前を 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
ディレクトリに置いておきます。
- 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
に変更します。
RgGen.define_list_item_feature(:bit_field, :type, :counter) do
# 以下省略
end
lib/rggen/my_plugin.rb
にある plugin.files
にファイルのパス (my_plugin.rb
がある場所からの相対パス) を追加します。これで追加した counter.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 ビット幅
なので、ビットフィールド特性の記述は、以下のようになります。
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
一度、以下のように、サンプルのレジスタマップから初期値の指定を削除してみましょう。
- 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 は input
と output
で、以下のように使用します。
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
- 配列の大きさと、フォーマットを指定します。
- 上記の記述の通り残しておいてください。
- name
- 宣言するポートの属性を連想配列を使って記述します。
counter
型のビットフィールドには、
-
i_clear
: 1 ビット入力 -
i_up
: 1 ビット入力 -
i_down
: 1 ビット入力 -
o_count
:width
ビット出力
があるので、ポート宣言は以下のようになります。
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
文で囲ってやります。
という訳で、ポート宣言は以下のようになります。
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/type
に 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 に埋め込まれます。
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
- 参照ビットフィールドが指定されている場合、参照ビットフィールドが持つ値への参照を返します。
これらを用いて、上記で空白に成っていた箇所を埋めていくと、テンプレートは以下のようになります。
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
を定義し、これをテンプレート内で使うようにします。
sv_rtl do
def clear_signal
if bit_field.reference?
reference_bit_field
else
clear[loop_variables]
end
end
end
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
で代替可能です。なので、シミュレーション用モデルの実装は、以下のようになります。
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 |
アクセス例
-
read_data
にrm0
が、write_mask
に 0 がドライブされているので、読み出しアクセスです。 -
read_data
に 0 が、write_mask
にwm0
がドライブされているので、読み出しアクセスです。 - 読み出しと、書き込みが連続で行われています。
counter
モジュールの実装
counter
型用のビットフィールドモジュールを実装していきます。モジュール名は rggen_bit_field_counter
とし、パラメータや、入出力などの仕様は以下のとおりです。
- パラメータ
- WIDTH
- カウンターの幅を示します。
- 型は
int
とします。
- INITIAL_VALUE
- カウンターの初期値です。
- 型は
bit [WIDTH-1:0]
です。
- WIDTH
- 入出力ポート
- 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
- 現在の、カウント値を示します。
- i_clk
本モジュールでは、read_data
にマスクをかけるなどの操作は特にしないので、value
には、カウント値をそのままドライブします。また、書き込みアクセスがあった場合は、書き込みデータをカウント値とするので、rggen_bit_field_counter
の実装は以下のようになります。
https://github.com/rggen/rggen-sample-plugin/blob/dc6a453ceb49b52feda270e9002d756c1be5a99d/sv_rtl/rggen_bit_field_counter.sv
最後に
デフォルトの実装も、上述する方法で実装されているので、独自ビットフィールドを追加する際の参考になると思います。
- ビットフィールドの属性
- RTL の生成
- シミュレーション用モデルの生成
質問などありましたら、コメントやメールなど、お気軽にご連絡ください