오늘은 AXI Read 동작과 Handshake 동작에 대한 부분을 알아보겠습니다.

 

먼저 Simulation Pulse를 확인하고 Read Operation과 Handshake에 대해 알아보도록 하겠습니다.

Simulation Pulse Of AXI Read Operation

 


Valid-Ready Handshake

 

Valid-Read Handshake of Read Operation

Valid와 Ready는 Handshake Signal입니다. 

 

Valid-Read Handshake는 Data를 보내고 받는 Source와 Destination사이에서 Data 이동 준비를 확인하는 작업입니다.

위처럼 Valid와 Ready가 모두 1이 될 때, Slave는 Read 할 Data를 Master에게 전달합니다. 

 

Write동작일 때는 Master가 Source, Slave가 Destination이기 때문에 동작이 반대로 일어납니다.

 

 


AXI Read Operation

Read Operation Pulse

Read Operation을 살펴보겠습니다.

1) Read ADDR 신호를 전송하기위해 Handshake 준비

2) AValid-ARead로 Handshake를 하고 ADDR(주소)를 전송한다.

3) Data를 보내기 위해서 Valid를 보내 Handshake를 준비한다.

4) Ready 신호를 보내 HandShake를 완료하고 Read할 Data를 전송한다.

+) Read Data의 마지막을 알리는 신호RLAST가 존재한다.


AXI Read Slave

`timescale 1ns / 1ps


module axi_slave(
    input RST,
    input CLK,
    input   [4:0]   AXI_ADDR,
    input           AXI_AVALID,
    output reg      AXI_AREADY,
    output  [7:0]   AXI_DATA,
    output  reg     AXI_VALID,
    input           AXI_READY
    );

parameter [1:0]     sidle = 2'b00,
                    saddr = 2'b01,
                    srom = 2'b10,
                    sdata = 2'b11;
reg [1:0]   cstate, nstate;                    

wire    [4:0] rom_addr;
wire    [7:0] rom_data;
    
rom32x8 rom_0 (
  .clka         (CLK),    // input wire clka
  .addra        (rom_addr),  // input wire [4 : 0] addra
  .douta        (rom_data)  // output wire [7 : 0] douta
);    

assign rom_addr = AXI_ADDR;
assign AXI_DATA = rom_data;

//fsm
always @(posedge CLK)
    if(RST)
        cstate <= sidle;
    else
        cstate <= nstate;        

always @(cstate, AXI_AVALID, AXI_READY)
begin
    AXI_AREADY = 1'b0;
    AXI_VALID = 1'b0;
    case (cstate)
        sidle : begin
            if(AXI_AVALID) 
                nstate = saddr;
            else
                nstate = sidle;
        end
        saddr : begin 
                nstate = srom;
                AXI_AREADY = 1'b1;
        end                
        srom : nstate = sdata;
        sdata : begin
            AXI_VALID = 1'b1;
            if(AXI_READY) begin
                AXI_VALID = 1'b1;
                nstate = sidle;
            end else
                nstate = sdata;
        end
        default : nstate = sidle;
    endcase
end     //always                                       
                                                        

endmodule

 


AXI Read Master

`timescale 1ns / 1ps

module my_axi_master(
    input RST,
    input CLK,
    input [4:0] ADDR,
    input START,
    
    output [4:0] AXI_ADDR,
    output reg AXI_AVALID,
    input AXI_AREADY,
    
    input [7:0] AXI_DATA,
    input AXI_VALID,
    output reg AXI_READY
    );

parameter   [1:0]   sidle = 2'b00,
                    saddr = 2'b01,
                    sdata = 2'b10;

reg [1:0] cstate, nstate;

assign AXI_ADDR = ADDR;
                    
always @(posedge CLK)
    if(RST) 
        cstate <= sidle;
    else
        cstate <= nstate;

always @(cstate, START,AXI_AREADY,AXI_VALID)
begin
    AXI_AVALID = 1'b0;
    AXI_READY = 1'b0;
    
    case (cstate)
        sidle : begin
            if(START)
                nstate = saddr;
            else
                nstate = sidle;
        end
        saddr : begin
            AXI_AVALID = 1'b1;
            if(AXI_AREADY)
                  nstate = sdata;
            else 
                nstate = saddr;  
        end
        sdata : begin
            AXI_READY = 1'b1;
            if(AXI_VALID)
                nstate = sidle;
            else
                nstate = sdata;
        end
        default : nstate = sidle;
    endcase                                                                                                                           
end     //always                     
endmodule

 


Testbench Of AXI Read Operation

`timescale 1ns / 1ps

module axi_tb();
parameter CLK_PD = 10.0;
reg rst, clk;
reg start;
reg [4:0] addr;

wire [4:0] axi_addr;
wire  [7:0] axi_data;
wire        axi_avalid, axi_aready;
wire        axi_valid, axi_ready;

// uut instantiation
my_axi_master master_0 (
    .RST     (rst),
    .CLK     (clk),
    .ADDR   (addr),
    .START  (start),
    
    .AXI_ADDR   (axi_addr),
    .AXI_AVALID (axi_avalid),
    .AXI_AREADY (axi_aready),
    
    .AXI_DATA   (axi_data),
    .AXI_VALID  (axi_valid),
    .AXI_READY  (axi_ready)
    );
    
axi_slave slave_0 (
    .RST        (rst),
    .CLK        (clk),
    .AXI_ADDR   (axi_addr),
    .AXI_AVALID (axi_avalid),
    .AXI_AREADY (axi_aready),
    .AXI_DATA   (axi_data),
    .AXI_VALID  (axi_valid),
    .AXI_READY  (axi_ready)
    );    
// rst, clk gen
initial begin
    rst = 1'b1;
    #(CLK_PD*10);
    rst = 1'b0;
end

initial clk = 1'b0;
always #(CLK_PD/2) clk = ~clk;

// stimulus for start, addr
integer i;

initial begin
    start = 1'b0;
    addr = 5'd0;
    #(CLK_PD/2);
    wait (rst == 1'b0);
 //   repeat(2) @(posedge clk);
    #(CLK_PD*10);
    for (i=0; i<32; i = i+1)
    begin
        start = 1'b1;
        wait (axi_aready == 1'b1);
        start = 1'b0;
        wait (axi_valid);
        #(CLK_PD*5);
        addr = addr + 1;

    end
    #100;
    $finish;
end     //always            
    
endmodule

 Testbench Pulse는 상단 첫번째 그림이니 생략하겠습니다.

 

다음 포스팅은 Write Opertaion으로 돌아오겠습니다.

 

감사합니다.