Examples

On-Target Test Suite

The test/target/ directory contains a comprehensive example of ZBC semihosting on bare metal. The test suite exercises all 23 syscalls and runs on multiple architectures.

Key Files

  • zbc_target_test.c: Complete test program using all semihosting calls

  • zbc_target_harness.h: Bare-metal test macros (no libc needed)

  • platforms/m6502/: 6502-specific files

    • crt6502.c: C runtime startup

    • zbc6502.ld: Linker script

  • platforms/i386/: x86 32-bit files

    • crti386.S: Assembly startup

    • zbci386.ld: Linker script

Building and Running

cmake -B build -DZBC_TARGET_TESTS=ON
cmake --build build
ctest --test-dir build -L target

This builds test binaries for available platforms and runs them on MAME’s zbci386 and zbcm6502 machines.

Minimal Client Example

Using the high-level API for a POSIX-like interface:

#include "zbc_api.h"

static zbc_client_state_t client;
static zbc_api_t api;
static uint8_t buf[256];

void _start(void) {
    /* Platform-specific device address */
    volatile uint8_t *dev = (volatile uint8_t *)0xFFFFBFDF;

    zbc_client_init(&client, dev);
    zbc_api_init(&api, &client, buf, sizeof(buf));

    /* Print via semihosting */
    zbc_api_write0(&api, "Hello, ZBC!\n");

    /* File I/O */
    int fd = zbc_api_open(&api, "/tmp/test.txt", SH_OPEN_W);
    if (fd >= 0) {
        zbc_api_write(&api, fd, "Test output\n", 12);
        zbc_api_close(&api, fd);
    }

    /* Exit */
    zbc_api_exit(&api, 0);
}

Using the low-level API (for libc integration or direct RIFF control):

#include "zbc_semihost.h"

static zbc_client_state_t client;
static uint8_t riff_buf[256];

void _start(void) {
    /* Platform-specific device address */
    volatile uint8_t *dev = (volatile uint8_t *)0xFFFFBFDF;

    zbc_client_init(&client, dev);

    /* Print via semihosting */
    uintptr_t args[1];
    args[0] = (uintptr_t)"Hello, ZBC!\n";
    zbc_semihost(&client, riff_buf, sizeof(riff_buf),
                 SH_SYS_WRITE0, (uintptr_t)args);

    /* Exit */
    args[0] = 0;
    zbc_semihost(&client, riff_buf, sizeof(riff_buf),
                 SH_SYS_EXIT, (uintptr_t)args);
}

The device address depends on the platform. For 32-bit systems, ZBC places the semihost device at 0xFFFFBFDF (end of address space minus reserved area).

Customization

  • Device Address: See zbc_target_harness.h for the address calculation formula based on pointer size.

  • Backend: Use zbc_backend_ansi() for sandboxed file access or zbc_backend_ansi_insecure() for full host filesystem access.

  • CPU: Works 8/16/32/64-bit; the CNFG chunk conveys int_size/ptr_size automatically.

See Also

  • Client Library for full client API documentation

  • Testing for test infrastructure details

  • test/target/ source for complete platform examples