0426~0502 AXI_master

이의혁·2023년 7월 26일
0

위와같이 CPU에서 read 동작을 하면 microblazed의 output을 통하여 신호가 나가서 gpio2를 통해서 read동작을 한다는 신호은 ren을 보내고 어느 주소를 읽을건지도 같이 master에게 보낸다. 그리고 master에서는 slave에게 그 신호를 전달하여 slave는 그 주소에 있는 data를 master를 통하여 gpio1에 보내고 cpu에 보내게 된다.
그리고 rdone이라는 신호를 slave에서부터 cpu까지 보내게 한다. 그 이유는 resp이라는 신호는 master와 slave사이에만 동작하는 신호라 read동작을 완료 했다라는 것을 cpu는 모르기 때문에 read신호가 끝이 났다는 신호는 rdone이라는 것을 만들어서 cpu에 보내게 하였다.

writet 동작은 write하라는 신호은 wen이라는 신호와 addr,data를 gpio2에 보내고 그 신호들을 master에게 보낸 후 slave에 동작을 하게한다.
read와 마찬가지로 wdone이라는 신호를 만들어서 cpu가 write동작이 다 끝났다는 것을 알게 하기 위해서 cpu에게 전달 하였다.

module axi_master (   
   axi_clk,
   axi_reset_n,
   
   GPIO_addr,
   GPIO_Wdata,
   GPIO_Rdata,
   GPIO_Ren,
   GPIO_Wen,
   GPIO_rrsep,
   GPIO_brsep,
   GPIO_W_DONE,
   GPIO_R_DONE,
   GPIO_byte_en,
   aximaster_awaddr,
   aximaster_awvalid,
   aximaster_awport,
   aximaster_awready,
   
   aximaster_wdata,
   aximaster_wstrb,
   aximaster_wvalid,
   aximaster_wready,
   
   aximaster_bresp,
   aximaster_bvalid,
   aximaster_bready,
   
   aximaster_araddr,
   aximaster_arvalid,
   aximaster_arport,
   aximaster_arready,
   
   aximaster_rresp,
   aximaster_rdata,
   aximaster_rvalid,
   aximaster_rready
);

input           axi_clk;
input           axi_reset_n;

input      [15:0]   GPIO_addr;
input      [31:0]   GPIO_Wdata;
output   reg   [31:0]   GPIO_Rdata;
input             GPIO_Wen;
input              GPIO_Ren;

output wire [1:0]   GPIO_rrsep,
               GPIO_brsep;
input[3:0] GPIO_byte_en;
//AW CH
output   reg   [15:0]    aximaster_awaddr;
output  reg         aximaster_awvalid;
output    reg   [2:0]     aximaster_awport;
input             aximaster_awready;
               
output    reg   [31:0]    aximaster_wdata;
output    reg   [3:0]     aximaster_wstrb;
output  reg         aximaster_wvalid;
input             aximaster_wready;
               
input      [1:0]     aximaster_bresp;
input             aximaster_bvalid;
output  reg         aximaster_bready;
               
output    reg   [15:0]    aximaster_araddr;
output  reg         aximaster_arvalid;
output    reg   [2:0]     aximaster_arport;
input                aximaster_arready;
               
input      [31:0]    aximaster_rdata;
input      [1:0]     aximaster_rresp;
input             aximaster_rvalid;
output reg          aximaster_rready;

//////////////////////////////////////////////////////
assign GPIO_rrsep = aximaster_rresp;
assign GPIO_brsep = aximaster_bresp;

output reg GPIO_R_DONE;
output reg GPIO_W_DONE;

/////////////////////////////////////////////////////////
//AW
parameter AW_S0=2'b00,AW_S1=2'b01,AW_S2=2'b10,AW_S3=2'b11;
reg [1:0] AW_state;
reg [1:0] AW_next_state;
//state register

reg s_GPIO_Wen;

/////////////////////////////////////////////////////////////////////
always @(posedge axi_clk or negedge  axi_reset_n)
begin

   if (!axi_reset_n)
      AW_state <= AW_S0;
   else
       s_GPIO_Wen <= GPIO_Wen;
      AW_state <= AW_next_state;
end

always @(*)
begin
   //aximaster_awvalid = 1'b0;
   AW_next_state = AW_S0;

   case(AW_state)
   AW_S0 : if(GPIO_Wen==1'b1 && s_GPIO_Wen==1'b0)begin 
            AW_next_state = AW_S1;
         end
         else begin 
            AW_next_state = AW_S0;
         end
   AW_S1 : if(aximaster_awready==1'b1 && aximaster_awvalid == 1'b1) begin  
            AW_next_state = AW_S2;
         end
         else begin
            AW_next_state = AW_S1;
         end
   AW_S2 :  AW_next_state = AW_S0;
   default: AW_next_state = AW_S0;
   endcase
