Gatefold — User Guide

A walkthrough of the interface and a reference for every primitive component and the simulator. Gatefold is a browser-based graphical designer and simulator for logic circuits: you place components, wire them together, group them into reusable parts, and simulate the result.


1. The interface

The screen is split into four areas:

Area Location Purpose

Toolbar

Top

Actions, simulation controls, navigation, save/load, theme

Sidebar

Left

Component tree, selected component’s properties, port editor

Canvas

Center

The schematic — place, select, wire, pan, zoom

Library

Right

Your custom components

The center panel has a tab bar with three views: Designer (the schematic canvas), Simulation timeline (the recorded probe waveforms — see §7), and Testing (the test-bench sheet — see §6b). The Designer and Testing views each have a horizontal primitive strip above the canvas — drag a card from it to place that primitive on the canvas below.

Toolbar

Left to right:

  • Group — turn the current selection into a named composite component (enabled only with a selection). With a single selected custom component it promotes it into the library.

  • New component (+) — create a new, empty custom component from scratch: name it and it is placed on the canvas (not yet in the library). Double-click it to descend and add inputs/outputs and internal components; then select it and press Group to add it to the library (see §3).

  • Simulate / Exit — switch between design and simulate mode.

  • Run / Step / Stop / Reset — simulation controls (see §7). Run also enters simulate mode from design mode and starts running; Space toggles run/pause while simulating.

  • Simulation settings (gear) — open the simulation settings dialog.

  • Breadcrumb — the path of components you’ve navigated into (main / adder / …); the ↑ button (or Escape) goes up one level. A template badge marks a library template.

  • Open / Save JSON — load or save the whole design as a .json file.

  • Export Verilog — generate synthesizable Verilog from the current design and download it as a .v file (see §8).

  • Save as default / Clear default — store the current design in the browser’s localStorage as the automatic launch state, or remove it so the app starts empty again.

  • Clear everything — wipe parts of the design after a confirmation dialog with checkboxes: the component tree (the root sheet) and the “My components” library, where the library can be deleted as a whole (All components) or per category (Uncategorized plus each user-defined category). Everything is checked by default; uncheck what you want to keep (disabled while simulating).

  • Copy link — copy a shareable URL to the clipboard: the design is gzipped and base64-encoded into a ?d= query parameter, and opening that URL restores the design on launch (see §9).

  • Settings — open the global settings dialog (lane distance, simulation history size, and history-limit behaviour; see below).

  • Theme toggle — switch between dark and light.

Sidebar (left)

  • Components — a tree of the current sheet’s instances. Double-click a composite to enter it; single-click to select it on the canvas.

  • Ports — the current scope’s terminals (shown first). Add (+) / remove (−) terminals (when the primitive allows it), rename them, reorder by dragging the ⣿ handle, and toggle the inversion checkbox (the negation bubble).

  • Properties — for the selected component: its name, its type, its primitive properties (e.g. a CLOCK’s Period, a BUS’s Lanes), and an editable terminal list for that component, so you can add/remove/reorder/rename/invert its terminals without entering it. Values commit on Enter or blur.

Library (right)

  • My components — your composite components. Drag to place; double-click to edit its template; × deletes it. Export / Import exchange your component library as JSON, and Apply to scope / Apply to all (shown when a template is selected) propagate that template’s edits (including its port names) to matching placed instances — in the current scope, or across the whole design. Delete opens a dialog that removes whole library categories (see below). The list scrolls if it grows tall. A category dropdown above the list shows one category at a time; the Move to category dropdown below the buttons moves the selected component to an existing category or + New category… (type a name and press Enter). It is always visible but disabled until a component is selected, and while you are editing a template.

