위와같이 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
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로 가게 한다.