<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://zeroboardcomputer.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Semihosting_Overview</id>
	<title>Semihosting Overview - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://zeroboardcomputer.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Semihosting_Overview"/>
	<link rel="alternate" type="text/html" href="https://zeroboardcomputer.com/wiki/index.php?title=Semihosting_Overview&amp;action=history"/>
	<updated>2026-06-03T23:32:41Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://zeroboardcomputer.com/wiki/index.php?title=Semihosting_Overview&amp;diff=5&amp;oldid=prev</id>
		<title>Jbyrd: ZBC wiki page from Semihosting_Overview.wiki</title>
		<link rel="alternate" type="text/html" href="https://zeroboardcomputer.com/wiki/index.php?title=Semihosting_Overview&amp;diff=5&amp;oldid=prev"/>
		<updated>2025-12-01T12:06:27Z</updated>

		<summary type="html">&lt;p&gt;ZBC wiki page from Semihosting_Overview.wiki&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= Semihosting Overview =&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Semihosting&amp;#039;&amp;#039;&amp;#039; is a mechanism that allows programs running on embedded systems or emulators to access host services during development. The Zero Board Computer uses a &amp;#039;&amp;#039;&amp;#039;memory-mapped semihosting peripheral&amp;#039;&amp;#039;&amp;#039; based on the RIFF protocol to provide architecture-agnostic I/O capabilities.&lt;br /&gt;
