AXI4‐Full外设,用VIP仿真,并且修改memory大小 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
创建AXI-Full的IP
默认位宽32bits,默认最大容量只能选择1024bytes。后面我们手动修改网表,让容量变为4096bytes。
打开ip,修改位宽。一共4个地方需要修改。
这里从10修改为12
这里也要从10修改为12
这里从7修改为9
这里从255修改为1023
修改完了后,用VIP仿真
testbench修改的部分, 我们增加了2次写,2次读。注意读/写的地址。 burst每次最大只能256。
task automatic S_AXI_TEST;
begin
#1;
for(int i = 0; i < 256; i++) begin
mtestWDataF[i*32+:32] = i+32'h11223344;
end
$display("Sequential write transfers example similar to AXI BFM WRITE_BURST method starts");
mtestID = 0;
mtestADDR = 0;
mtestBurstLength = 255;
mtestDataSize = xil_axi_size_t'(xil_clog2(32/8));
mtestBurstType = XIL_AXI_BURST_TYPE_INCR;
mtestLOCK = XIL_AXI_ALOCK_NOLOCK;
mtestCacheType = 0;
mtestProtectionType = 0;
mtestRegion = 0;
mtestQOS = 0;
result_slave = 1;
for(int i = 0; i < 255;i++) begin
mtestWUSER = 'h0;
end
mst_agent_0.AXI4_WRITE_BURST(
mtestID,
mtestADDR,
mtestBurstLength,
mtestDataSize,
mtestBurstType,
mtestLOCK,
mtestCacheType,
mtestProtectionType,
mtestRegion,
mtestQOS,
mtestAWUSER,
mtestWDataF,
mtestWUSER,
mtestBresp
);
mtestADDR = 256*4;
for(int i = 0; i < 256; i++) begin
mtestWDataF[i*32+:32] = i+32'h55667788;
end
mst_agent_0.AXI4_WRITE_BURST(
mtestID,
mtestADDR,
mtestBurstLength,
mtestDataSize,
mtestBurstType,
mtestLOCK,
mtestCacheType,
mtestProtectionType,
mtestRegion,
mtestQOS,
mtestAWUSER,
mtestWDataF,
mtestWUSER,
mtestBresp
);
$display("Sequential write transfers example similar to AXI BFM WRITE_BURST method completes");
$display("Sequential read transfers example similar to AXI BFM READ_BURST method starts");
mtestID = 0;
mtestADDR = 0;
mtestBurstLength = 255;
mtestDataSize = xil_axi_size_t'(xil_clog2(32/8));
mtestBurstType = XIL_AXI_BURST_TYPE_INCR;
mtestLOCK = XIL_AXI_ALOCK_NOLOCK;
mtestCacheType = 0;
mtestProtectionType = 0;
mtestRegion = 0;
mtestQOS = 0;
mst_agent_0.AXI4_READ_BURST (
mtestID,
mtestADDR,
mtestBurstLength,
mtestDataSize,
mtestBurstType,
mtestLOCK,
mtestCacheType,
mtestProtectionType,
mtestRegion,
mtestQOS,
mtestARUSER,
mtestRDataF,
mtestRresp,
mtestRUSER
);
mtestADDR=256*4;
mst_agent_0.AXI4_READ_BURST (
mtestID,
mtestADDR,
mtestBurstLength,
mtestDataSize,
mtestBurstType,
mtestLOCK,
mtestCacheType,
mtestProtectionType,
mtestRegion,
mtestQOS,
mtestARUSER,
mtestRDataF,
mtestRresp,
mtestRUSER
);
$display("Sequential read transfers example similar to AXI BFM READ_BURST method completes");
COMPARE_DATA(mtestWDataF,mtestRDataF);
$display("Sequential read transfers example similar to AXI VIP READ_BURST method completes");
$display("---------------------------------------------------------");
$display("EXAMPLE TEST S00_AXI: PTGEN_TEST_FINISHED!");
if ( result_slave ) begin
$display("PTGEN_TEST: PASSED!");
end else begin
$display("PTGEN_TEST: FAILED!");
end
$display("---------------------------------------------------------");
end
endtask
波形
可以看到,ip里面它是把1024x32的地址空间拆分为4个1024x8的地址空间。每个1024x8的地址空间用一个reg [7:0] mem [0:1023] 实现。 因此: {mem3[i], mem2[i], mem1[i], mem0[i]}=wdata; rdata={mem3[i], mem2[i], mem1[i], mem0[i]}
从下面的图可以看到
这个是mem3的数据写入。第一次写入的全是11,第二次写入的全是55。
AXI4-Full如何实现对外设的集成? 本质来说,就是如何实现硬件对byte_ram的读和写。
硬件的写入(例如这里的标志寄存器),通过 BRAM_GEN[0].BYTE_BRAM_GEN[0].byte_ram[0][0]这种方式,可以直接指定到某个byte_ram的某个指定位。
xfer_start的产生(当写入某个地址的时候产生)。硬件对byte_ram的读取,也使用BRAM_GEN[0].BYTE_BRAM_GEN[0].byte_ram[1]这种方式指定读取,甚至还可以拼接。虽然没有axi-lite那种方便,但也是完全可以的。
为了方便验证,我们还做了一个从xfer_start-->xfer_rdy/xfer_final的行为模型。 完整的代码如下:
// implement Block RAM(s)
generate
for(i=0; i<= USER_NUM_MEM-1; i=i+1)
begin:BRAM_GEN
wire mem_rden;
wire mem_wren;
assign mem_wren = axi_wready && S_AXI_WVALID ;
assign mem_rden = axi_arv_arr_flag ; //& ~axi_rvalid
for(mem_byte_index=0; mem_byte_index<= (C_S_AXI_DATA_WIDTH/8-1); mem_byte_index=mem_byte_index+1)
begin:BYTE_BRAM_GEN
wire [8-1:0] data_in ;
wire [8-1:0] data_out;
reg [8-1:0] byte_ram [0 : 1023];
integer j;
//assigning 8 bit data
assign data_in = S_AXI_WDATA[(mem_byte_index*8+7) -: 8];
assign data_out = byte_ram[mem_address];
always @( posedge S_AXI_ACLK )
begin
if(xfer_final)
BRAM_GEN[0].BYTE_BRAM_GEN[0].byte_ram[0][0]<=1;
if(xfer_rdy)
BRAM_GEN[0].BYTE_BRAM_GEN[0].byte_ram[0][1]<=1;
if (mem_wren && S_AXI_WSTRB[mem_byte_index])
begin
byte_ram[mem_address] <= data_in;
end
end
always @( posedge S_AXI_ACLK )
begin
if (mem_rden)
begin
mem_data_out[i][(mem_byte_index*8+7) -: 8] <= data_out;
end
end
end
end
endgenerate
//Output register or memory read data
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
reg xfer_final;
reg xfer_rdy;
wire xfer_start;
wire [7:0] data1;
wire [15:0] data2;
assign xfer_start=axi_wready && S_AXI_WVALID && (mem_address==0);
assign data1=BRAM_GEN[0].BYTE_BRAM_GEN[0].byte_ram[1];
assign data2={BRAM_GEN[0].BYTE_BRAM_GEN[1].byte_ram[2], BRAM_GEN[0].BYTE_BRAM_GEN[0].byte_ram[2]};
initial begin
xfer_final=0;
xfer_rdy=1;
while(1) begin
wait(xfer_start==1);
#1 xfer_rdy=0;
repeat(100)
@( posedge S_AXI_ACLK );
#1 xfer_final=1;
xfer_rdy=1;
@( posedge S_AXI_ACLK )
#1 xfer_final=0;
end
end
// User logic ends
可以看到xfer_start和xfer_rdy/xfer_final正确产生。
可以看到xfer_rdy/xfer_final可以正确设置byte_ram的对应位。
data1和data2可以正确读取到byte_ram的对应内容。
关于burst_size的设置
范围是0--255,表示传输1-256个
mst_agent_0.AXI4_WRITE_BURST(
mtestID,
0 /*mtestADDR*/,
0 /*mtestBurstLength*/,
mtestDataSize,
mtestBurstType,
mtestLOCK,
mtestCacheType,
mtestProtectionType,
mtestRegion,
mtestQOS,
mtestAWUSER,
32'habcdef/*mtestWDataF*/,
mtestWUSER,
mtestBresp
);
设置为0,最终的结果,只写入一个机器字长。
mst_agent_0.AXI4_WRITE_BURST(
mtestID,
0 /*mtestADDR*/,
1 /*mtestBurstLength*/,
mtestDataSize,
mtestBurstType,
mtestLOCK,
mtestCacheType,
mtestProtectionType,
mtestRegion,
mtestQOS,
mtestAWUSER,
64'h12345678_89abcdef/*mtestWDataF*/,
mtestWUSER,
mtestBresp
);
设置为1,最终的结果,只写入2个机器字长。