目录
一、PCIE结构
1、层次结构
绝大多数的总线或者接口,都是采用分层实现的。PCIe也不例外,它的层次结构如下:
PCIe定义了下三层:
- 事务层(Transaction Layer)
- 数据链路层(Data Link Layer)
- 物理层(Physical Layer)
每层职能不同,且下层为上层服务。
分层设计优势:接口版本改动时,硬件设计改动的层数较少。
PCIe传输的数据从上到下,都是以packet的形式传输的,每个packet都是有其固定的格式的。
事务层的主要职责是创建(发送)或者解析(接收)TLP (Transaction Layer packet),流量控制,QoS,事务排序等。
数据链路层的主要职责是创建(发送)或者解析(接收)DLLP(Data Link Layer packet),Ack/Nak协议(链路层检错和纠错),流控,电源管理等。
物理层的主要职责是处理所有的Packet数据物理传输,发送端数据分发到各个Lane传输(stripe),接收端把各个Lane上的数据汇总起来(De-stripe),每个Lane上加扰(Scramble,目的是让0和1分布均匀,去除信道的电磁干扰EMI)去扰(De-scramble),以及8/10或者128/130编码解码,等等。
2、数据包
TLP(Transmission Line Pulse)
TLP是传输线脉冲发生器的缩写,是集成电路静电放电(ESD)防护技术研究中的一种重要测试手段。与传统的HBM、MM、CDM、IEC等模型不同,TLP发出的是静电模拟方波。它通过调节上升沿和脉冲宽度,间接模拟了静电脉冲形式的损伤能力和不同上升沿CLAMP触发能力。
- 工作原理:
使用方波形式,每次施加一个脉冲,获得一个I-V点,通过施加不同幅值的电流,直至测量到泄露电流判定失效为止,从而获取完整的器件在ESD过程中的I-V曲线。
该曲线可用于集成电路ESD防护设计的仿真,达到集成电路ESD防护结构设计目的。 - 应用意义:
由于TLP的方波特性,它可以发现器件在ESD过程中的响应情况,包括开启和关断过程,对于解决CDM模型的ESD防护结构研究至关重要。
对于超深亚微米器件,由于snapback问题的影响,TLP测试技术显得尤为重要。 - 与其他模型的关系:
TLP脉冲是各静电放电模型的近似模拟手段,是ESD防护技术研究的核心手段,但与传统ESD脉冲形式又有不能替代的成份。
在不能替代性方面,TLP脉冲式方波与真实情况有一定的出入,但可以通过适当的评估确认不同模型静电等效方波。
DLLP(Data Link Layer Packet)
DLLP是PCIe(Peripheral Component Interconnect Express)协议中数据链路层(Data Link Layer)使用的数据包。
- 功能与用途:
主要用于链路层的控制、管理和错误处理,不涉及事务的具体内容。
主要功能包括链路管理、错误报告、确认机制、流控指示等,确保数据链路的可靠运行。 - 结构与格式:
结构相对简单,通常只有固定长度(如8字节),包含Framing(如Start-of-Frame、End-of-Frame标记)和特定类型的控制字段。
使用16位CRC进行错误检测。 - 与TLP的关系:
TLP(Transaction Layer Packet)是事务层产生的数据包,用于传输应用数据,即最终用户的数据负载。
DLLP与TLP在PCIe协议栈中各自承担不同的角色,TLP负责传输应用数据,而DLLP则负责数据链路层的控制、管理和错误处理。
总结来说,TLP和DLLP在PCIe协议栈中各有其独特的作用和应用场景,TLP侧重于集成电路的ESD防护测试,而DLLP则负责数据链路层的通信和控制。
PCIE寄存器配置
1、基址寄存器的作用
基址寄存器(Base Address Registers)就是 PCIe 协议提供的、用于向系统软件展示 PCIe 设备内部资源大小、资源类型和资源属性
的机制。
每个 PCIe 设备内部都会有一部分资源需要提供给系统软件访问。与此同时,不同的 PCIe 设备可供系统软件访问的资源大小、资源类型也不一样。在计算机系统中,只有系统软件可以为 PCIe 设备内部的资源指定合适的地址,而 PCIe 设备能做的就是告诉系统软件该设备内部可访问的资源大小、资源类型和资源特性。
2、基址寄存器的位置
基址寄存器(Base Address Registers)位于 PCIe 设备配置空间(configuration space)的配置头(configuration header)中。PCIe 设备有两种类型的配置头,分别为 0 型配置头(Type 0 configuration header)和 1 型配置头(Type 1 configuration header)。在两种配置头中,基址寄存器的位置如下图所示:
从图中可以看出,0 型配置头(Type 0 configuration header)包含 6 个基址寄存器,而 1 型配置头(Type 1 configuration header)只包含 2 个基址寄存器。
PCIe 桥类型设备,即 PCIe Root Complex 和 PCIe Switch,包含 1 型配置头(Type 1 configuration header)。
PCIe 非桥类型设备,例如 PCIe Endpoint,包含 0 型配置头(Type 0 configuration header)。
三、PCIE读取数据
当使用PCIE接口读取数据,通常需要遵循几个步骤。这些步骤可能因具体的硬件、驱动程序和操作系统而异,但基本的流程是相似的。
- 了解硬件和驱动程序:
首先,需要了解你的PCIE设备是如何工作的,包括其数据接口、寄存器映射等。
确认操作系统是否支持该PCIE设备,并已经安装了相应的驱动程序。 - 获取设备文件描述符:
在Linux系统中,PCIE设备通常会被映射为一个或多个设备文件,位于/dev/目录下。
使用open()函数打开这些设备文件,并获取一个文件描述符(file descriptor)。 - 配置设备:
使用ioctl()函数或其他类似机制来配置PCIE设备,例如设置数据传输模式、选择通道等。
这些配置命令通常是特定于你的设备的,并且需要参考设备的文档或驱动程序提供的API。 - 读取数据:
使用read()函数从设备文件中读取数据。
需要指定一个缓冲区来存储读取到的数据,并指定要读取的字节数。
read()函数会阻塞直到有足够的数据可用,或者发生错误。 - 处理数据:
一旦数据被读取到缓冲区中,你就可以使用C++代码来处理这些数据了。
这可能包括解析数据、执行计算、存储结果等。 - 关闭设备:
使用close()函数关闭设备文件描述符。
这是一个好习惯,可以确保资源被正确释放,并避免潜在的问题。 - 错误处理:
在整个过程中,需要处理可能出现的错误,例如设备无法打开、配置失败、读取数据错误等。
使用适当的错误代码和消息来通知用户或记录日志。 - 优化性能:
如果需要高性能的数据传输,需要优化你的代码和配置。
例如,使用非阻塞I/O、DMA传输、多线程或异步I/O等技术来提高性能。
示例代码:
以下是一个简化的示例代码框架,展示了如何使用C++与PCIE设备结合读取数据:
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include <cstring>
int main() {
// 打开设备文件
int fd = open("/dev/your_pcie_device", O_RDWR);
if (fd == -1) {
perror("Failed to open device");
return 1;
}
// 配置设备(这里是一个示例,具体命令取决于你的设备)
// ...
// 读取数据
char buffer[1024]; // 假设每次读取1024字节
ssize_t bytesRead = read(fd, buffer, sizeof(buffer));
if (bytesRead == -1) {
perror("Failed to read data");
close(fd);
return 1;
}
// 处理数据
// ...
// 关闭设备文件
close(fd);
return 0;
}
这是个简化示例,无法直接用于特定情况,需要根据你的硬件、驱动程序和操作系统的要求来修改和扩展这个代码。此外,还需要参考设备的文档和驱动程序的API来获取更详细的信息和示例代码。