Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>HDL StudioNew to Visual Studio Code? Get it now.
HDL Studio

HDL Studio

TwinT

|
1,383 installs
| (1) | Free
Synthesize Verilog/SystemVerilog with Yosys and simulate the circuit on an interactive schematic, with waveforms and Lua scripting.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

HDL Studio

vscode marketplace

Write Verilog/SystemVerilog, see the circuit, and watch it run — inside VS Code.

HDL Studio synthesizes your sources with Yosys, draws the result as an interactive schematic and simulates that same circuit gate by gate: 4-valued logic (0, 1, x, z), tri-state buses and per-cell delays. Flip switches, press buttons, read 7-segment displays and LED matrices, follow any wire in a waveform monitor, or drive the whole thing from a Lua script. It was made for teaching digital design, so what you see is what the synthesizer actually built.

The schematic with the waveform monitor

  • Requirements
  • Quick start
  • Features
  • Using HDL Studio
  • I/O widgets
  • Lua scripting
  • Settings
  • Troubleshooting
  • Development
  • Credits

Requirements

  • Yosys on the PATH (or set hdl-studio.yosysPath). With the yosys-slang plugin HDL Studio uses it automatically and gets full SystemVerilog (packages, interfaces, any file order); without it, Yosys's own read_verilog -sv is used. The twint/sd dev container has both; see hdl_studio_test for a ready-made setup.
  • Linux x64. The simulator is a native binary shipped inside the extension, so HDL Studio does not run in the browser (vscode.dev).

Quick start

  1. Open a .sv (or .v) file, e.g. this counter:

    module counter(input logic clk, input logic rst, output logic [3:0] count);
      always_ff @(posedge clk)
        if (rst) count <= '0;
        else     count <= count + 1'b1;
    endmodule
    
  2. Click the HDL Studio icon in the editor title bar (or right-click the file in the Explorer → Create circuit in HDL Studio). A new project is created with the file in it.

  3. Press Synthesize in the Synthesis panel. The schematic appears; clk became a clock, rst a switch and count a number display.

  4. Press Start (▶ in the editor title or the Control panel). Click rst to toggle it and watch count go.

  5. Double-click the count wire to add it to the waveform monitor.

  6. Save (Ctrl+S): the project is a .hdls file next to your sources.

More examples, each with a Lua test script, are in test/verilog/: latches, adders, an LFSR, RAM/ROM, a BCD to 7-segment decoder, an LED matrix, a tri-state bus, and a small RISC-V CPU (micro, soc).

Features

  • Interactive schematic of the synthesized netlist, laid out automatically; drag cells to rearrange it (the layout is saved). Subcircuits, memories (with a hex editor) and FSMs (as a state diagram) open in their own windows.
  • Gate-level simulation with 4-valued logic, tri-state buses and per-cell delays: run continuously at an adjustable speed (or flat out), one tick, one clock cycle, or a given time (2 us), and reset to tick 0.
  • Waveform monitor for any wire, with number formats, pause when conditions (rises, falls, changes, becomes x, equals a value), coloured collapsible groups and layouts saved with the project or to a file.
  • Time cursor: click a waveform and the whole circuit shows the values it had then.
  • Themes for the circuit view: Classic, VS Code, Solarized, Dracula, Nord and more.
  • I/O widgets inferred from the top module's ports: clocks, switches, push buttons, number fields, lamps, number displays, 7-segment displays and LED matrices.
  • Source highlighting: hover a cell or a wire to see the lines of code it came from.
  • Lua 5.4 scripting and a Lua terminal to drive and check the simulation.
  • Undo/redo of everything, from re-synthesis to moving a cell.
  • Image export to SVG, PNG or JPEG, signal levels included.
  • Several circuits open and simulating at once; mouse, trackpad and touch navigation.

Using HDL Studio

Projects and files

A project (.hdls, JSON) holds the source files' relative paths, the synthesis options, the synthesized circuit and its layout. To move it to another machine, copy the sources along with it, keeping the same relative paths.

  • New project: HDL Studio: New Circuit, or the HDL Studio icon in the editor title when the current file isn't part of a project.

  • From existing sources (.v, .sv, .vh, .lua): the HDL Studio icon on an open file, or Create circuit in HDL Studio in the Explorer's context menu (the Recursive variant takes a whole folder). The project takes the file's name.

    Creating a circuit from a source file

  • Adding files: the same icon and context menu (Add to HDL Studio), or Add Files in the Files panel.

    The Files panel

  • Other formats: projects from before 1.0 (.digitaljs) open as they are (Save As gives them the new extension). A .json file — a circuit from DigitalJS Online or a raw Yosys JSON netlist — opens with Open as circuit in HDL Studio or Open With. Without sources you can simulate but not re-synthesize.

The HDL Studio side bar has three panels: Files (the project's sources and Lua scripts), Synthesis (options and the Synthesize button) and Control (run controls and the top module's inputs and outputs).

Synthesis

Press Synthesize in the Synthesis panel. Its options are saved with the project:

Option What it does
Top module The top of the design (Auto lets Yosys pick it).
Optimize in Yosys opt -full. The circuit may differ a lot from the source.
Decompose to basic gates techmap: adders, comparators, muxes… become basic gates (flip-flops and memories are kept).
FSM FSM transform (fsm) or FSM as circuit element (fsm -nomap, an FSM cell with a state diagram).
Merge more logic into FSM fsm_expand.
Simplify diagram Post-process the netlist into fewer cells, easier to read. On by default.
Zero combinational propagation delay A combinational path settles in one tick instead of one tick per gate.

Yosys's script and output go to the HDL Studio (Yosys) output channel.

With the source open beside the schematic, hovering a cell or wire highlights the code that produced it:

Source highlighting

The schematic

  • Navigate: drag the background or scroll to pan; Ctrl + wheel or pinch to zoom; double-click the background to zoom in.

  • Rearrange: drag cells; their wires reroute around other cells. Moving is an edit (undoable, saved) and doesn't restart the simulation.

  • Open: subcircuits, memories and FSMs show a magnifying glass on hover — click it or double-click the cell.

  • Read values: hover a wire. Wires are coloured by value:

    Colour Value
    green all ones
    grey all zeros
    blue a defined mix of 0s and 1s
    orange high impedance (z)
    red undefined (x): drivers in conflict, or no value yet (before a reset)

    (each theme has its own shades of these).

  • Theme: right-click the background and pick one — Dracula (the default), Classic (white paper), VS Code (its colours), Solarized Light, Solarized Dark, Nord, Night Owl, Gruvbox Dark. The waveforms take its colours too.

Simulation

Start and pause with ▶/⏸ in the editor title or the Control panel, which also has:

  • Step — one tick.
  • One clock cycle — one period of the first clock; it stops at the same phase, with everything settled.
  • Run for — a given time (100 ns, 2 us…), then pause.
  • Reset — back to tick 0, registers and memories at their initial values. The layout, open windows and watched signals stay.
  • Speed — how fast Start runs, in ticks per second, up to max (as fast as possible). The panel shows the speed actually reached; a big circuit may not keep up.
  • Timescale — how long a tick is (1 tick = 1 ns by default), per project. Times and clock periods in the panel are shown and entered in these units.

Change inputs on the schematic (click a switch, hold a push button, type into or scroll over a number field) or in the Control panel, which also shows the outputs.

Waveforms

Hover a wire and click its waveform button, or double-click the wire, to add it to the monitor under the schematic.

  • Values are shown under the pointer (otherwise at the cursor, or the right edge), with a ruler in the project's time units.
  • Time cursor: click (or drag) on the waveforms to put the cursor at a time. The simulation pauses and the whole circuit — schematic, Control panel, memories, FSMs — shows the values it had then; drag the cursor to move through the run. The follow button goes back to the present (running again if it was), and so does anything that changes the run (Start, a step, an input).
  • Space runs and pauses the simulation; with the cursor in the past, it goes back to the present and runs.
  • Scroll with the wheel (Shift + wheel, or sideways) or by dragging with the middle button (or Alt + drag); Ctrl + wheel zooms.
  • Right-click a signal (or its … button) to change its number format, remove it, or pause the simulation when it rises, falls, changes, becomes x or equals a value. Press Start: the simulation runs until that happens, the cursor marks the moment and the monitor says why it paused; Space goes on.
  • Arrange: click a signal's name to select it (Ctrl+click adds, Shift+click a range, Esc clears) and drag it, or the selection, to reorder. New group (Group the N signals) in the menu puts them in a group, named in place; drag others onto the group's header. Groups have a colour (their signals are drawn in it) and collapse with their arrow. The menu's format and Remove apply to the whole selection. Drag the edges of the Signal and Value headers to resize the columns.
  • The monitor's arrangement is saved with the project; the 💾/📂 buttons save it to or open it from a .waves.json file (also Open a waveform layout… in the schematic's menu), to share or keep several. Signals are found by name, so a layout survives a new synthesis.

Saving, undo and export

The circuit view is a regular VS Code editor: save, Save As, revert, undo and redo all work, and undo covers re-synthesis and layout changes. Simulation state isn't saved. Save As reopens the project under its new name, which restarts the simulation.

Export Circuit As Image saves the open view (with its signal levels) as SVG, PNG or JPEG. Subcircuit windows are exported one at a time, while open.

I/O widgets

The top module's ports become widgets on the schematic and in the Control panel, chosen by name and width:

Port Widget
1-bit input named clk or clock Clock (period editable in the Control panel)
1-bit input named pushbutton*, or marked (* momentary *) Push button (high only while held)
any other 1-bit input Switch (click toggles)
multi-bit input Number field
1-bit output Lamp
8-bit output named display7 or display7_* 7-segment display
output with (* led_matrix_rows = R, led_matrix_cols = C *), width R*C LED matrix
any other multi-bit output Number display
module panel(
  input  logic clk,                       // Clock
  (* momentary *) input logic fire,       // Push button
  input  logic [7:0] speed,               // Number field
  output logic [7:0] display7_units,      // 7-segment display
  (* led_matrix_rows = 4, led_matrix_cols = 8 *)
  output logic [31:0] leds                // 4×8 LED matrix
);

