以下の内容はhttps://msyksphinz.hatenablog.com/entry/2025/10/27/040000より取得しました。


Common Cellsのaddr_decode_dyncの実装詳細解析:動的設定可能なアドレスデコーダ

github.com

module addr_decode_dync #(
  parameter int unsigned NoIndices = 32'd0,
  parameter int unsigned NoRules   = 32'd0,
  parameter type         addr_t    = logic,
  parameter type         rule_t    = logic,
  parameter bit          Napot     = 0,
  parameter int unsigned IdxWidth  = cf_math_pkg::idx_width(NoIndices),
  parameter type         idx_t     = logic [IdxWidth-1:0]
) (
  input  addr_t               addr_i,
  input  rule_t [NoRules-1:0] addr_map_i,
  output idx_t                idx_o,
  output logic                dec_valid_o,
  output logic                dec_error_o,
  input  logic                en_default_idx_i,
  input  idx_t                default_idx_i,
  input  logic                config_ongoing_i
);

基本的な設計方針としては、入力アドレスaddr_iを複数のルールaddr_map_i[NoRules-1:0]と順次比較し、マッチしたルールのインデックスを出力する。

NoIndices で出力先のインデックスを示し NoRules でルールの数を示す (このパラメータが別々に用意されているのは、複数のルールで1つのインデックスを指定できるようにするためだ)。

config_ongoing_i信号により動的な設定変更中は出力を無効化できる。

通常の範囲比較モード(Napot=0)とNAPOTマスク比較モード(Napot=1)の2つの動作モードをサポートする。

addr_map_irule_t の配列として定義される。 rule_t はデフォルトでは logic 型として定義されているが、これではもちろん動かないので、適切な型を設定する必要がある。 rule_t に搭載されること想定されるメンバは:

  • idx : ルールのインデックスを示す
  • start_addr : 範囲アドレスのスタート位置
  • end_addr : 範囲アドレスの終了位置
  /// typedef struct packed {
  ///   int unsigned idx;
  ///   addr_t       start_addr;
  ///   addr_t       end_addr;
  /// } rule_t;
  ///
  ///  - `idx`:        index of the rule, has to be < `NoIndices`
  ///  - `start_addr`: start address of the range the rule describes, value is included in range
  ///  - `end_addr`:   end address of the range the rule describes, value is NOT included in range
  ///                  if `end_addr == '0` end of address space is assumed

end_addr == 0 に設定すると、最後のアドレスを指定せず、アドレス範囲の最大までが指定されたことになる。

NoRules=3の場合のパラメータと動作

以下の設定例で動作を解析する:

NoIndices = 4
NoRules   = 3
addr_t    = logic[15:0]  (16ビットアドレス)
Napot     = 0  (通常の範囲比較モード)

ルール定義 (rule_t):
addr_map_i[0]: idx=0, start_addr=16'h0000, end_addr=16'h4000  // 16KB
addr_map_i[1]: idx=1, start_addr=16'h4000, end_addr=16'h8000  // 16KB
addr_map_i[2]: idx=2, start_addr=16'h8000, end_addr=16'hC000  // 16KB

内部信号は matched_rules[2:0] で各ルールのマッチング状態を保持する。

アドレスデコードの詳細動作

初期化フェーズ

  always_comb begin
    // default assignments
    matched_rules = '0;
    dec_valid_o   = 1'b0;
    dec_error_o   = (en_default_idx_i) ? 1'b0 : 1'b1;
    idx_o         = (en_default_idx_i) ? default_idx_i : '0;

en_default_idx_iの状態により初期値が変わる。つまり、en_default_idx_i が有効な場合には、すべてのルールに引っかからない場合には default_idx_i が設定され、エラー状態にはならない。

  • en_default_idx_i = 0の場合:
    • dec_error_o = 1 (エラー状態)
    • idx_o = 0
  • en_default_idx_i = 1, default_idx_i = 3の場合:
    • dec_error_o = 0 (エラーなし)
    • idx_o = 3 (デフォルトインデックス)