&lt;br /&gt;
== What is Semihosting? ==&lt;br /&gt;
&lt;br /&gt;
Semihosting enables guest code (running on the target CPU) to:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Read and write files&amp;#039;&amp;#039;&amp;#039; on the host filesystem&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Output text&amp;#039;&amp;#039;&amp;#039; to the host console&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Get timing information&amp;#039;&amp;#039;&amp;#039; from the host clock&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Execute host commands&amp;#039;&amp;#039;&amp;#039; and receive results&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Access command-line arguments&amp;#039;&amp;#039;&amp;#039; passed from the host&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Exit cleanly&amp;#039;&amp;#039;&amp;#039; with status codes&lt;br /&gt;
&lt;br /&gt;
These services are essential during development when:&lt;br /&gt;
* Device drivers are not yet implemented&lt;br /&gt;
* Operating system infrastructure is unavailable&lt;br /&gt;
* Testing requires interaction with the host environment&lt;br /&gt;
* File I/O is needed without implementing a filesystem&lt;br /&gt;
&lt;br /&gt;
Semihosting allows &amp;#039;&amp;#039;&amp;#039;printf() to work immediately&amp;#039;&amp;#039;&amp;#039; without UART drivers, console handling, or an operating system.&lt;br /&gt;
&lt;br /&gt;
== Traditional Semihosting vs. ZBC Semihosting ==&lt;br /&gt;
&lt;br /&gt;
=== Traditional Semihosting (ARM, RISC-V) ===&lt;br /&gt;
&lt;br /&gt;
Traditional semihosting implementations use &amp;#039;&amp;#039;&amp;#039;trap instructions&amp;#039;&amp;#039;&amp;#039; to communicate with the host:&lt;br /&gt;
* ARM: &amp;lt;code&amp;gt;BKPT 0xAB&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SVC 0x123456&amp;lt;/code&amp;gt;&lt;br /&gt;
* RISC-V: &amp;lt;code&amp;gt;EBREAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* Other architectures: Various trap/interrupt instructions&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Problems with traditional semihosting:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Requires debugger&amp;#039;&amp;#039;&amp;#039; - Trap instructions only work when debugger is attached&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Architecture-specific&amp;#039;&amp;#039;&amp;#039; - Different instructions for each CPU&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Execution model complexity&amp;#039;&amp;#039;&amp;#039; - Distinguishes between debug traps and semihosting traps&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Limited availability&amp;#039;&amp;#039;&amp;#039; - Only works in specific environments (debugger, emulator)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Portability issues&amp;#039;&amp;#039;&amp;#039; - Code using trap instructions not portable across architectures&lt;br /&gt;
&lt;br /&gt;
=== ZBC RIFF-Based Semihosting ===&lt;br /&gt;
&lt;br /&gt;
ZBC semihosting solves these problems by using &amp;#039;&amp;#039;&amp;#039;memory-mapped I/O&amp;#039;&amp;#039;&amp;#039;:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Standard memory operations&amp;#039;&amp;#039;&amp;#039; - Uses load/store instructions available on all CPUs&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;No debugger required&amp;#039;&amp;#039;&amp;#039; - Works in any execution environment&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Completely architecture-agnostic&amp;#039;&amp;#039;&amp;#039; - Same interface on all CPUs&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Self-describing protocol&amp;#039;&amp;#039;&amp;#039; - Guest declares its architecture parameters&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Extensible design&amp;#039;&amp;#039;&amp;#039; - New features can be added without breaking compatibility&lt;br /&gt;
&lt;br /&gt;
The device appears as a &amp;#039;&amp;#039;&amp;#039;memory-mapped peripheral&amp;#039;&amp;#039;&amp;#039; with 32 bytes of registers, just like a UART (16550) or RTC (DS1307) chip.&lt;br /&gt;
&lt;br /&gt;
== How ZBC Semihosting Works ==&lt;br /&gt;
&lt;br /&gt;
The semihosting peripheral uses the &amp;#039;&amp;#039;&amp;#039;RIFF protocol&amp;#039;&amp;#039;&amp;#039; (Resource Interchange File Format) for communication between guest and host.&lt;br /&gt;
&lt;br /&gt;
=== Basic Operation Flow ===&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Guest allocates buffer&amp;#039;&amp;#039;&amp;#039; - Creates a RIFF structure in its own RAM&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Guest builds request&amp;#039;&amp;#039;&amp;#039; - Fills RIFF buffer with configuration and syscall data&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Guest writes pointer&amp;#039;&amp;#039;&amp;#039; - Stores buffer address in RIFF_PTR device register&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Guest triggers request&amp;#039;&amp;#039;&amp;#039; - Writes to DOORBELL register to start processing&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Device processes&amp;#039;&amp;#039;&amp;#039; - Reads RIFF buffer, executes syscall on host&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Device writes response&amp;#039;&amp;#039;&amp;#039; - Overwrites request with return values in same buffer&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Guest reads result&amp;#039;&amp;#039;&amp;#039; - Examines RETN chunk in buffer for syscall results&lt;br /&gt;
&lt;br /&gt;
This approach keeps the &amp;#039;&amp;#039;&amp;#039;device footprint minimal&amp;#039;&amp;#039;&amp;#039; (32 bytes) while allowing &amp;#039;&amp;#039;&amp;#039;variable-sized communication&amp;#039;&amp;#039;&amp;#039; (guest controls buffer size).&lt;br /&gt;
&lt;br /&gt;
=== Buffer Management ===&lt;br /&gt;
&lt;br /&gt;
The RIFF communication buffer:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Allocated by guest&amp;#039;&amp;#039;&amp;#039; in its own RAM (stack, heap, or static data)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Owned by guest&amp;#039;&amp;#039;&amp;#039; - Device only accesses on request&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Pointed to&amp;#039;&amp;#039;&amp;#039; via RIFF_PTR register&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Variable size&amp;#039;&amp;#039;&amp;#039; - Guest allocates sufficient space (typically 256-1024 bytes)&lt;br /&gt;
&lt;br /&gt;
The buffer location is separate from device registers:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Device registers&amp;#039;&amp;#039;&amp;#039;: Fixed 32-byte region in memory map&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;RIFF buffer&amp;#039;&amp;#039;&amp;#039;: Guest chooses location (anywhere in RAM)&lt;br /&gt;
&lt;br /&gt;
This separation allows the device to have a tiny footprint while supporting large data transfers.&lt;br /&gt;
&lt;br /&gt;
=== Memory Location in ZBC Systems ===&lt;br /&gt;
&lt;br /&gt;
In ZBC systems, the semihosting device registers are located at:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Address = reserved_start - 1536 - 32&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For 16-bit CPUs, this typically places registers at &amp;#039;&amp;#039;&amp;#039;0xFBE0-0xFBFF&amp;#039;&amp;#039;&amp;#039;, with the RIFF buffer conventionally placed at &amp;#039;&amp;#039;&amp;#039;0xFC00-0xFDFF&amp;#039;&amp;#039;&amp;#039; (though guest can place buffer anywhere).&lt;br /&gt;
&lt;br /&gt;
See [[Memory Layout and Addressing]] for complete address calculations.&lt;br /&gt;
&lt;br /&gt;
== Device Registers ==&lt;br /&gt;
&lt;br /&gt;
The semihosting peripheral presents 32 bytes of memory-mapped registers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Offset !! Size !! Name !! Access !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x00 || 16 bytes || RIFF_PTR || RW || Pointer to RIFF buffer in guest RAM&lt;br /&gt;
|-&lt;br /&gt;
| 0x10 || 1 byte || DOORBELL || W || Write any value to trigger request&lt;br /&gt;
|-&lt;br /&gt;
| 0x11 || 1 byte || IRQ_STATUS || R || Interrupt status flags&lt;br /&gt;
|-&lt;br /&gt;
| 0x12 || 1 byte || IRQ_ENABLE || RW || Interrupt enable mask&lt;br /&gt;
|-&lt;br /&gt;
| 0x13 || 1 byte || IRQ_ACK || W || Write 1s to clear interrupt bits&lt;br /&gt;
|-&lt;br /&gt;
| 0x14 || 1 byte || STATUS || R || Device status flags&lt;br /&gt;
|-&lt;br /&gt;
| 0x15 || 11 bytes || RESERVED || - || Reserved for future use&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== RIFF_PTR Register ===&lt;br /&gt;
&lt;br /&gt;
Holds the guest memory address of the RIFF communication buffer.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Format&amp;#039;&amp;#039;&amp;#039;: Raw byte storage in guest&amp;#039;s native byte order&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Size&amp;#039;&amp;#039;&amp;#039;: Guest writes as many bytes as needed (2, 4, 8, or 16 bytes)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Interpretation&amp;#039;&amp;#039;&amp;#039;: Host knows CPU address width and endianness from system configuration&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;6502 (16-bit)&amp;#039;&amp;#039;&amp;#039;: Writes 2 bytes in little-endian order&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;68000 (32-bit)&amp;#039;&amp;#039;&amp;#039;: Writes 4 bytes in big-endian order&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;x86-64 (64-bit)&amp;#039;&amp;#039;&amp;#039;: Writes 8 bytes in little-endian order&lt;br /&gt;
&lt;br /&gt;
=== DOORBELL Register ===&lt;br /&gt;
&lt;br /&gt;
Trigger register that initiates request processing.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Write&amp;#039;&amp;#039;&amp;#039;: Any value (typically 0x01) starts processing&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Read&amp;#039;&amp;#039;&amp;#039;: Returns undefined value (typically 0x00)&lt;br /&gt;
&lt;br /&gt;
After building a RIFF structure, guest writes to DOORBELL to tell device &amp;quot;request is ready&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== STATUS Register ===&lt;br /&gt;
&lt;br /&gt;
General device status flags for polling mode.&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Bit 0: RESPONSE_READY&amp;#039;&amp;#039;&amp;#039; - Request completed, response available&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Bit 7: DEVICE_PRESENT&amp;#039;&amp;#039;&amp;#039; - Always 1 (device exists and functional)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Bits 1-6&amp;#039;&amp;#039;&amp;#039;: Reserved (read as 0)&lt;br /&gt;
&lt;br /&gt;
Guest polls bit 0 to wait for completion without using interrupts.&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Registers ===&lt;br /&gt;
&lt;br /&gt;
For asynchronous operation:&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;IRQ_STATUS&amp;#039;&amp;#039;&amp;#039; (0x11) - Which interrupt conditions are active&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;IRQ_ENABLE&amp;#039;&amp;#039;&amp;#039; (0x12) - Which conditions can trigger CPU interrupt&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;IRQ_ACK&amp;#039;&amp;#039;&amp;#039; (0x13) - Write 1s to clear interrupt bits&lt;br /&gt;
&lt;br /&gt;
See [[Operation Modes]] for details on interrupt-driven operation.&lt;br /&gt;
&lt;br /&gt;
== RIFF Protocol Fundamentals ==&lt;br /&gt;
&lt;br /&gt;
RIFF (Resource Interchange File Format) is a tagged container format—the same format used by WAV audio files, AVI video files, and many other standards.&lt;br /&gt;
&lt;br /&gt;
=== Why RIFF? ===&lt;br /&gt;
&lt;br /&gt;
RIFF provides:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Tagged structure&amp;#039;&amp;#039;&amp;#039; - Chunks have IDs identifying their type&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Size information&amp;#039;&amp;#039;&amp;#039; - Each chunk declares its data size&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Self-describing&amp;#039;&amp;#039;&amp;#039; - Parsers can skip unknown chunks&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Extensible&amp;#039;&amp;#039;&amp;#039; - New chunk types don&amp;#039;t break old implementations&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Standard format&amp;#039;&amp;#039;&amp;#039; - Well-documented, widely used&lt;br /&gt;
&lt;br /&gt;
=== RIFF Structure ===&lt;br /&gt;
&lt;br /&gt;
A RIFF file/buffer contains:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;#039;RIFF&amp;#039; (4 bytes)           - Signature&lt;br /&gt;
size (4 bytes, LE)         - Total size minus 8&lt;br /&gt;
&amp;#039;SEMI&amp;#039; (4 bytes)           - Form type (semihosting)&lt;br /&gt;
chunks...                  - CNFG, CALL, etc.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each chunk has:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chunk_id (4 bytes)         - ASCII fourCC code&lt;br /&gt;
chunk_size (4 bytes, LE)   - Data size (excludes 8-byte header)&lt;br /&gt;
data (chunk_size bytes)    - Chunk-specific data&lt;br /&gt;
[pad byte]                 - If size is odd, pad to even boundary&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Endianness Handling ===&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Critical distinction:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;RIFF structure&amp;#039;&amp;#039;&amp;#039; (chunk IDs, sizes): &amp;#039;&amp;#039;&amp;#039;Always little-endian&amp;#039;&amp;#039;&amp;#039; (RIFF standard)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Data values&amp;#039;&amp;#039;&amp;#039; (syscall arguments, return values): &amp;#039;&amp;#039;&amp;#039;Guest&amp;#039;s native endianness&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
This separation allows:&lt;br /&gt;
* Standard RIFF parsing tools to work&lt;br /&gt;
* Guest to use native byte order for data&lt;br /&gt;
* Protocol to work on any endianness&lt;br /&gt;
&lt;br /&gt;
{{Note|Big-endian guests must swap bytes in RIFF structure fields (sizes) but NOT in chunk data values. Helper functions should handle this transparently.}}&lt;br /&gt;
&lt;br /&gt;
== RIFF Chunk Types ==&lt;br /&gt;
&lt;br /&gt;
=== CNFG Chunk - Configuration ===&lt;br /&gt;
&lt;br /&gt;
Declares guest CPU architecture parameters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Chunk: &amp;#039;CNFG&amp;#039; (12 bytes total)&lt;br /&gt;
  int_size   (1 byte)  - Size of integer type (2, 4, 8 bytes)&lt;br /&gt;
  ptr_size   (1 byte)  - Size of pointer type (2, 4, 8, 16 bytes)&lt;br /&gt;
  endianness (1 byte)  - 0=LE, 1=BE, 2=PDP&lt;br /&gt;
  reserved   (1 byte)  - Must be 0x00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;int_size&amp;#039;&amp;#039;&amp;#039; specifies the natural integer size:&lt;br /&gt;
