Updated 7 November 2026

C8B_API reference

C8B_API is the table passed to plugin_init. It is declared in core8bit_plugin.h (C8B_API_VERSION 7) and contains three data fields and 64 function pointers.

Conventions on this page: Availability says whether a function works on the console, the emulator, or both; Since is the API version that added it. A function added after v1 can be NULL on older firmware, so check both the version and the pointer:

if (api->version >= 7u && api->present_set_async && api->present_wait) {
    api->present_set_async(1);
}

General rules:

  • All functions must be called from the plugin's main-thread entry points (plugin_init, plugin_update, plugin_call, plugin_cleanup). Never call them, alloc and free included, from an interrupt.
  • The screen is 480 × 272 on both platforms. The framebuffer is RGB565, 480 × 272, with a stride of 480 pixels.

Contents

Data fields

Field Type Value
version uint32_t API version of the running firmware (7)
screen_width uint16_t 480
screen_height uint16_t 272

Memory

alloc

void* alloc(size_t size);

Allocates a block from the shared 20 MB SDRAM asset pool. Blocks are 32-byte aligned and never move. Returns NULL when allocation is locked, when the plugin already holds 256 blocks (console) or when the pool is out of memory. Blocks still allocated at plugin.cleanup() are freed.

  • Availability: Console and emulator (no 256-block limit in the emulator)
  • Since: v1

Most plugins use their own C heap inside the plugin slot (set up by startup.cpp) and use alloc only for large buffers. See Memory.

free

void free(void* ptr);

Frees a block returned by alloc. An unknown pointer is ignored with a warning.

  • Availability: Console and emulator
  • Since: v1

get_free_mem

size_t get_free_mem(void);

Bytes available in the asset pool.

  • Availability: Console and emulator
  • Since: v1

alloc_lock

void alloc_lock(void);

Locks allocation: later alloc calls return NULL.

  • Availability: Console and emulator
  • Since: v2

alloc_unlock

void alloc_unlock(void);

Unlocks allocation.

  • Availability: Console and emulator
  • Since: v2

alloc_is_locked

bool alloc_is_locked(void);

Whether allocation is locked.

  • Availability: Console and emulator
  • Since: v2

alloc_get_used

size_t alloc_get_used(void);

Total size of the blocks the plugin currently holds.

  • Availability: Console and emulator
  • Since: v2

Files

Relative paths are resolved against the game folder. File handles are opaque pointers. Files left open are closed at plugin.cleanup().

file_open

void* file_open(const char* path, const char* mode);

Opens a file. A mode starting with w writes, a appends, anything else reads. Returns NULL on failure.

  • Availability: Console and emulator
  • Since: v1

file_read

size_t file_read(void* f, void* buf, size_t size);

Reads up to size bytes. Returns the number of bytes read (0 for a NULL handle).

  • Availability: Console and emulator
  • Since: v1

file_write

size_t file_write(void* f, const void* buf, size_t size);

Writes size bytes. Returns the number of bytes written.

  • Availability: Console and emulator
  • Since: v1

file_seek

int file_seek(void* f, int32_t offset, int whence);

Moves the file position. whence: 0 = from start, 1 = from current position, 2 = from end. Returns 0 on success, -1 on failure.

  • Availability: Console and emulator
  • Since: v1

file_tell

size_t file_tell(void* f);

Current file position.

  • Availability: Console and emulator
  • Since: v1

file_size

size_t file_size(void* f);

File size in bytes.

  • Availability: Console and emulator
  • Since: v1

file_close

void file_close(void* f);

Closes the file and releases the handle.

  • Availability: Console and emulator
  • Since: v1

file_mkdir

int file_mkdir(const char* path);

Creates the directory and any missing parent directories. Returns 0 on success.

  • Availability: Console and emulator
  • Since: v1

file_rename

int file_rename(const char* old_path, const char* new_path);

Renames or moves a file. Returns 0 on success.

  • Availability: Console and emulator
  • Since: v1

file_remove

int file_remove(const char* path);

Deletes a file. Returns 0 on success.

  • Availability: Console and emulator
  • Since: v1

dir_open

