7. SpaceLib API#
7.1. Introduction#
This page documents the SpaceLib design library API that is provided by the SpaceStudio environment.
7.2. SpaceLib classes#
-
class abstract_module : public sc_core::sc_module#
The
abstract_moduleclass is the base class for a SpaceStudio module. A module is a user-defined C/C++ algorithm. It can be mapped as a hardware co-processor or a software thread.-
uint32_t get_base_address(unsigned int id)#
This method returns the base address of the slave with the given ID.
- Parameters:
id – The ID of a slave device.
- Returns:
The base address of the slave with the given ID.
- Example:
uint32_t base_address = get_base_address(BRAM0_ID);
-
uint32_t get_high_address(unsigned int id)#
This method returns the high address of the slave with the given ID.
- Parameters:
id – The ID of a slave device.
- Returns:
The high address of the slave with the given ID.
- Example:
uint32_t high_address = get_high_address(BRAM0_ID);
-
void hw_compute_latency(int cycles)#
For a module mapped to hardware, this method adds a temporal annotation for a wait of the given number of cycles.
If a module is mapped to software, this method does nothing.
- Parameters:
cycles – The number of cycles to wait.
- Example:
hw_compute_latency(10); // Adds a temporal annotation for a wait of 10 cycles.
-
bool is_verbose()#
This method returns the verbose property for this module. Verbosity can be configured through the property view of the component instance in SpaceStudio.
- Returns:
The verbose property for this module.
- Example:
if (is_verbose()) { std::cout << "Verbose mode is enabled for this module." << std::endl; }
-
void request_stack(std::size_t size_bytes)#
This method asks for a specific stack capacity for the module. If this method is omitted, the default stack capacity is 16384 bytes (16 KiB). This method is called in the module’s constructor.
For hardware modules in simulation, this method will configure SystemC’s stack, similar to
sc_core::sc_module::set_stack_size.For software modules, this method will allocate a software stack for the thread running the module.
- Parameters:
size_bytes – The requested stack capacity in bytes.
- Example:
request_stack(16 * 1024); // Requests a stack capacity of 16 KiB.
-
space_transfer_t StreamWrite(unsigned int destination_id, uint32_t timeout, const T *data, uint32_t nb_elements = 1)#
This method sends data through a FIFO or DMA based communication channel. The type of communication (FIFO, direct streaming or DMA) can be configured in the SpaceStudio GUI using the “Manage Communications” button.
- Parameters:
destination_id – The ID of the destination module or hardware component. Must be a compile-time constant.
timeout – Delay determining whether the communication is blocking or non-blocking. Must be either set to
SPACE_BLOCKINGorSPACE_NON_BLOCKING.data – Pointer to the start of the buffer containing the data to send.
nb_elements – The number of elements to send (not bytes, but by number of elements of type T). This parameter is optional and defaults to 1.
- Returns:
A
space_transfer_tdescribing the transfer. Its status (seespace::get_status()) can beSPACE_OK,SPACE_EMPTY/SPACE_FULL(non-blocking FIFO not ready),SPACE_BUSY(non-blocking DMA channel busy) orSPACE_ERROR. A non-blocking call on a DMA-based channel may return a still-pending transfer (SPACE_PENDING); see Non-blocking communications.- Example:
SPACE_ALIGNED uint8_t data[4] = { 1, 2, 3, 4 }; space_transfer_t transfer = StreamWrite(CONSUMER0_ID, SPACE_NON_BLOCKING, data, 4); if (space::is_busy(transfer)) { // The channel was full: nothing was sent. }
Technical close-up
To ensure that communications work properly both in hardware and embedded software implementations, it is strongly recommended that the length of the data transferred in a
StreamWriteoperation is a multiple of 4 bytes (i.e. 32 bits). This is the case in this example, where the data length is 4 bytes (4 chars of 1 byte each). It is also strongly recommended that the message buffer address be aligned on a 4-byte boundary when the module is mapped to software. TheSPACE_ALIGNEDmodifier macro is provided to help with this alignment requirement, and it is used in the example above.Note
The type
Tfor this method is not a template type, and thus the method can be called as-is without specifying a type. Instead, the type will be determined by SpaceStudio’s static analysis engine, which will generate the appropriate code for the communication based on the type of the data.
-
space_transfer_t StreamWrite(unsigned int destination_id, uint32_t timeout)#
Convenience method for writing to a module without specifying data. This is useful for simple handshake operations.
See the general
space_transfer_t abstract_module::StreamWrite(unsigned int, uint32_t, const T*, uint32_t)method for details. This is equivalent to calling the general method with an array of a singleuint32_t:uint32_t dummy_data = 0; StreamWrite(destination_id, timeout, &dummy_data, 1);
- Example:
StreamWrite(CONSUMER0_ID, SPACE_BLOCKING); // Unblock CONSUMER0_ID by sending a message with dummy data.
-
space_transfer_t StreamWrite(unsigned int destination_id, uint32_t timeout, const T &data)#
Convenience method for writing a single element to a module without specifying the number of elements.
See the general
space_transfer_t abstract_module::StreamWrite(unsigned int, uint32_t, const T*, uint32_t)method for details.
-
space_transfer_t StreamRead(unsigned int destination_id, uint32_t timeout, T *data, uint32_t nb_elements = 1)#
This method reads a message from a FIFO or DMA based communication channel. The type of communication (FIFO, direct streaming or DMA) can be configured in the SpaceStudio GUI using the “Manage Communications” button.
- Parameters:
destination_id – The ID of the source module or hardware component. Must be a compile-time constant.
timeout – Delay determining whether the communication is blocking or non-blocking. Must be either set to
SPACE_BLOCKINGorSPACE_NON_BLOCKING.data – Pointer to the start of the buffer where the read data will be stored.
nb_elements – The number of elements to read (not bytes, but by number of elements of type T). This parameter is optional and defaults to 1.
- Returns:
A
space_transfer_tdescribing the transfer. Its status (seespace::get_status()) can beSPACE_OK,SPACE_EMPTY/SPACE_FULL(non-blocking FIFO not ready),SPACE_BUSY(non-blocking DMA channel busy) orSPACE_ERROR. A non-blocking call on a DMA-based channel may return a still-pending transfer (SPACE_PENDING); see Non-blocking communications.- Example:
SPACE_ALIGNED uint8_t data[4] = { 0 }; space_transfer_t transfer = StreamRead(PRODUCER0_ID, SPACE_BLOCKING, data, 4); if (space::is_completed(transfer)) { // 'data' holds the received message. }
Technical close-up
To ensure that communications work properly both in hardware and embedded software implementations, it is strongly recommended that the length of the data transferred in a
StreamReadoperation is a multiple of 4 bytes (i.e. 32 bits). This is the case in this example, where the data length is 4 bytes (4 chars of 1 byte each). It is also strongly recommended that the message buffer address be aligned on a 4-byte boundary when the module is mapped to software. TheSPACE_ALIGNEDmodifier macro is provided to help with this alignment requirement, and it is used in the example above.Note
The type
Tfor this method is not a template type, and thus the method can be called as-is without specifying a type. Instead, the type will be determined by SpaceStudio’s static analysis engine, which will generate the appropriate code for the communication based on the type of the data.
-
space_transfer_t StreamRead(unsigned int destination_id, uint32_t timeout)#
Convenience method for reading from a module without specifying a data buffer. This is useful for simple handshake operations.
See the general
space_transfer_t abstract_module::StreamRead(unsigned int, uint32_t, T*, uint32_t)method for details. This is equivalent to calling the general method with an array of a singleuint32_t:uint32_t dummy_data; StreamRead(destination_id, timeout, &dummy_data, 1);
- Example:
StreamRead(PRODUCER0_ID, SPACE_BLOCKING); // Waits for PRODUCER0_ID to send a message by reading with dummy data.
-
space_transfer_t StreamRead(unsigned int destination_id, uint32_t timeout, T &data)#
Convenience method for reading a single element from a module without specifying the number of elements.
See the general
space_transfer_t abstract_module::StreamRead(unsigned int, uint32_t, T*, uint32_t)method for details.
-
space_status_t DeviceWrite(unsigned int destination_id, uintptr_t offset, const T *data, uint32_t nb_elements = 1)#
This method writes a message to a device (i.e. a memory-mapped component, such as memories, timers, user-defined devices, etc…).
- Parameters:
destination_id – The ID of the destination device. Must be a compile-time constant.
offset – The offset from the base address of the device where the data will be written.
data – Pointer to the start of the buffer containing the data to send.
nb_elements – The number of elements to send (not bytes, but by number of elements of type T). This parameter is optional and defaults to 1.
- Returns:
The status of the communication, which can be
SPACE_OK,SPACE_ERROR.- Example:
// Write to a timer's control register. uint32_t control_value = 0x4; // Value to start the timer. space_status_t status = DeviceWrite(TIMER0_ID, 0x4, &control_value, 1);
Technical close-up
To ensure that communications work properly both in hardware and embedded software implementations, it is strongly recommended that the length of the data transferred in a
DeviceWriteoperation is a multiple of 4 bytes (i.e. 32 bits). It is also strongly recommended that the message buffer address be aligned on a 4-byte boundary when the module is mapped to software. TheSPACE_ALIGNEDmodifier macro is provided to help with this alignment requirement, and it is used in the example above.
-
space_status_t DeviceWrite(unsigned int destination_id, uintptr_t offset, const T &data)#
Convenience method for writing a single element to a device without specifying the number of elements.
See the general
space_status_t abstract_module::DeviceWrite(unsigned int, uintptr_t, const T*, uint32_t)method for details.
-
space_status_t DeviceRead(unsigned int destination_id, uintptr_t offset, T *data, uint32_t nb_elements = 1)#
This method reads a message from a device (i.e. a memory-mapped component, such as memories, timers, user-defined devices, etc…).
- Parameters:
destination_id – The ID of the source device. Must be a compile-time constant.
offset – The offset from the base address of the device where the data will be read.
data – Pointer to the start of the buffer where the read data will be stored.
nb_elements – The number of elements to read (not bytes, but by number of elements of type T). This parameter is optional and defaults to 1.
- Returns:
The status of the communication, which can be
SPACE_OK,SPACE_ERROR.- Example:
// Read from a timer's counter register. uint32_t counter_value; space_status_t status = DeviceRead(TIMER0_ID, 0x8, &counter_value, 1);
Technical close-up
To ensure that communications work properly both in hardware and embedded software implementations, it is strongly recommended that the length of the data transferred in a
DeviceReadoperation is a multiple of 4 bytes (i.e. 32 bits). It is also strongly recommended that the message buffer address be aligned on a 4-byte boundary when the module is mapped to software. TheSPACE_ALIGNEDmodifier macro is provided to help with this alignment requirement, and it is used in the example above.
-
space_status_t DeviceRead(unsigned int destination_id, uintptr_t offset, T &data)#
Convenience method for reading a single element from a device without specifying the number of elements.
See the general
space_status_t abstract_module::DeviceRead(unsigned int, uintptr_t, T*, uint32_t)method for details.
-
space_status_t RegisterWrite(unsigned int register_file_id, uint32_t register_id, const T *data)#
This method writes a value to a register of a register file.
- Parameters:
register_file_id – The ID of the register file containing the register to write. Must be a compile-time constant.
register_id – The ID of the register to write within the register file. Must be a compile-time constant.
data – Pointer to the start of the buffer containing the data to send. Should be a pointer to an
unsigned longor same-size type.
- Returns:
The status of the communication, which can be
SPACE_OK,SPACE_ERROR.- Example:
uint32_t register_value = 0x1; // Value to write to the register. space_status_t status = RegisterWrite(REGISTER_FILE0_ID, CONTROL_REGISTER_ID, ®ister_value);
-
space_status_t RegisterWrite(unsigned int register_file_id, uint32_t register_id, const T &data)#
Convenience method for writing a single element to a register without specifying a data buffer.
See the general
space_status_t abstract_module::RegisterWrite(unsigned int, uint32_t, const T*)method for details.- Example:
space_status_t status = RegisterWrite(REGISTER_FILE0_ID, CONTROL_REGISTER_ID, 0x1);
-
space_status_t RegisterRead(unsigned int register_file_id, uint32_t register_id, T *data)#
This method reads a value from a register of a register file.
- Parameters:
register_file_id – The ID of the register file containing the register to read. Must be a compile-time constant.
register_id – The ID of the register to read within the register file. Must be a compile-time constant.
data – Pointer to the start of the buffer where the read data will be stored. Should be a pointer to an
unsigned longor same-size type.
- Returns:
The status of the communication, which can be
SPACE_OK,SPACE_ERROR.- Example:
uint32_t register_value; space_status_t status = RegisterRead(REGISTER_FILE0_ID, CONTROL_REGISTER_ID, ®ister_value);
-
space_status_t RegisterRead(unsigned int register_file_id, uint32_t register_id, T &data)#
Convenience method for reading a single element from a register without specifying a data buffer.
See the general
space_status_t abstract_module::RegisterRead(unsigned int, uint32_t, T*)method for details.- Example:
uint32_t register_value; space_status_t status = RegisterRead(REGISTER_FILE0_ID, CONTROL_REGISTER_ID, register_value);
-
space_transfer_t StreamRead(unsigned int channel, uint32_t timeout, memory_region_t dst)#
Drains the stream of a hardware user module into a memory location, using a DMA. This is the conduit form of
abstract_module::StreamRead(): the caller does not consume the data itself, it splices the channel into a memory it names. The module on the other end is unaware of this and simply performs the ordinary, local-buffer form ofabstract_module::StreamWrite().- Parameters:
channel – The ID of the module producing the stream. Must be a compile-time constant.
timeout – Delay determining whether the communication is blocking or non-blocking. Must be either set to
SPACE_BLOCKINGorSPACE_NON_BLOCKING.dst – The block of memory the stream data lands in. See
memory_region_t; it must be built with aggregate initialization at the call site.
- Returns:
A
space_transfer_tdescribing the transfer. Its status (seespace::get_status()) can beSPACE_OK,SPACE_BUSY(DMA busy on a non-blocking call) orSPACE_ERROR. A non-blocking call may return a still-pending transfer (SPACE_PENDING); see Non-blocking communications.- Example:
// Transfer 1024 bytes from a hardware module to a memory location using DMA. space_transfer_t transfer = StreamRead(PRODUCER0_ID, SPACE_BLOCKING, memory_region_t{BRAM0_ID, 0x0, 1024});
Technical close-up
To ensure that communications work properly both in hardware and embedded software implementations, it is strongly recommended that the length of the data transferred is a multiple of 4 bytes (i.e. 32 bits).
Note
This replaces
Stream2Memory(module_source_id, memory_destination_id, memory_destination_offset, timeout, nb_bytes), which is deprecated. The direction is now the verb and the memory is an argument, so both ends of a stream channel are named with the same verb pair.
-
space_transfer_t StreamWrite(unsigned int channel, uint32_t timeout, memory_region_t src)#
Fills the stream of a hardware user module from a memory location, using a DMA. This is the conduit form of
abstract_module::StreamWrite(): the caller does not produce the data itself, it splices a memory it names into the channel. The module on the other end is unaware of this and simply performs the ordinary, local-buffer form ofabstract_module::StreamRead().- Parameters:
channel – The ID of the module consuming the stream. Must be a compile-time constant.
timeout – Delay determining whether the communication is blocking or non-blocking. Must be either set to
SPACE_BLOCKINGorSPACE_NON_BLOCKING.src – The block of memory the stream data comes from. See
memory_region_t; it must be built with aggregate initialization at the call site.
- Returns:
A
space_transfer_tdescribing the transfer. Its status (seespace::get_status()) can beSPACE_OK,SPACE_BUSY(DMA busy on a non-blocking call) orSPACE_ERROR. A non-blocking call may return a still-pending transfer (SPACE_PENDING); see Non-blocking communications.- Example:
// Transfer 1024 bytes from a memory location to a hardware module using DMA. space_transfer_t transfer = StreamWrite(CONSUMER0_ID, SPACE_BLOCKING, memory_region_t{BRAM0_ID, 0x0, 1024});
Technical close-up
To ensure that communications work properly both in hardware and embedded software implementations, it is strongly recommended that the length of the data transferred is a multiple of 4 bytes (i.e. 32 bits).
Note
This replaces
Memory2Stream(memory_source_id, memory_source_offset, module_destination_id, timeout, nb_bytes), which is deprecated.
-
space_transfer_t DmaCopy(memory_region_t dst, memory_region_t src, uint32_t timeout)#
Copies a memory location to another memory location, using a DMA. Unlike the two methods above this is not a stream operation at all – no AXI4-Stream endpoint is involved – which is why it is named after its transport rather than after a channel.
- Parameters:
dst – The block of memory the data is written to. Its
nb_bytesmust be at least that ofsrc.src – The block of memory the data is read from; its
nb_bytesis the length of the transfer.timeout – Delay determining whether the communication is blocking or non-blocking. Must be either set to
SPACE_BLOCKINGorSPACE_NON_BLOCKING.
- Returns:
A
space_transfer_tdescribing the transfer. Its status (seespace::get_status()) can beSPACE_OK,SPACE_BUSY(DMA busy on a non-blocking call) orSPACE_ERROR. A non-blocking call may return a still-pending transfer (SPACE_PENDING); see Non-blocking communications.- Example:
// Transfer 1024 bytes from a BRAM to another using DMA. space_transfer_t transfer = DmaCopy(memory_region_t{BRAM1_ID, 0x0, 1024}, memory_region_t{BRAM0_ID, 0x0, 1024}, SPACE_BLOCKING);
Technical close-up
To ensure that communications work properly both in hardware and embedded software implementations, it is strongly recommended that the length of the data transferred is a multiple of 4 bytes (i.e. 32 bits).
Note
This replaces
Memory2Memory(...), which is deprecated.
-
uint32_t get_base_address(unsigned int id)#
-
struct memory_region_t#
A block of data living in some memory instance of the architecture: which memory, where in it, and how many bytes. It is the data argument of the conduit forms of
abstract_module::StreamRead()andabstract_module::StreamWrite(), and both operands ofabstract_module::DmaCopy().-
unsigned int memory_id#
ID of the memory instance holding the block, e.g.
BRAM0_ID.
-
uintptr_t address#
Offset of the block within that memory instance.
-
unsigned long nb_bytes#
Size of the block, in bytes.
Warning
SpaceStudio’s Static Analysis Tools must resolve the three fields to compile-time constants, so build the region at the call site with aggregate initialization:
StreamWrite(CONSUMER0_ID, SPACE_BLOCKING, memory_region_t{BRAM0_ID, 0x0, 1024});
Building it in a variable first, or computing a field at run time, prevents the analysis from resolving the transfer.
-
unsigned int memory_id#
-
class master_device#
The
master_deviceclass is the base class for a master device. A master device is a user-defined C/C++ device capable of issuing master transactions on an interconnect. A master device is always connected as both a slave and a master to the interconnect.-
uint32_t get_base_address(unsigned int id)#
This method returns the base address of a slave device with a given ID. The device corresponding to the given ID must be connected to the same interconnect as the master device.
- Parameters:
id – The ID of a slave device.
- Returns:
The base address of the slave device with the given ID.
- Example:
uint32_t base_address = get_base_address(BRAM0_ID);
-
uint32_t get_high_address(unsigned int id)#
This method returns the high address of a slave device with a given ID. The device corresponding to the given ID must be connected to the same interconnect as the master device.
- Parameters:
id – The ID of a slave device.
- Returns:
The high address of the slave device with the given ID.
- Example:
uint32_t high_address = get_high_address(BRAM0_ID);
-
bool is_offset_valid(unsigned int id, uint32_t offset)#
Determines whether a provided offset is valid for the slave device with the given ID. The device corresponding to the given ID must be connected to the same interconnect as the master device.
- Parameters:
id – The ID of a slave device.
offset – The offset to check for validity.
- Returns:
trueif the provided offset is valid for the slave device with the given ID,falseotherwise.- Example:
// Checks whether offset 0x100 is valid for BRAM0_ID. bool valid = is_offset_valid(BRAM0_ID, 0x100);
-
uint32_t get_size(unsigned int id)#
Returns the size of the slave device with the given ID’s address space. The device corresponding to the given ID must be connected to the same interconnect as the master device.
- Parameters:
id – The ID of a slave device.
- Returns:
The size of the slave device with the given ID’s address space in bytes.
- Example:
uint32_t size = get_size(BRAM0_ID);
-
void DeviceRead(uintptr_t address, const void *data, uint32_t nb_bytes)#
Reads a message from a device (i.e. a memory-mapped component, such as memories, timers, user-defined devices, etc…) through an interconnect.
- Parameters:
address – The address where the data will be read. Must be mapped to a slave device.
data – Pointer to the start of the buffer where the read data will be stored.
nb_bytes – The number of bytes to read.
- Example:
uint32_t base = get_base_address(BRAM0_ID); uint32_t data[4] = { 0 }; DeviceRead(base, data, sizeof(uint32_t) * 4);
-
void DeviceWrite(uintptr_t address, const void *data, uint32_t nb_bytes)#
Writes a message to a device (i.e. a memory-mapped component, such as memories, timers, user-defined devices, etc…) through an interconnect.
- Parameters:
address – The address where the data will be written. Must be mapped to a slave device.
data – Pointer to the start of the buffer containing the data to send.
nb_bytes – The number of bytes to write.
- Example:
uint32_t base = get_base_address(BRAM0_ID); uint32_t data[4] = { 1, 2, 3, 4 }; DeviceWrite(base, data, sizeof(uint32_t) * 4);
-
uint32_t get_base_address(unsigned int id)#
-
class slave_device : public sc_core::sc_module#
The
slave_deviceclass is the base class for a slave device. A slave device is a user-defined C/C++ device capable of responding to transactions on an interconnect.-
unsigned int get_id()#
Returns the ID of the device. This ID can be configured in the SpaceStudio GUI, through the property view of the component instance in an architecture.
- Returns:
The ID of the device.
- Example:
unsigned int id = get_id();
-
uint32_t get_base_address()#
This method returns the base address of the device’s address space.
- Returns:
The base address of the device’s address space.
- Example:
uint32_t base_address = get_base_address();
-
uint32_t get_offset(tlm::tlm_generic_payload &trans)#
Returns the offset from a TLM transaction.
- Parameters:
trans – The TLM transaction received from the
accessmethod.- Returns:
The offset from the TLM transaction’s address.
-
uint32_t get_size()#
Returns the size of the device’s address space.
- Returns:
The size of the device’s address space in bytes.
-
bool is_verbose()#
This method returns the verbose property for this device. Verbosity can be configured through the property view of the component instance in SpaceStudio.
- Returns:
The verbose property for this device.
- Example:
if (is_verbose()) { std::cout << "Verbose mode is enabled for this device." << std::endl; }
-
void hw_compute_latency(int cycles)#
For a device mapped to hardware, this method adds a temporal annotation for a wait of the given number of cycles.
If a device is mapped to software, this method does nothing.
- Parameters:
cycles – The number of cycles to wait.
- Example:
hw_compute_latency(10); // Adds a temporal annotation for a wait of 10 cycles.
-
sc_core::sc_time &get_clock_period()#
Returns the clock period of the device.
-
unsigned int get_id()#
7.3. Non-blocking communications#
The communication methods that can be carried by a DMA (abstract_module::StreamRead(), abstract_module::StreamWrite() in either form, and abstract_module::DmaCopy()) return a space_transfer_t object describing the transfer.
-
struct space_transfer_t#
Describes a transfer initiated by a communication method. Do not access its fields directly: query it with the functions of the
spacenamespace below.A blocking call never returns a pending transfer. A non-blocking call on a DMA-based communication may return a pending transfer: the call returns immediately while the DMA moves the data in the background. While
space::is_pending()returnstrue, the data buffer (or memory region) belongs to the DMA and must not be read, modified or freed.For any transfer, exactly one of
space::is_pending(),space::is_busy(),space::is_error()andspace::is_completed()istrue.Completion is detected through the DMA driver on Linux, and by polling the status register of the AXI DMA / AXI CDMA engine on the other operating systems (where finite timeouts passed to
space::wait()behave likeSPACE_BLOCKING).
-
space_status_t space::get_status(const space_transfer_t &transfer)#
Returns the status of the transfer:
SPACE_OK,SPACE_EMPTY,SPACE_FULL,SPACE_BUSYorSPACE_ERRORonce completed, orSPACE_PENDINGwhile the transfer is still running.
-
unsigned long space::get_transfer_bytes(const space_transfer_t &transfer)#
Returns the number of bytes actually transferred. Only meaningful once the transfer has completed.
-
bool space::is_pending(space_transfer_t &transfer)#
Returns whether the communication is still in transfer. Probes the hardware without blocking and refreshes the transfer’s state. While this returns
true, the data buffer belongs to the DMA and must not be touched.
-
bool space::is_busy(const space_transfer_t &transfer)#
Returns whether the channel was unavailable when the communication was attempted (non-blocking call: DMA engine busy with another transfer, or FIFO not ready). Nothing was transferred and nothing is running: retry the communication call.
-
bool space::is_error(space_transfer_t &transfer)#
Returns whether the communication failed.
-
bool space::is_completed(space_transfer_t &transfer)#
Returns whether the communication went through: the transfer ran to completion and everything went smoothly. Probes the hardware without blocking and refreshes the transfer’s state. Once it returns
true,space::get_transfer_bytes()holds the final count and the data buffer belongs to the caller again. Nevertruefor a pending, busy or failed transfer.
-
space_status_t space::wait(space_transfer_t &transfer, space_timeout_t timeout = SPACE_BLOCKING)#
Waits until the transfer completes, up to
timeoutmilliseconds (SPACE_BLOCKINGwaits forever). Returns the final status of the transfer, orSPACE_PENDINGif the timeout expired first. ReturnsSPACE_BUSYimmediately for a transfer that was never submitted.
Example: overlapping computation with a non-blocking communication:
SPACE_ALIGNED uint32_t data[256];
fill_buffer(data);
// Start sending the buffer; the call returns immediately.
space_transfer_t transfer = StreamWrite(CONSUMER0_ID, SPACE_NON_BLOCKING, data, 256);
if (space::is_busy(transfer)) {
// The DMA was busy: nothing was sent, retry later.
return;
}
// While the transfer is pending, 'data' belongs to the DMA:
// do useful work that does not touch it.
while (space::is_pending(transfer)) {
do_other_work();
}
if (space::is_completed(transfer)) {
// Transfer done: 'data' can be reused.
}
7.4. Global Functions#
7.4.1. spacelib_global.h#
The spacelib_global.h header provides functions that are mostly useful to abstract_module, master_device, and slave_device classes.
-
std::string get_project_path()#
This function returns the path of the SpaceStudio project as a string.
- Returns:
The path of the SpaceStudio project.
- Example:
// Open a data file relative to the project path. std::ifstream file(spacelib_global::get_project_path() + "/import/signal.bin", std::ios::in | std::ios::binary);
7.4.2. SpaceDisplay.h#
Defines function that can be used to print messages to SpaceStudio’s console.
-
void SpacePrint(const char *message_format, ...)#
This function prints a formatted message to SpaceStudio’s console. It supports the same formatting syntax as
printf.- Parameters:
message_format – The format string for the message to print, followed by any additional arguments required by the format string.
- Example:
int data = 0xFF; SpacePrint("this is a message with data=%d", data);
-
void SpaceMessageVerbose(bool verbose, const char *name, const char *message_format, ...)#
Prints a formatted message to SpaceStudio’s console if the
verboseparameter istrue, prefixed by the provided name. It supports the same formatting syntax asprintf.- Parameters:
verbose – Whether to print the message or not.
name – The name to prefix the message with (usually the object or module name).
message_format – The format string for the message, followed by any additional arguments required by the format string.
- Example:
SpaceMessageVerbose(is_verbose(), name(), "this is a verbose message");
-
void SpaceMessageError(const char *name, const char *message_format, ...)#
Prints a formatted error message to SpaceStudio’s console, prefixed by the provided name. It supports the same formatting syntax as
printf.The message will be highlighted in red in the console to indicate that it is an error message.
- Parameters:
name – The name to prefix the error message with (usually the object or module name).
message_format – The format string for the error message, followed by any additional arguments required by the format string.
- Example:
int error_code = 0xFF; SpaceMessageError(name(), "Error %d", error_code);
-
void SpaceMessageWarning(const char *name, const char *message_format, ...)#
Prints a formatted warning message to SpaceStudio’s console, prefixed by the provided name. It supports the same formatting syntax as
printf.The message will be highlighted in yellow in the console to indicate that it is a warning message.
- Parameters:
name – The name to prefix the warning message with (usually the object or module name).
message_format – The format string for the warning message, followed by any additional arguments required by the format string.
- Example:
int warning_code = 0xFF; SpaceMessageWarning(name(), "This is a warning with code=%d", warning_code);
7.5. Globally defined macros#
Some macros are defined by the SpaceStudio engine to enable user code to adapt itself to the architecture mapping.
-
MODULENAME0_MAPPING#
The name of this macro will depend on the module instance name. For instance, the macro for the first instance of a module named
consumerwill beCONSUMER0_MAPPING, thenCONSUMER1_MAPPINGfor the second instance, and so on.This macro will be defined to either
HW_MAPPINGorSW_MAPPING(two other macro-defined values) depending on the mapping of its corresponding module instance. It allows a module to query the mapping of other instances.- Example:
#if CONSUMER0_MAPPING == HW_MAPPING // Code specific to the case where CONSUMER0 is mapped to hardware. #else // Code specific to the case where CONSUMER0 is mapped to software. #endif
-
MAPPING#
This macro is defined within the context of a module’s code to either
HW_MAPPINGorSW_MAPPING(two other macro-defined values) depending on the mapping of the module.It allows the module to query its own mapping.
- Example:
#if MAPPING == HW_MAPPING // Code specific to the case where this module is mapped to hardware. #else // Code specific to the case where this module is mapped to software. #endif
-
MODULENAME_GROUP_SIZE#
The name of this macro will depend on a module’s name. For instance, for a module named
producer, the macro will bePRODUCER_GROUP_SIZE.This macro gives the number of instances of a module in the architecture. This is useful to write code that adapts to the number of instances of a module, for instance by using it as the size of an array.
- Example:
// Define an array with an element for each instance of the producer module. int data[PRODUCER_GROUP_SIZE];
-
INDEX#
This macro gives the instance number of the instance of a module. For instance, if there are 4 instances of a module named
producer, the INDEX macro will be defined to 0 in the context of the first instance, 1 in the context of the second instance, and so on.- Example:
// One-to-one communication between producer and consumer modules using the INDEX macro to match instances. StreamWrite(CONSUMER_GROUP[INDEX], SPACE_BLOCKING, 0xdeadbeef);
-
SPACE_SIMULATION#
This macro is defined when the code is being compiled for simulation. It can be used to conditionally compile code that should only be included in the simulation version of the design, and not in the implementation version.
- Example:
#ifdef SPACE_SIMULATION // Code specific to the simulation. #else // Code specific to implementation. #endif
-
SPACE_IMPLEMENTATION#
This macro is defined when the code is being compiled for the implementation of the architecture. It can be used to conditionally compile code that should only be included in the implementation version of the design, and not in the simulation version.
- Example:
#ifdef SPACE_IMPLEMENTATION // Code specific to the implementation. #else // Code specific to simulation. #endif