FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

common_cells リポジトリに含まれる stream_モジュールの構成分析 (1. ストリーム・インタフェースについて)

common_cellsライブラリに含まれるstream_から始まるモジュール群の構成について分析する。 これらのモジュールは、ready/validハンド・シェイク・プロトコルを使用したストリームインターフェースを提供する。

github.com

stream_モジュール群では、一般的なハンド・シェイク・プロトコルを採用しており、valid信号(送信側がデータを有効であることを示す)とready信号(受信側がデータを受け取る準備ができていることを示す)の2つの信号により、データ転送のタイミングを制御する。 コードのコメントには「Handshaking rules as defined in the AXI standard」と記載されているが、これはAXI標準で定義されている規則に従っているという意味であり、AXI4専用のプロトコルという意味ではない。

ストリームインターフェースの基本

stream_intf.sv

ストリームモジュール群の基盤となるインターフェース定義である。 一般的なready/validハンド・シェイク・プロトコル(AXI標準でも使用されている)を提供し、カスタマイズ可能なペイロード型を受け付ける。

/// A stream interface with custom payload of type `payload_t`.
/// Handshaking rules as defined in the AXI standard.
interface STREAM_DV #(
  /// Custom payload type.
  parameter type payload_t = logic
)(
  /// Interface clock.
  input logic clk_i
);
  payload_t data;
  logic valid;
  logic ready;

  modport In (
    output ready,
    input valid, data
  );

  modport Out (
    output valid, data,
    input ready
  );

  /// Passive modport for scoreboard and monitors.
  modport Passive (
    input valid, ready, data
  );

  // Make sure that the handshake and payload is stable
  `ifndef COMMON_CELLS_ASSERTS_OFF
  `ASSERT(data_unstable, (valid && !ready |=> $stable(data)), clk_i, 1'b0)
  `ASSERT(valid_unstable, (valid && !ready |=> valid), clk_i, 1'b0)
  `endif
endinterface

InOutPassiveの3つのmodportを提供し、異なる方向の接続や監視用途に対応している。

Payload型の定義方法

stream_intf.svpayload_tパラメータは、ストリームで転送するデータの型を定義する。 SystemVerilogの任意の型を指定でき、以下のような定義方法がある。

  1. 基本的なビットベクトル型

最もシンプルな方法は、固定幅のビットベクトルを指定することである。

// 32ビットのデータ
STREAM_DV #(
  .payload_t (logic [31:0])
) stream_if (
  .clk_i (clk)
);

// または、パラメータを使用
parameter int unsigned DATA_WIDTH = 32;
STREAM_DV #(
  .payload_t (logic [DATA_WIDTH-1:0])
) stream_if (
  .clk_i (clk)
);
  1. 構造体型(struct packed)

複数のフィールドを含むデータを転送する場合は、struct packedを使用する。

typedef struct packed {
  logic [15:0] payload;
  logic [7:0]  index;
  logic        flag;
} payload_t;

STREAM_DV #(
  .payload_t (payload_t)
) stream_if (
  .clk_i (clk)
);