0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AXI4を理解する

Posted at

目的

AXIを理解する

対象

FPGA初心者の方

目次

AXIプロトコル

AXIプロトコルでは、5つのチャネルが定義されます。
※ここで言う「チャネル」とは、 AXI4のプロトコルレベルで特定の種類のデータを伝送する論理的な経路を言います。
他の方の説明を見ると、「バス」と言っている方もいますが、「バス」はその論理的構造を物理的に実装したものを指す場合が多いです。

2 つは読み出しトランザクションに使用されます。

  • 読み出しアドレス (Address and control)
  • 読み出しデータ (Read data)
    マスターがアドレスを送り付けて、スレーブがデータを返します。

image.png

3 つは書き込みトランザクションに使用されます。

  • 書き込みアドレス (Address and control)
  • 書き込みデータ (Write data)
  • 書き込み応答 (Write response)
    マスターがアドレスとデータを書き込み、スレーブがレスポンスを返します。
    image.png

重要なポイントとして、
5つのチャネルはそれぞれ独立して動作し、それぞれが個別のハンドシェイクを行う必要があります。
※AXIにおいてのハンドシェイクはValid信号とReady信号を用いて行われるものです。
ハンドシェイクについて詳しくはAXIの基礎を理解するをご確認ください。

5つのチャネルが独立して、ハンドシェイクするイメージ図は下記のようなものです。
image.png

AXIの比較

AXI4はAXI-LiteやAXI-Streamと比較して、複雑になりますがパフォーマンスに優れています。
下記にAXI4とAXI-Liteの比較を行っています。

特徴/項目 AXI4 AXI4-Lite
バースト長 最大256ワードのバースト長をサポート 単一ワードトランザクションのみ
データバス幅 最大128バイト(2のべき乗での使用が可能) 32ビットまたは64ビット(全幅を使用)
追加機能(トランザクションID、QoS、ユーザー情報の転送) サポート サポートなし、または制限あり
ロジック規模 大規模なロジックを必要とする 小規模なロジックで済む
使用用途 高機能が必要な場合に使用 シンプルな制御や低機能が必要な場合に使用

Verilog HDL による記述

AXI4のスレーブ側の記述

