libdragon
Data Structures | Macros | Typedefs | Functions

RSP Command queue. More...

Go to the source code of this file.

Data Structures

struct  rspq_write_t
 A write cursor, returned by rspq_write_begin. More...
 

Macros

#define RSPQ_MAX_COMMAND_SIZE   63
 Maximum size of a command (in 32-bit words).
 
#define RSPQ_MAX_SHORT_COMMAND_SIZE   16
 Maximum size of a command that it is writable with rspq_write (in 32-bit words). More...
 
#define rspq_write(ovl_id, cmd_id, ...)
 Write a new command into the RSP queue. More...
 
#define rspq_wait()
 Wait until all commands in the queue have been executed by RSP. More...
 

Typedefs

typedef struct rspq_block_s rspq_block_t
 A preconstructed block of commands. More...
 
typedef int rspq_syncpoint_t
 A syncpoint in the queue. More...
 

Functions

void rspq_init (void)
 Initialize the RSPQ library. More...
 
void rspq_close (void)
 Shut down the RSPQ library. More...
 
uint32_t rspq_overlay_register (rsp_ucode_t *overlay_ucode)
 Register a rspq overlay into the RSP queue engine. More...
 
void rspq_overlay_register_static (rsp_ucode_t *overlay_ucode, uint32_t overlay_id)
 Register an overlay into the RSP queue engine assigning a static ID to it. More...
 
void rspq_overlay_unregister (uint32_t overlay_id)
 Unregister a ucode overlay from the RSP queue engine. More...
 
void * rspq_overlay_get_state (rsp_ucode_t *overlay_ucode)
 Return a pointer to the overlay state (in RDRAM) More...
 
rspq_write_t rspq_write_begin (uint32_t ovl_id, uint32_t cmd_id, int size)
 Begin writing a new command into the RSP queue. More...
 
void rspq_write_arg (rspq_write_t *w, uint32_t value)
 Add one argument to the command being enqueued. More...
 
void rspq_write_end (rspq_write_t *w)
 Finish enqueuing a command into the queue. More...
 
void rspq_flush (void)
 Make sure that RSP starts executing up to the last written command. More...
 
rspq_syncpoint_t rspq_syncpoint_new (void)
 Create a syncpoint in the queue. More...
 
bool rspq_syncpoint_check (rspq_syncpoint_t sync_id)
 Check whether a syncpoint was reached by RSP or not. More...
 
void rspq_syncpoint_wait (rspq_syncpoint_t sync_id)
 Wait until a syncpoint is reached by RSP. More...
 
void rspq_block_begin (void)
 Begin creating a new block. More...
 
rspq_block_trspq_block_end (void)
 Finish creating a block. More...
 
void rspq_block_run (rspq_block_t *block)
 Add to the RSP queue a command that runs a block. More...
 
void rspq_block_free (rspq_block_t *block)
 Free a block that is not needed any more. More...
 
void rspq_highpri_begin (void)
 Start building a high-priority queue. More...
 
void rspq_highpri_end (void)
 Finish building the high-priority queue and close it. More...
 
void rspq_highpri_sync (void)
 Wait for the RSP to finish processing all high-priority queues. More...
 
void rspq_noop (void)
 Enqueue a no-op command in the queue. More...
 
void rspq_signal (uint32_t signal)
 Enqueue a command that sets a signal in SP status. More...
 
void rspq_dma_to_rdram (void *rdram_addr, uint32_t dmem_addr, uint32_t len, bool is_async)
 Enqueue a command to do a DMA transfer from DMEM to RDRAM. More...
 
void rspq_dma_to_dmem (uint32_t dmem_addr, void *rdram_addr, uint32_t len, bool is_async)
 Enqueue a command to do a DMA transfer from RDRAM to DMEM. More...
 

Detailed Description

RSP Command queue.

The RSP command queue library provides the basic infrastructure to allow a very efficient use of the RSP coprocessor. On the CPU side, it implements an API to enqueue "commands" to be executed by RSP into a ring buffer, that is concurrently consumed by RSP in background. On the RSP side, it provides the core loop that reads and execute the queue prepared by the CPU, and an infrastructure to write "RSP overlays", that is libraries that plug upon the RSP command queue to perform actual RSP jobs (eg: 3D graphics, audio, etc.).