Dialogs

  • Group dialog — name the new component and its inferred inputs/outputs (press Enter to create).

  • Simulation settings — default gate delay (ps), the step mode, and the simulation speed.

  • Settings — the global settings dialog:

    • Lane distance (0–7, world units) controls how far apart the individual wires of a bus terminal are drawn, so large buses can take less vertical space. It affects every bus terminal except those on the LED and switch arrays (whose indicator rows keep their fixed spacing).

    • Max simulation history (events) is the maximum number of probe-signal changes recorded for the simulation timeline (see §7), so a long simulation never exhausts memory.

    • History limit chooses what happens when that limit is hit: Stop simulation (pause and keep the full trace) or Sliding ring buffer (drop the oldest events and keep recording). The values persist across reloads.

  • Delete dialog — confirm deleting a library template.

  • Delete categories dialog — opened from the library’s Delete button: it lists every library category (including Uncategorized) with a checkbox, plus a Select all master toggle, so you can delete the whole library or just chosen categories. The list scrolls when it grows past ~15 categories.

  • Toast — transient messages (e.g. “Input already has a driver”).

  • In every dialog, Escape cancels/closes it, and the confirmation dialogs pre-focus their primary button so Enter completes the action immediately.


2. Canvas controls

Action How

Select

Click a component

Multi-select

Marquee (drag empty space), or Shift + click to toggle

Move

Drag a component (moves the whole selection)

Move by its terminal

Shift + drag on a terminal marker moves the owning component (and the whole selection if it’s part of it)

Pan

Shift + drag (or Shift + drag anywhere in simulate mode)

Zoom

Mouse wheel, anchored at the cursor

Enter a component

Double-click it

Exit up one level

Escape (while over the canvas) or the ↑ button

When you enter a component, the canvas automatically zooms and pans to frame its internals; Escape restores the exact view you left. Opening a design (Open JSON) — or launching with a saved default — also auto-frames the top-level sheet to fit the canvas. In simulate mode, pressing Escape at the top level leaves simulate mode; deeper, it ascends one level.

Wiring

  • Draw a wire — press an output pin, drag, and release on an input pin.

  • Re-target / delete a wire — press an input pin that already has a wire, drag, and release on a new input (re-target) or on empty space (delete).

  • Cut wires to delete — hold Alt and drag across the canvas: a red dashed line is drawn, and on release every wire it crosses is removed. A bus is removed only when the line cuts through all of its lanes. (Unlike Ctrl/Cmd+drag, this deletes rather than splitting, and it can remove many wires at once.)

  • An input can have at most one driver; dropping a second wire onto a driven input is rejected with a message.

Proximity auto-connect

Wire several nearby components at once instead of drawing each wire by hand:

  • With one or more components selected (or while dragging them), each unconnected terminal that sits near a matching terminal on another component is shown as a dashed orange preview wire. Inputs look for the nearest nearby output, outputs for the nearest nearby unconnected input — the closest within a short distance (about 20 world units) wins, and only width-compatible pairs are matched. The composite’s own input/output port groups are valid targets too.

  • Press c to wire every previewed match at once (a single undo step). Clear the selection (or press Escape) to dismiss the previews without connecting.

Keyboard shortcuts

Shortcut Action

Ctrl/Cmd + C

Copy selection

Ctrl/Cmd + V

Paste

Ctrl/Cmd + A

Select all components on the canvas (when the pointer is over a canvas)

Delete / Backspace

Delete selection

Ctrl/Cmd + Z

Undo

Ctrl/Cmd + Shift + Z / Ctrl/Cmd + Y

Redo

Escape

Go up one level (or leave simulate mode at the top level)

Space

Toggle run/pause (in simulate mode)

c

Connect the proximity auto-connect (orange) matches

i

Toggle inversion on the hovered terminal

1 / 0

Set (or remove) a pull-up / pull-down on the hovered input terminal (see §3)


3. Building circuits

  1. Place — drag a primitive from the strip above the canvas onto the canvas.

  2. Wire — connect outputs to inputs.

  3. Configure — select a component and set its properties in the sidebar.

  4. Group — select a sub-circuit and press Group to turn it into a named composite. Inputs/outputs are inferred from the wires crossing the selection; floating pins become extra terminals. Components are copied when placed, so editing one instance never affects the template or other instances.

  5. Edit internals — double-click any component (composite or gate) to descend into it.

New component (from scratch)

Instead of grouping existing components, you can start with an empty shell: press + in the toolbar, enter a name, and Create. A new empty component is placed on the canvas (at the center of the current view) — it is not added to the library yet. Double-click it to descend and build it up: add inputs/outputs in the Ports panel (which create the port-group pins) and place internal components and wires as usual. When you are done, go back up, select the component, and press Group to promote it into the library so it can be reused and edited as a template.

Array (duplicating a component)

