axi4_full master与slave ip通信 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
目标
- 第一步:创建axi4 full master与slave ip,用master读写slave
- 第二步,在axi4 full master/slave中,用二维数组替换
- 第三步,用bram替换
第一步
以上是axi4 master的设置,默认启动读写4k bytes
以上是axi4 slave的修改,让其ram容量有4k bytes
仿真结果
写入1-1024,读出也是1-1024正确
观察axi4_slave的内部波形,可见4块reg_mem都写入了数据。
第二步,在axi4 full master/slave中,用二维数组替换
先观察AXI4的几个关键信号。对于写,由于是burst模式,可见awvalid/awready只在开始发一次,后面就没有了,这与axi4-lite不同。因此awvalid/awready信号不能用来产生写信号。对于读也是这样,arvalid/arrready不能用于产生读信号。
注意mem_wren, mem_rden信号的产生。
代码对比,看我们在原始axi4 full slave代码上做了什么修改
parameter integer C_S_AXI_ADDR_WIDTH = 12,
localparam integer OPT_MEM_ADDR_BITS = 9;
// ------------------------------------------
// -- Example code to access user logic memory region
// ------------------------------------------
reg [31:0] my_mem[0:1023];
wire mem_rden;
wire mem_wren;
//wire [31:0] data_in ;
//wire [31:0] data_out;
assign mem_wren = axi_wready && S_AXI_WVALID ;
assign mem_rden = axi_arv_arr_flag ; //& ~axi_rvalid
assign mem_address = (axi_arv_arr_flag? axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:(axi_awv_awr_flag? axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:0));
//assigning 32 bit data
//assign data_in = S_AXI_WDATA;
//assign data_out = my_mem[mem_address];
always @( posedge S_AXI_ACLK )
begin
if (mem_wren && S_AXI_WSTRB==4'b1111)
begin
my_mem[mem_address] <= S_AXI_WDATA;
end
end
always @( posedge S_AXI_ACLK )
begin
if (mem_rden)
begin
mem_data_out[0] <=my_mem[mem_address] ;
end
end
always @( mem_data_out, axi_rvalid)
begin
if (axi_rvalid)
begin
// Read address mux
axi_rdata <= mem_data_out[0];
end
else
begin
axi_rdata <= 32'h00000000;
end
end
// Add user logic here
// User logic ends
仿真波形
可以看到axi4 full slave ip中mem的写入是正常。axi4 full master的发送和接收数据是正确的。axi4 full master ip的结果比对是正确的。
我们在axi4 master中定义了一块mem来接收到的数据。可见波形也是正确的。
第三步:用bram替换
bram的设置是32x1024,single-port
// ------------------------------------------
// -- Example code to access user logic memory region
// ------------------------------------------
wire mem_rden;
wire mem_wren;
assign mem_wren = axi_wready && S_AXI_WVALID ;
assign mem_rden = axi_arv_arr_flag ; //& ~axi_rvalid
assign mem_address = (axi_arv_arr_flag? axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:(axi_awv_awr_flag? axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:0));
wire clka;
wire [0 : 0] wea;
wire [9 : 0] addra;
wire [31 : 0] dina;
wire [31 : 0] douta;
assign clka=S_AXI_ACLK;
assign wea=mem_wren;
assign addra=mem_address;
assign dina=S_AXI_WDATA;
// Add user logic here
blk_mem_gen_0 your_instance_name (
.clka(clka), // input wire clka
.ena(1'b1), // input wire ena
.wea(wea), // input wire [0 : 0] wea
.addra(addra), // input wire [9 : 0] addra
.dina(dina), // input wire [31 : 0] dina
.douta(douta) // output wire [31 : 0] douta
);
always @( douta, axi_rvalid)
begin
if (axi_rvalid)
begin
// Read address mux
axi_rdata = douta;
end
else
begin
axi_rdata = 32'h00000000;
end
end
// User logic ends
仿真波形
可以看到结果正确