5.PCIe官方示例

官方提供3个使用PCIe的例子。第一个比较简单,我把例化参数剔除,整个文件结构如下:

module top_basic  (/*AUTOARG*/
   // Outputs
   hdoutp, hdoutn, pll_lk, poll, l0, dl_up, usr0, usr1, usr2, usr3,
   na_pll_lk, na_poll, na_l0, na_dl_up, na_usr0, na_usr1, na_usr2,
   na_usr3, led_out, dp, TP,
   // Inputs
   rstn, FLIP_LANES, LED_INV, refclkp, refclkn, hdinp, hdinn,
   dip_switch
   );

	....

   led_status led (....); // Templated
   
   pcie2_core pcie (.....		    );


   ip_rx_crpr #(.c_DATA_WIDTH (c_DATA_WIDTH)) cr (....);
   
   ip_crpr_arb crarb (.....);		 // Templated
   
 
   UR_gen #(.c_DATA_WIDTH (c_DATA_WIDTH)) ur (.......); // Templated
   
 
   ip_tx_arbiter #(.c_DATA_WIDTH (c_DATA_WIDTH)) tx_arb (.....);
   
   

   wb_tlc  #(.c_DATA_WIDTH(c_DATA_WIDTH)) wb_tlc (.....); // Templated
   

   wb_arb #(.c_DATA_WIDTH(c_DATA_WIDTH),
	    .S0_BASE     (32'h0000),
            .S1_BASE     (32'h4000),
            .S2_BASE     (32'h1000),
            .S3_BASE     (32'h5000)) 
   wb_arb (.....);
   

   wbs_gpio gpio (......);		 // Templated
   
   wbs_32kebr #(.c_DATA_WIDTH(c_DATA_WIDTH),
		.init_file("none"))
   ebr (......);		 // Templated
   
   
endmodule

这个文件里面调用几个IP,分别是led_status、pcie2_core、ip_rx_crpr、ip_crpr_arb、UR_gen、ip_tx_arbiter、wb_tlc、wb_arb、wbs_gpio、wbs_32kebr.连接框图如下:

上图中PCIe发来的TLP包送到UR Gen模块和WB TLC模块,WB TLC接收自己感兴趣的包,并转换为wishbone总线接口,产生读写时序到wishbone总线仲裁模块wishbone bus arbiter,仲裁器根据读写数据的地址操作对应的wishbone从设备,从设备返回的数据通过wb tlc打包成tlp包,再通过tx arbiter发送到PCIe EP,之后上传到上位机。UR Gen模块在这里主要是处理wb_tlc模块不感兴趣的包,回复完成报文并标识不支持的TLP包。

先挑简单文件看看,打开Tx Arbiter文件ip_tx_arbiter.v,内容如下:

// $Id: ip_tx_arbiter.v,v 1.1.1.1 2008/07/01 17:34:22 jfreed Exp $

module ip_tx_arbiter #(parameter c_DATA_WIDTH = 64) (/*AUTOARG*/
   // Outputs
   tx_rdy_0, tx_rdy_1, tx_rdy_2, tx_rdy_3, tx_req, tx_dout, tx_sop,
   tx_eop, tx_dwen,
   // Inputs
   clk, rstn, tx_val, tx_req_0, tx_din_0, tx_sop_0, tx_eop_0,
   tx_dwen_0, tx_req_1, tx_din_1, tx_sop_1, tx_eop_1, tx_dwen_1,
   tx_req_2, tx_din_2, tx_sop_2, tx_eop_2, tx_dwen_2, tx_req_3,
   tx_din_3, tx_sop_3, tx_eop_3, tx_dwen_3, tx_rdy
   );  

   input clk;
   input rstn;
   input tx_val;
   
   input                     tx_req_0;
   input [c_DATA_WIDTH-1:0]  tx_din_0;
   input 		     tx_sop_0;
   input 		     tx_eop_0;
   input 		     tx_dwen_0;
   output 		     tx_rdy_0;
   
   input 		     tx_req_1;
   input [c_DATA_WIDTH-1:0]  tx_din_1;
   input 		     tx_sop_1;
   input 		     tx_eop_1;
   input 		     tx_dwen_1;
   output 		     tx_rdy_1;
   
   input 		     tx_req_2;
   input [c_DATA_WIDTH-1:0]  tx_din_2;
   input 		     tx_sop_2;
   input 		     tx_eop_2;
   input 		     tx_dwen_2;
   output 		     tx_rdy_2;
   
   input 		     tx_req_3;
   input [c_DATA_WIDTH-1:0]  tx_din_3;
   input 		     tx_sop_3;
   input 		     tx_eop_3;
   input 		     tx_dwen_3;
   output 		     tx_rdy_3;
   
   output 		     tx_req;
   output [c_DATA_WIDTH-1:0] tx_dout;
   output 		     tx_sop;
   output 		     tx_eop;
   output 		     tx_dwen;
   input 		     tx_rdy;
   
   reg 			     tx_req;
   reg [c_DATA_WIDTH-1:0]    tx_dout;
   reg 			     tx_sop;
   reg 			     tx_eop;
   reg 			     tx_dwen;
   reg 			     tx_rdy_0;
   reg 			     tx_rdy_1;
   reg 			     tx_rdy_2;
   reg 			     tx_rdy_3;
   
   reg [1:0] 		     rr;
   reg 			     tx_rdy_p;
   reg 			     tx_rdy_p2;
   
   always @(/*AUTOSENSE*/rr or tx_din_0 or tx_din_1 or tx_din_2
	    or tx_din_3 or tx_dwen_0 or tx_dwen_1 or tx_dwen_2
	    or tx_dwen_3 or tx_eop_0 or tx_eop_1 or tx_eop_2
	    or tx_eop_3 or tx_rdy or tx_req_0 or tx_req_1 or tx_req_2
	    or tx_req_3 or tx_sop_0 or tx_sop_1 or tx_sop_2
	    or tx_sop_3) 
     begin
	case (rr)
	  2'b00: begin    // Service 0
	     tx_req   <= tx_req_0;
	     tx_dout  <= tx_din_0;
	     tx_sop   <= tx_sop_0;
	     tx_eop   <= tx_eop_0;
	     tx_dwen  <= tx_dwen_0;     
	     tx_rdy_0 <= tx_rdy;
	     tx_rdy_3 <= 1'b0;
	     tx_rdy_2 <= 1'b0;
	     tx_rdy_1 <= 1'b0;
	  end
	  2'b01: begin    // Service 1
	     tx_req   <= tx_req_1;
	     tx_dout  <= tx_din_1;
	     tx_sop   <= tx_sop_1;
	     tx_eop   <= tx_eop_1;
	     tx_dwen  <= tx_dwen_1;     
	     tx_rdy_1 <= tx_rdy;
	     tx_rdy_3 <= 1'b0;
	     tx_rdy_2 <= 1'b0;
	     tx_rdy_0 <= 1'b0;
	  end
	  2'b10: begin    // Service 2
	     tx_req   <= tx_req_2;
	     tx_dout  <= tx_din_2;
	     tx_sop   <= tx_sop_2;
	     tx_eop   <= tx_eop_2;
	     tx_dwen  <= tx_dwen_2;      
	     tx_rdy_2 <= tx_rdy;
	     tx_rdy_3 <= 1'b0;
	     tx_rdy_1 <= 1'b0;
	     tx_rdy_0 <= 1'b0;
	  end 
	  2'b11: begin    // Service 3
	     tx_req   <= tx_req_3;
	     tx_dout  <= tx_din_3;
	     tx_sop   <= tx_sop_3;
	     tx_eop   <= tx_eop_3;
	     tx_dwen  <= tx_dwen_3;      
	     tx_rdy_3 <= tx_rdy;
	     tx_rdy_2 <= 1'b0;
	     tx_rdy_1 <= 1'b0;
	     tx_rdy_0 <= 1'b0;
	  end 
	  default: begin
	  end
	endcase
     end // always @ (...
   
   // mux control
   always @(posedge clk or negedge rstn)
     begin
	if (~rstn) begin
	   rr        <= 2'b00;    
	   tx_rdy_p  <= 1'b0;
	   tx_rdy_p2 <= 1'b0;
	end
	else begin
	   tx_rdy_p  <= tx_rdy; // use pipe of tx_rdy to account for getting the tx_end through
	   tx_rdy_p2 <= tx_rdy_p;
	   
	   if (tx_val && ~tx_rdy_p2 && ~tx_rdy_p && ~tx_rdy) begin
	      if (tx_req_0 && ~tx_req)      rr <= 2'b00;
	      else if (tx_req_1 && ~tx_req) rr <= 2'b01;
	      else if (tx_req_2 && ~tx_req) rr <= 2'b10;
	      else if (tx_req_3 && ~tx_req) rr <= 2'b11;
	   end
	end // else: !if(~rstn)
     end // always @ (posedge clk or negedge rstn)
   
endmodule

这个文件实现4选一输出的功能

 本来想使用综合工具 查看RTL,生成的RTL太复杂,我把总线宽度从64改为4后生成RTL视图如下:

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
在Linux中,使用应用层代码与PCIe设备进行通信通常涉及以下步骤: 1. 打开设备文件:使用`open()`函数打开PCIe设备文件,获取文件描述符。 ```c #include <fcntl.h> #include <unistd.h> int fd = open("/dev/your_pci_device", O_RDWR); if (fd < 0) { perror("Failed to open device file"); return -1; } ``` 2. 进行读取操作:使用`read()`函数从设备文件中读取数据。 ```c #include <stdio.h> #include <unistd.h> uint32_t value; if (read(fd, &value, sizeof(value)) != sizeof(value)) { perror("Failed to read from device"); close(fd); return -1; } printf("Read value from PCIe device: %u\n", value); ``` 3. 进行写入操作:使用`write()`函数将数据写入设备文件。 ```c #include <unistd.h> uint32_t value = 1234; if (write(fd, &value, sizeof(value)) != sizeof(value)) { perror("Failed to write to device"); close(fd); return -1; } printf("Write value to PCIe device: %u\n", value); ``` 4. 关闭设备文件:使用`close()`函数关闭设备文件。 ```c #include <unistd.h> close(fd); ``` 请注意,上述代码示例中的`/dev/your_pci_device`需要替换为实际的PCIe设备文件路径。此外,你需要具有适当的权限来访问设备文件,通常需要使用`sudo`命令或将用户添加到相应的设备组中。 这只是一个基本的示例,你需要根据实际情况进行适当的修改。具体的读写操作和数据结构可能会根据设备的特性和驱动程序的实现而有所不同。因此,你应该参考设备的文档和驱动程序的接口,以了解如何正确地与特定的PCIe设备进行通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jjinl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值