Orange
Xilinx XDMA PCIe Windows上位机编写
发布于: 2024-02-16 分类于: FPGA

这学期刚开学我购买了一块Artix7 200t的开发板,上面有PCIe的相关资源,之前一直没有接触过相关内容,假期的时候正好使用了一下。因为要准备考研,并没有比较深入的研究相关内容。在尝试编写Linux版本上位机程序后,顺便测试了一下XDMA Windows的驱动。

需要注意的是,Windows版的驱动并没有正式签名,需要先在Windows内运行加载测试签名的驱动程序

以管理员身份运行cmd或powershell执行以下命令并重启即可。

1
Bcdedit.exe -set TESTSIGNING ON

Windows版驱动下载:
https://support.xilinx.com/s/article/65444?language=en_US

在Github上有驱动和测试程序的相关代码可以参考:SanjayRai/SRAI_HW_ACCEL_WINDOWS10_PCIe

同时下载xdma_public.h文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//
// Created by Orange on 1/10/2024.
//
#ifndef PC_PCIE_RW_XDMA_DEVICE_H
#define PC_PCIE_RW_XDMA_DEVICE_H

#include <stdlib.h>
#include <Windows.h>
#include <SetupAPI.h>
#include <INITGUID.H>
#include <strsafe.h>
#include <winioctl.h>
#include <stdint.h>

#pragma comment(lib, "setupapi.lib")

#define ONE_MB (1024UL * 1024UL)
#define BUFFER_SIZE (128UL * 1024UL)
#define USER_BUFFER_SIZE (4UL * 64UL / 8)

/* helper struct to remember the Xdma device names */
typedef struct {
TCHAR base_path[MAX_PATH + 1];
size_t user_buffer_size;
size_t buffer_size;
PBYTE buffer;
PBYTE user_buffer;
HANDLE c2h0;
HANDLE h2c0; /*host to card*/
HANDLE user;
} xdma_device;

int find_devices(GUID guid, TCHAR *devpath, size_t len_devpath);
HANDLE open_device(TCHAR *path, TCHAR *device);

#endif //PC_PCIE_RW_XDMA_DEVICE_H

下面是查找DMA设备和打开相关用户接口,需要在IP核中启用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
int find_devices(GUID guid, TCHAR *devpath, size_t len_devpath) {
//get a handle to a device information set.
HDEVINFO dev_info = SetupDiGetClassDevs((LPGUID) &guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (dev_info == INVALID_HANDLE_VALUE) {
fprintf(stderr, "GetDevices INVALID_HANDLE_VALUE\n");
exit(-1);
}

SP_DEVICE_INTERFACE_DATA dev_interface;
dev_interface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

// enumerate through devices
DWORD index;
for (index = 0; SetupDiEnumDeviceInterfaces(dev_info, NULL, &guid, index, &dev_interface); ++index) {

// get required buffer size
ULONG detail_size = 0;
if (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_interface, NULL, 0, &detail_size, NULL) &&
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
fprintf(stderr, "SetupDiGetDeviceInterfaceDetail - get length failed\n");
break;
}

// allocate space for device interface detail
PSP_DEVICE_INTERFACE_DETAIL_DATA dev_detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA) HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
detail_size);
if (!dev_detail) {
fprintf(stderr, "HeapAlloc failed\n");
break;
}
dev_detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

// get device interface detail
if (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_interface, dev_detail, detail_size, NULL, NULL)) {
fprintf(stderr, "SetupDiGetDeviceInterfaceDetail - get detail failed\n");
HeapFree(GetProcessHeap(), 0, dev_detail);
break;
}

StringCchCopy(devpath, len_devpath, dev_detail->DevicePath);
HeapFree(GetProcessHeap(), 0, dev_detail);
}

SetupDiDestroyDeviceInfoList(dev_info);

return index;
}