end

always @(*)
begin
aximaster_awvalid = 1'b0;
aximaster_awaddr = 16'b0;
case(AW_state)
      AW_S0:   begin aximaster_awvalid = 1'b0;
            aximaster_awaddr = GPIO_addr;
            end
      AW_S1:begin aximaster_awvalid = 1'b1;
            aximaster_awaddr = GPIO_addr;
                end
      AW_S2:    begin
            aximaster_awvalid = 1'b0;
            aximaster_awaddr = GPIO_addr;
            end
      default:   begin         aximaster_awvalid = 1'b0;
                            aximaster_awaddr = GPIO_addr; end
      endcase
end

//////////////////////////////////////////////////////////////
//W
parameter W_S0=2'b00,W_S1=2'b01,W_S2=2'b10,W_S3=2'b11;
reg [1:0] W_state;
reg [1:0] W_next_state;
//state register
always @(posedge axi_clk or negedge  axi_reset_n)
begin
   if (!axi_reset_n) 
      W_state <= W_S0;
   else
      W_state <= W_next_state;
end

always @(*)
begin
//aximaster_wvalid = 1'b0;
W_next_state = W_S0;
   case(W_state)
   W_S0 : if(GPIO_Wen==1'b1 && s_GPIO_Wen==1'b0) W_next_state = W_S1;
         else W_next_state = W_S0;
   W_S1 : if(aximaster_wready==1'b1 && aximaster_wvalid == 1'b1) begin  
            W_next_state = W_S2;
         end
         else W_next_state = W_S1;
   W_S2 :  W_next_state = W_S0;
   endcase
end

always @(*)
begin
aximaster_wstrb = GPIO_byte_en;
aximaster_wvalid = 1'b0;
aximaster_wdata = GPIO_Wdata;
case(W_state)
      W_S0:   aximaster_wvalid = 1'b0;
      W_S1:   aximaster_wvalid = 1'b1;
      W_S2:   begin   aximaster_wvalid = 1'b0;
            aximaster_wdata = GPIO_Wdata;
            end
      default: aximaster_wvalid = 1'b0;
endcase
end
//////////////////////////////////////////////////////////////

//B
parameter B_S0=2'b00,B_S1=2'b01,B_S2=2'b10,B_S3=2'b11;
reg  [1:0] B_state;
reg   [1:0] B_next_state;
//state register
always @(posedge axi_clk or negedge  axi_reset_n)
begin
   if (!axi_reset_n) 
      B_state <= B_S0;
   else
      B_state <= B_next_state;
end

always @(*)
begin

B_next_state = B_S0;
//aximaster_bready = 1'b0;
   case(B_state)
   B_S0 : if(aximaster_wvalid) B_next_state = B_S1;
         else B_next_state = B_S0;
   B_S1 : if(aximaster_bvalid ==1'b1 && aximaster_bready == 1'b1) 
            B_next_state = B_S2;
         else B_next_state = B_S1;
   B_S2 :  B_next_state = B_S0;
   endcase
end

always @(*)
begin
aximaster_bready = 1'b0;
case(B_state)
      B_S0: aximaster_bready = 1'b0;
      B_S1: aximaster_bready = 1'b1;
      B_S2: begin aximaster_bready =1'b0;

            end
      default: aximaster_bready =1'b0;
endcase
end
//////////////////////////////////////////////////////////////
reg s_GPIO_Ren;

//////////////////////////////////////////////////////////////
//AR
parameter AR_S0=2'b00,AR_S1=2'b01,AR_S2=2'b10,AR_S3=2'b11;
reg [1:0] AR_state;
reg [1:0] AR_next_state;
//state register
always @(posedge axi_clk or negedge  axi_reset_n)
begin

   if (!axi_reset_n) 
      AR_state <= AR_S0;
   else
   s_GPIO_Ren <= GPIO_Ren;
      AR_state <= AR_next_state;
end