`timescale 1ns / 1ps
module axi4_slave
(
    input  wire        s_axi_aclk,       // AXIクロック信号
    input  wire        s_axi_aresetn,    // 非同期リセット信号(低アクティブ)

    // 書き込みアドレスチャネルの信号群
    input  wire [2:0]  s_axi_awid,       // 書き込みアドレスID
    input  wire        s_axi_awvalid,    // 書き込みアドレスが有効であることを示す信号
    output reg         s_axi_awready,    // スレーブが書き込みアドレスを受け入れ可能であることを示す信号
    input  wire [23:0] s_axi_awaddr,     // 書き込みアドレス
    input  wire [7:0]  s_axi_awlen,      // 書き込みバーストの長さ
    input  wire [2:0]  s_axi_awsize,     // 書き込みデータのサイズ
    input  wire [1:0]  s_axi_awburst,    // 書き込みバーストタイプ
    input  wire [1:0]  s_axi_awlock,     // ロック信号
    input  wire [3:0]  s_axi_awcache,    // キャッシュ制御信号
    input  wire [2:0]  s_axi_awprot,     // 保護制御信号
    input  wire [3:0]  s_axi_awqos,      // Quality of Service
    input  wire [4:0]  s_axi_awuser,     // ユーザー定義信号
 
    // 書き込みデータチャネルの信号群
    input  wire [2:0]  s_axi_wid,        // 書き込みデータID
    input  wire        s_axi_wvalid,     // 書き込みデータが有効であることを示す信号
    output reg         s_axi_wready,     // スレーブが書き込みデータを受け入れ可能であることを示す信号
    input  wire [31:0] s_axi_wdata,      // 書き込みデータ
    input  wire [3:0]  s_axi_wstrb,      // 書き込みストローブ信号(どのバイトが有効かを示す)
    input  wire        s_axi_wlast,      // 書き込みバーストの最後であることを示す信号

    // 書き込み応答チャネルの信号群
    output reg  [2:0]  s_axi_bid,        // 書き込み応答ID
    output reg         s_axi_bvalid,     // 書き込み応答が有効であることを示す信号
    input  wire        s_axi_bready,     // マスターが書き込み応答を受け入れ可能であることを示す信号
    output reg  [1:0]  s_axi_bresp,      // 書き込み応答ステータス

    // 読み込みアドレスチャネルの信号群
    input  wire [2:0]  s_axi_arid,       // 読み込みアドレスID
    input  wire        s_axi_arvalid,    // 読み込みアドレスが有効であることを示す信号
    output reg         s_axi_arready,    // スレーブが読み込みアドレスを受け入れ可能であることを示す信号
    input  wire [23:0] s_axi_araddr,     // 読み込みアドレス
    input  wire [7:0]  s_axi_arlen,      // 読み込みバーストの長さ
    input  wire [2:0]  s_axi_arsize,     // 読み込みデータのサイズ
    input  wire [1:0]  s_axi_arburst,    // 読み込みバーストタイプ
    input  wire [1:0]  s_axi_arlock,     // ロック信号
    input  wire [3:0]  s_axi_arcache,    // キャッシュ制御信号
    input  wire [2:0]  s_axi_arprot,     // 保護制御信号
    input  wire [3:0]  s_axi_arqos,      // Quality of Service
    input  wire [4:0]  s_axi_aruser,     // ユーザー定義信号

    // 読み込みデータチャネルの信号群
    output reg  [2:0]  s_axi_rid,        // 読み込みデータID
    output reg         s_axi_rvalid,     // 読み込みデータが有効であることを示す信号
    input  wire        s_axi_rready,     // マスターが読み込みデータを受け入れ可能であることを示す信号
    output reg  [31:0] s_axi_rdata,      // 読み込みデータ
    output reg         s_axi_rlast,      // 読み込みバーストの最後であることを示す信号
    output reg  [1:0]  s_axi_rresp       // 読み込み応答ステータス
);

parameter BUSY_SLAVE_TEST = 1;              // スレーブがビジー状態かをテストするためのパラメータ
reg s_axis_aresetn_reg;                     // リセット信号のレジスタ
reg [6:0] memory_address;                   // メモリアドレス
reg [31:0] data_memory [0:127];             // メモリブロックの宣言

reg [23:0] read_address;                    // 読み込みアドレスの保持用レジスタ
reg [23:0] write_address;                   // 書き込みアドレスの保持用レジスタ
reg [31:0] write_data;                      // 書き込みデータの保持用レジスタ
reg        write_assert;                    // 書き込みアサートフラグ
wire       write_address_inrange;           // 書き込みアドレスが有効範囲内かどうかを示す信号
wire       read_address_inrange;            // 読み込みアドレスが有効範囲内かどうかを示す信号
localparam OKAY = 2'b00;                    // 応答が正常な場合のレスポンスコード
localparam DECERR = 2'b11;                  // デコーディングエラーのレスポンスコード
reg [3:0]  timer;                           // タイマー
localparam TIMEOUT = 15;                    // タイムアウト値
reg [7:0]  burst_count;                     // バーストカウント
reg [5:0]  lfsr = 6'b100100;                // 線形フィードバックシフトレジスタ(LFSR)
wire       slave_ready;                     // スレーブが準備完了かどうかを示す信号
reg        slave_was_ready;                 // スレーブが以前に準備完了だったかを示す信号

localparam WRITE_BASE_ADDRESS = 24'h000000; // 書き込み開始アドレス
localparam WRITE_LAST_ADDRESS = 24'h000200; // 書き込み終了アドレス
localparam READ_BASE_ADDRESS  = 24'h000000; // 読み込み開始アドレス
localparam READ_LAST_ADDRESS  = 24'h000200; // 読み込み終了アドレス

// 状態の定義
localparam INIT = 0, WRR_READY = 1, WADDR_ACCEPT = 2, WADDR_INRANGE = 3, WADDR_ERROR = 4,
            WRITE_READY = 5, DATA_WRITE = 6, WMAST_STALL = 7, WSLAVE_STALL = 8,
            WRITE_LAST = 9, WRITE_ERROR = 10,
            BRESP_VALID = 11, BRESP_ACCEPT = 12, BRESP_ERROR = 13,
            RADDR_ACCEPT = 14, RADDR_INRANGE = 15, RADDR_ERROR = 16,
            RDATA_VALID = 17, RMAST_STALL = 18, RSLAVE_STALL = 19,
            RDATA_LAST = 20, RDATA_ERROR = 21;
reg [4:0] state, next_state;               // 状態と次の状態を保持するレジスタ

reg [31:0] control_register;               // コントロールレジスタ
reg [31:0] status_register;                // ステータスレジスタ

// クロック信号の立ち上がりエッジでリセットおよびLFSRの制御を行う
always @(posedge s_axi_aclk)
begin
  s_axis_aresetn_reg <= s_axi_aresetn;
  slave_was_ready <= slave_ready;
  if (s_axi_aresetn == 0)
    lfsr <= 6'b110101;
  else if ((next_state == WRITE_READY) || (next_state == RADDR_INRANGE))
    lfsr[5:4] <= 2'b11;
  else
    lfsr[0] <= lfsr[5] ^ lfsr[4] ^ 1'b1;
    lfsr[5:1] <= lfsr[4:0];
end

// スレーブの準備完了信号をLFSRの値に基づいて決定する
assign slave_ready = BUSY_SLAVE_TEST ? lfsr[5] : 1;

// 状態遷移ロジック
always @(posedge s_axi_aclk)
begin
  s_axis_aresetn_reg <= s_axi_aresetn;
  if (s_axi_aresetn == 0)
    state <= INIT;
  else
    state <= next_state;
end

// 書き込みアドレスが有効範囲内かどうかの判定
assign write_address_inrange = ((write_address >= WRITE_BASE_ADDRESS)
                              && (write_address <= WRITE_LAST_ADDRESS)) ? 1 : 0;

// 読み込みアドレスが有効範囲内かどうかの判定
assign read_address_inrange = ((read_address >= READ_BASE_ADDRESS)
                              && (read_address <= READ_LAST_ADDRESS)) ? 1 : 0;

// 次の状態を決定するための組み合わせ回路
always @(*) begin
  next_state = state;
  case (state)
    INIT:
      next_state = WRR_READY; // 初期化後、準備完了状態へ遷移
    WRR_READY:
      if (s_axi_awvalid == 1)
        next_state = WADDR_ACCEPT; // 書き込みアドレスが有効ならアドレス受け入れ状態へ遷移
      else if (s_axi_arvalid == 1)
        next_state = RADDR_ACCEPT; // 読み込みアドレスが有効ならアドレス受け入れ状態へ遷移
    WADDR_ACCEPT:
      if (write_address_inrange == 1)
        next_state = WADDR_INRANGE; // 書き込みアドレスが範囲内なら次の状態へ
      else
        next_state = WADDR_ERROR; // アドレスが範囲外ならエラー状態へ遷移
    WADDR_INRANGE:
      if (slave_ready == 1)
        next_state = WRITE_READY; // スレーブが準備完了なら書き込み準備状態へ遷移
    WADDR_ERROR:
      next_state = BRESP_VALID; // 書き込みエラー応答を送信
    WRITE_READY:
      if ((s_axi_wvalid == 1) && ((burst_count == 0) || (s_axi_wlast == 1)))
        next_state = WRITE_LAST; // 最後のデータ書き込みへ
      else if ((s_axi_wvalid == 1) && (slave_ready == 1))
        next_state = DATA_WRITE; // データ書き込み状態へ遷移
      else if (timer == TIMEOUT)
        next_state = INIT; // タイムアウトしたら初期化へ遷移
    DATA_WRITE:
      if ((s_axi_wvalid == 1) && (slave_was_ready == 1) && 
          ((burst_count == 0) || s_axi_wlast == 1))
        next_state = WRITE_LAST; // 書き込みが完了したら次の状態へ
      else if (s_axi_wvalid == 0)
        next_state = WMAST_STALL; // マスターが待機状態なら遅延状態へ
      else if ((s_axi_wvalid == 1) && (slave_ready == 0))
        next_state = WSLAVE_STALL; // スレーブがビジーなら遅延状態へ
    WMAST_STALL:
      if ((s_axi_wvalid == 1) && (slave_ready == 1) && 
         ((burst_count == 0) || (s_axi_wlast == 1)))
        next_state = WRITE_LAST; // データ書き込み完了
      else if ((s_axi_wvalid == 1) && (slave_ready == 1))
        next_state = DATA_WRITE; // データ書き込み状態へ遷移
      else if ((s_axi_wvalid == 1) && (slave_ready == 0))
        next_state = WSLAVE_STALL; // スレーブがビジーなら遅延状態へ
      else if (timer == TIMEOUT)
        next_state = WRITE_ERROR; // タイムアウトしたらエラー状態へ
    WSLAVE_STALL:
      if ((s_axi_wvalid == 1) && (slave_ready == 1) && (burst_count == 0))
        next_state = WRITE_LAST; // データ書き込み完了
      else if ((s_axi_wvalid == 1) && (slave_ready == 1))
        next_state = DATA_WRITE; // データ書き込み状態へ遷移
      else if ((s_axi_wvalid == 0) && (slave_ready == 1))
        next_state = WMAST_STALL; // マスターが待機状態なら遅延状態へ
      else if (timer == TIMEOUT)
        next_state = WRITE_ERROR; // タイムアウトしたらエラー状態へ
    WRITE_LAST:
      next_state = BRESP_VALID; // 書き込み応答を送信
    WRITE_ERROR:
      next_state = BRESP_VALID; // 書き込みエラー応答を送信
    BRESP_VALID:
      if (s_axi_bready == 1)
        next_state = BRESP_ACCEPT; // マスターが応答を受け取ったら次の状態へ
      else if (timer == TIMEOUT)
        next_state = INIT; // タイムアウトしたら初期化へ
    BRESP_ACCEPT:
      next_state = INIT; // 応答が受け取られたら初期化へ
    BRESP_ERROR:
      next_state = INIT; // エラーが発生したら初期化へ
    RADDR_ACCEPT:
      if (read_address_inrange == 1)
        next_state = RADDR_INRANGE; // 読み込みアドレスが範囲内なら次の状態へ
      else
        next_state = RADDR_ERROR; // アドレスが範囲外ならエラー状態へ
    RADDR_INRANGE:
      if ((s_axi_rready == 1) && (slave_ready == 1) && (burst_count == 0)) 
        next_state = RDATA_LAST; // データの読み込み完了
      else if ((s_axi_rready == 1) && (slave_ready == 1))
        next_state = RDATA_VALID; // 読み込みデータが有効
      else if ((s_axi_rready == 0) && (slave_ready == 1))
        next_state = RMAST_STALL; // マスターが待機状態なら遅延状態へ
      else if (slave_ready == 0) 
        next_state = RSLAVE_STALL; // スレーブがビジーなら遅延状態へ
      else if (timer == TIMEOUT)
        next_state = RADDR_ERROR; // タイムアウトしたらエラー状態へ
    RADDR_ERROR:
      next_state = INIT; // エラーが発生したら初期化へ
    RDATA_VALID:
      if ((s_axi_rready == 1) && (slave_ready == 1) && (burst_count == 1))
        next_state = RDATA_LAST; // データの読み込み完了
      else if ((s_axi_rready == 1) && (slave_ready == 0))
        next_state = RSLAVE_STALL; // スレーブがビジーなら遅延状態へ
       else if (s_axi_rready == 0)
        next_state = RMAST_STALL; // マスターが待機状態なら遅延状態へ
    RMAST_STALL:
      if ((s_axi_rready == 1) && ( slave_ready == 1) && (burst_count == 1))
        next_state = RDATA_LAST; // データの読み込み完了
      else if ((s_axi_rready == 1) && (slave_ready == 1))
        next_state = RDATA_VALID; // 読み込みデータが有効
      else if ((s_axi_rready == 1) && (slave_ready == 0))
        next_state = RSLAVE_STALL; // スレーブがビジーなら遅延状態へ
      else if (timer == TIMEOUT)
        next_state = RDATA_ERROR; // タイムアウトしたらエラー状態へ
     RSLAVE_STALL:
      if ((s_axi_rready == 1) && (slave_ready == 1) && (burst_count <= 1))
        next_state = RDATA_LAST; // データの読み込み完了
      else if ((s_axi_rready == 1) && (slave_ready == 1))
        next_state = RDATA_VALID; // 読み込みデータが有効
      else if ((s_axi_rready == 1) && (slave_ready == 1))
        next_state = RMAST_STALL; // マスターが待機状態なら遅延状態へ
      else if (timer == TIMEOUT)
        next_state = RDATA_ERROR; // タイムアウトしたらエラー状態へ
   RDATA_LAST:
     if (s_axi_rready == 1)
       next_state = INIT; // 読み込みデータが受信されたら初期化へ
    RDATA_ERROR:
      next_state = INIT; // エラーが発生したら初期化へ
    default:
      next_state = INIT; // デフォルト状態は初期化へ
  endcase
end

// 書き込みおよび読み込みデータの処理
always @(posedge s_axi_aclk)
begin
  if (s_axi_aresetn == 0) begin
      s_axi_awready <= 1'b0;
      s_axi_wready  <= 1'b0;
      s_axi_bid     <= 3'b000;
      s_axi_bvalid  <= 1'b0;
      s_axi_bresp   <= 2'b00;
      s_axi_arready <= 1'b0;
      s_axi_rvalid  <= 1'b0;
      s_axi_rresp   <= 2'b00;
      s_axi_rid     <= 3'b000;
      s_axi_rlast   <= 1'b0;
  end else
  case (next_state)
    INIT : begin
      s_axi_awready <= 1'b0;
      s_axi_wready  <= 1'b0;
      s_axi_bvalid  <= 1'b0;
      s_axi_bid     <= 3'b000;
      s_axi_bresp   <= 2'b00;
      s_axi_arready <= 1'b0;
      s_axi_rid     <= 3'b000;
      s_axi_rvalid  <= 1'b0;
      s_axi_rresp   <= 2'b00;
      s_axi_rlast   <= 1'b0;
    end
    WRR_READY : begin
      s_axi_awready <= 1'b1;
      s_axi_arready <= 1'b1;
    end
    WADDR_ACCEPT : begin
      s_axi_awready <= 1'b0;
      s_axi_arready <= 1'b0;
    end
    WADDR_INRANGE : begin

    end
    WADDR_ERROR : begin

    end
    WRITE_READY : begin
      s_axi_wready  <= 1'b1;
      timer <= timer+1;
    end
    DATA_WRITE : begin
      timer <= 0;
      s_axi_bresp   <= OKAY;
      s_axi_wready  <= 1'b1;
    end
    WMAST_STALL : begin

    end
    WSLAVE_STALL : begin
      s_axi_wready  <= 1'b0;
    end
    WRITE_LAST : begin
      s_axi_wready  <= 1'b0;
    end
    WRITE_ERROR : begin
      s_axi_bresp   <= DECERR;
      s_axi_wready  <= 1'b0;
    end
    BRESP_VALID : begin
      s_axi_bvalid  <= 1'b1;
      timer <= timer+1;
    end
    BRESP_ACCEPT : begin
      s_axi_bvalid  <= 1'b0;
      s_axi_bresp   <= OKAY;
      timer <= 0;
    end
    BRESP_ERROR : begin

    end
    RADDR_ACCEPT : begin
      s_axi_awready <= 1'b0;
      s_axi_arready <= 1'b0;
    end
    RADDR_INRANGE : begin
      s_axi_rresp   <= OKAY;
      timer <= timer+1;
      if (burst_count != 0)
        s_axi_rvalid  <= 1'b1;
      else
        s_axi_rvalid  <= 1'b0;
    end
    RADDR_ERROR : begin
      s_axi_rresp   <= DECERR;
    end
    RDATA_VALID : begin
      s_axi_rvalid  <= 1'b1;
      s_axi_rresp   <= 2'b00;
      timer <= 0;
    end
    RMAST_STALL : begin
      timer <= timer+1;
    end
    RSLAVE_STALL : begin
      s_axi_rvalid  <= 1'b0;
      timer <= timer+1;
    end
    RDATA_LAST : begin
      s_axi_rlast   <= 1'b1;
      s_axi_rvalid  <= 1'b1;
    end
    RDATA_ERROR : begin
      s_axi_rvalid  <= 1'b0;
    end
  endcase
end

// バーストカウントの処理
always @(posedge s_axi_aclk)
begin
  if (next_state == WADDR_ACCEPT)
    burst_count   <= s_axi_awlen;
  else if (next_state == RADDR_ACCEPT)
    burst_count   <= s_axi_arlen;
  else if (next_state == DATA_WRITE)
    burst_count <= burst_count - 1;
  else if (next_state == RDATA_VALID)
    burst_count <= burst_count - 1;
end

// 書き込みアドレスの更新
always @(posedge s_axi_aclk)
begin
  if (next_state == WADDR_ACCEPT)
     write_address <= s_axi_awaddr;
  else if ((next_state == DATA_WRITE) && (state != WRITE_READY))
     write_address   <= write_address+4;
  else if ((next_state == WRITE_LAST) && (state != WRITE_READY))
     write_address   <= write_address+4;
end

// 書き込みデータの保持
always @(posedge s_axi_aclk)
begin
  if ((next_state == DATA_WRITE) && (state != WSLAVE_STALL))
    write_data <= s_axi_wdata;
  else if ((next_state == WSLAVE_STALL) && (state == DATA_WRITE))
    write_data <= s_axi_wdata;
  else if (next_state == WRITE_LAST)
    write_data <= s_axi_wdata;
end

// 書き込みアサート信号の制御
always @(posedge s_axi_aclk)
begin
  if ((next_state == DATA_WRITE) || (next_state == WRITE_LAST))
    write_assert <= 1'b1;
  else
     write_assert <= 1'b0;
end

// 読み込みアドレスの更新
always @(posedge s_axi_aclk)
begin
  if (next_state == RADDR_ACCEPT)
    read_address   <= s_axi_araddr;
  else if (next_state == RDATA_VALID)
    read_address   <= read_address+4;
  else if ((next_state == RDATA_LAST) && (state != RADDR_INRANGE) && (state != RDATA_LAST) && (state != RSLAVE_STALL))
    read_address   <= read_address+4;
end 

// 書き込みアサート時のメモリ書き込み
always @(posedge s_axi_aclk)
begin
  if (write_assert == 1)
    case (write_address)
      24'h000004: control_register <= write_data;
    endcase
end

// 読み込みデータの選択
always@(*)
begin
    case (read_address[23:8])
      16'h0000 :
        case (read_address[7:0])
          8'h04 : s_axi_rdata <= control_register;
          default : s_axi_rdata <= 32'h0;
        endcase
      24'h0001: s_axi_rdata <= data_memory[read_address[7:2]];
      default : s_axi_rdata <= 32'h0;
    endcase
end

// メモリデータの書き込み
always @(posedge s_axi_aclk)
begin
   if ((write_assert == 1) && (write_address[23:8] == 16'h0001))
     data_memory[write_address[7:2]] <= write_data;
end

endmodule

AXI4のマスター側の記述

`timescale 1ns / 1ps
module axi4_master
(
    input  wire        m_axi_aclk,       // AXIクロック信号
    input  wire        m_axi_aresetn,    // 非同期リセット信号(低アクティブ)

    // 書き込みアドレスチャネルの信号群
    output reg  [2:0]  m_axi_awid,       // 書き込みアドレスID
    output reg  [23:0] m_axi_awaddr,     // 書き込みアドレス
    output reg  [2:0]  m_axi_awsize,     // 書き込みデータサイズ
    output reg  [1:0]  m_axi_awburst,    // 書き込みバーストタイプ
    output reg  [7:0]  m_axi_awlen,      // 書き込みバースト長
    output reg  [1:0]  m_axi_awlock,     // ロック信号
    output reg  [3:0]  m_axi_awcache,    // キャッシュ制御信号
    output reg  [2:0]  m_axi_awprot,     // 保護制御信号
    output reg  [3:0]  m_axi_awqos,      // Quality of Service
    output reg  [4:0]  m_axi_awuser,     // ユーザー定義信号
    output reg         m_axi_awvalid,    // 書き込みアドレスが有効であることを示す信号
    input  wire        m_axi_awready,    // スレーブが書き込みアドレスを受け入れ可能であることを示す信号

    // 書き込みデータチャネルの信号群
    output reg  [2:0]  m_axi_wid,        // 書き込みデータID
    output wire [31:0] m_axi_wdata,      // 書き込みデータ
    output reg  [3:0]  m_axi_wstrb,      // 書き込みストローブ信号(どのバイトが有効かを示す)
    output reg         m_axi_wlast,      // 書き込みバーストの最後であることを示す信号
    output reg         m_axi_wvalid,     // 書き込みデータが有効であることを示す信号
    input  wire        m_axi_wready,     // スレーブが書き込みデータを受け入れ可能であることを示す信号

    // 書き込み応答チャネルの信号群
    input  wire        m_axi_bid,        // 書き込み応答ID
    input  wire        m_axi_bresp,      // 書き込み応答ステータス
    input  wire        m_axi_bvalid,     // 書き込み応答が有効であることを示す信号
    output reg         m_axi_bready,     // マスターが書き込み応答を受け入れ可能であることを示す信号

    // 読み込みアドレスチャネルの信号群
    output reg  [2:0]  m_axi_arid,       // 読み込みアドレスID
    output reg  [23:0] m_axi_araddr,     // 読み込みアドレス
    output reg  [7:0]  m_axi_arlen,      // 読み込みバースト長
    output reg  [2:0]  m_axi_arsize,     // 読み込みデータサイズ
    output reg  [1:0]  m_axi_arburst,    // 読み込みバーストタイプ
    output reg  [1:0]  m_axi_arlock,     // ロック信号
    output reg  [3:0]  m_axi_arcache,    // キャッシュ制御信号
    output reg  [2:0]  m_axi_arprot,     // 保護制御信号
    output reg  [3:0]  m_axi_arqos,      // Quality of Service
    output reg  [4:0]  m_axi_aruser,     // ユーザー定義信号
    output reg         m_axi_arvalid,    // 読み込みアドレスが有効であることを示す信号
    input  wire        m_axi_arready,    // スレーブが読み込みアドレスを受け入れ可能であることを示す信号

    // 読み込みデータチャネルの信号群
    input  wire [2:0]  m_axi_rid,        // 読み込みデータID
    input  wire [31:0] m_axi_rdata,      // 読み込みデータ
    input  wire [1:0]  m_axi_rresp,      // 読み込み応答ステータス
    input  wire        m_axi_rlast,      // 読み込みバーストの最後であることを示す信号
    input  wire        m_axi_rvalid,     // 読み込みデータが有効であることを示す信号
    output reg         m_axi_rready,     // マスターが読み込みデータを受け入れ可能であることを示す信号

    // 外部制御信号
    input  wire        write,            // 書き込み開始信号
    input  wire [23:0] write_address,    // 書き込みアドレス
    input  wire [7:0]  write_burstlen,   // 書き込みバースト長
    input  wire [31:0] write_data,       // 書き込みデータ
    input  wire        read,             // 読み込み開始信号
    input  wire [23:0] read_address,     // 読み込みアドレス
    input  wire [7:0]  read_burstlen,    // 読み込みバースト長
    output reg  [31:0] read_data         // 読み込みデータ出力
);

