Channel Declarations
ChannelDecl ::= SyncChannelDecl | AsyncChannelDecl
SyncChannelDecl ::= 'Sync' 'Chan' ident '=' ident '-->' ident ';'?
AsyncChannelDecl ::= 'Async'? 'Chan' ident '=' ident ('<->' | '-->') ident ViaClause? ';'?
ViaClause ::= 'via' ident ('<' Type '>')?
A channel declaration introduces one named communication endpoint between
two protection domains. Channels carry the events that show up inside a
process expression — c?x (receive) and c!e (send). They live in .fis
system files; the .fi files reference channels by name only.
Channel kinds
| Kind | Direction | Notation | Notes |
|---|---|---|---|
SyncUni | Unidirectional | pd_a --> pd_b | Synchronous call/reply; only the unidirectional shape is allowed. |
AsyncUni | Unidirectional | pd_a --> pd_b | Notification-only; no payload acknowledgement. |
AsyncBi | Bidirectional | pd_a <-> pd_b | Each side can send and receive on the same channel. |
The Async keyword may be omitted — a Chan without a leading Sync is
asynchronous by default. The default arrow is <->. Only Sync channels
require the unidirectional --> form.
Fields
-
Name —
snake_caseidentifier. The same name appears in process expressions on the LHS of?/!. -
Endpoints — two protection-domain names. Both must be declared in the same
.fisfile. -
Buffer (optional, after
via) — theMemoryRegionthat backs the channel’s payload buffer, optionally annotated with a typed slot:via packet_buffer_outer<int>or a declared data-layer struct (via eth_outer_output<Slot>). Withoutvia, the channel is treated as a pure synchronisation point with no shared payload buffer. A struct payload is the channel’s communication type: it must be a system (.fis) struct — never a program-local struct — and the C backend types receive binders from it (o2d?pktdeclaresstatic struct Slot pkt;).A buffer region is implicitly mapped into both endpoint PDs (
rw, cached) at compiler-allocated vaddrs — it must not also appear in an explicitMapping, and it may back only one channel. Each endpoint’s generated unit declares the loader-patched symbols<region>_vaddr/<region>_size(and driver code may declare<region>_paddron demand), named after the region, not a mapping.
The optional trailing semicolon is accepted but not required.
Examples
// Synchronous unidirectional — outer PD calls into the diode.
Sync Chan o2d = eth_outer --> dd;
// Asynchronous bidirectional — `Async` is the default, can be omitted.
Chan d2i = dd <-> eth_inner;
Async Chan s2o = simulate <-> eth_outer;
// Buffer-backed channel, typed slot.
Chan packet = eth_outer <-> eth_inner via packet_buffer_outer<int>;
// Buffer-backed, untyped (slot type defaults later).
Chan ring = eth_outer --> eth_inner via ring_buffer_outer;
Channel events in process bodies
Inside a process, channel events are written chan_name '?' ident (receive)
and chan_name '!' ident (send). The names must match exactly; the
validator resolves each event back to the declared ChannelDecl to check
direction and payload type.
See Event Declarations → Channel events for the inline event grammar and Process Definitions for how channel events sit in a process expression.
Limitations
- A struct payload types the receive binder in the generated C, but the payload transport (the ring copy through the backing region) is not generated yet — it is an explicit follow-up under the data-diode case study (#201). The generated code marks the pending copy with a comment.
- Send-site type checking (
c!eagainst the declared payload) needs expression typing and is tracked under the type-system work (#117). - The
Syncmodifier rejects bidirectional<->syntactically; sync bidirectional channels would require a richer call/reply protocol than the current implementation supports.