* 6502/Z80: 2 bytes (16-bit int)&lt;br /&gt;
* 68000/ARM/i386: 4 bytes (32-bit int)&lt;br /&gt;
* x86-64: 4 bytes (32-bit int, even on 64-bit CPU)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;ptr_size&amp;#039;&amp;#039;&amp;#039; specifies pointer size:&lt;br /&gt;
* 6502/Z80: 2 bytes (16-bit addressing)&lt;br /&gt;
* 68000/ARM/i386: 4 bytes (32-bit addressing)&lt;br /&gt;
* x86-64: 8 bytes (64-bit addressing)&lt;br /&gt;
&lt;br /&gt;
{{Note|int_size and ptr_size may differ. For example, x86-64 has 32-bit int but 64-bit pointers. This is correct and supported.}}&lt;br /&gt;
&lt;br /&gt;
The CNFG chunk is sent &amp;#039;&amp;#039;&amp;#039;once per session&amp;#039;&amp;#039;&amp;#039; (first request after device initialization). Device caches these values for all subsequent requests.&lt;br /&gt;
&lt;br /&gt;
=== CALL Chunk - Syscall Request ===&lt;br /&gt;
&lt;br /&gt;
Container chunk for a semihosting operation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Chunk: &amp;#039;CALL&amp;#039; (variable size)&lt;br /&gt;
  opcode   (1 byte)      - ARM semihosting syscall number&lt;br /&gt;
  reserved (3 bytes)     - Must be 0x00&lt;br /&gt;
  sub-chunks...          - PARM and DATA chunks for arguments&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Opcode&amp;#039;&amp;#039;&amp;#039; is the ARM semihosting syscall number (0x01-0x31):&lt;br /&gt;