Avoid repetitive work by replicating a single component many times in parallel. Select one composite (e.g. a full-adder) and press Array in the toolbar:

  • Count — how many copies to place. Each non-chained terminal becomes a count-wide bus (e.g. a full-adder’s A/B/Sum become 4-bit buses for Count = 4).

  • Orientation — lay the copies out horizontally (left to right) or vertically (top to bottom; the default). The surrounding flow — input port, fan-outs, the copies, fan-ins, output port — is always left-to-right; orientation only affects how the copies are arranged among themselves.

  • Inputs — for each input, choose Parallel (bus) (one wire per copy, the default) or Common (shared) (one wire delivered to every copy, routed through a NODE join-point). Use Common for a signal all copies share — e.g. the selection line of a word mux built from bit muxes. Chained inputs are already single-wire, so they show as chained and can’t be toggled.

  • Chains — optional rules that wire one output of each copy to the next copy’s input (copy[i].from → copy[i+1].to). The classic ripple-carry rule is Cout → Cin: the first copy’s Cin and last copy’s Cout become the array’s single-wire terminals. Add several chains for e.g. a shift register.

The array is a normal composite: its box shows a ×N badge, you can descend into it (showing the copies), and its Count appears in the properties panel — changing it regenerates the copies while keeping the external wiring. Editing the source template and applying it (“Apply to all” in the library panel) updates every copy, since the copies share the template’s lineage.

Arrays can be nested: select an array and press Array again — the dialog then shows a New layer checkbox. Leave it unchecked to edit the array in place (its count/chains/orientation are pre-filled); check it to wrap the array in a new layer (the fields reset to fresh defaults for the outer layer). This builds an array-of-arrays, e.g. an 8×4 ripple adder from 8 copies of a 4-bit adder. Note: chaining supports single-wire terminals only.

Terminal inversion

Any terminal can be logically inverted (a negation bubble). Toggle it by pressing i while hovering the terminal, or with the checkbox in the ports editor. Inversion is instance-level: a library template’s terminals stay clean, and inversion lives on the placed instance.

Inversion is external-only: it applies to a component instance’s terminals (as seen from the sheet it is placed on), never to a component’s own terminals from the inside. The current scope’s input/output port groups cannot be inverted and never show a bubble — to invert a composite’s terminal, select the composite instance on the parent sheet and invert it there.

Terminal pull-up / pull-down

An input terminal can be given a weak pull-up or pull-down, which drives it only while the pin is left floating (nothing wired to it). Press 1 while hovering an input pin to set a pull-up, 0 for a pull-down; press the same key again to remove it. A small 1/0 glyph is drawn just left of the pin while a pull is active and the pin is unconnected.

  • A floating pulled input reads as a real 1/0 in simulation (instead of x) — so, for example, an unconnected active-high reset can be tied inactive.

  • In Verilog export a pulled floating input is tied to a constant and is not reported as a floating net.

  • Like inversion, pull is instance-level and external-only: it lives on the placed instance, never on the template or on a component’s own port groups.

  • The DFF’s RST input is pulled down by default, so a DFF whose reset is left unconnected behaves as “no reset” rather than floating.

Copy-on-place and templates

When you place or group a component, Gatefold deep-copies its definition (a copy), so every instance is independent. My components lists your templates; editing a template (via its library card) and pressing Apply to scope updates every matching instance in the current scope, while Apply to all updates every matching instance in the whole design (including copies embedded inside other components). An instance matches when its terminals are the same (by id and order) as the template’s. Port names don’t affect matching and are overwritten with the template’s names, so renaming a template’s ports bulk-updates its instances.


4. Buses

A bus is a terminal carrying multiple wires (its width). Widths are derived, not stored — Gatefold solves them from the wiring. Hover a bus pin to see its ×n arity; an undetermined pin adopts the width of whatever it connects to and renders as a thin dashed wire (or a ? box on a display).

  • FAN-IN bundles n single wires into one n-wide bus.

  • FAN-OUT splits one n-wide bus into n single wires.

  • BUS-SPLIT splits one bus into two parts; BUS-MERGE joins two buses into one (twice the width). By default the split/merge is even, but a First lanes property lets you fix the first part to a specific width and give the rest to the second (e.g. a 64-lane bus with First lanes = 10 splits into a 10-lane and a 54-lane part). Set it to 0 to split evenly.

  • BUS (the primitive) fixes a bus to a specific width (Lanes), and is a passthrough.

  • COMPARE takes two buses of the same (derived) width and outputs 1 when they match, 0 when they differ.

  • Connecting mismatched widths is rejected at wiring time (“Bus width mismatch”), and an even bus splitter requires an even width (“Bus width must be even”).