void* dir_open(const char* path);

Opens a directory for reading. Returns NULL if path is not a directory.

  • Availability: Console and emulator
  • Since: v2

dir_read

int dir_read(void* d, char* name, int max, int* is_dir);

Reads the next entry into name (at most max bytes) and sets *is_dir. Returns 1 for an entry, 0 at the end. Names starting with . are skipped.

  • Availability: Console and emulator
  • Since: v2

dir_close

void dir_close(void* d);

Closes a directory handle.

  • Availability: Console and emulator
  • Since: v2

list_entries

int list_entries(const char* path, C8B_DirEntry* out, int max);

Fills up to max entries of out (C8B_DirEntry.name holds 256 bytes). Returns the number of entries, or -1 if path is not a directory. Names starting with . are skipped.

  • Availability: Console and emulator
  • Since: v3

set_working_directory

void set_working_directory(const char* path);

Sets the directory that relative paths are resolved against.

  • Availability: Emulator only (NULL on the console, where relative paths always use the game folder)
  • Since: v2

Graphics

get_framebuffer

uint16_t* get_framebuffer(void);

Returns the 480 × 272 RGB565 framebuffer. If an asynchronous present is still copying the previous frame, it waits for it first.

  • Availability: Console and emulator
  • Since: v1

present

void present(void);

Shows the framebuffer. The console already presents once per frame after the Lua update function returns, so plugins normally do not call this; calling it shows the frame twice.

  • Availability: Console (no effect in the emulator)
  • Since: v1

clear

void clear(uint16_t color);

Fills the whole screen with an RGB565 color. Completes before returning.

  • Availability: Console and emulator
  • Since: v1

fill_rect

void fill_rect(int x, int y, int w, int h, uint16_t color);

Fills a rectangle, clipped to the screen.

  • Availability: Console and emulator
  • Since: v1

fill_rect_dma

void fill_rect_dma(int x, int y, int w, int h, uint16_t color);

Fills a rectangle with the graphics accelerator and returns before the fill completes. The next accelerated operation waits for it.

  • Availability: Console only (NULL in the emulator)
  • Since: v3

fill_rect_blend

void fill_rect_blend(int x, int y, int w, int h, uint32_t argb);

Blends an ARGB8888 color over a rectangle. 0x80000000 (50 % black) is the fastest case.

  • Availability: Console and emulator
  • Since: v2

blit_indexed8

void blit_indexed8(const uint8_t* src, int w, int h, int x, int y,
                   const uint32_t* clut, int n);

Draws an 8-bit indexed image at (x, y) using a palette of up to 256 ARGB8888 entries (n = number of entries), converting to RGB565. The image is clipped to the screen. The palette alpha is ignored: every pixel is drawn, index 0 included. Completes before returning.

  • Availability: Console and emulator
  • Since: v1

blit_indexed8_blend

void blit_indexed8_blend(const uint8_t* src, int srcW, int srcH,
                         int dstX, int dstY,
                         const uint32_t* clut, int clutSize);

Like blit_indexed8, but blends each pixel over the framebuffer using the alpha of its palette entry. Completes before returning. Palette entries with alpha 0 are transparent; use palette index 0 for transparency in HUD and menu overlays.

  • Availability: Console and emulator
  • Since: v2

get_depth_strip

void* get_depth_strip(uint32_t* size_bytes);

Returns a 480 × 48 array of uint16_t (46 080 bytes) in fast cached memory for depth or scratch data, and writes its size to *size_bytes.

  • Availability: Console and emulator
  • Since: v6

get_dep_buffer

void* get_dep_buffer(void);

Returns a 240 × 272 uint16_t buffer in the emulator and NULL on the console. Fall back to alloc when it returns NULL. Prefer get_depth_strip.

  • Availability: Emulator only (NULL result on the console)
  • Since: v3

present_set_async

void present_set_async(int enable);

With enable = 1, the frame copy at the end of each frame runs in the background while your next frame starts. With 0, presentation is synchronous again (waiting for a running copy). Reset to synchronous at plugin.cleanup().

  • Availability: Console and emulator (the emulator always presents synchronously)
  • Since: v7