The library is extremely efficient. It is designed for very high throughput and low latency, as the RSP pulls by the queue concurrently as the CPU fills it. Through some complex synchronization paradigms, both CPU and RSP run fully lockless, that is never need to explicitly synchronize with each other (unless requested by the user). The CPU can keep filling the queue and must only wait for RSP in case the queue becomes full; on the other side, the RSP can keep processing the queue without ever talking to the CPU.

The library has been designed to be able to enqueue thousands of RSP commands per frame without its overhead to be measurable, which should be more than enough for most use cases.

This documentation describes the API of the queue, and how to use it. For details on how it is implemented, see the comments in rspq.c.

Commands

Each command in the queue is made by one or more 32-bit words (up to RSPQ_MAX_COMMAND_SIZE). The MSB of the first word is the command ID. The higher 4 bits are called the "overlay ID" and identify the overlay that is able to execute the command; the lower 4 bits are the command index, which identify the command within the overlay. For instance, command ID 0x37 is command index 7 in overlay 3.

As the RSP executes the queue, it will parse the command ID and dispatch it for execution. When required, the RSP will automatically load the RSP overlay needed to execute a command. In the previous example, the RSP will load into IMEM/DMEM overlay 3 (unless it was already loaded) and then dispatch command 7 to it.

Higher-level libraries and overlays

Higher-level libraries that come with their RSP ucode can be designed to use the RSP command queue to efficiently coexist with all other RSP libraries provided by libdragon. In fact, by using the overlay mechanism, each library can obtain its own overlay ID, and enqueue commands to be executed by the RSP through the same unique queue. Overlay IDs are allocated dynamically by rspq in registration order, to avoid conflicts between libraries.

End-users can then use all these libraries at the same time, without having to arrange for complex RSP synchronization, asynchronous execution or plan for efficient context switching. In fact, they don't even need to be aware that the libraries are using the RSP. Through the unified command queue, the RSP can be used efficiently and effortlessly without idle time, nor wasting CPU cycles waiting for completion of a task before switching to another one.

Higher-level libraries that are designed to use the RSP command queue must:

Normally, end-users will not need to manually enqueue commands in the RSP queue: they should only call higher-level APIs which internally do that.

Blocks

A block (rspq_block_t) is a prerecorded sequence of RSP commands that can be played back. Blocks can be created via rspq_block_begin / rspq_block_end, and then executed by rspq_block_run. It is also possible to do nested calls (a block can call another block), up to 8 levels deep.

A block is very efficient to run because it is played back by the RSP itself. The CPU just enqueues a single command that "calls" the block. It is thus much faster than enqueuing the same commands every frame.

Blocks can be used by higher-level libraries as an internal tool to efficiently drive the RSP (without having to repeat common sequence of commands), or they can be used by end-users to record and replay batch of commands, similar to OpenGL 1.x display lists.

Notice that this library does not support static (compile-time) blocks. Blocks must always be created at runtime once (eg: at init time) before being used.

Syncpoints

The RSP command queue is designed to be fully lockless, but sometimes it is required to know when the RSP has actually executed an enqueued command or not (eg: to use its result). To do so, this library offers a synchronization primitive called "syncpoint" (rspq_syncpoint_t). A syncpoint can be created via rspq_syncpoint_new and records the current writing position in the queue. It is then possible to call rspq_syncpoint_check to check whether the RSP has reached that position, or rspq_syncpoint_wait to wait for the RSP to reach that position.

Syncpoints are implemented using RSP interrupts, so their overhead is small but still measurable. They should not be abused.

High-priority queue

This library offers a mechanism to preempt the execution of RSP to give priority to very urgent tasks: the high-priority queue. Since the moment a high-priority queue is created via rspq_highpri_begin, the RSP immediately suspends execution of the command queue, and switches to the high-priority queue, waiting for commands. All commands added via standard APIs (rspq_write) are then directed to the high-priority queue, until rspq_highpri_end is called. Once the RSP has finished executing all the commands enqueue in the high-priority queue, it resumes execution of the standard queue.

The net effect is that commands enqueued in the high-priority queue are executed right away by the RSP, irrespective to whatever was currently enqueued in the standard queue. This can be useful for running tasks that require immediate execution, like for instance audio processing.

If required, it is possible to call rspq_highpri_sync to wait for the high-priority queue to be fully executed.

Notice that the RSP cannot be fully preempted, so switching to the high-priority queue can only happen after a command has finished execution (before starting the following one). This can have an effect on latency if a single command has a very long execution time; RSP overlays should in general prefer providing smaller, faster commands.