5. Signals

Logic values are 3-state:

Value Meaning Wire color

1

high

red

0

low

black

x

unknown / floating

yellow

x arises from unconnected inputs; it propagates through gates unless a dominant value determines the output (0 dominates AND, 1 dominates OR).


6. Primitive reference

Each entry lists the component’s terminals, its arity (which terminals can be added/removed), its properties, and what it does.

AND

  • Inputs: 2+ (A, B, … up to H) · Outputs: 1 (Y) · inputs variable

  • Output is 1 only when all inputs are 1; 0 dominates; x propagates otherwise.

OR

  • Inputs: 2+ (A, B, …) · Outputs: 1 (Y) · inputs variable

  • Output is 1 when any input is 1; 1 dominates.

XOR

  • Inputs: 2+ (A, B, …) · Outputs: 1 (Y) · inputs variable

  • Output is 1 on odd parity (an odd number of inputs are 1).

NOT

  • Inputs: 1 (A) · Outputs: 1 (Y, inverted)

  • Negates its input. Drawn as a triangle with a bubble (the bubble is the inverted output).

BUFFER

  • Inputs: 1 (A) · Outputs: 1 (Y)

  • Passes its input through unchanged. Useful for fan-out / signal cleanup.

CLOCK

  • Inputs: none · Outputs: 1 (CLK)

  • A source producing a periodic square wave. Property Period (picoseconds, default 100 000) sets the period. Its frequency (Hz / kHz / MHz) is shown above the component.

DFF

  • Inputs: D, CLK, RST · Outputs: 2 (Q, !Q) · Properties Edge (posedge / negedge, default posedge), Initial value (boolean, default off), Active-high reset (boolean, default on)

  • A D flip-flop. On the configured Edge of CLK, Q takes the value of D (after a clk-to-q delay); between edges Q holds.

  • !Q is always the complement of Q.

  • When RST is asserted (high by default, low with Active-high reset off), Q is forced asynchronously to the Initial value, overriding the clock. On power-on Q starts at the Initial value.

  • RST is pulled down by default, so leaving it unconnected reads as inactive (no reset) rather than floating.

COUNTER

  • Inputs: CLK, RST · Outputs: Q bus, or Q0… single wires · Properties Reset (sync / async, default sync), Terminal type (wire / bus, default wire), Width (0–32, default 0)

  • A binary counter. On each rising edge of CLK the count increments by one, wrapping at its width. Q0 is the least-significant bit.

  • Reset selects when an asserted RST (active-high) clears the count to zero:

    • sync — on the clock edge while RST is held high;

    • async — immediately when RST goes high.

  • Terminal type picks the output shape: wire gives one single-wire output per counting bit (Q0…Q(n-1)), with the count set by Width (0 uses the default count); bus gives one Q bus whose width is adopted from the connected bus when Width is 0, and pinned to Width lanes otherwise. Changing the terminal type keeps CLK/RST wiring but disconnects the output wires.

  • RST is pulled down by default, so an unconnected reset reads inactive.

  • In Verilog export this becomes an always @(posedge clk …) counter (with if (rst) for the chosen reset style) — the FPGA gets real synchronous counting logic rather than a ripple counter built from flip-flops.

REGISTER

  • Inputs: CLK, RST, DATA (bus) or D0… (single wires) · Outputs: Q bus, or Q0… single wires · Properties Reset (sync / async, default sync), Terminal type (wire / bus, default bus), Width (0–32, default 0)

  • An n-bit register (an array of 1-bit memory cells). On each rising edge of CLK the register samples DATA into Q (after a clk-to-q delay); between edges Q holds its value. D0/Q0 is the least-significant bit.

  • Reset selects when an asserted RST (active-high) clears the register to zero:

    • sync — on the clock edge while RST is held high;

    • async — immediately when RST goes high.

  • Terminal type picks the data shape: bus gives one DATA bus input and one Q bus output (always the same width — adopted from the connected bus when Width is 0, and pinned to Width lanes otherwise); wire gives one single-wire D0…/Q0… per bit, with the bit count set by Width (0 uses the default count). Changing the terminal type keeps CLK/RST wiring but disconnects the data and output wires.

  • RST is pulled down by default, so an unconnected reset reads inactive.

  • In Verilog export this becomes always @(posedge clk …) q <= data (with if (rst) for the chosen reset style) — a real synchronous register the FPGA can map to flip-flops.

