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

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

## はじめに

[前回の記事](https://qiita.com/taichi-ishitani/items/5155b2928b7d85370ae6)では RgGen の紹介をしました。今回は、独自のビットフィールド型を扱えるようにするために、RgGen の拡張方法について説明します。

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

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

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

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

プラグインを作成し、読み込ませることで、RgGen に独自の拡張を追加すること出来ます。[テンプレート](https://github.com/rggen/rggen-plugin-template)が GitHub 上にあるので、テンプレートを元にプラグインプロジェクトを作成します。

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

* テンプレートを元にリポジトリを作成する
![project_template.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144465/b3c19932-82a0-82cd-e475-eb1573f13284.png)
* ZIP としてコピーする
![copy_by_zip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144465/d2ecb4c1-8de8-7cfb-613f-872d02634946.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` ディレクトリに置いておきます。

```yaml: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` に変更します。

```ruby: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` が読み込まれます。

```ruby: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 ビット幅

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

```ruby: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
```

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

```yaml: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 は `input` と `output` で、以下のように使用します。

```ruby
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` ビット出力

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

```ruby: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` 文で囲ってやります。

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

```ruby: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**](https://magazine.rubyist.net/articles/0017/0017-BundledLibraries.html) をテンプレートエンジンとして使用しています。モジュールインスタンスを行うコード片を生成するために、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](https://github.com/rggen/rggen-sv-rtl/blob/master/rggen_bit_field_if.sv) 型のインターフェースポートです。
        * 書き込みデータ、マスク、読み出しデータなどが、このインターフェースを通じて、やり取りされます。
    * `i_clear`/`i_up`/`i_down`
        * カウンターの制御ポートです。
    * `o_count`
        * `WIDTH` 幅の出力ポートで、現在のカウント値を示します。

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

```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 に埋め込まれます。

```ruby: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`
    * 参照ビットフィールドが指定されている場合、参照ビットフィールドが持つ値への参照を返します。

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

```erb: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` を定義し、これをテンプレート内で使うようにします。

```ruby:counter.rb(抜粋)
sv_rtl do
  def clear_signal
    if bit_field.reference?
      reference_bit_field
    else
      clear[loop_variables]
    end
  end
end
```

```erb: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](https://www.design-reuse.com/articles/46675/uvm-ral-model-usage-and-application.html) は、検証フレームワークである UVM の一部で、CSR のシミュレーション用モデルを作るためのクラス郡が提供されています。RgGen では UVM RAL を使ったシミュレーション用モデルを生成することが出来ます。

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

* `access`
    * 既存のビットフィールド型で代替する場合に使用します。
    * 代替する型を引数に指定します。
        * `access 'RW'`
    * UVM で実装されている型は、[こちら](https://verificationacademy.com/verification-methodology-reference/uvm/docs_1.2/html/files/reg/uvm_reg_field-svh.html#uvm_reg_field.set_access)を参照ください。
* `model_name`
    * ビットフィールドを表すクラスを、自身で定義する場合に使用します。
    * 定義したクラス名を引数で指定します。
        * 例: `model_name 'rggen_ral_foo_field'`

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

```ruby: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](https://github.com/rggen/rggen-sv-rtl/blob/master/rggen_bit_field_if.sv) を通じて、やり取りされます。このインターフェースには、以下の信号が定義されています。

* valid
    * 所属するレジスタへのアクセスの有無を示します。
    * アクセス１回に付き、１クロック間アサートされます。
    * アクセスが連続する場合は、連続でアサートされます。
* 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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144465/024c65a0-1fc0-0055-a0e6-5a92e41759c6.png)

1. `read_data` に `rm0` が、`write_mask` に 0 がドライブされているので、読み出しアクセスです。
2. `read_data` に 0 が、`write_mask` に `wm0` がドライブされているので、読み出しアクセスです。
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

## 最後に

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

* ビットフィールドの属性
    * https://github.com/rggen/rggen-default-register-map/tree/master/lib/rggen/default_register_map/bit_field/type
* RTL の生成
    * https://github.com/rggen/rggen-systemverilog/tree/master/lib/rggen/systemverilog/rtl/bit_field/type
* シミュレーション用モデルの生成
    * https://github.com/rggen/rggen-systemverilog/tree/master/lib/rggen/systemverilog/ral/bit_field/type

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