This feature should normally not be used by end-users, but by libraries in which a very low latency of RSP execution is paramount to their workings.


Data Structure Documentation

◆ rspq_write_t

struct rspq_write_t

A write cursor, returned by rspq_write_begin.

Data Fields
uint32_t first_word value that will be written as first word
volatile uint32_t * pointer current pointer into the RSP queue
volatile uint32_t * first pointer to the first word of the command
bool is_first true if we are waiting for the first argument word

Macro Definition Documentation

◆ RSPQ_MAX_SHORT_COMMAND_SIZE

#define RSPQ_MAX_SHORT_COMMAND_SIZE   16

Maximum size of a command that it is writable with rspq_write (in 32-bit words).

For larger commands, use rspq_write_begin + rspq_write_arg + rspq_write_end.

◆ rspq_write

#define rspq_write (   ovl_id,
  cmd_id,
  ... 
)

Write a new command into the RSP queue.

This macro is the main entry point to add a command to the RSP queue. It can be used as a variadic argument function, in which the first argument is the overlay ID, the second argument is the command index within the overlay, and the other arguments are the command arguments (additional 32-bit words).

// This example adds to the queue a command called CMD_SPRITE with
// index 0xA, with its arguments, for a total of three words. The overlay
// was previously registered via #rspq_register_overlay.
#define CMD_SPRITE 0xA
rspq_write(gfx_overlay_id, CMD_SPRITE,
sprite_num,
(x0 << 16) | y0,
(x1 << 16) | y1);
#define rspq_write(ovl_id, cmd_id,...)
Write a new command into the RSP queue.
Definition: rspq.h:366

As explained in the top-level documentation, the overlay ID (4 bits) and the command index (4 bits) are composed to form the command ID, and are stored in the most significant byte of the first word. So, the first command argument word, if provided, must have the upper MSB empty, to leave space for the command ID itself.

For instance, assuming the overlay ID for an overlay called "gfx" is 1, rspq_write(gfx_id, 0x2, 0x00FF2233) is a correct call, which writes 0x12FF2233 into the RSP queue; it will invoke command #2 in overlay with ID 0x1, and the first word contains other 24 bits of arguments that will be parsed by the RSP code. Instead, rspq_write(gfx_id, 0x2, 0x11FF2233) is an invalid call because the MSB of the first word is non-zero, and thus the highest byte "0x11" would clash with the overlay ID and command index.

rspq_write(gfx_id, 0x2) is a valid call, and equivalent to rspq_write(gfx_id, 0x2, 0x0). It will write 0x12000000 in the queue.

Notice that after a call to rspq_write, the command might or might not get executed by the RSP, depending on timing. If you want to make sure that the command will be executed, use rspq_flush. You can call rspq_flush after you have finished writing a batch of related commands. See rspq_flush documentation for more information.

rspq_write allows to write a full command with a single call, which is normally the easiest way to do it; it supports up to 16 argument words. In case it is needed to assemble larger commands, see rspq_write_begin for an alternative API.

Note
Each command can be up to RSPQ_MAX_SHORT_COMMAND_SIZE 32-bit words.
Parameters
ovl_idThe overlay ID of the command to enqueue. Notice that this must be a value preshifted by 28, as returned by rspq_overlay_register.
cmd_idIndex of the command to call, within the overlay.
...Optional arguments for the command
See also
rspq_overlay_register
rspq_flush
rspq_write_begin

◆ rspq_wait

#define rspq_wait ( )
Value:
({ \
rspq_syncpoint_wait(rspq_syncpoint_new()); \
})
rspq_syncpoint_t rspq_syncpoint_new(void)
Create a syncpoint in the queue.
Definition: rspq.c:1238

Wait until all commands in the queue have been executed by RSP.

This function blocks until all commands present in the queue have been executed by the RSP and the RSP is idle.

This function exists mostly for debugging purposes. Calling this function is not necessary, as the CPU can continue adding commands to the queue while the RSP is running them. If you need to synchronize between RSP and CPU (eg: to access data that was processed by RSP) prefer using rspq_syncpoint_new / rspq_syncpoint_wait which allows for more granular synchronization.

Typedef Documentation

◆ rspq_block_t

typedef struct rspq_block_s rspq_block_t

A preconstructed block of commands.