parameter BUSY_MASTER_TEST = 0;            // マスターがビジー状態かをテストするためのパラメータ
reg [3:0] timer;                           // タイマー
localparam TIMEOUT = 15;                   // タイムアウト値
reg [7:0] burst_count;                     // バーストカウント
reg [31:0] data_gen;                       // データ生成用レジスタ
reg [5:0] lfsr = 6'b100000;                // 線形フィードバックシフトレジスタ(LFSR)
wire master_ready;                         // マスターが準備完了かどうかを示す信号
reg master_was_ready;                      // マスターが以前に準備完了だったかを示す信号

// 状態の定義
localparam INIT = 0, STANDBY = 1, WADDR_VALID = 2, WADDR_ACCEPT = 3,
            WADDR_ERROR = 4, WDATA_VALID = 5, WSLAVE_STALL = 6,
            WMAST_STALL = 7, WDATA_LAST = 8, WDATA_ERROR = 9,
            WAIT_RESPONSE = 10, ACCEPT_RESPONSE = 11, RESPONSE_ERROR = 12,
            RADDR_VALID = 13, RADDR_ACCEPT = 14, RDATA_VALID = 15,
            RSLAVE_STALL = 16, RMAST_STALL = 17, RDATA_LAST = 18, RDATA_ERROR = 19;