ROM

  • Inputs: 1 (ADDR) · Outputs: 1 (DATA) · Properties Address width (busWidth, default 8, 1–16), Data width (dataWidth, default 8, 1–64), Access (async / sync, default async), Value format (HEX / DEC / BINARY, default HEX)

  • A read-only memory: put an address on the ADDR bus and the stored word appears on the DATA bus. The Access property picks the read timing: async reads combinationally — there is no clock and no address latching, so DATA follows ADDR like any combinational gate (and resolves before any clock edge); sync adds a CLK input and latches the address + registers the data on a clock edge (one-cycle latency). Any unknown (x) address bit drives all-x data; addresses past the stored contents read 0.

  • The memory holds 2^AddressWidth words of DataWidth bits each (so an 8-bit address is 256 × 8-bit). Click Edit contents… in the properties panel to open the contents editor:

    • Each line is ADDR value value … — an address followed by one or more values, all shown in the selected Value format and zero-padded to a fixed width (hex is padded to whole 4-bit nibbles, binary to the full bit width). The number of values per line (1, 2, 4, or 8) is chosen automatically to fit the editor’s width.

    • Addresses are read-only; you edit only the values. A cursor highlights a single digit of the values, and typing overwrites that digit and advances (arrow keys move it; hex/binary digits map to nibbles/bits, and a decimal digit re-parses the word, clamping to the value range).

    • Load file… fills the memory from a file. By default a file is data-only — every token is a value, placed consecutively from the start of memory. To place values at specific addresses, prefix each line with an address followed by a colon: ADDR: value value …. The first line decides which format the whole file uses.

    • Copy / Paste (and Ctrl/Cmd+C / Ctrl/Cmd+V) move the memory through the clipboard. Copy writes address-prefixed ADDR: value value … text in the current Value format; paste parses it exactly like a loaded file (same current-format, data-only-or-ADDR: rules).

    • Value format only sets the editor’s entry/display radix — the stored contents are kept radix-independent, so switching radices never corrupts the memory.

  • In Verilog export the ROM follows its Access: async emits a combinational case lookup (distributed LUTs, DATA available before any clock edge), while sync emits an inferred memory (reg mem[] + an initial block + always @(posedge CLK) DATA <= mem[ADDR]), which the FPGA toolchain can implement as block RAM.

FAN-IN

  • Inputs: 2+ (single-wire), default 4 · Outputs: 1 (BUS) · inputs variable

  • Bundles its n single-wire inputs into one n-wide bus output.

FAN-OUT

  • Inputs: 1 (BUS) · Outputs: 2+ (single-wire), default 4 · outputs variable

  • Splits one n-wide bus input into n single-wire outputs.

BUS-SPLIT

  • Inputs: 1 (BUS, width n) · Outputs: 2 (Y1, Y2)

  • Splits a bus into two parts. By default it splits evenly (Y1/Y2 each n/2, requiring an even width); the First lanes property (default 0, 0–64) fixes Y1 to that many lanes and gives Y2 the remainder (n − First lanes). 0 means “split evenly”.

BUS-MERGE

  • Inputs: 2 (A, B) · Outputs: 1 (BUS)

  • Concatenates two buses into one. By default the two inputs are equal (each m, the output 2m); the First lanes property (default 0, 0–64) fixes A to that many lanes and gives B the remainder (output − First lanes). 0 means “merge evenly”.

BUS

  • Inputs: 1 (A) · Outputs: 1 (Y)

  • A passthrough that fixes the bus width. Property Lanes (default 8, 1–64) sets the width of both terminals; use it to pin a bus to a specific width regardless of its source. Property Flip (default off) reverses the lane order, so the input’s LSB becomes the output’s MSB (the width is unchanged); a flipped bus shows a small diagonal X in place of its middle lane.