After present_set_async(1), call present_wait() or get_framebuffer() before writing the framebuffer or using it as scratch memory. clear, fill_rect*, blit_* and frame_scratch_prefetch_to wait on their own.

present_wait

void present_wait(void);

Waits until the background frame copy has finished (at most 50 ms).

  • Availability: Console and emulator
  • Since: v7

Input

Buttons are reported as C8B_BTN_* bit masks.

get_buttons

uint32_t get_buttons(void);

Buttons currently held.

  • Availability: Console and emulator
  • Since: v1

get_buttons_pressed

uint32_t get_buttons_pressed(void);

Buttons pressed since the previous frame.

  • Availability: Console and emulator
  • Since: v1

get_buttons_released

uint32_t get_buttons_released(void);

Buttons released since the previous frame.

  • Availability: Console and emulator
  • Since: v1

get_axis_x, get_axis_y

int16_t get_axis_x(void);
int16_t get_axis_y(void);

Left analog stick, -32767 to 32767.

  • Availability: Console and emulator
  • Since: v1

get_axis_rx, get_axis_ry

int16_t get_axis_rx(void);
int16_t get_axis_ry(void);

Right analog stick, -32767 to 32767.

  • Availability: Console and emulator
  • Since: v1

Button mapping

Key Console Emulator
Menu C8B_BTN_START and C8B_BTN_L1 C8B_BTN_MENU
Start — C8B_BTN_START
Select C8B_BTN_SELECT C8B_BTN_SELECT
Shoulder buttons C8B_BTN_L2, C8B_BTN_R2 C8B_BTN_L1, C8B_BTN_R1, C8B_BTN_L2, C8B_BTN_R2

C8B_BTN_MENU and C8B_BTN_R1 are never set on the console. Test C8B_BTN_START for pause.

Audio

Plugin audio is one mono stream at 22050 Hz. See Audio.

audio_queue

void audio_queue(const int16_t* samples, size_t frames, bool stereo);

Queues frames frames (not samples). With stereo = true, samples holds interleaved L/R pairs, which are mixed down to mono. Frames that do not fit are dropped; the call never blocks.

  • Availability: Console and emulator
  • Since: v1

audio_get_free

size_t audio_get_free(void);

Number of frames that fit in the queue (at most 16 383).

  • Availability: Console and emulator
  • Since: v1

audio_get_sample_rate

uint32_t audio_get_sample_rate(void);

Output rate: 22050.

  • Availability: Console and emulator
  • Since: v1

System

get_ticks_ms

uint32_t get_ticks_ms(void);

Milliseconds since start.

  • Availability: Console and emulator
  • Since: v1

get_cycles

uint32_t get_cycles(void);

CPU cycle counter at 480 MHz. Wraps about every 8.9 seconds. The emulator provides a virtual 480 MHz counter.

  • Availability: Console and emulator
  • Since: v3

delay_ms

void delay_ms(uint32_t ms);

Blocks for ms milliseconds. The frame does not advance while it waits.

  • Availability: Console and emulator
  • Since: v1

log

void log(const char* msg);

Prints a message to the debug log. The console prints it as is; end messages with \n.

  • Availability: Console and emulator
  • Since: v1

request_exit

void request_exit(void);

Sets the exit flag read by exit_requested. It does not stop the plugin: return false from plugin_update to stop.

  • Availability: Console and emulator
  • Since: v1

exit_requested

bool exit_requested(void);

Whether request_exit was called. Cleared at plugin.cleanup().

  • Availability: Console and emulator
  • Since: v1

profile_begin, profile_end, profile_report

void profile_begin(const char* name);
void profile_end(const char* name);
void profile_report(int topN);

Named profiling scopes. profile_report prints the topN most expensive scopes.

  • Availability: Console and emulator
  • Since: v1

is_valid_code_ptr

int is_valid_code_ptr(void* fn);

Returns 1 if fn points into plugin code: the plugin ITCM area (0x800–0xFFFF) or the loaded image. Code in the D2 tail and addresses in .bss count as invalid. Use it to guard calls through function pointers.

  • Availability: Console and emulator
  • Since: v3