To improve performance of execution of sequences of commands, it is possible to create a "block". A block is a fixed set of commands that is created once and executed multiple times.

To create a block, use rspq_block_begin and rspq_block_end. After creation, you can use rspq_block_run at any point to run it. If you do not need the block anymore, use rspq_block_free to dispose it.

◆ rspq_syncpoint_t

typedef int rspq_syncpoint_t

A syncpoint in the queue.

A syncpoint can be thought of as a pointer to a position in the command queue. After creation, it is possible to later check whether the RSP has reached that position or not.

To create a syncpoint, use rspq_syncpoint_new that returns a syncpoint that references the current position. Call rspq_syncpoint_check or rspq_syncpoint_wait to respectively do a single check or block waiting for the syncpoint to be reached by RSP.

Syncpoints are implemented using interrupts, so they have a light but non trivial overhead. Do not abuse them. For instance, it is reasonable to use tens of syncpoints per frame, but not hundreds or thousands of them.

Note
A valid syncpoint is an integer greater than 0.

Function Documentation

◆ rspq_init()

void rspq_init ( void  )

Initialize the RSPQ library.

This should be called by the initialization functions of the higher-level libraries using the RSP command queue. It can be safely called multiple times without side effects.

It is not required by applications to call this explicitly in the main function.

◆ rspq_close()

void rspq_close ( void  )

Shut down the RSPQ library.

This is mainly used for testing.

◆ rspq_overlay_register()

uint32_t rspq_overlay_register ( rsp_ucode_t overlay_ucode)

Register a rspq overlay into the RSP queue engine.

This function registers a rspq overlay into the queue engine. An overlay is a RSP ucode that has been written to be compatible with the queue engine (see rsp_queue.inc for instructions) and is thus able to execute commands that are enqueued in the queue. An overlay doesn't have a single entry point: it exposes multiple functions bound to different commands, that will be called by the queue engine when the commands are enqueued.

The function returns the overlay ID, which is the ID to use to enqueue commands for this overlay. The overlay ID must be passed to rspq_write when adding new commands. rspq allows up to 16 overlays to be registered simultaneously, as the overlay ID occupies the top 4 bits of each command. The lower 4 bits specify the command ID, so in theory each overlay could offer a maximum of 16 commands. To overcome this limitation, this function will reserve multiple consecutive IDs in case an overlay with more than 16 commands is registered. These additional IDs are silently occupied and never need to be specified explicitly when queueing commands.

For example if an overlay with 32 commands were registered, this function could return ID 0x60, and ID 0x70 would implicitly be reserved as well. To queue the twenty first command of this overlay, you would write rspq_write(ovl_id, 0x14, ...), where ovl_id is the value that was returned by this function.

Parameters
overlay_ucodeThe overlay to register
Returns
The overlay ID that has been assigned to the overlay. Note that this value will be preshifted by 28 (eg: 0x60000000 for ID 6), as this is the expected format used by rspq_write.

◆ rspq_overlay_register_static()

void rspq_overlay_register_static ( rsp_ucode_t overlay_ucode,
uint32_t  overlay_id 
)

Register an overlay into the RSP queue engine assigning a static ID to it.

This function works similar to rspq_overlay_register, except it will attempt to assign the specified ID to the overlay instead of automatically choosing one. Note that if the ID (or a consecutive IDs) is already used by another overlay, this function will assert, so careful usage is advised.

Assigning a static ID can mostly be useful for debugging purposes.

Parameters
overlay_ucodeThe ucode to register
overlay_idThe ID to register the overlay with. This ID must be preshifted by 28 (eg: 0x40000000).
See also
rspq_overlay_register

◆ rspq_overlay_unregister()

void rspq_overlay_unregister ( uint32_t  overlay_id)

Unregister a ucode overlay from the RSP queue engine.

This function removes an overlay that has previously been registered with rspq_overlay_register or rspq_overlay_register_static from the queue engine. After calling this function, the specified overlay ID (and consecutive IDs in case the overlay has more than 16 commands) is no longer valid and must not be used to write new commands into the queue.

Note that when new overlays are registered, the queue engine may recycle IDs from previously unregistered overlays.

Parameters
overlay_idThe ID of the ucode (as returned by rspq_overlay_register) to unregister.

◆ rspq_overlay_get_state()

void * rspq_overlay_get_state ( rsp_ucode_t overlay_ucode)