* 0x01: SYS_OPEN&lt;br /&gt;
* 0x05: SYS_WRITE&lt;br /&gt;
* 0x06: SYS_READ&lt;br /&gt;
* 0x02: SYS_CLOSE&lt;br /&gt;
* (see [[Syscall Reference]] for complete list)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Sub-chunks&amp;#039;&amp;#039;&amp;#039; contain the syscall parameters in order.&lt;br /&gt;
&lt;br /&gt;
=== PARM Chunk - Parameter Value ===&lt;br /&gt;
&lt;br /&gt;
Represents a scalar parameter (integer, pointer):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Chunk: &amp;#039;PARM&amp;#039; (variable size)&lt;br /&gt;
  param_type (1 byte)    - 0x01=integer, 0x02=pointer&lt;br /&gt;
  reserved   (3 bytes)   - Must be 0x00&lt;br /&gt;
  value      (N bytes)   - Parameter value in guest endianness&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Value size&amp;#039;&amp;#039;&amp;#039;:&lt;br /&gt;
* Type 0x01 (integer): int_size bytes from CNFG&lt;br /&gt;
* Type 0x02 (pointer): ptr_size bytes from CNFG&lt;br /&gt;
&lt;br /&gt;
Parameters must appear in the order expected by the syscall.&lt;br /&gt;
&lt;br /&gt;
=== DATA Chunk - Binary Data or String ===&lt;br /&gt;
&lt;br /&gt;
Represents binary data, strings, or buffer contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Chunk: &amp;#039;DATA&amp;#039; (variable size)&lt;br /&gt;
  data_type (1 byte)     - 0x01=binary, 0x02=string&lt;br /&gt;
  reserved  (3 bytes)    - Must be 0x00&lt;br /&gt;
  payload   (N bytes)    - Actual data&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used for:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;In CALL&amp;#039;&amp;#039;&amp;#039;: Filenames, data to write, command strings&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;In RETN&amp;#039;&amp;#039;&amp;#039;: Data read from files or console&lt;br /&gt;
