AXI4を理解する



# 目的
AXIを理解する

# 対象
FPGA初心者の方

# 目次

# AXIプロトコル

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

2 つは読み出しトランザクションに使用されます。
- 読み出しアドレス (Address and control)
- 読み出しデータ (Read data)
マスターがアドレスを送り付けて、スレーブがデータを返します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624715/29c16bd1-706d-1137-53e3-ba5cb5111f05.png)


3 つは書き込みトランザクションに使用されます。
- 書き込みアドレス (Address and control)
- 書き込みデータ (Write data)
- 書き込み応答 (Write response)
マスターがアドレスとデータを書き込み、スレーブがレスポンスを返します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624715/0d6d7eb7-890c-af21-7e06-a0afeaaf3cd7.png)


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

５つのチャネルが独立して、ハンドシェイクするイメージ図は下記のようなものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624715/c84b0d5a-a643-b13d-584b-8b6330f05a3b.png)

# AXIの比較

AXI4はAXI-LiteやAXI-Streamと比較して、複雑になりますがパフォーマンスに優れています。
下記にAXI4とAXI-Liteの比較を行っています。
| 特徴/項目                      | AXI4                                    | AXI4-Lite                                  |
|--------------------------------|-----------------------------------------|--------------------------------------------|
| **バースト長**                 | 最大256ワードのバースト長をサポート      | 単一ワードトランザクションのみ              |
| **データバス幅**               | 最大128バイト（2のべき乗での使用が可能）  | 32ビットまたは64ビット（全幅を使用）        |
| **追加機能（トランザクションID、QoS、ユーザー情報の転送）** | サポート                                | サポートなし、または制限あり               |
| **ロジック規模**               | 大規模なロジックを必要とする            | 小規模なロジックで済む                     |
| **使用用途**                   | 高機能が必要な場合に使用                | シンプルな制御や低機能が必要な場合に使用   |

# Verilog HDL による記述
AXI4のスレーブ側の記述
```verilog
`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のマスター側の記述
```verilog
`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
```

テストベンチ
```verilog
`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

```