Return a pointer to the overlay state (in RDRAM)

Overlays can define a section of DMEM as persistent state. This area will be preserved across overlay switching, by reading back into RDRAM the DMEM contents when the overlay is switched away.

This function returns a pointer to the state area in RDRAM (not DMEM). It is meant to modify the state on the CPU side while the overlay is not loaded. The layout of the state and its size should be known to the caller.

Parameters
overlay_ucodeThe ucode overlay for which the state pointer will be returned.
Returns
Pointer to the overlay state (in RDRAM)

◆ rspq_write_begin()

rspq_write_t rspq_write_begin ( uint32_t  ovl_id,
uint32_t  cmd_id,
int  size 
)
inline

Begin writing a new command into the RSP queue.

This command initiates a sequence to enqueue a new command into the RSP queue. Call this command passing the overlay ID and command ID of the command to create. Then, call rspq_write_arg once per each argument word that composes the command. Finally, call rspq_write_end to finalize and enqueue the command.

A sequence made by rspq_write_begin, rspq_write_arg, rspq_write_end is functionally equivalent to a call to rspq_write, but it allows to create bigger commands, and might better fit some situations where arguments are calculated on the fly. Performance-wise, the code generated by rspq_write_begin + rspq_write_arg + rspq_write_end should be very similar to a single call to rspq_write, though just a bit slower. It is advisable to use rspq_write whenever possible.

Make sure to read the documentation of rspq_write as well for further details.

Parameters
ovl_idThe overlay ID of the command to enqueue. Notice that this must be a value preshifted by 28, as returned by rspq_overlay_register.
cmd_idIndex of the command to call, within the overlay.
sizeThe size of the commands in 32-bit words
Returns
A write cursor, that must be passed to rspq_write_arg and rspq_write_end
See also
rspq_write_arg
rspq_write_end
rspq_write

◆ rspq_write_arg()

void rspq_write_arg ( rspq_write_t w,
uint32_t  value 
)
inline

Add one argument to the command being enqueued.

This function adds one more argument to the command currently being enqueued. This function must be called after rspq_write_begin; it should be called multiple times (one per argument word), and then rspq_write_end should be called to terminate enqueuing the command.

See also rspq_write for a more straightforward API for command enqueuing.

Parameters
wThe write cursor (returned by rspq_write_begin)
valueNew 32-bit argument word to add to the command.
Note
The first argument must have its MSB set to 0, to leave space for the command ID. See rspq_write documentation for a more complete explanation.
See also
rspq_write_begin
rspq_write_end
rspq_write

◆ rspq_write_end()

void rspq_write_end ( rspq_write_t w)
inline

Finish enqueuing a command into the queue.

This function should be called to terminate a sequence for command enqueuing, after rspq_write_begin and (multiple) calls to rspq_write_arg.

After calling this command, the write cursor cannot be used anymore.

Parameters
wThe write cursor (returned by rspq_write_begin)
See also
rspq_write_begin
rspq_write_arg
rspq_write

◆ rspq_flush()

void rspq_flush ( void  )

Make sure that RSP starts executing up to the last written command.

RSP processes the command queue asynchronously as it is being written. If it catches up with the CPU, it halts itself and waits for the CPU to notify that more commands are available. On the contrary, if the RSP lags behind it might keep executing commands as they are written without ever sleeping. So in general, at any given moment the RSP could be crunching commands or sleeping waiting to be notified that more commands are available.

This means that writing a command via rspq_write is not enough to make sure it is executed; depending on timing and batching performed by RSP, it might either be executed automatically or not. rspq_flush makes sure that the RSP will see it and execute it.

This function does not block: it just make sure that the RSP will run the full command queue written until now. If you need to actively wait until the last written command has been executed, use rspq_wait.

It is suggested to call rspq_flush every time a new "batch" of commands has been written. In general, it is not a problem to call it often because it is very very fast (takes only ~20 cycles). For instance, it can be called after every rspq_write without many worries, but if you know that you are going to write a number of subsequent commands in straight line code, you can postpone the call to rspq_flush after the whole sequence has been written.