bios_debug

int bios_debug(int op, int arg);

Diagnostics hook. Op 1 switches the SDRAM cache policy to write-allocate (arg = 1) or back (arg = 0) and returns 1. Unknown ops return -1. Not needed by games.

  • Availability: Console and emulator (op 1 only)
  • Since: v7

FastBuffer, code placement and DMA

The FastBuffer is a 128 KB block of fast internal SRAM at 0x30027740 for the plugin's hot data. The system's image drawing also uses it, so its contents are not preserved while Lua draws images.

get_fast_buffer

void* get_fast_buffer(void);

Returns the FastBuffer. Waits until any pending system transfer into it has finished.

  • Availability: Console and emulator
  • Since: v2

get_fast_buffer_size

uint32_t get_fast_buffer_size(void);

Usable size: 131 072 bytes, or 100 352 bytes (98 KB) in C8B_FB_MODE_DATA_PLUS_CODE mode.

  • Availability: Console and emulator
  • Since: v2

set_fast_buffer_mode

int set_fast_buffer_mode(int mode);

Selects C8B_FB_MODE_FULL (0) or C8B_FB_MODE_DATA_PLUS_CODE (1, reserves the last 30 KB for .d2_hot code). Returns the previous mode; invalid values are ignored. Reset to FULL at plugin.cleanup().

  • Availability: Console and emulator
  • Since: v3

invalidate_icache

void invalidate_icache(void* addr, uint32_t size);

Makes freshly written code at addr executable: writes back the data cache and invalidates the instruction cache for the range. Call it after copying or generating code in D2 or SDRAM.

  • Availability: Console (no effect in the emulator)
  • Since: v2

fast_buffer_prefetch

void fast_buffer_prefetch(const void* src, uint32_t size);

Starts a background DMA copy of size bytes from src to the start of the FastBuffer. Ignored if size exceeds the usable size. Wait with fast_buffer_wait() before using the data.

  • Availability: Console and emulator (synchronous copy in the emulator)
  • Since: v2

fast_buffer_prefetch_to

void fast_buffer_prefetch_to(uint32_t offset, const void* src, uint32_t size);

Like fast_buffer_prefetch, to FastBuffer + offset. The range must fit the usable size.

  • Availability: Console and emulator
  • Since: v3

frame_scratch_prefetch_to

void frame_scratch_prefetch_to(uint32_t offset, const void* src, uint32_t size);

Starts a background DMA copy into the framebuffer, used as scratch memory before the frame is drawn. The range must fit 480 × 272 × 2 bytes. Redraw the whole frame afterwards.

  • Availability: Console and emulator
  • Since: v5

fast_buffer_wait

void fast_buffer_wait(void);

Waits until all transfers started by fast_buffer_prefetch* and frame_scratch_prefetch_to have finished. These transfers run one after another.

  • Availability: Console and emulator
  • Since: v2

load_itcm_overlay

int load_itcm_overlay(const void* src, uint32_t size);

Copies up to 16 KB of code to the ITCM overlay window at 0x0000C000, verifies it and makes it executable. Synchronous. Returns 1 on success, 0 on failure. See Building: ITCM phase overlays.

  • Availability: Console and emulator (the emulator only validates the arguments and returns 1)
  • Since: v4

Constants

Name Value Meaning
C8B_API_VERSION 7 API version of the header
C8B_BTN_UP … C8B_BTN_MENU bits 0 to 14 Button masks (see Button mapping)
C8B_FB_MODE_FULL 0 FastBuffer fully available for data
C8B_FB_MODE_DATA_PLUS_CODE 1 98 KB data + 30 KB code tail
C8B_D2_CODE_VMA 0x3003FF40 Link address of .d2_hot (FastBuffer + 98 KB)
C8B_D2_CODE_SIZE 30 KB Size of the D2 code tail
C8B_PLUGIN_ITCM_OVERLAY_VMA 0x0000C000 ITCM overlay window
C8B_PLUGIN_ITCM_OVERLAY_SIZE 16 KB Size of the overlay window
C8B_PLUGIN_DTCM_SLOT_SIZE 40 KB Plugin DTCM area