&lt;br /&gt;
For strings (type 0x02), payload includes null terminator.&lt;br /&gt;
&lt;br /&gt;
=== RETN Chunk - Return Value ===&lt;br /&gt;
&lt;br /&gt;
Device response containing syscall result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Chunk: &amp;#039;RETN&amp;#039; (variable size)&lt;br /&gt;
  result   (int_size bytes) - Return value in guest endianness&lt;br /&gt;
  errno    (4 bytes, LE)    - POSIX errno (0=success)&lt;br /&gt;
  sub-chunks...             - Optional DATA chunks for read operations&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Result field&amp;#039;&amp;#039;&amp;#039; interpretation depends on syscall:&lt;br /&gt;
* File descriptor (SYS_OPEN)&lt;br /&gt;
* Byte count (SYS_READ, SYS_WRITE)&lt;br /&gt;
* Status code (SYS_CLOSE)&lt;br /&gt;
* Typically -1 indicates error&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Errno field&amp;#039;&amp;#039;&amp;#039; is standard POSIX errno:&lt;br /&gt;
* 0 = Success&lt;br /&gt;
* 2 = ENOENT (file not found)&lt;br /&gt;
* 13 = EACCES (permission denied)&lt;br /&gt;
* (see errno.h for complete list)&lt;br /&gt;
&lt;br /&gt;
The device &amp;#039;&amp;#039;&amp;#039;overwrites the CALL chunk&amp;#039;&amp;#039;&amp;#039; with RETN in the same buffer location.&lt;br /&gt;
&lt;br /&gt;
=== ERRO Chunk - Error Response ===&lt;br /&gt;
&lt;br /&gt;
Written by device when request is malformed:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Chunk: &amp;#039;ERRO&amp;#039; (variable size)&lt;br /&gt;
  error_code (2 bytes, LE)    - Error code&lt;br /&gt;
  reserved   (2 bytes)        - Must be 0x00&lt;br /&gt;
  message    (N bytes)        - Optional ASCII error message&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Error codes:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* 0x01: Invalid chunk structure&lt;br /&gt;