// This example shows some code configuring the lights for a scene.
// The command in this sample is called CMD_SET_LIGHT and requires
// a light index and the RGB colors for the list to update.
uint32_t gfx_overlay_id;
#define CMD_SET_LIGHT 0x7
for (int i=0; i<MAX_LIGHTS; i++) {
rspq_write(gfx_overlay_id, CMD_SET_LIGHT, i,
(lights[i].r << 16) | (lights[i].g << 8) | lights[i].b);
}
// After enqueuing multiple commands, it is sufficient
// to call rspq_flush once to make sure the RSP runs them (in case
// it was idling).
void rspq_flush(void)
Make sure that RSP starts executing up to the last written command.
Definition: rspq.c:1066
Note
This is an experimental API. In the future, it might become a no-op, and flushing could happen automatically at every rspq_write. We are keeping it separate from rspq_write while experimenting more with the RSPQ API.
This function is a no-op if it is called while a block is being recorded (see rspq_block_begin / rspq_block_end). This means calling this function in a block recording context will not guarantee the execution of commands that were queued prior to starting the block.

◆ rspq_syncpoint_new()

rspq_syncpoint_t rspq_syncpoint_new ( void  )

Create a syncpoint in the queue.

This function creates a new "syncpoint" referencing the current position in the queue. It is possible to later check when the syncpoint is reached by the RSP via rspq_syncpoint_check and rspq_syncpoint_wait.

Returns
ID of the just-created syncpoint.
Note
It is not possible to create a syncpoint within a block because it is meant to be a one-time event. Otherwise the same syncpoint would potentially be triggered multiple times, which is not supported.
It is not possible to create a syncpoint from the high-priority queue due to the implementation requiring syncpoints to be triggered in the same order they have been created.
See also
rspq_syncpoint_t

◆ rspq_syncpoint_check()

bool rspq_syncpoint_check ( rspq_syncpoint_t  sync_id)

Check whether a syncpoint was reached by RSP or not.

This function checks whether a syncpoint was reached. It never blocks. If you need to wait for a syncpoint to be reached, use rspq_syncpoint_wait instead of polling this function.

Parameters
[in]sync_idID of the syncpoint to check
Returns
true if the RSP has reached the syncpoint, false otherwise
See also
rspq_syncpoint_t

◆ rspq_syncpoint_wait()

void rspq_syncpoint_wait ( rspq_syncpoint_t  sync_id)

Wait until a syncpoint is reached by RSP.

This function blocks waiting for the RSP to reach the specified syncpoint. If the syncpoint was already called at the moment of call, the function exits immediately.

Parameters
[in]sync_idID of the syncpoint to wait for
See also
rspq_syncpoint_t

◆ rspq_block_begin()

void rspq_block_begin ( void  )

Begin creating a new block.

This function begins writing a command block (see rspq_block_t). While a block is being written, all calls to rspq_write will record the commands into the block, without actually scheduling them for execution. Use rspq_block_end to close the block and get a reference to it.

Only one block at a time can be created. Calling rspq_block_begin twice (without any intervening rspq_block_end) will cause an assert.

During block creation, the RSP will keep running as usual and execute commands that have been already added to the queue.

Note
Calls to rspq_flush are ignored during block creation, as the RSP is not going to execute the block commands anyway.

◆ rspq_block_end()

rspq_block_t * rspq_block_end ( void  )

Finish creating a block.

This function completes a block and returns a reference to it (see rspq_block_t). After this function is called, all subsequent rspq_write will resume working as usual: they will add commands to the queue for immediate RSP execution.

To run the created block, use rspq_block_run.

Returns
A reference to the just created block
See also
rspq_block_begin
rspq_block_run

◆ rspq_block_run()

void rspq_block_run ( rspq_block_t block)

Add to the RSP queue a command that runs a block.

This function runs a block that was previously created via rspq_block_begin and rspq_block_end. It schedules a special command in the queue that will run the block, so that execution of the block will happen in order relative to other commands in the queue.

Blocks can call other blocks. For instance, if a block A has been fully created, it is possible to call rspq_block_run(A) at any point during the creation of a second block B; this means that B will contain the special command that will call A.

Parameters
blockThe block that must be run
Note
The maximum depth of nested block calls is 8.

◆ rspq_block_free()

void rspq_block_free ( rspq_block_t block)

Free a block that is not needed any more.

After calling this function, the block is invalid and must not be called anymore.

Parameters
blockThe block
Note
If the block was being called by other blocks, these other blocks become invalid and will make the RSP crash if called. Make sure that freeing a block is only done when no other blocks reference it.

◆ rspq_highpri_begin()

void rspq_highpri_begin ( void  )

