API Reference
Every function libsparsr_host.so exports, as declared in include/sparsr.h. This is the
interface your host application uses. For the intrinsics a kernel uses, see
Writing a Kernel in C.
Include the header and link the library:
#include "sparsr.h" /* -lsparsr_host */
The header is guarded for C++, so a C++ program includes it unchanged.
Constants
| Name | Value | Meaning |
|---|---|---|
SPARSR_BACKEND_ENV_VAR |
"SPARSR_BACKEND" |
The environment variable that picks the backend |
SPARSR_WMEM_COMPRESSED_SIZE |
240 |
Bytes one vector takes on the wire when it is compressed |
SPARSR_WMEM_UNCOMPRESSED_SIZE |
512 |
Bytes in one whole wide vector, 4,096 bits |
SPARSR_WMEM_SLOT_COUNT |
64 |
WMEM rows the machine has |
Use the constants rather than the numbers. SPARSR_WMEM_SLOT_COUNT keeps an older name. A
row once stored a compressed slot. Today it stores one whole wide vector.
Setup
void sparsr_kernel_init(void)
Selects and configures the backend, reading SPARSR_BACKEND from the environment. Call it
before anything else on this page. Values are vm, vmproc, fpgasim and fpgaf2.
Unset, empty or auto uses an F2 card when one answers and the VM otherwise, and prints one
line to standard error when the F2 backend is installed but no card answers.
See Choosing a backend.
If the backend you named cannot answer, the library reports "no device" and does not switch to another backend.
This happens when its library is missing, when it lacks a call, or when the name is not a
backend. Every call then answers "no device":
the kernel does not run, reads return NULL, sparsr_wide_bytes() returns 0, and
sparsr_read_status() returns done with the fault SPARSR_STATUS_FAULT_NO_DEVICE. Standard
error gets one line per function, the first time it is called. The library never exits
your process.
Loading a kernel
void sparsr_load_batch_from_bin(char inst_bin_file[30], uint32_t start_address)
Reads a .spex kernel image from disk and writes it into instruction memory at
start_address. The path is at most 30 characters.
An image may contain initialised data as well as instructions. That happens when a kernel declares a lookup table or a global with a starting value. This call then also places that data in data memory. A kernel cannot do it for itself: its own image is in instruction memory, and a data load from there is a fatal trap.
void sparsr_load_batch(uint32_t *instructions, uint32_t start_address, uint32_t numb_of_inst)
The same thing without the file: you supply the instruction words, in the target's own byte order. Useful for a library with its own built-in kernels, or a program that generates one.
This loads instructions and nothing else. A kernel with initialised data also needs that
data written, with sparsr_write_data_dmem. sparsr_load_batch_from_bin is the call that
does both.
Running a kernel
void sparsr_execute_batch(uint32_t start_address)
Starts execution at start_address in instruction memory. Returns immediately.
uint32_t sparsr_read_status(void)
Returns the status word. Bit 0 is 0 while the batch is still running and 1 when it has
finished. Bits 8-15 hold a fault code, where one is reported.
sparsr_execute_batch(0);
while (sparsr_read_status() == 0) { }
| Name | Value | Meaning |
|---|---|---|
SPARSR_STATUS_DONE |
0x1 |
Bit 0: the device is idle, so the last batch has finished |
SPARSR_STATUS_FAULT_SHIFT |
8 |
Where the fault field starts in the status word |
SPARSR_STATUS_FAULT_MASK |
0xFF |
The fault field, once shifted down |
SPARSR_STATUS_FAULT_OF(status) |
macro | The fault code in a status word. 0 means no fault. |
SPARSR_STATUS_FAULT_NO_DEVICE |
0xFF |
The fault when there is no device at all |
A batch that faulted still sets the done bit, so a loop that polls for it always stops.
The vm backend returns the done bit alone.
Wide vectors (WMEM), compressed on the wire
The ordinary path. You hand over and receive whole vectors, and the compression and decompression happen on the way to and from the device.
void sparsr_write_data_wmem(uint8_t *data, uint32_t address)
Writes 512 bytes from host memory into WMEM row address.
At most 48 of the vector's 128 32-bit lanes may contain any bits, because the vector crosses to the device compressed. A denser vector is an error rather than a truncation, and the row keeps what it had.
uint8_t *sparsr_read_data_wmem(uint32_t address)
Reads WMEM row address and returns a pointer to 512 bytes in host memory, or NULL if
the read failed.
Wide vectors (WMEM), sent raw
For a vector too dense for the call above. This pair takes any density.
void sparsr_write_data_wmem_raw(uint8_t *data, uint32_t row)
Writes a full 512-byte vector into WMEM row row, with no compression on the wire.
uint8_t *sparsr_read_data_wmem_raw(uint32_t row)
Reads the 512 bytes of WMEM row row. It returns what sparsr_read_data_wmem() returns,
and it is kept for callers that already use the name. Returns NULL if the read failed or
the active backend has no raw path.
These calls address the same rows as the pair above. A WMEM row stores one whole wide vector either way, so a vector written with one call reads back correctly with the other. The only difference is whether the library compresses it for the transfer.
Scalars (DMEM)
void sparsr_write_data_dmem(uint32_t *data, uint32_t start_address, uint32_t numb_of_data)
Writes numb_of_data 32-bit words into data memory at start_address. This is how a host
passes arguments into a kernel that was compiled once and has to work on whatever the host
picked, such as the WMEM base address for a register-indirect wide load.
uint32_t *sparsr_read_data_dmem(uint32_t start_address, uint32_t numb_of_data)
Reads numb_of_data words from data memory at start_address and returns a pointer to them
in host memory.
Compression helpers
Available if you want to see or produce the compressed form yourself. Ordinary host programs never need them, because the WMEM calls above do the conversion.
uint8_t *sparsr_lil_comp_32b(uint8_t *uncomp_data, uint8_t show_compression)
Compresses 512 bytes into the 240-byte LIL form. Pass 1 for show_compression to print
the encoded values, 0 to skip the printing.
uint8_t *sparsr_lil_decomp_32b(uint8_t *comp_data, uint8_t show_compression)
Decompresses 240 bytes back into 512.
Buffer ownership
The calls that return a pointer return a buffer the library owns. Read it or copy it before the next call of the same kind, and do not free it.