HANDLE open_device(TCHAR *path, TCHAR *device) {
HANDLE handle;
TCHAR device_path[MAX_PATH + 1];
strcpy_s(device_path, sizeof device_path, path);
strcat_s(device_path, sizeof device_path, device);
fprintf(stdout,"device_path: %s\r\n",device);
handle = CreateFile(device_path, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE) {
fprintf(stderr, "Error opening device, win32 error code: %d\n", GetLastError());
}

return handle;
}

下面是读写测速的main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <stdio.h>
#include <process.h>

#include "xdma_device/xdma_device.h"
#include "xdma_device/xdma_public.h"

LARGE_INTEGER start;
LARGE_INTEGER stop;
LARGE_INTEGER freq;

xdma_device device;
union TestData *testData;

int main() {
QueryPerformanceFrequency(&freq);

device.user_buffer_size = 8 * 1024;
int status = 0;
int devices_number = find_devices(GUID_DEVINTERFACE_XDMA, &device.base_path[0], sizeof(device.base_path));
if (devices_number >= 1) {
printf("Found %d device%s.\r\n", devices_number, devices_number == 1 ? "" : "s");
printf("Device base path: %s\r\n", device.base_path);
} else {
printf("Counld not find device.");
exit(-1);
}


device.c2h0 = open_device(device.base_path, "\\c2h_0");
device.h2c0 = open_device(device.base_path, "\\h2c_0");
device.user = open_device(device.base_path, "\\user");
if (device.c2h0 == INVALID_HANDLE_VALUE || device.h2c0 == INVALID_HANDLE_VALUE ||
device.user == INVALID_HANDLE_VALUE) {
status = -1;
goto cleanup_handles;
}


SYSTEM_INFO sys_info;
GetSystemInfo(&sys_info);

union TestData *testData = (union TestData *) _aligned_malloc(sizeof(union TestData) * TEST_DATA_SIZE, sys_info.dwPageSize);
memset(testData, 0, sizeof(union testData) * TEST_DATA_SIZE);

device.buffer = (BYTE *) _aligned_malloc(BUFFER_SIZE, sys_info.dwPageSize);
device.user_buffer = (BYTE *) _aligned_malloc(USER_BUFFER_SIZE, sys_info.dwPageSize);
memset(device.buffer, 0, BUFFER_SIZE);
memset(device.user_buffer, 0, USER_BUFFER_SIZE);


if (read_fft_data("./data.dat", testData) == -1) {
status = -1;
goto cleanup_handles;
}

DWORD buffer_size = sizeof(union testData) * TEST_DATA_SIZE;

QueryPerformanceCounter(&start);
if (!WriteFile(device.h2c0, testData, buffer_size, &buffer_size, NULL)) {
fprintf(stderr, "WriteFile to device failed with Win32 error code: %lu\n", GetLastError());
status = -1;
goto cleanup_handles;
}
QueryPerformanceCounter(&stop);

double time_sec = (unsigned long long) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart;
printf("Sent in %fs . speed: %f MB/s\n", time_sec, (buffer_size / time_sec / 1024 / 1024));

memset(testData, 0, buffer_size);

QueryPerformanceCounter(&start);
if (!ReadFile(device.c2h0, testData, buffer_size, &buffer_size, NULL)) {
fprintf(stderr, "ReadFile from device failed with Win32 error code: %lu\n", GetLastError());
goto cleanup_handles;
}
QueryPerformanceCounter(&stop);

time_sec = (unsigned long long) (stop.QuadPart - start.QuadPart) / (double) freq.QuadPart;
printf("Received in %fs . speed: %f MB/s\n", time_sec, (buffer_size / time_sec / 1024 / 1024));

cleanup_handles:
if (device.c2h0) CloseHandle(device.c2h0);
if (device.h2c0) CloseHandle(device.h2c0);
if (device.buffer) _aligned_free(device.buffer);
if (device.user_buffer) _aligned_free(device.user_buffer);
if (fftData) _aligned_free(fftData);
return status;
}

--- 本文结束 The End ---