In an LED matrix, bit r*C + c is row r, column c (bit 0 is top-left). See 10_led_matrix and 09_bcd_to_7seg.

Lua scripting

Add a .lua file to the project and press its ▶ in the Files panel (it becomes ■ to stop it). Running a script starts the simulation; the simulation pauses when it ends. Only one script runs at a time.

-- Reset the counter, then print it on 20 rising clock edges.
sim.setinput("rst", true)
sim.wait(sim.posedge("clk"))
sim.setinput("rst", false)

for i = 1, 20 do
  sim.wait(sim.posedge("clk"))
  print(string.format("cycle %2d: count = %s\n", i, sim.getoutput("count"):tohex()))
end

The Lua terminal (Show Lua Terminal in the Files panel) runs Lua interactively, with line editing and history, and prints the value of an expression. While it's open, scripts print to it instead of to notifications. Ctrl+C aborts the command being typed in, not other scripts.

The Lua terminal

sim: the circuit

Names are as in the sources. A wire inside a subcircuit is named by the instance path first: sim.getvalue("core_i", "pc").

Function Does
sim.setinput(name, value) Set a top-level input.
sim.getoutput(name) Read a top-level output (a vec).
sim.getvalue(..., wire) Read any named wire.
sim.tick() The current tick.
sim.sleep(n) Wait n ticks.
sim.wait(event[, n]) Wait for an event, at most n ticks.
sim.posedge(..., wire), sim.negedge(..., wire) Event: the wire rises / falls.
sim.value(v, ..., wire) Event: the wire takes value v.
e1 \| e2 Event: whichever happens first.

Values given to sim can be vecs, booleans, integers or strings like "8hff". print shows its arguments; in the Lua terminal it doesn't end the line, so add "\n" yourself.

vec: 4-valued vectors

Make vec(5), vec(-3, 8), vec(true), vec("8ha5"), vec("4b1x0z"), vec.frombin("1x0z"), vec.fromhex("f0", 12), vec.fromoct(s[, bits]), vec.frombool(b[, bits]), vec.frominteger(n[, bits])
Read v:tobin(), v:tohex(), v:tooct(), v:tointeger(), v:tointegersigned() (up to 63 bits), #v (width), v(i) (bit i, negative counts from the top), v(i, n) (n bits from i)
Operators &, \|, ~ (xor), ~v (not), ==, a .. b (concatenation, a on top as in {a, b})
Bitwise band bor bxor bnand bnor bxnor bnot
Reductions rand ror rxor rnand rnor rxnor
Tests ishigh islow isdefined isfullydefined, xmask

Settings

Setting Default
hdl-studio.yosysPath "" (use PATH) Path to the yosys executable.
hdl-studio.theme dracula Colours of the circuit view: dracula, classic, vscode, solarized-light, solarized-dark, nord, night-owl, gruvbox-dark.
hdl-studio.waveform.colors {} (the theme's) Waveform colours as CSS colours, over the theme's: background, altBackground, foreground, grid, signal, undefined, highImpedance, cursor, fillOpacity. Any key can be left out.

The simulation speed is global and remembered between sessions.

Troubleshooting

  • Nothing happens on Synthesize / "yosys not found". Check that yosys runs in a terminal, or set hdl-studio.yosysPath. Yosys's errors are in the HDL Studio (Yosys) output channel.
  • SystemVerilog constructs are rejected (packages, interfaces, import). Install the yosys-slang plugin; plain read_verilog -sv supports only part of SystemVerilog.
  • $readmemh can't find its file. Add the data file to the project; a bare file name ("memory.hex") is found even if the file is in a subfolder.
  • A huge or slow netlist. Size indices with $clog2(N) instead of using int: Yosys keeps an index's full width, which turns mem[i] into 32-bit logic.
  • A circuit doesn't do anything for a while. Some take thousands of cycles to show something (the soc board needs ~1500 after reset); set the speed to max.

Development

npm install
npm run compile   # engine (cargo build --release) + webview and host bundles
npm test          # Rust, pipeline (needs yosys), golden traces, schematic (Playwright), VS Code
npm run lint

Press F5 in VS Code to launch an Extension Development Host; after rebuilding, run Developer: Reload Window there. The simulator, converter and Lua engine are the Rust workspace in crates/ (hdlstudio, a native process per circuit view); the schematic is TypeScript in view/; the extension host is src/. Packaging (vsce package) produces a per-platform .vsix.

Contributions are welcome — open an issue or a pull request.

Credits

HDL Studio is a fork of digitaljs_code by Yichao Yu, maintained with a focus on classroom use. It was built on DigitalJS, yosys2digitaljs and digitaljs_lua by Marek Materzok at the University of Wrocław. Version 1.0 replaces them with its own simulator, converter and Lua engine, which keep their semantics and file format: projects from earlier versions and circuits from DigitalJS Online open as they are. Third-party notices are in NOTICE.

License

BSD 2-Clause. See LICENSE.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft