1 xillybus介绍
- xillybus是由Xilinx的合作伙伴xillybus推出的用于在FPGA和主机间进行数据传输的解决方案。在FPGA端通过标准FIFO与用户逻辑相连接,在主机端(Window或Linux)安装了相应的驱动程序后,可以以读写设备的方式接收数据或发送数据。本文主要介绍Linux系统下的数据传输。
- xillybus有三种数据传输的方案。第一是通过PCIE实现FPGA和外部PC主机间数据的传输。第二是通过转接ZYNQ的ACP、HP、GP接口实现FPGA和PS间数据的传输。第三是通过地址映射Lite的方式实现FPGA和PS间的数据传输。
2 用户接口信号
2.1 DMA方式
- 时钟:所有连到xillybus IP核的模块时钟都要用bus_clk驱动,PCIE平台根据最大链路带宽有62.5 MHz,125MHz,250 MHz,ZYNQ平台为100MHz。与用户逻辑连接时要用异步FIFO进行跨时钟域处理。
- user_w前缀为host到fpga端下行数据流,user_r前缀为fpga到host端上行数据流。
- 下行数据流部分:
user_w_devfile_data为host到fpga的数据。
user_w_devfile_wren为xillybus给fifo的写有效信号,指示data上的数据有效。
user_w_devfile_full为fifo给xillybus的信号,指示fifo已满。当该信号为低时,xillybus认为可以从host向fpga传输数据。
user_w_devfile_open信号当host端进行open系统调用打开设备时,该信号有效。 - 上行数据流部分:
user_r_devfile_data为fpga到host的数据。
user_r_devfile_rden为xillybus给fifo的读有效信号,拉高后,下个时钟时data开始上传数据。
user_r_devfile_empty为fifo给xillybus的信号,指示fifo为空。
user_r_devfile_eof为xillybus的输入信号,指示产生eof事件。一旦拉高,xillybus将不再读取输入数据,除非host关闭fd并再次打开。在host端read系统调用会返回eof。
user_r_devfile_open为xillybus输出信号,指示host端已open。 - quiesce
3 PL部分工程介绍
3.1 IP factory
- 使用xillybus需要先在xillybus的官网根据需求配置数据传输通道的参数。ip factory网址
- 我这里配置了一个上行通道、一个下行通道和一个双向通道,还配置了期望带宽,数据传输方式设置为异步传输。配置好后可生成对应的ngc网表文件,例化到vavado工程中即可。
3.2 总线连接
- blockdesign如下图所示,xillybus_ip_v1_0核和xillybus_lite_v1_0核挂接在zynq的GP总线上。这两个IP核都挂接在系统物理总线上,占用了一定的物理地址空间。我们在Address Editor中可以看到地址的分配情况,我们在后面导出的hdf文件中也描述了对这些地址空间的占用。
- xillybus_ip_v1_0核用于DMA方式的数据传输。xillybus_M_AXI是xillybus的主AXI接口,用于上行数据传输。xillybus_S_AXI是xillybus的从AXI接口,用于下行数据传输。xillybus_bus_clk和xillybus_bus_rst_n是IP核输出的控制ngc部分的时钟和复位信号。xillybus_host_interrupt是用户主机的中断信号。
- xillybus_lite_v1_0核用于LITE方式的数据传输。
3.3 例化ngc
- xillybus_core模块中例化了ngc网表文件,将xillybus_M_AXI和xillybus_S_AXI协议按照用户在IP factory中的配置进行转换,转换成用户配置的指定通道的接口信号。lite与xillybus_core无关。
xillybus_core xillybus_core_ins(
.S_AXI_AWADDR_w(S_AXI_AWADDR),
.S_AXI_AWVALID_w(S_AXI_AWVALID),
.S_AXI_WDATA_w(S_AXI_WDATA),
.S_AXI_WSTRB_w(S_AXI_WSTRB),
.S_AXI_WVALID_w(S_AXI_WVALID),
.S_AXI_BREADY_w(S_AXI_BREADY),
.S_AXI_ARADDR_w(S_AXI_ARADDR),
.S_AXI_ARVALID_w(S_AXI_ARVALID),
.S_AXI_RREADY_w(S_AXI_RREADY),
.S_AXI_ARREADY_w(S_AXI_ARREADY),
.S_AXI_RDATA_w(S_AXI_RDATA),
.S_AXI_RRESP_w(S_AXI_RRESP),
.S_AXI_RVALID_w(S_AXI_RVALID),
.S_AXI_WREADY_w(S_AXI_WREADY),
.S_AXI_BRESP_w(S_AXI_BRESP),
.S_AXI_BVALID_w(S_AXI_BVALID),
.S_AXI_AWREADY_w(S_AXI_AWREADY),
.M_AXI_ACP_ARREADY_w(M_AXI_ACP_ARREADY),
.M_AXI_ACP_ARVALID_w(M_AXI_ACP_ARVALID),
.M_AXI_ACP_ARADDR_w(M_AXI_ACP_ARADDR),
.M_AXI_ACP_ARLEN_w(M_AXI_ACP_ARLEN),
.M_AXI_ACP_ARSIZE_w(M_AXI_ACP_ARSIZE),
.M_AXI_ACP_ARBURST_w(M_AXI_ACP_ARBURST),
.M_AXI_ACP_ARPROT_w(M_AXI_ACP_ARPROT),
.M_AXI_ACP_ARCACHE_w(M_AXI_ACP_ARCACHE),
.M_AXI_ACP_RREADY_w(M_AXI_ACP_RREADY),
.M_AXI_ACP_RVALID_w(M_AXI_ACP_RVALID),
.M_AXI_ACP_RDATA_w(M_AXI_ACP_RDATA),
.M_AXI_ACP_RRESP_w(M_AXI_ACP_RRESP),
.M_AXI_ACP_RLAST_w(M_AXI_ACP_RLAST),
.M_AXI_ACP_AWREADY_w(M_AXI_ACP_AWREADY),
.M_AXI_ACP_AWVALID_w(M_AXI_ACP_AWVALID),
.M_AXI_ACP_AWADDR_w(M_AXI_ACP_AWADDR),
.M_AXI_ACP_AWLEN_w(M_AXI_ACP_AWLEN),
.M_AXI_ACP_AWSIZE_w(M_AXI_ACP_AWSIZE),
.M_AXI_ACP_AWBURST_w(M_AXI_ACP_AWBURST),
.M_AXI_ACP_AWPROT_w(M_AXI_ACP_AWPROT),
.M_AXI_ACP_AWCACHE_w(M_AXI_ACP_AWCACHE),
.M_AXI_ACP_WREADY_w(M_AXI_ACP_WREADY),
.M_AXI_ACP_WVALID_w(M_AXI_ACP_WVALID),
.M_AXI_ACP_WDATA_w(M_AXI_ACP_WDATA),
.M_AXI_ACP_WSTRB_w(M_AXI_ACP_WSTRB),
.M_AXI_ACP_WLAST_w(M_AXI_ACP_WLAST),
.M_AXI_ACP_BREADY_w(M_AXI_ACP_BREADY),
.M_AXI_ACP_BVALID_w(M_AXI_ACP_BVALID),
.M_AXI_ACP_BRESP_w(M_AXI_ACP_BRESP),
.bus_clk_w(bus_clk),
.bus_rst_n_w(bus_rst_n),
.host_interrupt_w(host_interrupt),
.quiesce_w(quiesce),
.GPIO_LED_w(GPIO_LED),
.user_r_channel_1_rden_w(user_r_channel_1_rden),
.user_r_channel_1_data_w(user_r_channel_1_data),
.user_r_channel_1_empty_w(user_r_channel_1_empty),
.user_r_channel_1_eof_w(user_r_channel_1_eof),
.user_r_channel_1_open_w(user_r_channel_1_open),
.user_w_channel_1_wren_w(user_w_channel_1_wren),
.user_w_channel_1_data_w(user_w_channel_1_data),
.user_w_channel_1_full_w(user_w_channel_1_full),
.user_w_channel_1_open_w(user_w_channel_1_open),
.user_r_channel_2_rden_w(user_r_channel_2_rden),
.user_r_channel_2_data_w(user_r_channel_2_data),
.user_r_channel_2_empty_w(user_r_channel_2_empty),
.user_r_channel_2_eof_w(user_r_channel_2_eof),
.user_r_channel_2_open_w(user_r_channel_2_open),
.user_w_channel_3_wren_w(user_w_channel_3_wren),
.user_w_channel_3_data_w(user_w_channel_3_data),
.user_w_channel_3_full_w(user_w_channel_3_full),
.user_w_channel_3_open_w(user_w_channel_3_open));
3.4 数据传输测试设计
- DMA上行数据传输测试,FPGA端产生自增数,在PS端读取自增数后检验数据的正确性。用vio控制产生自增数的速率。
reg [9:0] count;
wire [9:0] vio_output_value_channel_2;
assign user_r_channel_2_eof = 0;
vio_up_speed_control vio_up_speed_control_inst (
.clk(clk_102p4MHz),
.probe_out0(vio_output_value_channel_2)
);
/*
count = 16 6.4MB
count = 32 12.8MB
count = 64 25.6MB
*/
always@(posedge clk_102p4MHz)
begin
if(!rst_n)
count <= 1'b0;
else
count <= count + 1'b1;
end
always@(posedge clk_102p4MHz)
begin
if(!rst_n)
begin
upstream_data <= 32'b0;
upstream_data_valid <= 1'b0;
end
else if(count <= vio_output_value_channel_2)
begin
upstream_data <= upstream_data + 1'b1;
upstream_data_valid <= 1'b1;
end
else
begin
upstream_data <= upstream_data;
upstream_data_valid <= 1'b0;
end
end