Start building a high-priority queue.

This function enters a special mode in which a high-priority queue is activated and can be filled with commands. After this function has been called, all commands will be put in the high-priority queue, until rspq_highpri_end is called.

The RSP will start processing the high-priority queue almost instantly (as soon as the current command is done), pausing the normal queue. This will also happen while the high-priority queue is being built, to achieve the lowest possible latency. When the RSP finishes processing the high priority queue (after rspq_highpri_end closes it), it resumes processing the normal queue from the exact point that was left.

The goal of the high-priority queue is to either schedule latency-sensitive commands like audio processing, or to schedule immediate RSP calculations that should be performed right away, just like they were preempting what the RSP is currently doing.

It is possible to create multiple high-priority queues by calling rspq_highpri_begin / rspq_highpri_end multiple times with short delays in-between. The RSP will process them in order. Notice that there is a overhead in doing so, so it might be advisable to keep the high-priority mode active for a longer period if possible. On the other hand, a shorter high-priority queue allows for the RSP to switch back to processing the normal queue before the next one is created.

Note
It is not possible to create a block while the high-priority queue is active. Arrange for constructing blocks beforehand.
It is currently not possible to call a block from the high-priority queue. (FIXME: to be implemented)

◆ rspq_highpri_end()

void rspq_highpri_end ( void  )

Finish building the high-priority queue and close it.

This function terminates and closes the high-priority queue. After this command is called, all following commands will be added to the normal queue.

Notice that the RSP does not wait for this function to be called: it will start running the high-priority queue as soon as possible, even while it is being built.

◆ rspq_highpri_sync()

void rspq_highpri_sync ( void  )

Wait for the RSP to finish processing all high-priority queues.

This function will spin-lock waiting for the RSP to finish processing all high-priority queues. It is meant for debugging purposes or for situations in which the high-priority queue is known to be very short and fast to run. Also note that it is not possible to create syncpoints in the high-priority queue.

◆ rspq_noop()

void rspq_noop ( void  )

Enqueue a no-op command in the queue.

This function enqueues a command that does nothing. This is mostly useful for debugging purposes.

◆ rspq_signal()

void rspq_signal ( uint32_t  signal)

Enqueue a command that sets a signal in SP status.

The SP status register has 8 bits called "signals" that can be atomically set or cleared by both the CPU and the RSP. They can be used to provide asynchronous communication.

This function allows to add a command to the queue that will set and/or clear a combination of the above bits.

Notice that signal bits 2-7 are used by the RSP queue engine itself, so this function must only be used for bits 0 and 1.

Parameters
[in]signalA signal set/clear mask created by composing SP_WSTATUS_* defines.
Note
This is an advanced function that should be used rarely. Most synchronization requirements should be fulfilled via rspq_syncpoint_new which is easier to use.

◆ rspq_dma_to_rdram()

void rspq_dma_to_rdram ( void *  rdram_addr,
uint32_t  dmem_addr,
uint32_t  len,
bool  is_async 
)

Enqueue a command to do a DMA transfer from DMEM to RDRAM.

Parameters
rdram_addrThe RDRAM address (destination, must be aligned to 8)
[in]dmem_addrThe DMEM address (source, must be aligned to 8)
[in]lenNumber of bytes to transfer (must be multiple of 8)
[in]is_asyncIf true, the RSP does not wait for DMA completion and processes the next command as the DMA is in progress. If false, the RSP waits until the transfer is finished before processing the next command.
Note
The argument is_async refers to the RSP only. From the CPU standpoint, this function is always asynchronous as it just adds a command to the queue.

◆ rspq_dma_to_dmem()

void rspq_dma_to_dmem ( uint32_t  dmem_addr,
void *  rdram_addr,
uint32_t  len,
bool  is_async 
)

Enqueue a command to do a DMA transfer from RDRAM to DMEM.

Parameters
[in]dmem_addrThe DMEM address (destination, must be aligned to 8)
rdram_addrThe RDRAM address (source, must be aligned to 8)
[in]lenNumber of bytes to transfer (must be multiple of 8)
[in]is_asyncIf true, the RSP does not wait for DMA completion and processes the next command as the DMA is in progress. If false, the RSP waits until the transfer is finished before processing the next command.
Note
The argument is_async refers to the RSP only. From the CPU standpoint, this function is always asynchronous as it just adds a command to the queue.