Simten

Component Model

Primitives, composites, and the full primitive reference

Try a Primitive

Search for any primitive, see its ports and parameters, and interact with a live demo:

67 primitives
Select a primitive above to see its ports and a live demo

The Core Invariant

Circuits are either structural (nodes + connections) or behavioral (eval/onTick functions). Structural circuits have zero runtime overhead: they're elaborated away before simulation.

When you write a composite like HalfAdder using nodes and connect, you're defining structure. The simulator expands it to primitives before running. This is called elaboration. All runtime behavior ultimately comes from circuits with eval or onTick functions.

You can also write your own behavioral circuits using eval (combinational) or state + onTick (sequential). See the API Reference for details.

Component Resolution

When the system encounters a node:

  1. Check for eval / onTick on the circuit; if found, treat as a behavioral leaf
  2. Check for nodes / connect; if found, elaborate (expand recursively)
  3. Error: circuit has neither

Primitive Reference

Logic Gates

PrimitiveInputsOutputsDescription
Anda: Bit, b: Bitout: BitAND: true when both inputs are true
Ora: Bit, b: Bitout: BitOR: true when at least one input is true
Notin: Bitout: BitNOT: inverts the input
Nanda: Bit, b: Bitout: BitNAND: false only when both inputs are true
Nora: Bit, b: Bitout: BitNOR: true only when both inputs are false
Xora: Bit, b: Bitout: BitXOR: true when inputs differ
Xnora: Bit, b: Bitout: BitXNOR: true when inputs match
Bufferin: Bitout: BitPasses input through unchanged

I/O

PrimitiveInputsOutputsParametersDescription
Switchout: Bitvalue (default: 0)Clickable 1-bit toggle
Buttonout: BitMomentary push button
Inputout: Bus[N]value (default: 0), width (default: 8)Editable numeric input
Ledin: BitVisual LED indicator
Outputin: Bus[8]Multi-bit output sink
Constantout: Bitvalue (default: 0)Fixed value source
Probein: Bitout: BitDebug passthrough

Arithmetic

All arithmetic primitives support a width parameter (default: 8, options: 4, 8, 16, 32).

PrimitiveInputsOutputsDescription
Addera, b, carry_insum, carry_outN-bit adder with carry
Subtractora, b, borrow_indifference, borrow_outN-bit subtractor with borrow
Multipliera, bproduct: Bus[2N]N×N → 2N-bit multiplier
Comparatora, beq, lt, gtN-bit comparator
IncrementerinoutAdds 1 (wraps at max)
LeftShiftervalue, shiftresultLogical left shift
RightShiftervalue, shiftresultLogical right shift
SignedAddera, b, carry_insum, overflow, carry_outSigned add with overflow
SignedComparatora, beq, lt, gt, lte, gteSigned compare
SignedMultipliera, bproduct: Bus[2N]Signed N×N multiplier

Bus Operations

All support width parameter (default: 8).

PrimitiveInputsOutputsDescription
BusAnda, boutBitwise AND
BusOra, boutBitwise OR
BusNotinoutBitwise NOT
BusXora, boutBitwise XOR

Routing

PrimitiveInputsOutputsParametersDescription
Muxin0, in1, sel: Bitoutwidth (default: 1)2-to-1 multiplexer
Decoderin: Bus[2]out0out3: Bit2-to-4 decoder
Splitterin: Bus[8]out0, out1: Bus[4]Split bus in half
Splitter8to8in: Bus[8]bit0bit7: BitSplit bus to individual bits
Combiner8to8bit0bit7: Bitout: Bus[8]Combine bits to bus
BitSlicein: Bus[8]out: Bus[N]low (0), high (7)Extract bit range [low..high]
Concathigh, lowoutlowWidth (4)Concatenate buses
AddressCombinerlo: Bus[8], hi: Bus[8]out: Bus[16]Combine to 16-bit address

Sequential

These components have clocked state that updates on the rising edge of clk.

"Sequential" isn't a flag you set: a primitive is sequential exactly when it declares state (these two do), and a composite is sequential when it contains one. That same state declaration is what gives the circuit its single implicit clock, which is why you never wire clk yourself. See How it works.

PrimitiveInputsOutputsParametersDescription
DFlipFlopd: Bitq: Bit, q_bar: Bit1-bit register, captures d on clock edge
Registerdata: Bus[N], we: Bitq: Bus[N]width (8), value (0)N-bit register, writes when we is high

Key difference: DFlipFlop always captures its input on every clock edge. Register only writes when we (write enable) is high, which lets you hold a value across multiple cycles.

Reset behavior (Verilog export): when the exporter's auto-plumbed rst_n is low, both DFlipFlop and Register snap back to their value arg. In simulation, sim.reset() produces the same effect. Memory primitives (RAM, DualPortRAM) preserve their contents during reset; only writes are suppressed.

Memory

PrimitiveInputsOutputsParametersDescription
ROMaddr: Bus[16]data_out: Bus[8]baseAddressRead-only, combinational read
RAMaddr, data_in, we: Bitdata_outaddressWidth (8), dataWidth (8)Single-port, combinational read, clocked write
DualPortRAMaddrA, dataA, weA: Bit, addrBoutA, outBaddressWidth (8), dataWidth (8)Port A reads/writes, port B read-only
DualPortROMaddrA: Bus[32], addrB: Bus[32]dataA: Bus[32], dataB: Bus[32]Two independent read ports, one shared memory. Byte-addressable, returns 32-bit little-endian words. Used for architectures that need simultaneous instruction fetch and data read (e.g. rv32i-board.circuit.ts).

Memory is initialized by calling the component factory with the memory parameter:

nodes: {
  ram: DualPortRAM({ memory: {
    0: 42,    // address 0 = 42
    1: 100,   // address 1 = 100
    64: 33,   // address 64 = 33
  } }),
},

Reads are combinational (address in → data out immediately). Writes happen on the rising clock edge when we is high.

Display

PrimitiveInputsOutputsDescription
SevenSegmentin: Bus[4]Hex digit display (0–F)
HexDisplayin: Bus[N]Multi-digit hex display
ScreendataIn: Bus[8]addrB: Bus[8]8×8 pixel framebuffer display
RasterDisplaydataIn: Bus[8]addrB, scanX, scanY, hblank, vblankHardware-accurate raster with scan counters

The Screen primitive works with DualPortRAM: connect screen.addrB → ram.addrB and ram.outB → screen.dataIn. The screen scans through addresses 0–63 to read pixel data.

I/O Devices

PrimitiveInputsOutputsDescription
Consoledata: Bus[8], we: BitMemory-mapped text output
UART_TXaddr, data_in, we, redata_outMemory-mapped serial transmit
NIC_FIFOaddr, data_in, we, redata_out, tx_data, tx_valid, etc.Network interface with TX/RX FIFOs

On this page