UH-OH

It looks like you don’t have access to that feature yet

Contact sales to get upgraded to the full DevStudio experience.

UH-OH

It looks like you don't have access to that feature yet.

to select
to navigate
escto close
Chimera Compute Library (CCL) API Reference

experimental::Device C++ APIs

⚠️ Work In Progress

These interfaces are new and may still change. Some features are missing and the API is not yet at feature parity with the legacy Device interface.

Overview

The experimental::Device C++ API provides a hierarchical interface for managing EPU devices, kernel execution, and interrupt handling. The main classes are:

  • experimental::DeviceManager - Factory for creating experimental::Device instances
  • experimental::Device - Represents a device and manages memory allocation and kernel loading
  • experimental::KernelGroup - A group of virtual cores that execute kernels together
  • experimental::VirtualCore - Represents a single virtual core within a kernel group
  • experimental::Interrupt - Provides access to interrupt status and the interrupted core within an interrupt handler
  • experimental::InterruptedCore - A specialized interface for interacting with a core during interrupt handling
  • experimental::InterruptStatus - Parses and provides access to interrupt status flags and codes

Class Hierarchy

experimental::DeviceManager
    └── experimental::Device
            └── experimental::KernelGroup
                    └── experimental::VirtualCore

experimental::Interrupt (passed to interrupt handlers)
    ├── experimental::InterruptedCore (accessed via Interrupt::core())
    └── experimental::InterruptStatus (accessed via Interrupt::readInterruptStatus())

Getting Started

Creating a Device

Use experimental::DeviceManager to create a experimental::Device:

#include <quadric/host.h>

using namespace chimera;

// Create a device manager
experimental::DeviceManager manager;

// Get a device with specified cluster configuration
// Parameters: clusterSize, numClusters, deviceConfig (optional)
experimental::Device device = manager.getDevice(4, 1);  // 4 cores per cluster, 1 cluster

Loading a Kernel

Once you have a device, load your kernel binary:

// Load a kernel from the kernel registry
device.loadKernel(myKernel);

// Or load with an offset
device.loadKernel(myKernel, loadOffset);

Memory Management

The experimental::Device provides methods for allocating and transferring data between host and device memory:

Allocating Memory

Host::DeviceBufferRef inputBuffer;
Host::DeviceBufferRef outputBuffer;

// Allocate using a tensor shape (recommended for structured data)
device.allocate<MyTensorShape>(inputBuffer);

// Or allocate a raw buffer by size
device.allocate(sizeInBytes, outputBuffer);

Copying Data to Device

// Copy a tensor to device
MyTensorShape hostTensor;
// ... fill hostTensor with data ...
device.copyBufferToDevice(hostTensor, inputBuffer);

// Or allocate and copy in one step
device.allocateAndCopyToDevice(hostTensor, inputBuffer);

// Also works with std::vector
std::vector<float> hostData = {...};
device.allocateAndCopyToDevice(hostData, inputBuffer);

Copying Data from Device

// Copy results back to host
MyTensorShape hostOutput;
device.copyBufferFromDevice(outputBuffer, hostOutput);

// Also works with std::vector
std::vector<float> hostResults(size);
device.copyBufferFromDevice(outputBuffer, hostResults);

Working with Kernel Groups

A KernelGroup represents a set of virtual cores that can execute kernels. Allocate a kernel group from the device:

std::uint8_t numCores = 4;

KernelGroup kernelGroup = device.allocKernelGroup(numCores);

Starting a Kernel

Start kernel execution on all cores in the group:

// Start the kernel with arguments
kernelGroup.startKernel(entrypoint, arg1, arg2, arg3);

// Kernel runs asynchronously - wait for completion if needed
device.blockUntilIdle();

Accessing Individual Virtual Cores

You can access individual virtual cores to read/write kernel parameters:

// Get a specific virtual core using operator[]
VirtualCore vc = kernelGroup[0];

// Iterate over all virtual cores using range-based for loop
for (auto vc : kernelGroup) {
    std::uint32_t result = vc.readKernelParameterRegister<std::uint32_t>(paramIndex);
}

// Or get all virtual cores as a vector
std::vector<VirtualCore> allCores = kernelGroup.getAllVirtualCores();

// Write a kernel parameter register
vc.writeKernelParameterRegister(paramIndex, value);

// Read a kernel parameter register
std::uint32_t result = vc.readKernelParameterRegister<std::uint32_t>(paramIndex);

Interrupt Handling

The API supports interrupt-driven communication between host and device using the Interrupt class.

Setting Up an Interrupt Handler

Register an interrupt handler on a kernel group or individual virtual core:

// Set handler on entire kernel group (applies to all cores)
kernelGroup.setInterruptHandler([](chimera-compute-library-ccl-api-reference/Interrupt& interrupt) {
    const auto& interruptStatus = interrupt.readInterruptStatus();

    // End-of-kernel interrupt: clear without resuming
    if (interruptStatus.isEndOfKernel()) {
        interrupt.core().clearInterrupt();
        return;
    }

    // Read kernel parameter registers if needed
    std::uint32_t status = interrupt.core().readKernelParameterRegister<std::uint32_t>(statusRegister);

    // Process the interrupt...

    // Clear interrupt and resume execution
    interrupt.core().clearInterruptsAndResume();
});

// Or set handler on a specific virtual core
VirtualCore vc = kernelGroup[0];
vc.setInterruptHandler([](chimera-compute-library-ccl-api-reference/Interrupt& interrupt) {
    const auto& interruptStatus = interrupt.readInterruptStatus();

    if (interruptStatus.isEndOfKernel()) {
        interrupt.core().clearInterrupt();
        return;
    }

    // Handle interrupt for this specific core
    interrupt.core().clearInterruptsAndResume();
});