例1: addr_i = 16'h5000, config_ongoing_i = 1'b0 の場合

  • ループ i=0 (Rule[0]のチェック)
  • ループ0: 条件チェック: !Napot && (addr_i >= addr_map_i[0].start_addr) && ((addr_i < addr_map_i[0].end_addr) || (addr_map_i[0].end_addr == '0))
= !0 && (16'h5000 >= 16'h0000) && (16'h5000 < 16'h4000)
= 1 && 1 && 0
= 0  → マッチせず
  • ループ0: 状態:
matched_rules[0] = 0
dec_valid_o = 0
dec_error_o = 1 (初期値のまま)
idx_o = 0 (初期値のまま)
  • ループ i=1 (Rule[1]のチェック)
  • ループ1: 条件チェック: !Napot && (addr_i >= addr_map_i[1].start_addr) && ((addr_i < addr_map_i[1].end_addr) || (addr_map_i[1].end_addr == '0))
= 1 && (16'h5000 >= 16'h4000) && (16'h5000 < 16'h8000)
= 1 && 1 && 1
= 1  → マッチ!
  • ループ1: マッチング処理:
matched_rules[1] = ~config_ongoing_i = ~0 = 1
dec_valid_o      = ~config_ongoing_i = 1
dec_error_o      = 1'b0
idx_o            = config_ongoing_i ? default_idx_i : idx_t'(addr_map_i[1].idx)
= 0 ? default_idx_i : 1
= 1
  • ループ0: 状態更新:
matched_rules = 3'b010
dec_valid_o = 1
dec_error_o = 0
idx_o = 1
  • ループ i=2 (Rule[2]のチェック)
  • ループ2: 条件チェック:
= 1 && (16'h5000 >= 16'h8000) && (16'h5000 < 16'hC000)
= 1 && 0 && 1
= 0  → マッチせず
  • 状態: 変化なし
  • 最終出力:
matched_rules = 3'b010
dec_valid_o = 1
dec_error_o = 0
idx_o = 1

addr_i = 16'h6000, config_ongoing_i = 1 の場合 (設定変更中)

config_ongoing_i == 1 の場合、 dec_valid_o が強制的に無効化される。

重複するルールがある場合 (優先順位の動作)

forループで順次上書きされるため、配列の後ろ側(インデックスの大きい方)のルールが優先される。

NAPOTモード (Napot=1) の詳細動作

NAPOTモードでは、start_addrがベースアドレス、end_addrがマスクとして機能する。

マッチング条件の詳細

if (
  Napot && (addr_map_i[i].start_addr & addr_map_i[i].end_addr) == (addr_i & addr_map_i[i].end_addr)
) begin

例: NAPOT モードでの 4KB 領域のデコード

addr_map_i[0]: idx=0, base=16'h4000, mask=16'hF000  ← 4KB境界でアライン

addr_i = 16'h4800 の場合:

  • ループ i=0:
  • ループ0: 条件チェック:
Napot && (addr_map_i[0].start_addr & addr_map_i[0].end_addr) == (addr_i & addr_map_i[0].end_addr)
  • ループ0: 計算:
(base & mask)   = 16'h4000 & 16'hF000 = 16'h4000
(addr_i & mask) = 16'h4800 & 16'hF000 = 16'h4000
16'h4000 == 16'h4000  → True, マッチ
  • ループ0: 結果:
matched_rules[0] = 1
dec_valid_o = 1
idx_o = 0

例: NAPOT モードでマッチしない場合

同じルール設定で: addr_i = 16'h5800 の場合:

  • 計算:
(base & mask)   = 16'h4000 & 16'hF000 = 16'h4000
(addr_i & mask) = 16'h5800 & 16'hF000 = 16'h5000
16'h4000 == 16'h5000  → False, マッチせず
  • 結果:
matched_rules[0] = 0
dec_valid_o = 0 (初期値のまま)
idx_o = default_idx_i or 0 (en_default_idx_i による)

アサーションによる検証

1. matched_rulesのワンホット性チェック

`ASSERT_FINAL(more_than_1_bit_set, $onehot0(matched_rules) || config_ongoing_i, "More than one bit set in the one-hot signal, matched_rules")

$onehot0(matched_rules)は、matched_rulesが0個または1個のビットしかセットされていないことを確認する。複数のルールがマッチする場合、警告が出る(ただし動作自体は後のルールが優先される)。

例:

  • matched_rules = 3'b000 → OK (0個)
  • matched_rules = 3'b010 → OK (1個)
  • matched_rules = 3'b011 → NG (2個、警告)

2. start_addr < end_addr のチェック (通常モード)

`ASSUME_I(check_start, Napot || addr_map_i[i].start_addr < addr_map_i[i].end_addr || addr_map_i[i].end_addr == '0, ...)

通常モード(Napot=0)では、start_addr < end_addrまたはend_addr == '0でなければならない。

例:

  • start_addr=16'h4000, end_addr=16'h8000 → OK (0x4000 < 0x8000)
  • start_addr=16'h8000, end_addr=16'h4000 → NG (エラー)

3. インデックスの範囲チェック

`ASSUME_I(check_idx, addr_map_i[i].idx < NoIndices, ...)

すべてのルールのidxNoIndices未満であることを確認。

4. 重複領域の警告 (通常モード)

`A`ASSUME_I(check_overlap, Napot || !((addr_map_i[j].start_addr < addr_map_i[i].end_addr) && (addr_map_i[j].end_addr > addr_map_i[i].start_addr)) || ...)

通常モードで重複する領域がある場合、警告を出す。

例:

  • Rule[0]: [0x4000, 0x8000), Rule[1]: [0x8000, 0xC000) → OK (重複なし)
  • Rule[0]: [0x4000, 0x8000), Rule[1]: [0x6000, 0xA000) → 警告 (重複あり)



以上の内容はhttps://msyksphinz.hatenablog.com/entry/2025/10/27/040000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14