* 0x02: Malformed RIFF format&lt;br /&gt;
* 0x03: Missing CNFG chunk&lt;br /&gt;
* 0x04: Unsupported opcode&lt;br /&gt;
* 0x05: Invalid parameter count&lt;br /&gt;
&lt;br /&gt;
== ARM Semihosting Compatibility ==&lt;br /&gt;
&lt;br /&gt;
ZBC uses &amp;#039;&amp;#039;&amp;#039;ARM semihosting syscall numbers&amp;#039;&amp;#039;&amp;#039; for maximum compatibility with existing toolchains.&lt;br /&gt;
&lt;br /&gt;
=== Supported Toolchains ===&lt;br /&gt;
&lt;br /&gt;
Programs using standard C libraries work immediately:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;gcc&amp;#039;&amp;#039;&amp;#039; with newlib&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;clang&amp;#039;&amp;#039;&amp;#039; with picolibc&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;llvm-mos&amp;#039;&amp;#039;&amp;#039; for 6502 targets&lt;br /&gt;
* Any toolchain supporting ARM semihosting&lt;br /&gt;
&lt;br /&gt;
These toolchains compile code with semihosting backend, generating syscalls for I/O operations.&lt;br /&gt;
&lt;br /&gt;
=== Standard I/O Operations ===&lt;br /&gt;
&lt;br /&gt;
Common syscalls available:&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_OPEN&amp;#039;&amp;#039;&amp;#039; (0x01) - Open file with mode flags&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_CLOSE&amp;#039;&amp;#039;&amp;#039; (0x02) - Close file descriptor&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_WRITE&amp;#039;&amp;#039;&amp;#039; (0x05) - Write data to file/stdout&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_READ&amp;#039;&amp;#039;&amp;#039; (0x06) - Read data from file/stdin&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_WRITEC&amp;#039;&amp;#039;&amp;#039; (0x03) - Write single character&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_WRITE0&amp;#039;&amp;#039;&amp;#039; (0x04) - Write null-terminated string&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_READC&amp;#039;&amp;#039;&amp;#039; (0x07) - Read single character&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_SEEK&amp;#039;&amp;#039;&amp;#039; (0x0A) - Seek to file position&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_FLEN&amp;#039;&amp;#039;&amp;#039; (0x0C) - Get file length&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_REMOVE&amp;#039;&amp;#039;&amp;#039; (0x0E) - Delete file&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_RENAME&amp;#039;&amp;#039;&amp;#039; (0x0F) - Rename file&lt;br /&gt;
&lt;br /&gt;
=== Timing and System Operations ===&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_CLOCK&amp;#039;&amp;#039;&amp;#039; (0x10) - Get centiseconds since start&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_TIME&amp;#039;&amp;#039;&amp;#039; (0x11) - Get seconds since Unix epoch&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_ELAPSED&amp;#039;&amp;#039;&amp;#039; (0x30) - Get 64-bit tick count&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_TICKFREQ&amp;#039;&amp;#039;&amp;#039; (0x31) - Get ticks per second&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_SYSTEM&amp;#039;&amp;#039;&amp;#039; (0x12) - Execute host command&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_GET_CMDLINE&amp;#039;&amp;#039;&amp;#039; (0x15) - Get command-line arguments&lt;br /&gt;
&lt;br /&gt;
=== Program Exit ===&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_EXIT&amp;#039;&amp;#039;&amp;#039; (0x18) - Exit with status code&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SYS_EXIT_EXTENDED&amp;#039;&amp;#039;&amp;#039; (0x20) - Exit with exception info&lt;br /&gt;
&lt;br /&gt;
See [[Syscall Reference]] for complete documentation of all syscalls.&lt;br /&gt;
&lt;br /&gt;
== Operation Modes ==&lt;br /&gt;
&lt;br /&gt;
=== Synchronous Mode (Polling) ===&lt;br /&gt;
&lt;br /&gt;
Guest blocks waiting for completion:&lt;br /&gt;
&lt;br /&gt;
# Build RIFF request in buffer&lt;br /&gt;
# Write buffer address to RIFF_PTR&lt;br /&gt;
# Write to DOORBELL register&lt;br /&gt;
# Poll STATUS register until bit 0 set&lt;br /&gt;
# Read RETN chunk from buffer&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Advantages:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Simple to implement&lt;br /&gt;
* No interrupt handler needed&lt;br /&gt;
* Deterministic execution&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Disadvantages:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Guest wastes CPU cycles waiting&lt;br /&gt;
* Cannot multitask during I/O&lt;br /&gt;
&lt;br /&gt;
See [[Synchronous Operation]] for programming examples.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous Mode (Interrupts) ===&lt;br /&gt;
&lt;br /&gt;
Guest continues work while device processes request:&lt;br /&gt;
&lt;br /&gt;
# Enable interrupts via IRQ_ENABLE register&lt;br /&gt;
# Build RIFF request in buffer&lt;br /&gt;
# Write buffer address to RIFF_PTR&lt;br /&gt;
# Write to DOORBELL register&lt;br /&gt;
# Continue other work or enter low-power mode&lt;br /&gt;
# Device asserts interrupt when complete&lt;br /&gt;
# Interrupt handler reads RETN chunk&lt;br /&gt;
# Handler writes IRQ_ACK to clear interrupt&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Advantages:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Guest can multitask&lt;br /&gt;
* Efficient CPU utilization&lt;br /&gt;
* Suitable for operating systems&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Disadvantages:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Requires interrupt handler&lt;br /&gt;
* More complex implementation&lt;br /&gt;
&lt;br /&gt;
See [[Asynchronous Operation]] for programming examples.&lt;br /&gt;
&lt;br /&gt;
{{Warning|Programs using cached memory architectures must flush data cache before triggering requests and invalidate cache before reading responses. See [[Cache Coherency]] for details.}}&lt;br /&gt;
&lt;br /&gt;
== Use Cases ==&lt;br /&gt;
&lt;br /&gt;
=== Compiler Testing ===&lt;br /&gt;
&lt;br /&gt;
Test code generation immediately:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
printf(&amp;quot;Hello from %s!\n&amp;quot;, &amp;quot;ZBC&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This works without implementing console drivers because semihosting provides I/O.&lt;br /&gt;
&lt;br /&gt;
=== File I/O Testing ===&lt;br /&gt;
&lt;br /&gt;
Read test data, write results:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FILE *f = fopen(&amp;quot;test.dat&amp;quot;, &amp;quot;r&amp;quot;);&lt;br /&gt;
fread(buffer, 1, size, f);&lt;br /&gt;
fclose(f);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
No filesystem implementation needed—host provides file operations.&lt;br /&gt;
&lt;br /&gt;
=== Benchmarking ===&lt;br /&gt;
&lt;br /&gt;
Measure execution time accurately:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
uint64_t start = get_ticks();&lt;br /&gt;
run_test();&lt;br /&gt;
uint64_t elapsed = get_ticks() - start;&lt;br /&gt;
printf(&amp;quot;Test took %llu ticks\n&amp;quot;, elapsed);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Host provides high-resolution timing.&lt;br /&gt;
&lt;br /&gt;
=== Debugging ===&lt;br /&gt;
&lt;br /&gt;
Output trace information during development:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
debug_printf(&amp;quot;Register A = 0x%02X\n&amp;quot;, reg_a);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
No UART configuration or interrupt handling required.&lt;br /&gt;
&lt;br /&gt;
== Implementation Considerations ==&lt;br /&gt;
&lt;br /&gt;
=== Virtual vs. Physical Devices ===&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Virtual devices (emulators):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Can accept virtual addresses from guest&lt;br /&gt;
* Emulator translates using guest&amp;#039;s MMU&lt;br /&gt;
* Simplifies guest software&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Physical devices (FPGA/ASIC):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Require physical addresses&lt;br /&gt;
* Guest must disable MMU or use identity-mapped memory&lt;br /&gt;
* Guest responsible for address translation&lt;br /&gt;
&lt;br /&gt;
See [[Device Registers]] for address interpretation details.&lt;br /&gt;
&lt;br /&gt;
=== Cache Coherency ===&lt;br /&gt;
&lt;br /&gt;
On CPUs with data cache:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Before DOORBELL write&amp;#039;&amp;#039;&amp;#039;: Flush data cache (ensure RIFF buffer visible to device)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Before reading RETN&amp;#039;&amp;#039;&amp;#039;: Invalidate cache (ensure fresh data from device)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Memory barriers&amp;#039;&amp;#039;&amp;#039;: Ensure DOORBELL write completes before continuing&lt;br /&gt;
&lt;br /&gt;
Failure to manage cache causes stale data or corruption.&lt;br /&gt;
&lt;br /&gt;
=== Buffer Sizing ===&lt;br /&gt;
&lt;br /&gt;
Recommended buffer sizes:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Minimum&amp;#039;&amp;#039;&amp;#039;: 256 bytes (handles most syscalls)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Typical&amp;#039;&amp;#039;&amp;#039;: 1024 bytes (comfortable for all operations)&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Large transfers&amp;#039;&amp;#039;&amp;#039;: May need larger buffers or chunked operations&lt;br /&gt;
&lt;br /&gt;
== Next Steps ==&lt;br /&gt;
&lt;br /&gt;
Explore semihosting in detail:&lt;br /&gt;
&lt;br /&gt;
* [[Device Registers]] - Complete register reference&lt;br /&gt;
* [[RIFF Protocol Fundamentals]] - Detailed protocol specification&lt;br /&gt;
* [[Syscall Reference]] - All syscalls documented with examples&lt;br /&gt;
* [[Synchronous Operation]] - Polling mode programming guide&lt;br /&gt;
* [[Asynchronous Operation]] - Interrupt-driven programming guide&lt;br /&gt;
* [[Example Programs]] - Working code examples&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[System Overview]] - Complete ZBC architecture&lt;br /&gt;
* [[Memory Layout and Addressing]] - Semihosting device location&lt;br /&gt;
* [[Writing Programs for ZBC]] - Development guide&lt;br /&gt;
* [[Toolchain Integration]] - Compiler and library support&lt;br /&gt;
&lt;br /&gt;
{{ZBC Navigation}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Semihosting]]&lt;br /&gt;
[[Category:Overview]]&lt;/div&gt;</summary>
		<author><name>Jbyrd</name></author>
	</entry>
</feed>