> **Documentation index**
>
> Fetch the complete documentation index at: https://circ-lang.org/llms.txt
> Use this file to discover all available pages before exploring further.


# Circuit File Format

> The .circ language: declarations, ports, components, and built-ins.

`.circ` files describe a digital circuit as a set of named components and their connections. The format is a simple declarative DSL that maps directly onto the simulation engine's component and connection model.

> **Status**: Parsing, semantic validation, and compilation to WASM exist for the supported surface below. A single root `.circ` (plus any sibling files it imports) produces one self-contained `.wasm` artifact via the in-process topology-splice pipeline; the runtime is prebuilt and embedded.

## Syntax Overview

A `.circ` file contains a sequence of top-level declarations. Each declaration either names input pins or instantiates a component with named port connections. Every signal-carrying declaration may carry a width annotation `[N]`, where `N` is in `[1, 64]`; a missing `[N]` means width 1.

```
input  [<width>] <name> [, <name> ...]
output [<width>] <name> [, <name> ...]

<type> [<width>] <instance-name> [<call-widths>] (
    <port> = <signal> [,
    <port> = <signal> ...]
)
```

`<width>` is a literal `[N]` (or a parameter inside a parametric sub-circuit; see [`language.md`](https://circ-lang.org/reference.md) §6.3). `<call-widths>` is a comma-separated list `[w0, w1, ...]` that pins the width parameters of an imported sub-circuit at the call site.

For the full language reference (parametric sub-circuits, slice/index/concat signals, the `<W>` introduction form, built-in parametric macros, and diagnostic semantics), see [`language.md`](https://circ-lang.org/reference.md).

## Comments

Line comments start with `//` and run to end of line (see `Annotation` in `lib/grammar/proto-circ.peg`). Hash (`#`) is not a comment starter in `.circ`.

## Declarations

### Input Pins

```
input pin1, pin2
input[4] addr
input<W>[W] data
```

Declares one or more named input pins for the circuit. The host drives input pins from outside the circuit; they have no input ports of their own. An optional `[N]` after `input` makes the pin `N` bits wide; the parametric form `input<W>[W]` declares both a width parameter and an input of that width (see [`language.md`](https://circ-lang.org/reference.md) §6.3).

### Component Instances

```
<type> <instance-name> (
    <input-port> = <signal>,
    ...
)
```

`<type>` is the gate kind. Recognised types:

| Type     | Ports    | Width rule                                                                    | Description                                                         |
|----------|----------|-------------------------------------------------------------------------------|---------------------------------------------------------------------|
| `and`    | `a`, `b` | bit-parallel; both inputs must match the instance width                       | AND gate                                                            |
| `not`    | `in`     | bit-parallel; input must match the instance width                             | NOT gate (inverter)                                                 |
| `led`    | `in`     | input must match the instance width; widths `> 1` render as a numeric display | Output indicator                                                    |
| `wire`   | `in`     | input must match the instance width                                           | Pass-through                                                        |
| `output` | `in`     | input must match the instance width                                           | Externally observable output pin (special-cased declaration kind)   |
| `rom`    | `addr`   | declared `[W, A]` (data width, address width); `addr` is `A` wide, `out` is `W` wide | Read-only memory of `2^A` words; contents are loaded at runtime (see [`language.md`](https://circ-lang.org/reference.md) §6.5) |
| `ram`    | `addr`, `din`, `we`, `clk` | declared `[W, A]`; `addr` is `A`, `din`/`out` are `W`, `we`/`clk` are 1  | Read/write memory; writes `din` on the rising edge of `clk` when `we` is high; contents loaded at runtime (see [`language.md`](https://circ-lang.org/reference.md) §6.5) |

`input` is a sibling pin declaration with its own syntax (no port list), described above. All primitives accept an optional `[N]` width annotation; absent it, width is 1. Memories are the exception: they take exactly two width arguments, `[W, A]`, after the instance name.

**Built-in macro gates** expand at compile time to nested `and` / `not` (and optionally other macros). They use **`a`** and **`b`** as input ports and expose **`out`**. Unlike `and`/`not`, they need **no `import`**: the compiler behaves as if `import … from "<builtin>/<name>.circ"` were present. Each macro is parametric: `or[8] g(a=x, b=y)` produces a bit-parallel 8-bit OR.

| Type   | Ports    | Expansion |
|--------|----------|-----------|
| `or`   | `a`, `b` | OR from `not`/`and`            |
| `nand` | `a`, `b` | NAND                           |
| `nor`  | `a`, `b` | NOR (uses internal `or` macro)|
| `xor`  | `a`, `b` | XOR                            |
| `xnor` | `a`, `b` | XNOR (uses internal `xor` macro)|

`<input-port>` is the name of the port being driven (e.g. `a`, `b`, `in`).

`<signal>` is one of:
- `<instance-name>.out` — the output of a named component or primitive with a single implicit output `.out`.
- `<instance-name>.<port>` — the output pin of an imported subcircuit that exposes `<port>` (`sum`, `carry`, and so on).
- `<signal>[i]` — single-bit index into a multi-bit signal (yields width 1).
- `<signal>[lo..hi]` — half-open slice `[lo, hi)` of a multi-bit signal (yields width `hi - lo`).
- `{<signal>, <signal>, ...}` — concatenation, **low operand on the left**, so `{a, b}` puts `a` in the low bits and `b` in the high bits.
- An inline component expression (see nested components below).

See [`language.md`](https://circ-lang.org/reference.md) §4 and §6 for the full signal grammar and width-checking rules.

## Signal References

A signal reference connects a port to the output of a previously declared name:

```
a = pin1.out
```

This wires port `a` to the output of the component named `pin1`.

## Nested Component Expressions

You can define a component inline as the value of a port connection. The nested component has no instance name, but its `.out` output wires directly to the enclosing port:

```
and combine (
    a = pin1.out,
    b = not (
        in = pin2.out
    ).out
)
```

Here an anonymous `not` gate drives port `b` of `combine`.

## Full Example

```
input pin1, pin2

and combine (
    a = pin1.out,
    b = not (
        in = pin2.out
    ).out
)

led result (
    in = combine.out
)
```

This circuit computes `pin1 AND (NOT pin2)` and displays the result on an LED.

The compiled `.wasm` exposes no programmatic graph-construction API; the topology is baked into the artifact as a custom section and materialised by the embedded runtime at `init()`. Hosts see only the fixed export surface (`setPin`, `run`, paired `getOutputValue` / `getOutputDefined`, …) described in [`wasm-api.md`](https://circ-lang.org/reference/wasm-api.md); the component IDs they need come from the `circ.topology.v0.full` section, where each record carries the component's name and kind. `circ-compile --inspect` prints resolver-local ids that match the artifact's only for a single-file circuit without sub-circuits.

## Grammar

The maintainer's langlang fork (`-output-language zig`) generates the parser from a PEG grammar at `lib/grammar/proto-circ.peg`; the generated file is vendored at `lib/parser/parser.zig`, and `lib/syntax/translate.zig` walks it.

Parse tree node types used by `lib/syntax/translate.zig`:

| Node type (`parser.runtime.NodeType`) | Meaning                                  |
|---------------------------------------|------------------------------------------|
| `.sequence`                           | Ordered list of child nodes              |
| `.node`                               | Named grammar rule match                 |
| `.string`                             | Matched literal text (identifier, etc.)  |
| `.err`                                | A recovered parse error at this position |

## Topology Format Version

Compiled `.wasm` artifacts embed the resolved circuit as a custom section. The current format identifier is `CIRC` (v03). v02 added a `width: u8` byte to every serialised component (the runtime materialises the corresponding pool tier on `init()`); v03 adds the memory kinds `rom = 8` and `ram = 9`, whose records carry one trailing `addr_width` byte, and the port bytes `addr`/`din`/`we`/`clk`. The topology excludes memory contents; they are loaded at runtime. See [`wasm-api.md`](https://circ-lang.org/reference/wasm-api.md) for the host-facing ABI and `lib/topology/serializer.zig` for the wire layout.

## Diagnostic Codes

`lib/validator/codes.zig` registers the stable validator surface (E001–E018, W001–W003); the rules behind each code are in [`language.md`](https://circ-lang.org/reference.md) §4.1. The full catalogue follows, with each code's default message:

| Code | Meaning |
| --- | --- |
| E001 | undeclared name |
| E002 | unknown port (also an out-of-range or inverted slice, and an unknown memory port) |
| E003 | multiple drivers for input port |
| E004 | required input is unconnected |
| E005 | duplicate instance name |
| E006 | name shadows built-in (`and`, `not`, `wire`, `led`, `rom`, `ram`, `input_pin`, `output_pin`, …) |
| E007 | output has no assigned driver |
| E008 | combinational loop detected |
| E009 | import not found |
| E010 | import cycle detected |
| E011 | import alias collision (with another import or a built-in name) |
| E012 | unknown sub-circuit port |
| E013 | sub-circuit arity mismatch (a required sub-circuit input left unconnected) |
| E014 | width mismatch between a driver and the port it feeds (added with v02) |
| E015 | sub-circuit is not parametric (caller passed `[N]` call-widths to a scalar callee; v02) |
| E016 | parameter count mismatch (wrong number of `[w0, w1, ...]` call-widths at the call site; v02) |
| E017 | memory parameter list malformed (a `rom`/`ram` declaration without exactly two instance-position width arguments `[W, A]`; v03) |
| E018 | memory width out of range (`W` outside `1..64` or `A` outside `1..16`; v03) |
| W001 | unused input declaration |
| W002 | dangling output declaration |
| W003 | unused import declaration |
