Skip to main content

Cookbook

This section collects short recipes for moving distributional data between your host application and a compute module, and for using that data on both sides. Each recipe shows one pattern in a few lines of code and links to the reference pages that document the calls in full.

The recipes combine two parts.

  • On the module, a C device application reads the input buffer and writes the output buffer through the Hardware Abstraction Layer, and computes on distributions through the UxHw API.
  • On the host, a Python application moves bytes through the same buffers with the signaloid_utilities package, and works with distributions through the signaloid package from the signaloid-python repository.

The recipes apply to the C0-microSD and the C0-microSD+. The data-path code is the same on both, and Module Differences below collects the few real differences.

The recipes

Before you start

The recipes assume a module with a flashed device application and a known device path. Every host-side recipe is Python and needs Python 3.10 or later. See Python Environment. For the end-to-end workflow that gets you there, see the getting-started tutorial of your module, Getting Started With the C0-microSD or Getting Started With the C0-microSD+. For complete, runnable programs that use these patterns, see Examples and Demos.

Every device-side snippet runs inside the command loop of a device application, which waits for a command, computes, reports done, and returns to waiting. The Hardware Abstraction Layer page of each module documents the loop itself. See A Minimal Device Application (C0-microSD) and A Minimal Device Application (C0-microSD+).

Every host-side snippet assumes an interface object named compute_module. Construct it once for your module.

from signaloid_utilities.c0microsd.interface import C0microSDSignaloidSoCInterface

compute_module = C0microSDSignaloidSoCInterface("/dev/disk4")

Replace /dev/disk4 with your device path, and run host applications with sudo, because raw block-device access requires root privileges. The Python Host Interface page of each module covers the package installation and the full interface reference. See Using the Python Host Interface (C0-microSD) and Using the Python Host Interface (C0-microSD+).

Conventions

The round trip

Host snippets drive the module with calculate_command(), which writes the command word, polls the status register until the device application reports done, reads the data back, returns it as bytes, and drives the device back to idle. The read covers the whole readable window, meaning the 4 KiB MISO buffer on the C0-microSD and the full 64 KiB MMIO buffer on the C0-microSD+. On both modules your output data starts at byte 0 of the returned bytes. The recipes call it with a small poll_sleep_time, because the 0.5-second default adds half a second to even the fastest computation.

output = compute_module.calculate_command(1, poll_sleep_time=0.001, verbose=False)

The command values themselves are application-defined. The value 1 in the recipes stands for whichever command your device application handles.

Self-describing buffers

A fixed layout, such as four floats at the start of the input buffer, is the simplest convention and is what most recipes show. When one buffer has to carry a mix of plain floats and distributions, or a variable number of values, use a self-describing layout instead.

FieldSizeMeaning
Value count4 bytes, uint32Number of values that follow
Value size4 bytes, uint32Byte length of the next value
Value payloadValue-size bytesA plain float when the size is 4, Ux Binary Data otherwise

The value size and value payload fields repeat, once per value. A reader distinguishes plain floats from distributions by the size alone, because a float is 4 bytes and a Ux Binary Data value is always larger.

Buffer capacities

Size your transfers from the interface attributes INPUT_BUFFER_SIZE_BYTES and OUTPUT_BUFFER_SIZE_BYTES rather than from literals. The current values are the following.

ModuleInput bufferOutput buffer
C0-microSD4 KiB (MOSI buffer)4 KiB (MISO buffer)
C0-microSD+32 KiB (input half of the MMIO buffer)32 KiB (output half of the MMIO buffer)
caution

When your device application is built with debug logging enabled, the log window occupies the last 512 bytes of the output buffer. Keep results clear of that region, or the logger and your output data overwrite each other.

Alignment

The layout you pack on the host is the layout the device application reads, and the RISC-V core requires every load to be naturally aligned. Place each field on a multiple of its own size. See Memory Alignment (C0-microSD) and Memory Alignment (C0-microSD+).

Module differences

AspectC0-microSDC0-microSD+
Host interface classC0microSDSignaloidSoCInterfaceC0microSDPlusInterface
BuffersSeparate 4 KiB MOSI and MISO buffersOne 64 KiB MMIO buffer, 32 KiB per direction
Core controlNone. The device application runs whenever the module is in Signaloid SoC mode.The host starts, stops, and resets the core, so bring the core up before the round trip.
Device HALThe same C0HAL.h API on both modules, selected by DEVICE_TYPE at build timeSame
Debug log windowThe same C0Logger.h device library and 512-byte window on both modulesSame

On the C0-microSD+, construct the interface and bring the core up before you drive the round trip, for example with compute_module.reset_core(). See Control the Core.