reg [4:0] state, next_state;               // 現在の状態と次の状態を保持するレジスタ

// 状態遷移ロジック
always @(posedge m_axi_aclk)
begin
    if (m_axi_aresetn == 0)
      state <= INIT;                       // リセット時は初期状態に戻る
    else
      state <= next_state;                 // 次の状態へ遷移
end

// LFSRの更新とマスター準備完了フラグの更新
always @(posedge m_axi_aclk)
begin
      lfsr[0] <= lfsr[5] ^ lfsr[4] ^ 1'b1;
      lfsr[5:1] <= lfsr[4:0];
    master_was_ready <= master_ready;
end

// マスターの準備完了状態をLFSRに基づいて決定
assign master_ready = BUSY_MASTER_TEST ? lfsr[5] : 1;

// 次の状態を決定するための組み合わせ回路
always @(*) begin
  next_state = state;
  case (state)
    INIT:
      next_state = STANDBY;                  // 初期化後、待機状態へ
    STANDBY:
      if (write == 1)
        next_state = WADDR_VALID;            // 書き込み要求があれば書き込みアドレスを送信
      else if (read == 1)
        next_state = RADDR_VALID;            // 読み込み要求があれば読み込みアドレスを送信
    WADDR_VALID:
      if ((m_axi_awready == 1) && (m_axi_wready == 1) && (burst_count == 0))
        next_state = WDATA_LAST;             // 最後の書き込みデータ送信状態へ
      else if ((m_axi_awready == 1) && (m_axi_wready == 1))
        next_state = WDATA_VALID;            // 書き込みデータ送信状態へ
      else if (m_axi_awready == 1)
        next_state = WADDR_ACCEPT;           // 書き込みアドレス受信完了
      else if (timer == TIMEOUT)
        next_state = WADDR_ERROR;            // タイムアウトでエラー状態へ
    WADDR_ACCEPT:
      if ((m_axi_wready == 1) && (burst_count == 0))
        next_state = WDATA_LAST;             // 最後の書き込みデータ送信状態へ
      else if (m_axi_wready == 1)
        next_state = WDATA_VALID;            // 書き込みデータ送信状態へ
      else if (timer == TIMEOUT)
        next_state = WDATA_ERROR;            // タイムアウトでエラー状態へ
    WADDR_ERROR:
      next_state = WAIT_RESPONSE;            // 書き込みアドレスエラー発生時は応答待機へ
    WDATA_VALID:
      if ((m_axi_wready == 1) && (master_was_ready == 1) && (burst_count == 0))
        next_state = WDATA_LAST;             // 最後の書き込みデータ送信状態へ
      else if ((m_axi_wready == 1) && (master_ready == 0))
        next_state = WMAST_STALL;            // マスターがビジー状態で遅延へ
      else if (m_axi_wready == 0)
        next_state = WSLAVE_STALL;           // スレーブがビジー状態で遅延へ
    WSLAVE_STALL:
      if ((m_axi_wready == 1) && (master_ready == 1) && (burst_count == 0))
        next_state = WDATA_LAST;             // 最後の書き込みデータ送信状態へ
      else if ((m_axi_wready == 1) && (master_ready == 1))
        next_state = WDATA_VALID;            // 書き込みデータ送信状態へ
      else if ((m_axi_wready == 1) && (master_ready == 0))
        next_state = WDATA_VALID;            // マスターがビジー状態で遅延へ
      else if (m_axi_wready == 1)
        next_state = WMAST_STALL;            // マスターがビジー状態で遅延へ
      else if (timer == TIMEOUT)
        next_state = WDATA_ERROR;            // タイムアウトでエラー状態へ
    WMAST_STALL:
      if ((m_axi_wready == 1) && (master_was_ready == 1) && (burst_count == 0))
        next_state = WDATA_LAST;             // 最後の書き込みデータ送信状態へ
      else if ((m_axi_wready == 1) && (master_ready == 1))
        next_state = WDATA_VALID;            // 書き込みデータ送信状態へ
      else if ((m_axi_wready == 0) && (master_ready == 1))
        next_state = WSLAVE_STALL;           // スレーブがビジー状態で遅延へ
      else if (timer == TIMEOUT)
        next_state = WDATA_ERROR;            // タイムアウトでエラー状態へ
    WDATA_LAST:
      if (m_axi_bvalid == 1) 
        next_state = ACCEPT_RESPONSE;        // 書き込み完了応答受信
      else
        next_state = WAIT_RESPONSE;          // 書き込み完了応答待機
    WAIT_RESPONSE:
      if (m_axi_bvalid == 1)
        next_state = ACCEPT_RESPONSE;        // 書き込み完了応答受信
      else if (timer == TIMEOUT)
        next_state = RESPONSE_ERROR;         // タイムアウトでエラー状態へ
    ACCEPT_RESPONSE:
      next_state = INIT;                     // 初期化へ遷移
    RESPONSE_ERROR:
      next_state = INIT;                     // エラー発生で初期化へ
    RADDR_VALID:
      if (m_axi_arready == 1)
        next_state = RADDR_ACCEPT;           // 読み込みアドレス受信完了
      else if (timer == TIMEOUT)
        next_state = RESPONSE_ERROR;         // タイムアウトでエラー状態へ
    RADDR_ACCEPT:
      if ((m_axi_rvalid == 1) && ((burst_count == 0) || (m_axi_rlast == 1)))
        next_state = RDATA_LAST;             // 最後の読み込みデータ受信状態へ
      else if (m_axi_rvalid == 1)
        next_state = RDATA_VALID;            // 読み込みデータ受信状態へ
      else
        next_state = RSLAVE_STALL;           // スレーブがビジー状態で遅延へ
    RDATA_VALID:
      if ((m_axi_rvalid == 1) && (master_was_ready == 1) && ((burst_count == 0) || (m_axi_rlast == 1)))
        next_state = RDATA_LAST;             // 最後の読み込みデータ受信状態へ
      else if ((m_axi_rvalid == 1) && (master_ready == 0))
        next_state = RMAST_STALL;            // マスターがビジー状態で遅延へ
      else if (m_axi_rvalid == 0)
        next_state = RSLAVE_STALL;           // スレーブがビジー状態で遅延へ
    RSLAVE_STALL:
      if ((m_axi_rvalid == 1) && (master_ready == 1) && (burst_count == 0))
        next_state = RDATA_LAST;             // 最後の読み込みデータ受信状態へ
      else if ((m_axi_rvalid == 1) && (master_ready == 1))
        next_state = RDATA_VALID;            // 読み込みデータ受信状態へ
      else if (m_axi_rvalid == 1)
        next_state = RMAST_STALL;            // マスターがビジー状態で遅延へ
    RMAST_STALL:
      if ((m_axi_rvalid == 1) && (master_was_ready == 1) && ((burst_count == 0) || (m_axi_rlast == 1)))
        next_state = RDATA_LAST;             // 最後の読み込みデータ受信状態へ
      else if ((m_axi_rvalid == 1) && (master_ready == 1))
        next_state = RDATA_VALID;            // 読み込みデータ受信状態へ
      else if (master_ready == 1)
        next_state = RSLAVE_STALL;           // スレーブがビジー状態で遅延へ
    RDATA_LAST:
      next_state = INIT;                     // 読み込み完了後、初期化へ遷移
    RDATA_ERROR:
      next_state = INIT;                     // エラー発生で初期化へ
    default:
      next_state = INIT;                     // デフォルトで初期化へ遷移
  endcase