always @(*)
begin
   //aximaster_arvalid = 1'b0;
   AR_next_state = AR_S0;
   
   case(AR_state)
   AR_S0 : if(GPIO_Ren==1'b1 && s_GPIO_Ren==1'b0)begin
            AR_next_state = AR_S1;
         end
         else begin 
            AR_next_state = AR_S0;
         end
   AR_S1 : if(aximaster_arready==1 && aximaster_arvalid==1) begin  
            AR_next_state = AR_S2;
         end
         else begin
            AR_next_state = AR_S1;
         end
   AR_S2 :  AR_next_state = AR_S3;
   default: AR_next_state = AR_S0;
   endcase
end

always @(*)
begin
aximaster_arvalid = 1'b0;
aximaster_araddr = 16'b0;
case(AR_state)
      AR_S0:begin
            aximaster_arvalid = 1'b0;
            aximaster_araddr = GPIO_addr;
            end
      AR_S1:begin
            aximaster_arvalid = 1'b1;
            aximaster_araddr = GPIO_addr;
            end
      AR_S2: begin
            aximaster_arvalid = 1'b0;
            aximaster_araddr = GPIO_addr;
            end
      default: begin   
             aximaster_arvalid = 1'b0;
            aximaster_araddr = GPIO_addr;
                end
      endcase
end
//////////////////////////////////////////////////////////////
//R
parameter R_S0=2'b00,R_S1=2'b01,R_S2=2'b10,R_S3=2'b11;
reg [1:0] R_state=R_S0;
reg [1:0] R_next_state=R_S0;
//state register
always @(posedge axi_clk or negedge  axi_reset_n)
begin
   if (!axi_reset_n) 
      R_state <= R_S0;
   else
      R_state <= R_next_state;

end

always @(*)
begin
    R_next_state = R_S0;
   //aximaster_rvalid == 1'b0;
   //aximaster_rready = 1'b0;
   case(R_state)
   R_S0 : if(GPIO_Ren==1'b1 && s_GPIO_Ren==1'b0)begin
            R_next_state = R_S1;
         end
         else begin 
            R_next_state = R_S0;
         end
   R_S1 : if(aximaster_rready==1'b1 && aximaster_rvalid == 1'b1) begin  
            R_next_state = R_S2;
         end
         else begin
            R_next_state = R_S1;
         end
   R_S2 :  begin   
      R_next_state = R_S3;
            end
   default :  R_next_state = R_S0;

   endcase
end

always @(*)
begin
aximaster_rready = 1'b0;
//GPIO_Rdata = 32'b0;
case(R_state)
         R_S0:begin
            
            aximaster_rready = 1'b0;
            end
         R_S1:begin
            aximaster_rready = 1'b1;
            GPIO_Rdata = aximaster_rdata;
            end
         R_S2:begin
            aximaster_rready = 1'b0;
            GPIO_Rdata = aximaster_rdata; end
         default:   aximaster_rready = 1'b0;
endcase
end
//////////////////////////////////////////////////////////////
// DONE 
parameter DONE_W_S0=1'b0, DONE_W_S1=1'b1;
reg  DONE_W_state;
reg  DONE_W_next_state;

// DONE_S0,S1 => WRITE_DONE/ DONE_S2,S3 => READ_DONE  
always @(posedge axi_clk or negedge  axi_reset_n)
begin
   if (!axi_reset_n) 
      DONE_W_state <= DONE_W_S0;
   else
      DONE_W_state <= DONE_W_next_state;
end  

always @(*)
begin
   DONE_W_next_state = DONE_W_S0;
   case(DONE_W_state)
   DONE_W_S0 : if(aximaster_bvalid ==1'b1 && aximaster_bready == 1'b1)begin 
            DONE_W_next_state = DONE_W_S1;
         end
         else begin 
            DONE_W_next_state = DONE_W_S0;
         end
   DONE_W_S1 : if(GPIO_Wen==1'b1 && s_GPIO_Wen==1'b0) begin  
            DONE_W_next_state = DONE_W_S0;
         end
         else begin
            DONE_W_next_state = DONE_W_S1;
         end
   endcase
end

always @(*)
begin
GPIO_W_DONE=1'b0;
case(DONE_W_state)
      DONE_W_S0:begin 
                  GPIO_W_DONE =1'b0;
                  end
      DONE_W_S1:begin
               GPIO_W_DONE =1'b1;
                end
      endcase
end
/////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////
// DONE 
parameter DONE_R_S0=1'b0, DONE_R_S1=1'b1;
reg  DONE_R_state;
reg  DONE_R_next_state;

// DONE_S0,S1 => WRITE_DONE/ DONE_S2,S3 => READ_DONE  
always @(posedge axi_clk or negedge  axi_reset_n)
begin
   if (!axi_reset_n) 
      DONE_R_state <= DONE_R_S0;
   else
      DONE_R_state <= DONE_R_next_state;
