본문 바로가기

주의!!! 코드는 아직 검증되기 전입니다. 전체적인 구조를 잡기 위해 올려두는 부분이니 그대로 활용이 불가합니다.

AXI 마스터 모듈을 설계할 때는 AXI 프로토콜을 준수해야 합니다. 이 예제에서는 마스터 모듈이 기본적인 쓰기 및 읽기 작업을 수행할 수 있도록 간단하게 구현해 보겠습니다. 이 마스터 모듈은 주소, 데이터, 그리고 컨트롤 신호를 슬레이브로 전송하고, 응답을 처리할 수 있어야 합니다.

다음은 SystemVerilog를 사용한 AXI 마스터 모듈의 기본 구현입니다:

AXI 마스터 모듈을 수정하여 리셋 시 모든 상태 및 신호를 초기화하고, 각 상태 변화시에 적절한 $display 디버깅 메시지를 추가하여 이벤트를 추적할 수 있도록 했습니다. 또한, 주석도 보강하여 코드의 가독성을 높였습니다.

module axi_master #(
  parameter ADDR_WIDTH = 32,   // 주소 폭
  parameter DATA_WIDTH = 128   // 데이터 폭
)(
  input wire aclk,             // 시스템 클록
  input wire aresetn,          // 비동기 리셋 (저수준 활성화)
  interface axi_if             // AXI 인터페이스
);

  // // AXI4 full interface signals
  // reg [ADDR_WIDTH-1:0] axi_awaddr;
  // reg [7:0] axi_awlen = 8'd0;        // 버스트 길이는 0으로 초기화 (단일 전송)
  // reg [2:0] axi_awsize;
  // reg [1:0] axi_awburst = 2'b01;     // 버스트 유형, 기본은 INCR
  // reg axi_awvalid;
  // reg [DATA_WIDTH-1:0] axi_wdata;
  // reg [(DATA_WIDTH/8)-1:0] axi_wstrb;
  // reg axi_wlast;
  // reg axi_wvalid;
  // reg axi_bready;

  // Write operation state machine
  typedef enum {IDLE, WRITE_ADDR, WRITE_DATA, WRITE_RESP} write_state_t;
  write_state_t write_state = IDLE;

  // Write data task to initiate a write transaction
  task automatic write_data(input [ADDR_WIDTH-1:0] write_addr, input [DATA_WIDTH-1:0] data);
    axi_if.awaddr = write_addr;
    axi_if.wdata = data;
    axi_if.wstrb = {(DATA_WIDTH/8){1'b1}}; // 모든 바이트 레인 활성화
    axi_if.awvalid = 1'b1;
    axi_if.wvalid = 1'b1;
    axi_if.bready = 1'b1;
    write_state = WRITE_ADDR;
    $display("AXI Master: Write initiated at address %h with data %h", write_addr, data);
  endtask

  // Handle write transactions based on the state machine
  always @(posedge aclk) begin
    if (!aresetn) begin
      // 리셋 로직: 모든 신호를 초기 상태로 리셋
      axi_if.awaddr <= 0;
      axi_if.awlen <= 0;
      axi_if.awsize <= 0;
      axi_if.awburst <= 2'b01;
      axi_if.awvalid <= 1'b0;
      axi_if.wdata <= 0;
      axi_if.wstrb <= 0;
      axi_if.wlast <= 1'b0;
      axi_if.wvalid <= 1'b0;
      axi_if.bready <= 1'b0;
      write_state <= IDLE;
      $display("AXI Master: Reset state. All signals are cleared.");
    end else begin
      case (write_state)
        IDLE: begin
          if (axi_if.awvalid && axi_if.awready) begin
            axi_if.awvalid <= 1'b0;
            write_state <= WRITE_DATA;
            $display("AXI Master: Address written and accepted.");
          end
        end
        WRITE_ADDR: begin
          if (axi_if.awready) begin
            axi_if.awvalid <= 1'b0;
            write_state <= WRITE_DATA;
          end
        end
        WRITE_DATA: begin
          if (axi_if.wready) begin
            axi_if.wvalid <= 1'b0;
            axi_if.wlast <= 1'b1;
            write_state <= WRITE_RESP;
            $display("AXI Master: Data written and accepted.");
          end
        end
        WRITE_RESP: begin
          if (axi_if.bvalid && axi_if.bready) begin
            axi_if.bready <= 1'b0;
            write_state <= IDLE;
            $display("AXI Master: Write response received.");
          end
        end
        default: write_state <= IDLE;
      endcase
    end
  end
endmodule

-

설명

  1. State Machine: 쓰기 작업을 처리하기 위한 간단한 상태 머신을 구현했습니다. 쓰기 주소를 슬레이브에 전달하고, 데이터를 전달하며, 응답을 기다립니다.
  2. Write Task: 쓰기 작업을 시작하는 테스크를 정의했습니다. 이 테스크는 주소와 데이터를 입력으로 받고, AXI 버스에 쓰기 작업을 시작합니다.
  3. Signal Handling: AXI 프로토콜에 따라 주소와 데이터를 슬레이브에 전달하고, 슬레이브의 준비 상태에 따라 신호들을 업데이트합니다.
  4. 리셋 상태: 모든 내부 레지스터를 안전한 초기값으로 설정하여 시뮬레이션 시작 시 'X' 상태를 방지합니다.
  • $display 문: 각 주요 동작 단계에서 디버깅 정보를 출력하여 시뮬레이션을 추적할 수 있습니다.

이렇게 변경함으로써, AXI 마스터 모듈이 더욱 안정적으로 동작하고 디버깅하기 쉬워집니다.

이 모듈은 기본적인 쓰기 작업만을 수행하도록 설계되었으며, 필요에 따라 읽기 작업 및 추가 기능을 포함시킬 수 있습니다. 모듈의 성능과 기능을 확장하기 위해 추가적인 로직과 상태 처리가 필요할 수 있습니다.

B로그0간

개발 관련 글과 유용한 정보를 공유하는 공간입니다.