增加xdma相关学习
parent
0e392272f9
commit
0bf2017e9e
@ -0,0 +1,177 @@
|
||||
|
||||
module axi_bram #(
|
||||
parameter AXI_IDWIDTH = 4, // AXI的id宽度
|
||||
parameter AXI_AWIDTH = 64, // AXI的 地址总线宽度
|
||||
parameter AXI_DWIDTH = 256, // AXI的数据总线宽度 一次读取的数据位数
|
||||
parameter MEM_AWIDTH = 12 // BRAM size = MEM_AWIDTH*C_M_AXI_DATA_WIDTH (bits) = MEM_AWIDTH*C_M_AXI_DATA_WIDTH/8 (bytes)
|
||||
) (
|
||||
input wire rstn,
|
||||
input wire clk,
|
||||
// AXI-MM AW interface ----------------------------------------------------
|
||||
output wire s_axi_awready, // 从写地址准备好
|
||||
input wire s_axi_awvalid, // 主准备好
|
||||
input wire [ AXI_AWIDTH-1:0] s_axi_awaddr,
|
||||
input wire [ 7:0] s_axi_awlen,
|
||||
input wire [ AXI_IDWIDTH-1:0] s_axi_awid,
|
||||
// AXI-MM W interface ----------------------------------------------------
|
||||
output wire s_axi_wready,
|
||||
input wire s_axi_wvalid,
|
||||
input wire s_axi_wlast,
|
||||
input wire [ AXI_DWIDTH-1:0] s_axi_wdata,
|
||||
input wire [(AXI_DWIDTH/8)-1:0] s_axi_wstrb,
|
||||
// AXI-MM B interface ----------------------------------------------------
|
||||
input wire s_axi_bready,
|
||||
output wire s_axi_bvalid,
|
||||
output wire [ AXI_IDWIDTH-1:0] s_axi_bid,
|
||||
output wire [ 1:0] s_axi_bresp,
|
||||
// AXI-MM AR interface ----------------------------------------------------
|
||||
output wire s_axi_arready, // 表示S 已经可以接受 读地址信号
|
||||
input wire s_axi_arvalid, // 表示M 地址已经准备就绪
|
||||
input wire [ AXI_AWIDTH-1:0] s_axi_araddr, // M 发送的地址
|
||||
input wire [ 7:0] s_axi_arlen, // 突发长度
|
||||
input wire [ AXI_IDWIDTH-1:0] s_axi_arid,
|
||||
// AXI-MM R interface ----------------------------------------------------
|
||||
input wire s_axi_rready, // 只有当M ready的时候, S才可以发数据
|
||||
output wire s_axi_rvalid, // S的数据已经准备好, 可以发送到M
|
||||
output wire s_axi_rlast,
|
||||
output reg [ AXI_DWIDTH-1:0] s_axi_rdata,
|
||||
output wire [ AXI_IDWIDTH-1:0] s_axi_rid,
|
||||
output wire [ 1:0] s_axi_rresp
|
||||
);
|
||||
|
||||
|
||||
function automatic int log2 (input int x);
|
||||
int xtmp = x, y = 0;
|
||||
while (xtmp != 0) begin
|
||||
y ++;
|
||||
xtmp >>= 1;
|
||||
end
|
||||
return (y == 0) ? 0 : (y - 1);
|
||||
endfunction
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// AXI READ state machine
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
enum reg [0:0] {R_IDLE, R_BUSY} rstate = R_IDLE;
|
||||
|
||||
reg [AXI_IDWIDTH-1:0] rid = '0; // 从 读地址 传过来的id
|
||||
reg [ 7:0] rcount = '0; // 从 读地址 传过来的读取次数
|
||||
reg [ MEM_AWIDTH-1:0] mem_raddr, mem_raddr_last; // 当前操作的地址, 和上次操作的地址
|
||||
|
||||
assign s_axi_arready = (rstate == R_IDLE); // 读地址 可以进行 接收
|
||||
assign s_axi_rvalid = (rstate == R_BUSY); // 读数据 以准备就绪
|
||||
assign s_axi_rlast = (rstate == R_BUSY) && (rcount == 8'd0); // 是否是最后一个数据, 直接连线
|
||||
assign s_axi_rid = rid; // 直接连线
|
||||
assign s_axi_rresp = '0;
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if (~rstn) begin
|
||||
rstate <= R_IDLE;
|
||||
rid <= '0;
|
||||
rcount <= '0;
|
||||
end
|
||||
else begin
|
||||
case (rstate)
|
||||
R_IDLE :
|
||||
if (s_axi_arvalid) begin // M发起 读地址 请求
|
||||
rstate <= R_BUSY; // S切换到忙碌
|
||||
rid <= s_axi_arid; // 记录本次 M读地址 ID
|
||||
rcount <= s_axi_arlen; // 记录本次 M的读长度
|
||||
end
|
||||
R_BUSY :
|
||||
if (s_axi_rready) begin
|
||||
if (rcount == 8'd0) // 如果是 忙碌状态, 且 是最后一个数据
|
||||
rstate <= R_IDLE; // 则切换 S状态 为 空闲, 状态结束
|
||||
rcount <= rcount - 8'd1; // 每次忙碌状态 rcount 都会减1
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// 组合逻辑块,根据当前状态计算内存读地址
|
||||
always_comb
|
||||
if (rstate == R_IDLE && s_axi_arvalid) // 如果空闲状态 且 M已经准备好地址
|
||||
|
||||
mem_raddr = (MEM_AWIDTH)'(s_axi_araddr >> log2(AXI_DWIDTH/8)); // 计算地址,
|
||||
// 因为每次数据都会 传256位数据, 这里除以8, 得到需要传的次数, 每次1字节传输, 256/8就是32次
|
||||
// 看能整除多少次2, 然后 s_axi_araddr 进行右移, 移动到传过来的地址的 AXI_DWIDTH的字节边界 start起始的位置
|
||||
|
||||
else if (rstate == R_BUSY && s_axi_rready) // 如果繁忙, 且 M 已经准备好 接收 S发来的数据
|
||||
mem_raddr = mem_raddr_last + (MEM_AWIDTH)'(1); // 计算下一个内存地址, 加一即可, 这是一个二维数组
|
||||
else
|
||||
mem_raddr = mem_raddr_last; // 保持地址不变
|
||||
|
||||
// 在每个时钟上升沿,更新上一次的读地址
|
||||
always @ (posedge clk)
|
||||
mem_raddr_last <= mem_raddr;
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// AXI WRITE state machine
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
enum reg [1:0] {W_IDLE, W_BUSY, W_RESP} wstate = W_IDLE;
|
||||
|
||||
reg [AXI_IDWIDTH-1:0] wid = '0;
|
||||
reg [ 7:0] wcount = '0;
|
||||
reg [ MEM_AWIDTH-1:0] mem_waddr = '0;
|
||||
|
||||
assign s_axi_awready = (wstate == W_IDLE);
|
||||
assign s_axi_wready = (wstate == W_BUSY);
|
||||
assign s_axi_bvalid = (wstate == W_RESP);
|
||||
assign s_axi_bid = wid;
|
||||
assign s_axi_bresp = '0;
|
||||
|
||||
always @ (posedge clk or negedge rstn)
|
||||
if (~rstn) begin
|
||||
wstate <= W_IDLE;
|
||||
wid <= '0;
|
||||
wcount <= '0;
|
||||
mem_waddr <= '0;
|
||||
end else begin
|
||||
case (wstate)
|
||||
W_IDLE :
|
||||
if (s_axi_awvalid) begin
|
||||
wstate <= W_BUSY;
|
||||
wid <= s_axi_awid;
|
||||
wcount <= s_axi_awlen;
|
||||
mem_waddr <= (MEM_AWIDTH)'(s_axi_awaddr >> log2(AXI_DWIDTH/8));
|
||||
end
|
||||
W_BUSY :
|
||||
if (s_axi_wvalid) begin
|
||||
if (wcount == 8'd0 || s_axi_wlast)
|
||||
wstate <= W_RESP;
|
||||
wcount <= wcount - 8'd1;
|
||||
mem_waddr <= mem_waddr + (MEM_AWIDTH)'(1);
|
||||
end
|
||||
W_RESP :
|
||||
if (s_axi_bready)
|
||||
wstate <= W_IDLE;
|
||||
default :
|
||||
wstate <= W_IDLE;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// a block RAM
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
reg [AXI_DWIDTH-1:0] mem [ 1<<MEM_AWIDTH ]; // 这是一个二维数组
|
||||
|
||||
always @ (posedge clk)
|
||||
s_axi_rdata <= mem[mem_raddr]; // 一次读出 AXI_DWIDTH 位的数据
|
||||
|
||||
always @ (posedge clk)
|
||||
if (s_axi_wvalid & s_axi_wready)
|
||||
for (int i=0; i<(AXI_DWIDTH/8); i++)
|
||||
if (s_axi_wstrb[i])
|
||||
mem[mem_waddr][i*8+:8] <= s_axi_wdata[i*8+:8];
|
||||
|
||||
endmodule
|
||||
|
||||
|
@ -0,0 +1,220 @@
|
||||
|
||||
module fpga_top (
|
||||
output wire o_led0,
|
||||
input wire i_pcie_rstn,
|
||||
input wire i_pcie_refclkp, i_pcie_refclkn,
|
||||
input wire [0:0] i_pcie_rxp, i_pcie_rxn,
|
||||
output wire [0:0] o_pcie_txp, o_pcie_txn
|
||||
);
|
||||
|
||||
|
||||
localparam AXI_IDWIDTH = 4;
|
||||
localparam AXI_AWIDTH = 64;
|
||||
localparam AXI_DWIDTH = 64;
|
||||
|
||||
|
||||
wire pcie_rstn;
|
||||
wire pcie_refclk;
|
||||
|
||||
wire rstn;
|
||||
wire clk;
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PCIe XDMA's AXI interface
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
wire axi_awready;
|
||||
wire axi_awvalid;
|
||||
wire [ AXI_AWIDTH-1:0] axi_awaddr;
|
||||
wire [ 7:0] axi_awlen;
|
||||
wire [ AXI_IDWIDTH-1:0] axi_awid;
|
||||
// AXI Master Write Data Channel
|
||||
wire axi_wready;
|
||||
wire axi_wvalid;
|
||||
wire axi_wlast;
|
||||
wire [ AXI_DWIDTH-1:0] axi_wdata;
|
||||
wire [(AXI_DWIDTH/8)-1:0] axi_wstrb;
|
||||
// AXI Master Write Response Channel
|
||||
wire axi_bready;
|
||||
wire axi_bvalid;
|
||||
wire [ AXI_IDWIDTH-1:0] axi_bid;
|
||||
wire [ 1:0] axi_bresp;
|
||||
// AXI Master Read Address Channel
|
||||
wire axi_arready;
|
||||
wire axi_arvalid;
|
||||
wire [ AXI_AWIDTH-1:0] axi_araddr;
|
||||
wire [ 7:0] axi_arlen;
|
||||
wire [ AXI_IDWIDTH-1:0] axi_arid;
|
||||
// AXI Master Read Data Channel
|
||||
wire axi_rready;
|
||||
wire axi_rvalid;
|
||||
wire axi_rlast;
|
||||
wire [ AXI_DWIDTH-1:0] axi_rdata;
|
||||
wire [ AXI_IDWIDTH-1:0] axi_rid;
|
||||
wire [ 1:0] axi_rresp;
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Ref clock input buffer
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
IBUFDS_GTE2 refclk_ibuf (
|
||||
.CEB ( 1'b0 ),
|
||||
.I ( i_pcie_refclkp ),
|
||||
.IB ( i_pcie_refclkn ),
|
||||
.O ( pcie_refclk ),
|
||||
.ODIV2 ( )
|
||||
);
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Reset input buffer
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
IBUF sys_reset_n_ibuf (
|
||||
.I ( i_pcie_rstn ),
|
||||
.O ( pcie_rstn )
|
||||
);
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PCIe XDMA core
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
xdma_0 xdma_0_i (
|
||||
// PCI Express (PCIe) Interface : connect to the pins of FPGA chip
|
||||
.sys_rst_n ( pcie_rstn ),
|
||||
.sys_clk ( pcie_refclk ),
|
||||
.pci_exp_txn ( o_pcie_txn ),
|
||||
.pci_exp_txp ( o_pcie_txp ),
|
||||
.pci_exp_rxn ( i_pcie_rxn ),
|
||||
.pci_exp_rxp ( i_pcie_rxp ),
|
||||
// PCIe link up
|
||||
.user_lnk_up ( o_led0 ),
|
||||
// interrupts
|
||||
.usr_irq_req ( 16'h0 ),
|
||||
.usr_irq_ack ( ),
|
||||
//
|
||||
.msix_enable ( ),
|
||||
// clock/reset for user (for AXI)
|
||||
.axi_aclk ( clk ),
|
||||
.axi_aresetn ( rstn ),
|
||||
// AXI Interface
|
||||
.m_axi_awready ( axi_awready ),
|
||||
.m_axi_awvalid ( axi_awvalid ),
|
||||
.m_axi_awaddr ( axi_awaddr ),
|
||||
.m_axi_awlen ( axi_awlen ),
|
||||
.m_axi_awid ( axi_awid ),
|
||||
.m_axi_awsize ( ),
|
||||
.m_axi_awburst ( ),
|
||||
.m_axi_awprot ( ),
|
||||
.m_axi_awlock ( ),
|
||||
.m_axi_awcache ( ),
|
||||
.m_axi_wready ( axi_wready ),
|
||||
.m_axi_wvalid ( axi_wvalid ),
|
||||
.m_axi_wdata ( axi_wdata ),
|
||||
.m_axi_wstrb ( axi_wstrb ),
|
||||
.m_axi_wlast ( axi_wlast ),
|
||||
.m_axi_bready ( axi_bready ),
|
||||
.m_axi_bvalid ( axi_bvalid ),
|
||||
.m_axi_bid ( axi_bid ),
|
||||
.m_axi_bresp ( axi_bresp ),
|
||||
.m_axi_arready ( axi_arready ),
|
||||
.m_axi_arvalid ( axi_arvalid ),
|
||||
.m_axi_araddr ( axi_araddr ),
|
||||
.m_axi_arlen ( axi_arlen ),
|
||||
.m_axi_arid ( axi_arid ),
|
||||
.m_axi_arsize ( ),
|
||||
.m_axi_arburst ( ),
|
||||
.m_axi_arprot ( ),
|
||||
.m_axi_arlock ( ),
|
||||
.m_axi_arcache ( ),
|
||||
.m_axi_rready ( axi_rready ),
|
||||
.m_axi_rvalid ( axi_rvalid ),
|
||||
.m_axi_rlast ( axi_rlast ),
|
||||
.m_axi_rdata ( axi_rdata ),
|
||||
.m_axi_rid ( axi_rid ),
|
||||
.m_axi_rresp ( axi_rresp ),
|
||||
// AXI bypass interface
|
||||
.m_axib_awready ( '0 ),
|
||||
.m_axib_awvalid ( ),
|
||||
.m_axib_awaddr ( ),
|
||||
.m_axib_awlen ( ),
|
||||
.m_axib_awid ( ),
|
||||
.m_axib_awsize ( ),
|
||||
.m_axib_awburst ( ),
|
||||
.m_axib_awprot ( ),
|
||||
.m_axib_awlock ( ),
|
||||
.m_axib_awcache ( ),
|
||||
.m_axib_wready ( '0 ),
|
||||
.m_axib_wvalid ( ),
|
||||
.m_axib_wlast ( ),
|
||||
.m_axib_wdata ( ),
|
||||
.m_axib_wstrb ( ),
|
||||
.m_axib_bready ( ),
|
||||
.m_axib_bvalid ( '0 ),
|
||||
.m_axib_bid ( '0 ),
|
||||
.m_axib_bresp ( '0 ),
|
||||
.m_axib_arready ( '0 ),
|
||||
.m_axib_arvalid ( ),
|
||||
.m_axib_araddr ( ),
|
||||
.m_axib_arlen ( ),
|
||||
.m_axib_arid ( ),
|
||||
.m_axib_arsize ( ),
|
||||
.m_axib_arburst ( ),
|
||||
.m_axib_arprot ( ),
|
||||
.m_axib_arlock ( ),
|
||||
.m_axib_arcache ( ),
|
||||
.m_axib_rready ( ),
|
||||
.m_axib_rvalid ( '0 ),
|
||||
.m_axib_rlast ( '0 ),
|
||||
.m_axib_rdata ( '0 ),
|
||||
.m_axib_rid ( '0 ),
|
||||
.m_axib_rresp ( '0 )
|
||||
);
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AXI BRAM connected to PCIe XDMA's AXI interface
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
axi_bram #(
|
||||
.AXI_IDWIDTH ( AXI_IDWIDTH ),
|
||||
.AXI_AWIDTH ( AXI_AWIDTH ),
|
||||
.AXI_DWIDTH ( AXI_DWIDTH ),
|
||||
.MEM_AWIDTH ( 14 ) // BRAM size = MEM_AWIDTH*AXI_DWIDTH (bits) = MEM_AWIDTH*AXI_DWIDTH/8 (bytes)
|
||||
) axi_bram_i (
|
||||
.rstn ( rstn ),
|
||||
.clk ( clk ),
|
||||
// AXI Memory Mapped interface
|
||||
.s_axi_awready ( axi_awready ),
|
||||
.s_axi_awvalid ( axi_awvalid ),
|
||||
.s_axi_awaddr ( axi_awaddr ),
|
||||
.s_axi_awlen ( axi_awlen ),
|
||||
.s_axi_awid ( axi_awid ),
|
||||
.s_axi_wready ( axi_wready ),
|
||||
.s_axi_wvalid ( axi_wvalid ),
|
||||
.s_axi_wlast ( axi_wlast ),
|
||||
.s_axi_wdata ( axi_wdata ),
|
||||
.s_axi_wstrb ( axi_wstrb ),
|
||||
.s_axi_bready ( axi_bready ),
|
||||
.s_axi_bvalid ( axi_bvalid ),
|
||||
.s_axi_bid ( axi_bid ),
|
||||
.s_axi_bresp ( axi_bresp ),
|
||||
.s_axi_arready ( axi_arready ),
|
||||
.s_axi_arvalid ( axi_arvalid ),
|
||||
.s_axi_araddr ( axi_araddr ),
|
||||
.s_axi_arlen ( axi_arlen ),
|
||||
.s_axi_arid ( axi_arid ),
|
||||
.s_axi_rready ( axi_rready ),
|
||||
.s_axi_rvalid ( axi_rvalid ),
|
||||
.s_axi_rlast ( axi_rlast ),
|
||||
.s_axi_rdata ( axi_rdata ),
|
||||
.s_axi_rid ( axi_rid ),
|
||||
.s_axi_rresp ( axi_rresp )
|
||||
);
|
||||
|
||||
|
||||
endmodule
|
||||
// 1000_0000_0000_0000_0000
|
Loading…
Reference in New Issue