본문 바로가기
Digital Design/SoC

[AMBA] AXI Protocol 설계(Verilog) - ③ Read Transaction

by 스테고사우르스 2023. 2. 26.

들어가기 앞서...

 

"  AXI는 말 그대로 Interface이기 때문에 실체라고 할게 딱히 없습니다.

 

Master와 Slave를 연결하는 Bus의 규격을 ARM에서 정해놓은 것인데요,

저와 같은 학부생들은 Master와 Slave를 구하기 어렵습니다.

 

BFM(Bus Functional Model)을 짜서 Bus의 동작을 시뮬레이션해도 되지만

그건 조금 어려워서 아직 공부 중 입니다.

그래서 제멋대로 AXI Slave를 Verilog로 짜보겠습니다.

목적은 오로지 AMBA를 복습하고 기능을 직접 확인해보기 위함입니다!  "

 

조금 더 공부한 후에 정확한 코드를 올려보겠습니다.

 


 

이번 글에선 AXI Protocol에서 Read Transaction을 살펴보겠습니다.

 

먼저 채널이 응답하는 순서를 알아야 합니다.

 

순서도에 나온 것처럼 당연히 읽을 주소를 알아야 data를 가져올 수 있습니다.

 

Read Transaction 역시 burst 모드를 지원하고 type을 INCR입니다.

burst type 같은 경우, 추후에 추가할 계획입니다.

 


Verilog Code

DUT

  • burst lengh counter
    always @ (posedge i_clk or negedge i_resetn) begin
        if (!i_resetn) begin
            arlen_cnt <= 5'd0;
        end
        else if (arlen_cnt >= r_rburstn) begin
            arlen_cnt <= 5'd0;
        end
        else if (o_rlast) begin
            arlen_cnt <= 5'd0;
        end
        else if (r_handshake) begin
            arlen_cnt <= arlen_cnt + 5'd1;
        end
        else begin
            arlen_cnt <= arlen_cnt;
        end
    end

읽어올 Data의 개수를 카운트하기 위해 만들었습니다.

Burst length 정보는 i_arlen으로 들어옵니다.

지금은 카운터가 1씩 증가하는 구조라 INCR type만 가능하지만

조금만 수정하면 WRAP type도 가능할 것 같습니다.

 

 

  • Read Address
    always @ (posedge i_clk or negedge i_resetn) begin
        if (!i_resetn) begin
            r_raddr <= 8'd0;
        end
        else if (ar_handshake) begin
            r_raddr <= i_araddr;
            r_raddr_on <= 1'd1;
        end
        else begin
            r_raddr <= r_raddr;
        end
    end    
    
    always @ (posedge i_clk or negedge i_resetn) begin
        if (!i_resetn) begin
            r_rburstn <= 4'd0;
        end
        else if (ar_handshake) begin
            r_rburstn <= i_arlen;
        end
        else begin
            r_rburstn <= r_rburstn;
        end
    end

Handshake 구간에서 input으로 들어온 정보를 register에 저장합니다.

r_raddr_on을 flag로 이용해 현재 addr 값이 있는지 알려줍니다.

 

 

  • Read Data
    always @ (posedge i_clk or negedge i_resetn) begin
        if (!i_resetn) begin
            o_rvalid <= 1'd0;
        end
        else if (test_rvalid && r_raddr_on) begin
            o_rvalid = 1'd1;
        end
        else begin
            o_rvalid <= 1'd0;
        end
    end
        
    always @ (posedge i_clk) begin
        if (test_rvalid && r_raddr_on) begin
            o_rdata <= mem[r_raddr + arlen_cnt];
        end
    end
    
    always @ (posedge i_clk or negedge i_resetn) begin
        if (!i_resetn) begin
            o_rlast <= 1'd0;
        end
        else if (test_rvalid && r_raddr_on && (arlen_cnt == i_arlen-1)) begin
            o_rlast <= 1'd1;
            if (r_handshake) begin
                r_raddr_on <= 1'd0;
                o_rlast <= 1'd0;
            end
        end
    end
    
    always @ (posedge i_clk or negedge i_resetn) begin
        if (!i_resetn) begin
            //o_rresp <= 2'd0;
        end
        else if (o_rlast && r_handshake) begin
            o_rresp <= test_rresp;
        end
        else begin
            o_rresp <= o_rresp;
        end
    end

Slave가 준비가 되면 valid와 함께 읽은 Data를 띄워줍니다.

물론 이때는 r_raddr_on == HIGH, 즉 주소값을 받아온 상태여야합니다.

Handshake 구간에서 데이터를 주고받으면 다음 Data를 띄워줍니다.

마지막 Data를 전송할때는 r_rlast도 띄워주고, 이제 r_raddr_on을 내려줍니다.

마지막 handshake까지 끝나면 o_rresp를 이용해 잘 읽었는지 Master에게 알려줍니다.

 

 

 

Testbench

i_araddr = 8'd8;
        i_arlen = 4'd4;
        i_arvalid = 1'd1;
        #10
        test_arready = 1'd1;
        #20
        test_arready = 1'd0;
        i_arvalid = 1'd0;
        #20
        test_rvalid = 1'd1;
        #20
        i_rready = 1'd1;
        #10
        i_rready = 1'd0;
        #10
        i_rready = 1'd1;
        #10
        i_rready = 1'd0;
        #10
        i_rready = 1'd1;
        #10
        i_rready = 1'd0;
        #10
        i_rready = 1'd1;
        #10
        i_rready = 1'd0;
        #30
        $finish;

 

Simulation

이전 Write Transaction 게시글에서 8, 9, 10, 11번지 주소에 37, 38, 39, 40을 write 하였습니다.

이번에는 이 값들을 읽어왔습니다.

 

Handshake 구간이 끝나면 다음 rising edge에서 다음 data를 띄워줍니다.

마지막 data를 띄울때는 o_rlast도 함께 HIGH가 된 것을 볼 수 있습니다.

그리고 마지막 handshake까지 끝나면 o_rresp로 에러 여부를 알려주고 있습니다.

 


 

댓글