end  

always @(*)
begin
   DONE_R_next_state = DONE_R_S0;
   case(DONE_R_state)
   DONE_R_S0 : if(aximaster_rready==1'b1 && aximaster_rvalid == 1'b1)begin 
            DONE_R_next_state = DONE_R_S1;
         end
         else begin 
            DONE_R_next_state = DONE_R_S0;
         end
   DONE_R_S1 : if(GPIO_Ren==1'b1 && s_GPIO_Ren==1'b0) begin  
            DONE_R_next_state = DONE_R_S0;
         end
         else begin
            DONE_R_next_state = DONE_R_S1;
         end
   endcase
end

always @(*)
begin
GPIO_R_DONE=1'b0;
case(DONE_R_state)
      DONE_R_S0:begin 
                  GPIO_R_DONE =1'b0;
                  end
      DONE_R_S1:begin
               GPIO_R_DONE =1'b1;
                end
      endcase
end

endmodule

WRITE

AW-CH

AW-CH의 경우 state를 총 3개를 만들었다
먼저 초기상태인 S0상태에서는 awvalid값을 0을 주고
gpio에서 받은 주소를 axi-master_awaddr이라는 곳에 계속 집어 넣어준다
그러다가 GPIO에서 write동작을 하라는 gpio_wen신호가 1이 되고 그 신호를 1개의 clock을 소비하여 쉬프트 해서 만든 신호인 s_gpio_wen신호를 만든후 gpio_wen이 1 그리고 s_gpio_wen신호가 0일 때 state의 상태를 S1으로 넘어가게 만들었다. 한칸 쉬프트 한 신호를 만든 이유는 wen신호만 있게 되면 원하지 않은 동작이 계속 발생할 수 있기 때문에 만들게 되었다.
S1에서는 axi_master에서 slave에 valid신호를 1 올려주게 되고 그때 주소를 같이 보내주게 된다.
그리고 slave에서 ready신호를 받고 그때 valid신호가 1이 되는 상황이면 state를 S2로 넘겨준다.
S2에서는 valid신호를 0으로 주고 자동으로 state의 상태가 초기의 상태인 S0로 가게 만들었다

W-CH

W-CH의 경우에도 state를 3개를 만들었다
초기 상태 S0에서는 wvalid값을 으로 주고 gpio로부터 wen신호가 오고 aw와 똑같이 쉬프트 한값이 0일 때 state를 넘긴다 S1에서는 wvalid값을 1로 준다
그리고 wready라는 신호가 slave로부터 1을 받게되면 그때 state를 S2로 옮긴다 그리고 wvalid값을 0으로 바꾸고 data값을 집어 넣는다.
그리고 자동으로 초기 상태인 S0로 가게 만들었다.

B-CH

B채널의 경우에서는 AW와 W신호가 같이 동작하기 때문에 초기 상태는 bready신호는 0으로 주었다가 AW신호 혹은W신호의 valid신호가 발생하게 되면 state를 S1으로 옮기고 bready값을 1로 올려준다.
그후 slave로 부터 bvalid값을 받게 되면 state를 S2로 바꾸고 거기서 ready값을 0으로 주고 자동으로 state를 S0로 바꾼다.

AR-CH

초기 상태는 S0이고 그 때 arvalid값은 0이 되고있다
gpio로 부터 read하라는 신호인 ren이 발생하게 되고 그 신호를 쉬프트한 신호인 s_ren신호가 0이 되면 state를 S1으로 보낸다. S1에서는 valid값을 1로 주고 그때 gpio에서 보낸 addr과 aximaster에 있는 addr이 같아지게 된다.
그리고 slave에서 보낸 arready신호가 발생하게 되면 state가 S2로 바뀌게 된다.
S2에서는 다시 valid값을 0으로 주고 자동으로 다시 S3를 걸쳐서 S0으로 가게 만든다.

R-CH

R채널의 경우 초기 상태 SO에서 ready값을 0으로 주고
gpio로부터 read신호가 들어와서 read동작을 실행하게 되면 state가 S1으로 가게 된다. S1에서는 ready값을 1로 주고
aximaster의 addr를 gpio에 넣게 된다.
그리고 slave로부터 rvalid신호가 발생하게 되면 state를 S2로 바뀌게 하고 rready값을0으로 주게하고 자동으로 state를 S3을 걸쳐서 S0로 가게 한다.


profile
코딩왕이 되는 길

0개의 댓글