平台:vivado2023.1
应用场景,在设计的过程中,在xilinx内部的IP采用AXI接口协议。而我们外部的FIFO,BRAM等接口有时候使用的Native接口。使用AMM Master Bridge IP将普通的native接口转换为AXI接口协议。
参考文件:pg287.下载地址
AMM Master Bridge (xilinx.com)
关于该IP的配置说明
IP可以将Avalon接口读写在内部仲裁转换为AXI接口读写。IP最多支持八个主Avalon接口。
Avalon Address Width:接口的地址位宽。最多支持64位地址。
DATA Width:接口的数据位宽,最大支持1024位宽。
Number of Avalon Masters:主Avalon接口。
Mode of operation:可以选择仅读,仅写和读写。
性能展示
关于读写操作的使能转换延迟。
关于读写操作的吞吐量。
从上面可以看出来,官方给出的指示在时钟为200MHz时,在理论带宽为6.4Gb/s时,不同的BL位宽的吞吐量。
端口介绍
这里主要学习他的Avalon端口。
端口名字 | I/O | 位宽 | 描述 |
avs_address_s# | I | C_AVA_ADDR_WIDTH | Avalon 地址通道 |
avs_byteenable_s# | I | C_AVA_DATA_WIDTH/8 | 字节启用写入。 |
avs_write_s# | I | 1 | 从 Avalon 写入指示。 |
avs_read_s# | I | 1 | 读取 Avalon 的指示。 |
avs_writedata_s# | I | C_AVA_DATA_WIDTH | 写入数据。 |
avs_waitrequest_s# | O | 1 | 等待请求给 |
avs_readdata_s# | O | C_AVA_DATA_WIDTH | 读取数据输出。 |
avs_readdatavalid_s# | O | 1 | 读取数据对 Avalon 主站的有效指示。 |
avs_burstcount_s# | I | 11 | 命令的突发计数 |
下面对该IP进行仿真学习。
新建BD文件,添加AMM Master Bridge IP。添加BRAM。自动连线后。生成顶层。
下面直接对其进行仿真。看一下他是怎么转换的。
直接看仿真结果。
设置地址为0,突发长度为100个数据。
在Avalon端口,写入0-99。
可以看到在avs_write_s0为1和avs_waitrequest_s0为0的情况下写入有效。
读出。
在avs_read_s0为1和avs_waitrequest_s0为0时读使能握手成功。IP从BRAM中读出100个数据。
在AXI接口上写地址握手后写入数据。
仿真代码。
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/06/19 10:59:29
// Design Name:
// Module Name: vtf_amm_axi_bridge
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module vtf_amm_axi_bridge;
reg [31:0] Avalon_S0_0_address ;
reg [10:0] Avalon_S0_0_burstcount;
reg Avalon_S0_0_read ;
reg Avalon_S0_0_write ;
reg [31:0] Avalon_S0_0_writedata;
reg aresetn_0 ;
reg clk_0 ;
wire [31:0] Avalon_S0_0_readdata ;
wire Avalon_S0_0_readdatavalid;
wire Avalon_S0_0_waitrequest;
design_1_wrapper u_design_1_wrapper(
.Avalon_S0_0_address (Avalon_S0_0_address ),
.Avalon_S0_0_burstcount (Avalon_S0_0_burstcount ),
.Avalon_S0_0_read (Avalon_S0_0_read ),
.Avalon_S0_0_readdata (Avalon_S0_0_readdata ),
.Avalon_S0_0_readdatavalid (Avalon_S0_0_readdatavalid ),
.Avalon_S0_0_waitrequest (Avalon_S0_0_waitrequest ),
.Avalon_S0_0_write (Avalon_S0_0_write ),
.Avalon_S0_0_writedata (Avalon_S0_0_writedata ),
.aresetn_0 (aresetn_0 ),
.clk_0 (clk_0 ));
initial
begin
Avalon_S0_0_address=0;
Avalon_S0_0_burstcount=0;
aresetn_0=0;
clk_0=0;
#100;
aresetn_0=1;
Avalon_S0_0_address=0;
Avalon_S0_0_burstcount=11'd100;
end
always@(posedge clk_0 or negedge aresetn_0)
begin
if(aresetn_0 == 1'b0)begin
Avalon_S0_0_writedata <= 32'h0;
end
else if(Avalon_S0_0_write==1'b1 && Avalon_S0_0_waitrequest ==1'b0) begin
Avalon_S0_0_writedata <= Avalon_S0_0_writedata + 32'h1;
end
else begin
Avalon_S0_0_writedata <= Avalon_S0_0_writedata;
end
end
always@(posedge clk_0 or negedge aresetn_0)
begin
if(aresetn_0 == 1'b0)begin
Avalon_S0_0_write <= 1'h0;
end
else if(Avalon_S0_0_writedata<32'd99) begin
Avalon_S0_0_write <= 1'h1;
end
else begin
Avalon_S0_0_write <= 1'b0;
end
end
always@(posedge clk_0 or negedge aresetn_0)
begin
if(aresetn_0 == 1'b0)begin
Avalon_S0_0_read <= 1'h0;
end
else if(Avalon_S0_0_writedata==32'd99) begin
Avalon_S0_0_read <= 1'h1;
end
else if(Avalon_S0_0_read == 1'b1 && Avalon_S0_0_waitrequest == 1'b0)begin
Avalon_S0_0_read <=1'b0;
end
else begin
Avalon_S0_0_read <= Avalon_S0_0_read;
end
end
always#5 clk_0 = ~clk_0;
endmodule