Visible to Intel only — GUID: GUID-C01EE6B5-6589-4D06-95A0-36A1C9AB7FAC
Intel® oneAPI FPGA Handbook
Introduction To FPGA Design Concepts
Intel oneAPI FPGA Development
Defining a Kernel for FPGAs
Debugging and Verifying Your Design
Analyzing Your Design
Optimizing Your Kernel
Optimizing Your Host Application
Integrating Your RTL IP Core Into a System
RTL IP Core Kernel Interfaces
Loops
Pipes
Data Types and Arithmetic Operations
Parallelism
Memories and Memory Operations
Libraries
Additional FPGA Acceleration Flow Considerations
Additional SYCL* HLS Flow Considerations
FPGA Optimization Flags, Attributes, Pragmas, and Extensions
Quick Reference
Additional Information
Document Revision History for the Intel oneAPI FPGA Handbook
Notices and Disclaimers
Refactor the Loop-Carried Data Dependency
Relax Loop-Carried Dependency
Transfer Loop-Carried Dependency to Local Memory
Minimize the Memory Dependencies for Loop Pipelining
Unroll Loops
Fuse Loops to Reduce Overhead and Improve Performance
Optimize Loops With Loop Speculation
Remove Loop Bottlenecks
Improve fMAX/II with Shannonization
Optimize Inner Loop Throughput
Improve Loop Performance by Caching Data in On-Chip Memory
Global Memory Bandwidth Use Calculation
Manual Partition of Global Memory
Partitioning Buffers Across Different Memory Types (Heterogeneous Memory)
Partitioning Buffers Across Memory Channels of the Same Memory Type
Ignoring Dependencies Between Accessor Arguments
Contiguous Memory Accesses
Static Memory Coalescing
Use SYCL Shared Library With Third-Party Applications
Use of RTL Libraries for FPGA
Object Manifest File Syntax of an RTL Library
Restrictions and Limitations in RTL Support
Intel® Stratix® 10 and Intel Agilex® 7 Design-Specific Reset Requirements for Stall-Free and Stallable RTL Libraries
Stall-Free RTL
Specify Schedule FMAX Target for Kernels (-Xsclock=<clock target>)
Create a 2xclock Interface (-Xsuse-2xclock)
Disable Burst-Interleaving of Global Memory (-Xsno-interleaving=<global_memory_name>)
Force Ring Interconnect for Global Memory (-Xsglobal-ring)
Force a Single Store Ring to Reduce Area (-Xsforce-single-store-ring)
Force Fewer Read Data Reorder Units to Reduce Area (-Xsnum-reorder)
Disable Hardware Kernel Invocation Queue (-Xsno-hardware-kernel-invocation-queue)
Modify the Handshaking Protocol Between Clusters (-Xshyper-optimized-handshaking)
Disable Automatic Fusion of Loops (-Xsdisable-auto-loop-fusion)
Fuse Adjacent Loops With Unequal Trip Counts (-Xsenable-unequal-tc-fusion)
Pipeline Loops in Non-task Kernels (-Xsauto-pipeline)
Control Semantics of Floating-Point Operations (-fp-model=<value>)
Modify the Rounding Mode of Floating-point Operations (-Xsrounding=<rounding_type>)
Global Control of Exit FIFO Latency of Stall-free Clusters (-Xssfc-exit-fifo-type=<value>)
Enable the Read-Only Cache for Read-Only Accessors (-Xsread-only-cache-size=<N>)
Control Hardware Implementation of the Supported Data Types and Math Operations (-Xsdsp-mode=<option>)
Generate Register Map Wrapper (-Xsregister-map-wrapper-type)
Visible to Intel only — GUID: GUID-C01EE6B5-6589-4D06-95A0-36A1C9AB7FAC
Memory-Mapped Host Interfaces Using Accessors
The following example shows how to create a memory-mapped interface using the buffer_location property in SYCL*:
#include <sycl/sycl.hpp>
#include <iostream>
#include <sycl/ext/intel/fpga_extensions.hpp>
#include <vector>
using namespace sycl;
// Forward declare the kernel name in the global scope.
// This is an FPGA best practice that reduces name mangling in the
// optimization reports.
class SimpleVAdd;
// The members of the functor serve as inputs and outputs to your IP.
// The code inside the operator()() function describes your IP.
template <class AccA, class AccB, class AccC>
struct SimpleVAddKernel {
AccA A;
AccB B;
AccC C;
int count;
void operator()() const {
for (int i = 0; i < count; i++) {
C[i] = A[i] + B[i];
}
}
};
constexpr int VECT_SIZE = 4;
int main() {
#if FPGA_SIMULATOR
auto selector = sycl::ext::intel::fpga_simulator_selector_v;
#elif FPGA_HARDWARE
auto selector = sycl::ext::intel::fpga_selector_v;
#else // #if FPGA_EMULATOR
auto selector = sycl::ext::intel::fpga_emulator_selector_v;
#endif
queue q(selector);
int count = VECT_SIZE; // pass array size by value
// declare arrays and fill them
std::vector<int> VA;
std::vector<int> VB;
std::vector<int> VC(count);
for (int i = 0; i < count; i++) {
VA.push_back(i);
VB.push_back(count - i);
}
std::cout << "add two vectors of size " << count << std::endl;
buffer bufferA{VA};
buffer bufferB{VB};
buffer bufferC{VC};
q.submit([&](handler &h) {
accessor accessorA{bufferA, h, read_only};
accessor accessorB{bufferB, h, read_only};
accessor accessorC{bufferC, h, read_write, no_init};
h.single_task<SimpleVAdd>(SimpleVAddKernel<decltype(accessorA), decltype(accessorB), decltype(accessorC)>{accessorA, accessorB, accessorC, count});
});
// verify that VC is correct
bool passed = true;
for (int i = 0; i < count; i++) {
int expected = VA[i] + VB[i];
std::cout << "idx=" << i << ": result " << VC[i] << ", expected (" << expected << ") VA=" << VA[i] << " + VB=" << VB[i] << std::endl;
if (VC[i] != expected) {
passed = false;
}
}
std::cout << (passed ? "PASSED" : "FAILED") << std::endl;
return passed ? EXIT_SUCCESS : EXIT_FAILURE;
}