Interrupt and InterruptedCore Methods

The Interrupt class provides access to interrupt status and the interrupted core:

  • readInterruptStatus() - Read the current interrupt status as an InterruptStatus object
  • core() - Get a reference to the InterruptedCore for core operations

The InterruptedCore class provides methods for interacting with the interrupted core:

  • readKernelParameterRegister<T>(index) - Read a kernel parameter register
  • writeKernelParameterRegister(index, value) - Write a kernel parameter register
  • clearInterrupt() - Clear the interrupt flag without resuming execution. Use this for end-of-kernel interrupts.
  • clearInterruptsAndResume() - Clear the interrupt flag and resume kernel execution. Use this for all other interrupts (e.g. software blocking).

Important: Every interrupt handler must call clearInterrupt() or clearInterruptsAndResume() before returning. For end-of-kernel interrupts, use clearInterrupt() since there is no execution to resume. For all other interrupts, use clearInterruptsAndResume() to clear the interrupt and allow the kernel to continue.

Complete Example

#include <quadric/host.h>

using namespace chimera;

int main() {
    // 1. Create device
    experimental::DeviceManager manager;
    experimental::Device device = manager.getDevice(4, 1);

    // 2. Load kernel
    device.loadKernel(myKernel);

    // 3. Allocate and copy input data
    Host::DeviceBufferRef inputBuffer, outputBuffer;
    std::vector<float> inputData = {...};
    device.allocateAndCopyToDevice(inputData, inputBuffer);
    device.allocate<OutputTensorShape>(outputBuffer);

    // 4. Allocate kernel group
    KernelGroup kernelGroup = device.allocKernelGroup(4);

    // 5. Set up interrupt handler (optional)
    kernelGroup.setInterruptHandler([](chimera-compute-library-ccl-api-reference/Interrupt& interrupt) {
        const auto& interruptStatus = interrupt.readInterruptStatus();

        if (interruptStatus.isEndOfKernel()) {
            interrupt.core().clearInterrupt();
            return;
        }

        // Handle interrupt...
        interrupt.core().clearInterruptsAndResume();
    });

    // 6. Start kernel execution
    kernelGroup.startKernel(entrypoint, inputBuffer, outputBuffer);

    // 7. Wait for completion
    device.blockUntilIdle();

    // 8. Copy results back
    std::vector<float> results(outputSize);
    device.copyBufferFromDevice(outputBuffer, results);

    return 0;
}

API Reference

experimental::DeviceManager

MethodDescription
getDevice(clusterSize, numClusters, config)Create a experimental::Device with the specified configuration

experimental::Device

MethodDescription
allocKernelGroup(numCores)Allocate a kernel group with the specified number of cores
loadKernel(kernel, offset)Load a kernel binary to the device
allocate<TensorShape>(bufferRef)Allocate device memory for a tensor
allocate(size, bufferRef)Allocate raw device memory
allocateAndCopyToDevice(host, bufferRef)Allocate and copy data to device
copyBufferToDevice(host, bufferRef)Copy data to an allocated buffer
copyBufferFromDevice(bufferRef, host)Copy data from device to host
blockUntilIdle()Wait for all kernel execution to complete
printProfile()Print profiling information

experimental::KernelGroup

MethodDescription
startKernel(entrypoint, args...)Start async kernel execution on all cores
operator[](chimera-compute-library-ccl-api-reference/index)Get a specific virtual core by index
begin() / end()Iterator support for range-based for loops
getAllVirtualCores()Get all virtual cores in the group
size()Get the number of cores in the group
kernelGroupId()Get the kernel group ID
setInterruptHandler(handler)Set interrupt handler for all cores
writeKernelParameterRegister(index, value)Write to a kernel parameter register

experimental::VirtualCore

MethodDescription
writeKernelParameterRegister(index, value)Write to a kernel parameter register
readKernelParameterRegister<T>(index)Read a kernel parameter register
setInterruptHandler(handler)Set interrupt handler for this core

experimental::Interrupt

MethodDescription
readInterruptStatus()Read the interrupt status as InterruptStatus
core()Get a reference to the InterruptedCore

experimental::InterruptedCore

MethodDescription
readKernelParameterRegister<T>(index)Read a kernel parameter register
writeKernelParameterRegister(index, value)Write to a kernel parameter register
clearInterrupt()Clear interrupt without resuming (use for end-of-kernel interrupts)
clearInterruptsAndResume()Clear interrupt and resume execution

experimental::InterruptStatus

MethodDescription
isEndOfKernel()Check if this is an end-of-kernel interrupt
isHwBlocking()Check if this is a hardware blocking interrupt
isHwNonBlocking()Check if this is a hardware non-blocking interrupt
isSwBlocking()Check if this is a software blocking interrupt
isSwNonBlocking()Check if this is a software non-blocking interrupt
getHwBlockingCode()Get the hardware blocking interrupt code
getHwNonBlockingCode()Get the hardware non-blocking interrupt code
getSwBlockingCode()Get the software blocking interrupt code
getSwNonBlockingCode()Get the software non-blocking interrupt code
Table of Contents


© Copyright 2026 Quadric All Rights Reserved • Privacy Policy
This documentation is preliminary and confidential. It is subject to change. Quadric does not give any warranty express or implied that the contents will be complete or accurate or up to date. The company shall not be liable for any loss, actions, claims, proceedings, demands or costs or damages whatsoever or howsoever caused arising directly or indirectly in connection with or arising out of the use of this material.

Sign in to your account

Don't have an account? Create an Account
By signing in, you are agreeing to our Terms of Use and Privacy Policy.

Develop.

Simulate.

Profile.

Collaborate.

We use cookies to enhance your browsing experience, and analyze our traffic.
By clicking "Accept All", you consent to our use of cookies.