내머리속은이런걸로 2024. 7. 10. 12:02

Overlapping read bursts

: 읽기 작업을 동시에 수행하여 데이터 전송 속도 향상시킨다.

  1. 마스터가 첫 번째 읽기 요청으로 주소 ARADDR를 슬레이브로 전송한다.
  2. 슬레이브가 RDATA를 마스터에게 보낸다.
  3. 첫 번째 데이터가 전송되는 동안, 마스터가 두 번째로 읽을 주소 ARDDR을 슬레이브로 전송한다.
  4. 슬레이브가 첫 번재 데이터 전송이 완료되면 두 번째 데이터를 전송한다.
  5. 과정이 반복된다. 

Write Burst

: Master가 여러 데이터 단위를 Slave로 연속적으로 전송할 때 사용한다.

  • 주소 설정 (Address Phase) : AWADDR, AWVALID / AWREADY
  • 데이터 전송 (Data Phase) : WDATA, WVALID / WREADY, WLAST
  • 응답 전송 (Response Phase) : BREADY /  BRESP, BVALID

(Master / Slave)

 

  • BREADY : Master가 응답을 받을 준비가 되었음을 나타낸다.
  • BRESP : Slave가 쓰기 요청에 대한 응답 상태를 설정한다. (정상/에러)
  • BVALID : 응답이 유효함을 나타내기 위해 이 신호를 1로 설정한다.

AWID

: Master가 여러 쓰기 요청을 동시에 발생할 때 요청을 구별할 수 있도록 한다.


AMBA  BUS Lite

VALID & READY

READY : VALID와 IFO가 ON되면 ON

 

MASTER에서 VALID를 ON하고, Write할 주소를 보내면 Slave에서 READY 신호를 보낸다.

 

AXI channels

 

AW_Channel, VAILD 신호를 받은 후 INFO 처리.
W_Channel, INFO를 받을 준비가 되어있다.
1clk 내에서 INFO를 처리한다.

 


- WLAST는 AXI4-Lite에서는 사용하지 않는다.

 

Slave를 Memory라고 생각하여 AWADDR, AWVALID 신호를 보낸다.

 


: 쓰기 데이터가 유효한 바이트를 식벼랗여 특정 바이트만 수정할 수 있게 한다.

 

  • strobe : WSTRB
  • Master → Slave Data byte 정보
  • 32bit의 경우 4bit
  • 64bit의 경우 8bit

 

ex)

  • WDATA : 0x11223344
  • WSTRB : 1100
  • WSTRB[3] → 상위 바이트(11)은 유효하다.
  • WSTRB[2] → 두 번째 바이트(22)은 유효하다.
  • WSTRB[1] → 세 번째 바이트(33)은 유효하다.
  • WSTRB[0] → 하위 바이트(44)은 유효하다.

코드 구현 주의사항

Master에서 Slave로 AWADDR, AWVALID를 전송, triggering을 하는 시점은 정해져있지 않는다.

→ 개발자하기 나름이다.

 

  • Address가 0 이상이면 triggering
  • VALID = 1이면 triggering
  • READY = 1이면 transaction을 종료한다.

→ Address가 0인 것은 사용하지 못한다는 단점이 존재한다.


AXI_Memory.sv

`timescale 1ns / 1ps

module AXI_Memory ();
endmodule

module AXI_Master (
    // Global Signal
    input  logic        ACLK,
    input  logic        ARESETn,  // n : negetive active
    // AW Channel
    output logic [31:0] AWADDR,
    output logic        AWVALID,
    input  logic        AWREADY,
    // AR Channel
    output logic [31:0] ARADDR,
    output logic        ARVALID,
    input  logic        ARREADY,
    // W Channel
    output logic [31:0] WDATA,
    output logic        WVALID,
    output logic [ 3:0] WSTRB,
    input  logic        WREADY,
    // R Channel
    input  logic [31:0] RDATA,
    input  logic        RVALID,
    output logic        RREADY,
    // B Channel
    input  logic [ 1:0] BRESP,
    input  logic        BVALID,
    output logic        BREADY,
    // user signal write transaction
    input  logic [31:0] aw_addr,
    input  logic [31:0] w_data,
    input  logic        valid,
    input  logic [ 3:0] w_strb,
    output logic        ready,
    // user signal read transaction
    input  logic [31:0] raddr,
    input  logic        rvalid,
    output logic [31:0] rdata,
    output logic        rready
);
    // AW Channel
    enum bit {
        AW_IDLE_S,
        AW_VALID_S
    }
        aw_state, aw_state_next;

    logic [31:0] aw_addr_reg, aw_addr_next;

    always_ff @(posedge ACLK, negedge ARESETn) begin
        if (!ARESETn) begin
            aw_state    <= AW_IDLE_S;
            aw_addr_reg <= 0;
        end else begin
            aw_state <= aw_state_next;
            aw_addr_reg <= aw_addr_next;
        end
    end

    // next, output logic
    always_comb begin
        aw_state_next = aw_state;
        aw_addr_next = aw_addr_reg;
        AWVALID = 1'b0;
        case (aw_state)
            AW_IDLE_S: begin
                AWVALID = 1'b0;
                if (valid) begin  // triggering time decision
                    aw_state_next = AW_VALID_S;
                    aw_addr_next  = aw_addr;  // address latch
                end
            end
            AW_VALID_S: begin
                AWVALID = 1'b1;
                AWADDR  = aw_addr_reg;
                if (AWVALID && AWREADY) begin
                    aw_state_next = AW_IDLE_S;
                end
            end
        endcase
    end

    // AR Channel
    enum bit {
        AR_IDLE_S,
        AR_VALID_S
    }
        ar_state, ar_state_next;

    logic [31:0] ar_addr_reg, ar_addr_next;

    always_ff @(posedge ACLK, negedge ARESETn) begin
        if (!ARESETn) begin
            ar_state    <= AR_IDLE_S;
            ar_addr_reg <= 0;
        end else begin
            ar_state    <= ar_state_next;
            ar_addr_reg <= ar_addr_next;
        end
    end

    // next, output logic
    always_comb begin
        ar_state_next = ar_state;
        ar_addr_next  = ar_addr_reg;
        ARVALID       = 1'b0;
        case (ar_state)
            AR_IDLE_S: begin
                ARVALID = 1'b0;
                if (rvalid) begin  // triggering time decision
                    ar_state_next = AR_VALID_S;
                    ar_addr_next  = raddr;  // address latch
                end
            end
            AR_VALID_S: begin
                ARVALID = 1'b1;
                ARADDR  = ar_addr_reg;
                if (ARVALID && ARREADY) begin
                    ar_state_next = AR_IDLE_S;
                end
            end
        endcase
    end

    // W Channel
    enum bit {
        W_IDLE_S,
        W_VALID_S
    }
        w_state, w_state_next;

    logic [31:0] w_data_reg, w_data_next;
    logic [3:0] w_strb_reg, w_strb_next;

    always_ff @(posedge ACLK, negedge ARESETn) begin
        if (!ARESETn) begin
            w_state    <= W_IDLE_S;
            w_data_reg <= 0;
            w_strb_reg <= 0;
        end else begin
            w_state    <= w_state_next;
            w_data_reg <= w_data_next;
            w_strb_reg <= w_strb_next;
        end
    end

    // next, output logic
    always_comb begin
        w_state_next = w_state;
        w_data_next  = w_data_reg;
        w_strb_next  = w_strb_reg;
        WVALID       = 1'b0;
        case (w_state)
            W_IDLE_S: begin
                WVALID = 1'b0;
                if (valid) begin
                    w_state_next = W_VALID_S;
                    w_data_next  = w_data;  // data latch
                    w_strb_next  = w_strb;  // strobe latch
                end
            end
            W_VALID_S: begin
                WVALID = 1'b1;
                WDATA  = w_data_reg;
                WSTRB  = w_strb_reg;
                if (WVALID && WREADY) begin
                    w_state_next = W_IDLE_S;
                end
            end
        endcase
    end

    // R Channel
    enum bit {
        R_IDLE_S,
        R_READY_S
    }
        r_state, r_state_next;

    logic [31:0] r_data_reg, r_data_next;

    always_ff @(posedge ACLK, negedge ARESETn) begin
        if (!ARESETn) begin
            r_state    <= R_IDLE_S;
            r_data_reg <= 0;
        end else begin
            r_state    <= r_state_next;
            r_data_reg <= r_data_next;
        end
    end

    // next, output logic
    always_comb begin
        r_state_next = r_state;
        RREADY = 1'b0;
        rready = 1'b0;
        case (r_state)
            R_IDLE_S: begin
                RREADY = 1'b0;
                rready = 1'b0;
                if (ARVALID) begin
                    r_state_next = R_READY_S;
                end
            end
            R_READY_S: begin
                RREADY = 1'b1;
                if (RVALID && RREADY) begin
                    r_state_next = R_IDLE_S;
                    rdata        = RDATA;
                    rready       = 1'b1;
                end
            end
        endcase
    end

    // B Channel
    enum bit {
        B_IDLE_S,
        B_READY_S
    }
        b_state, b_state_next;

    logic [31:0] b_resp_reg, b_resp_next;  // response

    always_ff @(posedge ACLK, negedge ARESETn) begin
        if (!ARESETn) begin
            b_state    <= B_IDLE_S;
            b_resp_reg <= 0;
        end else begin
            b_state    <= b_state_next;
            b_resp_reg <= b_resp_next;
        end
    end

    // next, output logic
    always_comb begin
        b_state_next = b_state;
        b_resp_next  = b_resp_reg;
        BREADY       = 1'b0;
        case (b_state)
            B_IDLE_S: begin
                BREADY = 1'b0;
                ready  = 1'b0;
                if (WVALID) begin
                    b_state_next = B_READY_S;
                end
            end
            B_READY_S: begin
                BREADY = 1'b1;
                if (BVALID && BREADY) begin
                    b_state_next = B_IDLE_S;
                    b_resp_next  = BRESP;
                    ready        = 1'b1;
                end
            end
        endcase
    end

endmodule

module AXI_Slave_Memory (
    // Global Signal
    input  logic        ACLK,
    input  logic        ARESETn,
    // AW Channel (Write Address)
    input  logic [31:0] AWADDR,
    input  logic        AWVALID,
    output logic        AWREADY,
    // AR Channel
    input  logic [31:0] ARADDR,
    input  logic        ARVALID,
    output logic        ARREADY,
    // W Channel
    input  logic [31:0] WDATA,
    input  logic        WVALID,
    input  logic [ 3:0] WSTRB,
    output logic        WREADY,
    // R Channel
    output logic [31:0] RDATA,
    output logic        RVALID,
    input  logic        RREADY,
    // B Channel
    output logic [ 1:0] BRESP,
    output logic        BVALID,
    input  logic        BREADY,
    output logic        ready
);
    logic [7:0] slave_mem[0:15];

    // AW Channel
    enum bit {
        AW_IDLE_S,
        AW_READY_S
    }
        aw_state, aw_state_next;

    logic [31:0] aw_addr_reg, aw_addr_next;  // latch data

    always_ff @(posedge ACLK, negedge ARESETn) begin
        if (!ARESETn) begin
            aw_state    <= AW_IDLE_S;
            aw_addr_reg <= 0;
        end else begin
            aw_state    <= aw_state_next;
            aw_addr_reg <= aw_addr_next;
        end
    end

    // next, output logic
    always_comb begin
        aw_state_next = aw_state;
        aw_addr_next  = aw_addr_reg;
        AWREADY       = 1'b0;
        case (aw_state)
            AW_IDLE_S: begin
                AWREADY = 1'b0;
                if (AWVALID) begin
                    aw_state_next = AW_READY_S;
                    aw_addr_next  = AWADDR;  // address latch
                end
            end
            AW_READY_S: begin
                AWREADY = 1'b1;
                aw_addr_next = AWADDR;
                if (AWVALID && AWREADY) begin
                    aw_state_next = AW_IDLE_S;
                end
            end
        endcase
    end

    // AR Channel
    enum bit {
        AR_IDLE_S,
        AR_READY_S
    }
        ar_state, ar_state_next;

    logic [31:0] ar_addr_reg, ar_addr_next;

    always_ff @(posedge ACLK, negedge ARESETn) begin
        if (!ARESETn) begin
            ar_state    <= AR_IDLE_S;
            ar_addr_reg <= 0;
        end else begin
            ar_state    <= ar_state_next;
            ar_addr_reg <= ar_addr_next;
        end
    end

    // next, output logic
    always_comb begin
        ar_state_next = ar_state;
        ar_addr_next  = ar_addr_reg;
        ARREADY       = 1'b0;
        case (ar_state)
            AR_IDLE_S: begin
                ARREADY = 1'b0;
                if (ARVALID) begin  // triggering time decision
                    ar_state_next = AR_READY_S;
                    ar_addr_next  = ARADDR;  // address latch
                end
            end
            AR_READY_S: begin
                ARREADY      = 1'b1;
                ar_addr_next = ARADDR;
                if (ARVALID && ARREADY) begin
                    ar_state_next = AR_IDLE_S;
                end
            end
        endcase
    end

    // W Channel
    enum bit {
        W_IDLE_S,
        W_READY_S
    }
        w_state, w_state_next;

    logic [31:0] w_data_reg, w_data_next;
    logic [3:0] w_strb_reg, w_strb_next;

    always_ff @(posedge ACLK, negedge ARESETn) begin
        if (!ARESETn) begin
            w_state    <= W_IDLE_S;
            w_data_reg <= 0;
            w_strb_reg <= 0;
        end else begin
            w_state    <= w_state_next;
            w_data_reg <= w_data_next;
            w_strb_reg <= w_strb_next;
        end
    end

    // next, output logic
    always_comb begin
        w_state_next = w_state;
        w_data_next  = w_data_reg;
        w_strb_next  = w_strb_reg;
        WREADY       = 1'b0;
        case (w_state)
            W_IDLE_S: begin
                WREADY = 1'b0;
                if (AWREADY && WVALID) begin  // get address && wdata in 
                    w_state_next = W_READY_S;
                    w_data_next  = WDATA;  // data latch
                    w_strb_next  = WSTRB;  // strobe latch
                end
            end
            W_READY_S: begin
                WREADY = 1'b1;
                //slave_mem[aw_addr_reg] = w_data_reg;  // write
                case (w_strb_reg)
                    4'b0001: begin
                        slave_mem[aw_addr_reg] = w_data_reg[7:0];
                    end
                    4'b0010: begin
                        slave_mem[aw_addr_reg+1] = w_data_reg[15:8];
                    end
                    4'b0100: begin
                        slave_mem[aw_addr_reg+2] = w_data_reg[23:16];
                    end
                    4'b1000: begin
                        slave_mem[aw_addr_reg+3] = w_data_reg[31:24];
                    end
                    4'b0011: begin
                        slave_mem[aw_addr_reg]   = w_data_reg[7:0];
                        slave_mem[aw_addr_reg+1] = w_data_reg[15:8];
                    end
                    4'b0101: begin
                        slave_mem[aw_addr_reg]   = w_data_reg[7:0];
                        slave_mem[aw_addr_reg+2] = w_data_reg[23:16];
                    end
                    4'b1001: begin
                        slave_mem[aw_addr_reg]   = w_data_reg[7:0];
                        slave_mem[aw_addr_reg+3] = w_data_reg[31:24];
                    end
                    4'b0110: begin
                        slave_mem[aw_addr_reg+1] = w_data_reg[15:8];
                        slave_mem[aw_addr_reg+2] = w_data_reg[23:16];
                    end
                    4'b1010: begin
                        slave_mem[aw_addr_reg+1] = w_data_reg[15:8];
                        slave_mem[aw_addr_reg+3] = w_data_reg[31:24];
                    end
                    4'b1100: begin
                        slave_mem[aw_addr_reg+2] = w_data_reg[23:16];
                        slave_mem[aw_addr_reg+3] = w_data_reg[31:24];
                    end
                    4'b0111: begin
                        slave_mem[aw_addr_reg]   = w_data_reg[7:0];
                        slave_mem[aw_addr_reg+1] = w_data_reg[15:8];
                        slave_mem[aw_addr_reg+2] = w_data_reg[23:16];
                    end
                    4'b1011: begin
                        slave_mem[aw_addr_reg]   = w_data_reg[7:0];
                        slave_mem[aw_addr_reg+1] = w_data_reg[15:8];
                        slave_mem[aw_addr_reg+3] = w_data_reg[31:24];
                    end
                    4'b1101: begin
                        slave_mem[aw_addr_reg]   = w_data_reg[7:0];
                        slave_mem[aw_addr_reg+2] = w_data_reg[23:16];
                        slave_mem[aw_addr_reg+3] = w_data_reg[31:24];
                    end
                    4'b1110: begin
                        slave_mem[aw_addr_reg+1] = w_data_reg[15:8];
                        slave_mem[aw_addr_reg+2] = w_data_reg[23:16];
                        slave_mem[aw_addr_reg+3] = w_data_reg[31:24];
                    end
                    4'b1111: begin
                        slave_mem[aw_addr_reg]   = w_data_reg[7:0];
                        slave_mem[aw_addr_reg+1] = w_data_reg[15:8];
                        slave_mem[aw_addr_reg+2] = w_data_reg[23:16];
                        slave_mem[aw_addr_reg+3] = w_data_reg[31:24];
                    end
                    default: begin
                    end
                endcase
                if (WVALID && WREADY) begin
                    w_state_next = W_IDLE_S;
                end
            end
        endcase
    end

    // R Channel
    enum bit {
        R_IDLE_S,
        R_VALID_S
    }
        r_state, r_state_next;

    logic [31:0] r_data_reg, r_data_next;

    always_ff @(posedge ACLK, negedge ARESETn) begin
        if (!ARESETn) begin
            r_state    <= R_IDLE_S;
            r_data_reg <= 0;
        end else begin
            r_state    <= r_state_next;
            r_data_reg <= r_data_next;
        end
    end

    // next, output logic
    always_comb begin
        r_state_next = r_state;
        r_data_next  = r_data_reg;
        RVALID       = 1'b0;
        case (r_state)
            R_IDLE_S: begin
                RVALID = 1'b0;
                if (ARREADY && ARVALID) begin
                    r_state_next       = R_VALID_S;
                    r_data_next[7:0]   = slave_mem[ar_addr_reg+0];
                    r_data_next[15:8]  = slave_mem[ar_addr_reg+1];
                    r_data_next[23:16] = slave_mem[ar_addr_reg+2];
                    r_data_next[31:24] = slave_mem[ar_addr_reg+3];
                end
            end
            R_VALID_S: begin
                RVALID = 1'b1;
                RDATA  = r_data_reg;
                if (RVALID && RREADY) begin
                    r_state_next = R_IDLE_S;
                end
            end
        endcase
    end

    // B Channel
    logic [31:0] b_resp_reg, b_resp_next;  // response

    enum bit {
        B_IDLE_S,
        B_VALID_S
    }
        b_state, b_state_next;

    always_ff @(posedge ACLK, negedge ARESETn) begin
        if (!ARESETn) begin
            b_state    <= B_IDLE_S;
            b_resp_reg <= 0;
        end else begin
            b_state    <= b_state_next;
            b_resp_reg <= b_resp_next;
        end
    end

    // next, output logic
    always_comb begin
        b_state_next = b_state;
        b_resp_next  = b_resp_reg;
        BVALID       = 1'b0;
        ready        = 1'b0;
        case (b_state)
            B_IDLE_S: begin
                BVALID = 1'b0;
                if (WVALID && WREADY) begin  // WREADY : Write done
                    b_state_next = B_VALID_S;
                    b_resp_next  = 2'b00;  // OKAY Response
                end
            end
            B_VALID_S: begin
                BVALID = 1'b1;
                BRESP  = b_resp_reg;
                if (BVALID && BREADY) begin
                    b_state_next = B_IDLE_S;
                    b_resp_next = BRESP;
                    ready = 1'b1;
                end
            end
        endcase
    end
endmodule

 

tb_AXI_Memory .sv

`timescale 1ns / 1ps

module tb_AXI_Memory ();

    // Global Signal
    logic        ACLK;
    logic        ARESETn;
    // AW Channel (Write Address)
    logic [31:0] AWADDR;
    logic        AWVALID;
    logic        AWREADY;
    // AR Channel
    logic [31:0] ARADDR;
    logic        ARVALID;
    logic        ARREADY;
    // W Channel
    logic [31:0] WDATA;
    logic        WVALID;
    logic [ 3:0] WSTRB;
    logic        WREADY;
    // R Channel
    logic [31:0] RDATA;
    logic        RVALID;
    logic        RREADY;
    // B Channel
    logic [ 1:0] BRESP;
    logic        BVALID;
    logic        BREADY;
    // user signal write transaction
    logic [31:0] aw_addr;
    logic [31:0] w_data;
    logic        valid;
    logic [ 3:0] w_strb;
    logic        ready;
    // user signal read transaction
    logic [31:0] raddr;
    logic        rvalid;
    logic [31:0] rdata;
    logic        rready;

    always #5 ACLK = ~ACLK;

    AXI_Master dut_master (.*);
    AXI_Slave_Memory dut_slave (.*);

    initial begin
        ACLK = 1'b0;
        ARESETn = 1'b0;
        #20 ARESETn = 1'b1;

        // write
        // 1 transaction        
        @(posedge ACLK);
        aw_addr = 32'd0;
        w_data  = 32'h000000ff;
        w_strb  = 4'b0001;
        valid   = 1'b1;
        @(posedge ACLK);
        valid = 1'b0;
        @(posedge ready);
        #20 $finish;

        // 1 transaction        
        @(posedge ACLK);
        aw_addr = 32'd1;
        w_data  = 32'h0000aabb;
        w_strb  = 4'b0011;
        valid   = 1'b1;
        @(posedge ACLK);
        valid = 1'b0;
        @(posedge ready);
        #20 $finish;

        // 1 transaction        
        @(posedge ACLK);
        aw_addr = 32'd3;
        w_data  = 32'h00aabbcc;
        w_strb  = 4'b0111;
        valid   = 1'b1;
        @(posedge ACLK);
        valid = 1'b0;
        @(posedge ready);

        // 1 transaction        
        @(posedge ACLK);
        aw_addr = 32'd6;
        w_data  = 32'haabbccdd;
        w_strb  = 4'b1111;
        valid   = 1'b1;
        @(posedge ACLK);
        valid = 1'b0;
        @(posedge ready);

        // read
        // 1 transaction        
        @(posedge ACLK);
        raddr = 32'd0;
        rvalid   = 1'b1;
        @(posedge ACLK);
        rvalid = 1'b0;
        @(posedge rready);

        // 1 transaction        
        @(posedge ACLK);
        raddr = 32'd1;
        rvalid   = 1'b1;
        @(posedge ACLK);
        rvalid = 1'b0;
        @(posedge rready);

        #20 $finish;
    end
endmodule

 

simulation

Master
Slave