This repository contains host-side and device-side test programs for validating basic CXL functionality on the FPGA platform, including:
- CXL.io MMIO access
- CXL.mem device-memory read/write
- Host-memory sharing between Host and Device (CXL.cache support verified)
- Device-memory sharing between Host and Device (CXL.cache support verified)
The software is organized to support both Linux host execution and bare-metal debugging on the HPS through RiscFree.
The main software tree is located under sw/ and is organized as follows:
sw/
├── 1-1_CXL_io/
├── 1-2_CXL_mem/
├── 1-3_CXL_cache/
├── 2_HostMem_sharing/
├── 3_DeviceMem_sharing/
├── fpga_image.rbf
└── run_riscfree.sh
Files used across multiple tests for setup, configuration, and fundamental operations.
run_riscfree.sh: Launches the RiscFree workspace for the provided HPS projects.fpga_image.rbf: FPGA bitstream used by the initialization scripts.sw/*/Host/bwvfio.h&bwvfio.c: Low-level VFIO header and implementation for PCIe BAR MMIO access and DMA memory allocation/mapping.sw/*/Host/dma.lib.h: Common DMA helper library for descriptor setup, queue initialization, doorbell, completion polling, and cleanup.
-
1-1_CXL_io/: CXL.io validation. Checks whether the host can access FPGA BAR space through PCIe/CXL.io and confirm read/write behavior.- Source:
sw/1-1_CXL_io/src/cxl_io_test.c
- Source:
-
1-2_CXL_mem/: CXL.mem validation. Checks whether the host can read and write a portion of device memory through the DMA-based path.- Source:
sw/1-2_CXL_mem/src/cxl_mem_test.c
- Source:
-
2_HostMem_sharing/: Host-memory sharing test. The host starts first and initializes the shared memory region. The device starts later to issue requests.- Host Source:
sw/2_HostMem_sharing/Host/main.c - Device Source:
riscfree/HostMem_sharing/src/main.c
- Host Source:
-
3_DeviceMem_sharing/: Device-memory sharing test. The device starts first. The host starts later and participates in the synchronized increment test.- Host Source:
sw/3_DeviceMem_sharing/Host/main.c - Device Source:
riscfree/DeviceMem_sharing/src/main.c
- Host Source:
This test verifies that the host can access the FPGA MMIO space through the BAR/QCSR path.
- Initialize FPGA:
cd sw ./run_riscfree.sh # only when opening RiscFree is needed cd 1-1_CXL_io ./run_init.sh # Enter 'y' once when asked
- Run Test: After
Initiation Done!appears, run:./run_cxl_io_test.sh
Expected Result: The program prints a sequence of MMIO read/write checks and reports whether the written value matches the readback value.
This test verifies that the host can access a portion of device memory through the DMA path.
- Initialize FPGA:
cd sw ./run_riscfree.sh # only when opening RiscFree is needed cd 1-2_CXL_mem ./run_init.sh # Enter 'y' once when asked
- Run Test: After
Initiation Done!appears, run:./run_cxl_mem_test.sh
Expected Result: The program performs multiple device-memory write/readback checks and prints pass/fail messages for each address.
Although sw/1-3_CXL_cache/ contains source files, the code is identical to the memory coherency tests. Therefore, there is no separate script for it.
Completing the subsequent Host memory sharing and Device memory sharing tests is sufficient to verify support for CXL.cache. This is because satisfying atomic access on shared memory requires not only support for the CXL.cache protocol, but also a guarantee of memory coherency.
Test Flow: Device first -> Host second
- Launch RiscFree:
cd sw ./run_riscfree.sh - Initialize the FPGA and host environment:
(Enter
cd 3_DeviceMem_sharing ./run_init.shyonce when prompted. Continue only afterInitiation Done!is printed.) - Build the device-side project in RiscFree:
- Right-click
DeviceMem_sharing-> Select Clean Project -> Select Build Project. (Use Refresh first if the view is stale).
- Right-click
- Start device execution in RiscFree:
- Right-click
DeviceMem_sharing-> Select Debug As -> Select 1 Ashling ...
- Right-click
- Run to the synchronization end point:
- In
main.c, findend = 1;. Right-click that line and select Run to Line.
- In
- Run the host-side program:
(Optional: run with
./run_host.sh
./run_host.sh -n 5000to set increment count). - Check the final result: Verify the
Final countervalue printed in the terminal.
Test Flow: Host first -> Device second
- Launch RiscFree:
cd sw ./run_riscfree.sh - Initialize the FPGA and host environment:
(Enter
cd 2_HostMem_sharing ./run_init.shyonce when prompted. Continue only afterInitiation Done!is printed.) - Run the host-side program first:
(Optional: run with
./run_host.sh
./run_host.sh -n 5000to set increment count). - Build the device-side project in RiscFree:
- Right-click
HostMem_sharing-> Select Clean Project -> Select Build Project.
- Right-click
- Start device execution in RiscFree:
- Right-click
HostMem_sharing-> Select Debug As -> Select 1 Ashling ...
- Right-click
- Run to the synchronization end point:
- In
main.c, findend = 1;. Right-click that line and select Run to Line.
- In
- Check the final result: Verify the
Final countervalue printed in the terminal.
For the memory-sharing tests, the host script supports modifying the number of host-side increment operations using the -n flag:
./run_host.sh -n [increment_count]
# Example:
./run_host.sh -n 1000Note: To compare host and device contributions symmetrically, match the host increment count with the device-side increment constant in the device source.
- BAR/QCSR read/write test messages
- PASS/WARN/FAIL readback logs
- Device-memory DMA read/write test messages
- PASS/WARN/FAIL readback logs
- Handshake progress
- Increment execution
- Final output:
Final counter = ...(This printed value is the main result to check).