end

// 各信号の制御とデータの生成
always @(posedge m_axi_aclk)
begin
  if (m_axi_aresetn == 0) begin
      // リセット時はすべての出力信号を無効化
      m_axi_awvalid <= 0;
      m_axi_awid    <= 0;
      m_axi_awaddr  <= 0;
      m_axi_awprot  <= 0;
      m_axi_wvalid  <= 0;
      m_axi_awlen   <= 0;
      m_axi_awsize  <= 0;
      m_axi_awburst <= 0;
      m_axi_awlock  <= 0;
      m_axi_awcache <= 0;
      m_axi_awqos   <= 0;
      m_axi_awuser  <= 0;
      m_axi_wid     <= 0;
      data_gen      <= 0;
      m_axi_wstrb   <= 0;
      m_axi_wlast   <= 0;
      m_axi_bready  <= 0;
      m_axi_arvalid <= 0;
      m_axi_arid    <= 0;
      m_axi_araddr  <= 0;
      m_axi_arlen   <= 0;
      m_axi_arsize  <= 0;
      m_axi_arburst <= 0;
      m_axi_arqos   <= 0;
      m_axi_arprot  <= 0;
      m_axi_arlock  <= 0;
      m_axi_arcache <= 0;
      m_axi_aruser  <= 0;
      m_axi_rready  <= 0;
  end else    
  case (next_state)
    INIT: begin
      // 初期化状態
      m_axi_awvalid <= 0;
      m_axi_awaddr  <= 0;
      m_axi_awburst <= 1;
      m_axi_awprot  <= 0;
      m_axi_wvalid  <= 0;
      data_gen      <= 0;
      m_axi_wstrb   <= 0;
      m_axi_bready  <= 0;
      m_axi_arvalid <= 0;
      m_axi_arburst <= 1;
      m_axi_araddr  <= 0;
      m_axi_arprot  <= 0;
      m_axi_rready  <= 0;
    end
    STANDBY: begin
      // 待機状態
      timer <= 0;
    end
    WADDR_VALID: begin
      // 書き込みアドレス送信
      m_axi_awvalid <= 1;
      m_axi_wvalid  <= 1;
      m_axi_awaddr  <= write_address;
      m_axi_awlen   <= write_burstlen;
      data_gen      <= write_data;
      burst_count   <= write_burstlen;
      if (write_burstlen == 0)
        m_axi_wlast <= 1;
    end
    WADDR_ACCEPT: begin
      // 書き込みアドレス受信完了
      m_axi_awvalid <= 0;
      if (m_axi_wready == 1)
        data_gen      <= data_gen + 1;
    end
    WADDR_ERROR: begin
      // 書き込みアドレスエラー(処理なし)
    end
    WDATA_VALID: begin
      // 書き込みデータ送信
      m_axi_wvalid  <= 1;
      if (burst_count == 1)
        m_axi_wlast <= 1;
      data_gen      <= data_gen + 1;
      m_axi_awvalid <= 0;
      timer <= 0;
      m_axi_bready  <= 0;
      burst_count <= burst_count - 1;
    end
    WSLAVE_STALL: begin
      // スレーブビジー状態
      timer <= timer + 1;
    end
    WMAST_STALL: begin
      // マスタービジー状態
      timer <= timer + 1;
      m_axi_wvalid  <= 0;
    end
    WDATA_LAST: begin
      // 最後の書き込みデータ送信完了
      timer <= 0;
      m_axi_awvalid <= 0;
      m_axi_wvalid  <= 0;
      m_axi_wlast   <= 0;
      m_axi_bready  <= 1;
    end
    WDATA_ERROR: begin
      // 書き込みデータエラー(処理なし)
    end
    WAIT_RESPONSE: begin
      // 書き込み応答待機
      m_axi_bready  <= 1;
    end
    ACCEPT_RESPONSE: begin
      // 書き込み応答受信完了
      m_axi_bready  <= 0;
    end
    RESPONSE_ERROR: begin
      // 応答エラー(処理なし)
    end
    RADDR_VALID: begin
      // 読み込みアドレス送信
      m_axi_araddr  <= read_address;
      burst_count   <= read_burstlen;
      m_axi_arlen   <= read_burstlen;
      m_axi_arvalid <= 1;
      m_axi_rready  <= 1;
    end
    RADDR_ACCEPT: begin
      // 読み込みアドレス受信完了
      m_axi_arvalid <= 0;
    end
    RDATA_VALID: begin
      // 読み込みデータ受信
      burst_count   <= burst_count - 1;
      m_axi_rready  <= 1;
    end
    RSLAVE_STALL: begin
      // スレーブビジー状態
      m_axi_rready  <= 1;
    end
    RMAST_STALL: begin
      // マスタービジー状態
      m_axi_rready <= 0;
    end
    RDATA_LAST: begin
      // 最後の読み込みデータ受信完了
      m_axi_rready  <= 0;
    end
    RDATA_ERROR: begin
      // 読み込みデータエラー(処理なし)
    end
  endcase