COMPARE

  • Inputs: 2 (A, B, equal derived width) · Outputs: 1 (EQ)

  • Compares its two bus inputs bit-for-bit: EQ is 1 when they match, 0 when they differ, and x when either input has an unknown bit. Both inputs adopt the same width (neither is fixed), so the comparator follows whatever width its buses carry.

NODE

  • Inputs: 1 (A) · Outputs: 1 (Y)

  • A single-wire join point: a filled dot whose input and output terminals coincide, drawn with no labels. It passes its input through unchanged, and multiple wires exit by fan-out from its single output. Drag a wire onto the dot to feed it; press the dot to start another outgoing wire; Alt+press grabs the incoming wire. To move it, drag the ring just around the dot (or region-select it first). The dot is wire-colored, signal-colored in simulation, and red while hovered.

  • Two shortcuts insert a NODE into an existing wire, splitting it in two:

    • Drop a NODE from the primitive strip straight onto a wire.

    • Ctrl/Cmd+drag across a wire — an imaginary dashed line is drawn, and on release a NODE is inserted where the line crosses the wire.

7-SEG

  • Inputs: 1 (BUS) · Outputs: none · Properties Mode (HEX / DEC / SIGNED DEC) and Order (asc / desc)

  • A multi-digit display. Its bus width must be a multiple of 4 and ≤ 64. The Mode controls how the bus bits are decoded:

    • HEX — one digit per 4-bit nibble (0–F), most-significant digit leftmost.

    • DEC — the bus as an unsigned decimal number, with enough digit slots for the full value (unused leading slots stay blank).

    • SIGNED DEC — the bus as a two’s-complement signed number, with a leading − sign slot that lights when negative. Order selects which end of the bus is the least-significant bit.

SWITCHES

  • Inputs: none · Outputs: 1+ · Properties Terminal type (wire / bus, default bus), Initial value (text, default 0), Value format (HEX / DEC / SIGNED DEC / BINARY, default HEX), Order (asc / desc, default asc), and Compact (boolean, default on)

  • A multi-lane interactive source. In wire mode each output terminal is one switch; in bus mode a single bus output carries one lane per wire. Every lane starts at the Initial value when simulation starts (and shows that state, colored, in design mode). In simulate mode, click an indicator circle to toggle its lane, or use the −/+ step buttons to increment or decrement the whole value.

  • Initial value is a number entered in the current Value format (signed or unsigned decimal, or hex); Order decides how the typed value maps onto the lanes. In Verilog export a non-exported switch becomes a constant fixed at this value.

  • Compact renders the switch as a single small box showing its current value (in the instance’s Value format) instead of one circle per lane — useful for wide buses. Its lanes are set via the # badge / set-value dialog or the −/+ buttons rather than individual clicks.

LEDS

  • Inputs: 1+ · Outputs: none · Properties Terminal type (wire / bus, default bus), Value format (HEX / DEC / SIGNED DEC / BINARY, default HEX), Order (asc / desc, default asc), and Compact (boolean, default off)

  • A multi-lane lamp. In wire mode each input terminal is one LED; in bus mode a single bus input lights one LED per lane. Each lane lights when its signal is 1.

  • Compact renders the LED as a single small box showing the current value of its input (in the instance’s Value format) instead of one circle per lane — useful for wide buses. The value updates during simulation; in design mode (no signal yet) it shows a ? placeholder. Order picks which end of the bus is the least-significant bit for the display.

PROBE

  • Inputs: 1 (IN) · Outputs: none · Properties: Pause on trigger, Trigger on

  • A monitoring tap: it records the signal on whatever it is wired to (a single wire or a whole bus, adopting the connected width) so you can inspect it in the Simulation timeline (§7). It has no effect on the circuit. Probes are not grouped — if you select a probe alongside other components and click Group, the probe stays on the sheet and keeps tapping the new component’s output. A probe is ignored by the Verilog export.

  • Pause on trigger arms a run pause: when enabled, the simulation stops the moment the probe’s input meets the Trigger on condition. The condition is an edge — RISING_EDGE (0→1), FALLING_EDGE (1→0), or EDGE (either). On a bus input the trigger fires if any lane meets the condition. Only strict 0↔1 transitions count (x never triggers).

Internal primitives (INPUT-PORT / OUTPUT-PORT) are not in the primitive strip: they model a composite’s own input/output terminals internally and are created automatically when you group components or edit a composite’s ports.