end

// 書き込みデータの生成
assign m_axi_wdata = data_gen;

endmodule

テストベンチ

`timescale 1ns / 1ps
module t_axi4_master;

reg         s_axi_aclk;      // クロック信号
reg         s_axi_aresetn;   // リセット信号(低アクティブ)

// AXI 書き込みアドレスチャネルの信号群
wire [2:0]  s_axi_awid;
wire        s_axi_awvalid;
wire        s_axi_awready;
wire [23:0] s_axi_awaddr;
wire [7:0]  s_axi_awlen;
wire [2:0]  s_axi_awsize;
wire [1:0]  s_axi_awburst;
wire [1:0]  s_axi_awlock;
wire [3:0]  s_axi_awcache;
wire [2:0]  s_axi_awprot;
wire [3:0]  s_axi_awqos;
wire [4:0]  s_axi_awuser;

// AXI 書き込みデータチャネルの信号群
wire [2:0]  s_axi_wid;
wire        s_axi_wvalid;
wire        s_axi_wready;
wire [31:0] s_axi_wdata;
wire [3:0]  s_axi_wstrb;
wire        s_axi_wlast;

// AXI 書き込み応答チャネルの信号群
wire  [2:0] s_axi_bid;
wire        s_axi_bvalid;
wire        s_axi_bready;
wire  [1:0] s_axi_bresp;

// AXI 読み込みアドレスチャネルの信号群
wire [2:0]  s_axi_arid;
wire        s_axi_arvalid;
wire        s_axi_arready;
wire [23:0] s_axi_araddr;
wire [7:0]  s_axi_arlen;
wire [2:0]  s_axi_arsize;
wire [1:0]  s_axi_arburst;
wire [1:0]  s_axi_arlock;
wire [3:0]  s_axi_arcache;
wire [2:0]  s_axi_arprot;
wire [3:0]  s_axi_arqos;
wire [4:0]  s_axi_aruser;

// AXI 読み込みデータチャネルの信号群
wire  [2:0] s_axi_rid;
wire        s_axi_rvalid;
wire        s_axi_rready;
wire  [31:0] s_axi_rdata;
wire        s_axi_rlast;
wire  [1:0] s_axi_rresp;

// マスターからスレーブへの操作指示用の信号
reg        write;           // 書き込み開始信号
reg [23:0] write_address;   // 書き込みアドレス
reg [7:0]  write_burstlen;  // 書き込みバースト長
reg [31:0] write_data;      // 書き込みデータ
reg        read;            // 読み込み開始信号
reg [23:0] read_address;    // 読み込みアドレス
reg [7:0]  read_burstlen;   // 読み込みバースト長
wire [31:0] read_data;      // 読み込みデータ

// AXI4スレーブモジュールのインスタンス化
axi4_slave slave (
  .s_axi_aclk   (s_axi_aclk),
  .s_axi_aresetn(s_axi_aresetn),
  .s_axi_awid   (s_axi_awid),
  .s_axi_awvalid(s_axi_awvalid),
  .s_axi_awready(s_axi_awready),
  .s_axi_awaddr (s_axi_awaddr),
  .s_axi_awlen  (s_axi_awlen),
  .s_axi_awsize (s_axi_awsize),
  .s_axi_awburst(s_axi_awburst),
  .s_axi_awlock (s_axi_awlock),
  .s_axi_awcache(s_axi_awcache),
  .s_axi_awprot (s_axi_awprot),
  .s_axi_awqos  (s_axi_awqos),
  .s_axi_awuser (s_axi_awuser),
  .s_axi_wid    (s_axi_wid),
  .s_axi_wvalid (s_axi_wvalid),
  .s_axi_wready (s_axi_wready),
  .s_axi_wdata  (s_axi_wdata),
  .s_axi_wstrb  (s_axi_wstrb),
  .s_axi_wlast  (s_axi_wlast),
  .s_axi_bid    (s_axi_bid),
  .s_axi_bvalid (s_axi_bvalid),
  .s_axi_bready (s_axi_bready),
  .s_axi_bresp  (s_axi_bresp),
  .s_axi_arid   (s_axi_arid),
  .s_axi_arvalid(s_axi_arvalid),
  .s_axi_arready(s_axi_arready),
  .s_axi_araddr (s_axi_araddr),
  .s_axi_arlen  (s_axi_arlen),
  .s_axi_arsize (s_axi_arsize),
  .s_axi_arburst(s_axi_arburst),
  .s_axi_arlock (s_axi_arlock),
  .s_axi_arcache(s_axi_arcache),
  .s_axi_arprot (s_axi_arprot),
  .s_axi_arqos  (s_axi_arqos),
  .s_axi_aruser (s_axi_aruser),
  .s_axi_rid    (s_axi_rid),
  .s_axi_rvalid (s_axi_rvalid),
  .s_axi_rready (s_axi_rready),
  .s_axi_rdata  (s_axi_rdata),
  .s_axi_rlast  (s_axi_rlast),
  .s_axi_rresp  (s_axi_rresp)
);

// AXI4マスターモジュールのインスタンス化
axi4_master master ( 
  .m_axi_aclk   (s_axi_aclk),
  .m_axi_aresetn(s_axi_aresetn),
  .m_axi_awid   (s_axi_awid),
  .m_axi_awvalid(s_axi_awvalid),
  .m_axi_awready(s_axi_awready),
  .m_axi_awaddr (s_axi_awaddr),
  .m_axi_awlen  (s_axi_awlen),
  .m_axi_awsize (s_axi_awsize),
  .m_axi_awburst(s_axi_awburst),
  .m_axi_awlock (s_axi_awlock),
  .m_axi_awcache(s_axi_awcache),
  .m_axi_awprot (s_axi_awprot),
  .m_axi_awqos  (s_axi_awqos),
  .m_axi_awuser (s_axi_awuser),
  .m_axi_wid    (s_axi_wid),
  .m_axi_wvalid (s_axi_wvalid),
  .m_axi_wready (s_axi_wready),
  .m_axi_wdata  (s_axi_wdata),
  .m_axi_wstrb  (s_axi_wstrb),
  .m_axi_wlast  (s_axi_wlast),
  .m_axi_bid    (s_axi_bid),
  .m_axi_bvalid (s_axi_bvalid),
  .m_axi_bready (s_axi_bready),
  .m_axi_bresp  (s_axi_bresp),
  .m_axi_arid   (s_axi_arid),
  .m_axi_arvalid(s_axi_arvalid),
  .m_axi_arready(s_axi_arready),
  .m_axi_araddr (s_axi_araddr),
  .m_axi_arlen  (s_axi_arlen),
  .m_axi_arsize (s_axi_arsize),
  .m_axi_arburst(s_axi_arburst),
  .m_axi_arlock (s_axi_arlock),
  .m_axi_arcache(s_axi_arcache),
  .m_axi_arprot (s_axi_arprot),
  .m_axi_arqos  (s_axi_arqos),
  .m_axi_aruser (s_axi_aruser),
  .m_axi_rid    (s_axi_rid),
  .m_axi_rvalid (s_axi_rvalid),
  .m_axi_rready (s_axi_rready),
  .m_axi_rdata  (s_axi_rdata),
  .m_axi_rlast  (s_axi_rlast),
  .m_axi_rresp  (s_axi_rresp),
  .write        (write),
  .write_address(write_address),
  .write_burstlen(write_burstlen),
  .write_data   (write_data),
  .read         (read),
  .read_address (read_address),
  .read_burstlen(read_burstlen),
  .read_data    (read_data)
);

// クロック生成(50ns周期、20MHz)
initial
begin
  s_axi_aclk = 1'b0;
end

always
  #50 s_axi_aclk = ~s_axi_aclk;  // 50nsごとにクロックを反転

// テストベンチの初期化とシミュレーションシナリオ
initial
begin
  // リセットをアサート
  s_axi_aresetn = 0;
  repeat(2) @(posedge s_axi_aclk);  // 2クロック待機
  s_axi_aresetn = 1;  // リセット解除
  repeat(10) @(posedge s_axi_aclk);  // 10クロック待機

  // シナリオ1: 単一ワードの書き込み
  write = 1;
  write_address = 24'h000004;  // アドレス 0x000004 に書き込み
  write_burstlen = 8'h00;      // バースト長 1(単一ワード)
  write_data = 32'h55555555;   // データ 0x55555555 を書き込む
  @(posedge s_axi_aclk);       // 1クロック待機
  write = 0;                   // 書き込み完了

  // シナリオ2: 単一ワードの読み込み
  repeat(20) @(posedge s_axi_aclk);  // 20クロック待機
  read = 1;
  read_address = 24'h000004;  // アドレス 0x000004 から読み込み
  read_burstlen = 8'h00;      // バースト長 1(単一ワード)
  @(posedge s_axi_aclk);      // 1クロック待機
  read = 0;                   // 読み込み完了

  // シナリオ3: バースト書き込み
  repeat(20) @(posedge s_axi_aclk);  // 20クロック待機
  write = 1;
  write_address = 24'h000100;  // アドレス 0x000100 に書き込み
  write_burstlen = 8'h0F;      // バースト長 16ワード
  write_data = 32'h0;          // データ 0 を書き込む
  @(posedge s_axi_aclk);       // 1クロック待機
  write = 0;                   // 書き込み完了

  // シナリオ4: バースト読み込み
  repeat(40) @(posedge s_axi_aclk);  // 40クロック待機
  read = 1;
  read_address = 24'h000100;  // アドレス 0x000100 から読み込み
  read_burstlen = 8'h0F;      // バースト長 16ワード
  @(posedge s_axi_aclk);      // 1クロック待機
  read = 0;                   // 読み込み完了

  // シミュレーション終了
  repeat(40) @(posedge s_axi_aclk);  // 40クロック待機
  $finish;
end
endmodule

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?