6b. The Testing tab (test bench)

The Testing tab is a sheet one level above your top-level design, where you connect the outside world — clocks, buttons (switches), displays — to the design’s interface without adding them to the design itself.

  • The design appears as a single fixed main box (named after the top-level sheet) with its input ports on the left and output ports on the right. It is movable (drag it) but not deletable.

  • A horizontal primitive strip above the canvas offers every primitive (the same set as the Designer tab), so you can model arbitrary external circuitry — not just CLOCK, SWITCHES, LEDS, 7-SEG, and PROBE, but also gates, buses, and stateful parts. Drag one onto the sheet, then wire it to a main port exactly like on the designer canvas (drag from an output pin to an input pin; grab an existing wire to re-target or delete it). The component you just placed becomes the selection.

  • Editing works like the designer: drag components, marquee/Shift-click to select, Delete to remove a component, and pan (Shift+drag) / zoom (mouse wheel).

  • In simulate mode the test-bench components drive and read main: toggle a SWITCHES lane by clicking it (or use its # badge to type a whole value, or the −/+ buttons to step the value), and watch LEDS/7-SEG/probe outputs update. The designer still shows the same simulation, one level down inside main.

  • The test bench is saved with your project JSON, but it is ignored by the Verilog export — it never affects the generated .v, the component library, or the design’s own interface.


7. Simulation

Press Simulate — or just Run — to enter simulation mode (it resets to the top-level sheet and builds a simulation of your design). The canvas background turns dark green while simulating. In this mode editing is disabled — you can’t place components from the library or enter a library template — but you can still pan, zoom, and navigate into the components on the canvas.

Controls

  • Run — enter simulate mode (if not already) and advance the simulation continuously.

  • Step — advance one step (see Step mode).

  • Stop — pause a running simulation.

  • Reset — rebuild the simulation from scratch.

  • Space — toggle between running and paused while simulating.

  • Settings — set the default gate delay (ps), the step mode, and the simulation speed.

Timing lamp

When the design has exactly one CLOCK, a small lamp appears in the toolbar next to the simulation controls and reports how fast the logic settles relative to that clock’s period:

  • green — the combinational logic settles within half a clock period.

  • yellow — it takes more than half a period (it doesn’t settle before the next clock edge).

  • red — it takes more than a full period (the clock is too fast for the logic).

A yellow or red lamp latches on and stays until the next Run/Reset. Hover the lamp for a tooltip.

Simulation speed

The Simulation speed setting is a multiplier of simulated time per real time: 1 means real-time, larger values run faster, smaller values run slower. While running, each tick advances a fixed slice of simulated time, so increasing a CLOCK’s period makes it cycle slower on screen (a period longer than the slice simply fires its edge on a later tick). At speed s, a clock with period P ps cycles at s × 10^12 / P Hz. The default speed (0.001) with the built-in 100 000 ps clock is therefore ~10 kHz — too fast to see — so use a much larger period (e.g. 1 000 000 000 ps for ~1 Hz) to watch slow motion. Set the speed to 1 for real-time behavior (again, with a much larger clock period).

While simulating, the current speed is shown as a small badge in the top-left corner of the canvas (e.g. 10x faster, 200x slower, or real-time at 1).

How it works

The engine is event-driven with inertial gate delays: a gate’s output changes a configured number of picoseconds after its inputs change. On start (or reset), driven nets begin at 0 (floating stay x), then a zero-delay settle pass resolves feedback loops (latches, flip-flops) to a stable state; a true oscillator is detected and shown as x. A floating input with a pull-up/pull-down (§3) starts at its pulled level (1/0) instead of x.

Signals and probes

  • Wires and terminal markers are colored by their value: red = 1, black = 0, yellow = x.

  • CLOCK toggles its output on a square wave with its Period.

  • SWITCHES lanes toggle by clicking their indicator circles (a double-click just toggles twice — it does not enter the component).

  • LEDS lanes light when their signal is 1.

  • 7-SEG displays the value of each 4-bit nibble of its bus.

  • PROBE records the signal on its input for the timeline (below).

Simulation timeline

The Simulation timeline tab shows the recorded state history of every PROBE in the design (at every level of the hierarchy). Each probe is a group of one or more lanes (a bus is one group, one row per wire); its drag handle and name are on the left, and a colored line shows the signal over time (red = 1, black = 0, yellow = x).

  • The horizontal axis is time-proportional: the distance between two events is proportional to the time between them.

  • Mouse wheel zooms the time axis (anchored at the cursor); press-and-drag on the waveform area pans horizontally; rows that don’t fit scroll vertically.

  • Drag a probe’s handle/name up or down to reorder it — a bus moves as one unit. The order is remembered while the app is open.

  • The timeline keeps the last simulation, so you can inspect it after leaving simulate mode.

  • If the history limit is hit in Stop mode, the simulation pauses and the timeline shows a "`History limit reached`" notice (change the limit or switch to Sliding in Settings).

Setting a switch value

Each SWITCHES component shows a small # badge in its top-left corner while simulating. Click it to type a value into that switch instead of clicking lanes one by one: a dialog titled "`enter N-bit value in …`" opens with a radix dropdown (HEX / DEC / SIGNED DEC, initialized from the instance’s Value format) and an input pre-filled with the current value (selected, so typing replaces it).

  • Enter parses the value (in the chosen radix) and sets the switches, closing the dialog; an out-of-range or malformed value shows an error and stays open.

  • Escape (or Cancel) closes without changing anything.

  • The radix chosen in the dialog only affects that dialog — it does not change the instance’s Value format. The instance’s Order is applied when the typed value is mapped onto the lanes.

Every SWITCHES component also shows two small step buttons (− and +) in its top-right corner while simulating. They increment or decrement the switch’s whole binary value by one, wrapping around at 0 and the maximum (2^n − 1) — a quick way to cycle a bus through its states without typing.

Step mode

  • Quiescent — each Step advances until the circuit settles (no pending events).

  • Clock-edge — each Step advances to the next clock edge.

Navigating in simulate mode

Double-click a component to descend into it and inspect its internals live; Escape ascends back up. At the top level, Escape leaves simulate mode and returns to design mode.


8. Exporting Verilog

Press Export Verilog in the toolbar to generate synthesizable Verilog from the current design (the same JSON you get from Save JSON) and download it as design.v, so the circuit can be taken into an FPGA toolchain or an HDL simulator.

What the generator produces:

  • One module per composite, with the top-level sheet (main) as the top module.

  • Gates (AND/OR/XOR/NOT/BUFFER) as assign expressions, so terminal inversion becomes a ~.

  • DFF as always @(posedge clk …), with the async reset (when connected) and INIT from the Initial value property, plus a power-on initial block.

  • Buses as [n-1:0] vectors — FAN-IN/BUS-MERGE concatenate, FAN-OUT/BUS-SPLIT slice.

  • ROM following its Access: async as a combinational case lookup (distributed LUTs), or sync as an inferred memory (reg mem[] + an initial block + a registered read), so the synthesis toolchain can pick block RAM.

  • Hierarchy as nested module instantiations; composite ports become module ports.

The top module’s inputs and outputs are only the port terminals of the main scope, plus a top-level CLOCK (an input pin, for the FPGA clock). A SWITCHES at the main scope becomes an input pin only when its Exported property is checked; otherwise — and always when placed inside a composite — it is emitted as a constant fixed at its Initial value. A SWITCHES that isn’t wired to anything is ignored, and LEDS and 7-SEG are always ignored.

The export reports issues by severity:

  • Errors (shown as a toast and logged to the console): floating nets (an input/output with no driver) and a nested CLOCK (a clock inside a composite can’t be exported). A floating input with a pull-up/pull-down is not an error — its net is tied to a constant (assign net = 1’b1; / 1’b0).

The same generator is available as a CLI: pnpm --filter @gatefold/verilog cli <design.json> [out.v].


The Copy link toolbar button copies a URL that encodes the whole design: it is serialized to JSON, gzipped, then base64-encoded (URL-safe) into a ?d= query parameter. Pasting that URL into a browser opens Gatefold with that design loaded — it takes precedence over any saved default state. If the parameter is missing or corrupt, the app falls back to the normal launch path (localStorage default, then an empty design).

Saved designs (JSON files, the launch default, and share links alike) are stored compactly: built-in primitives are inline references (never stored as definitions), and component coordinates are rounded to two decimals.