Skip to content

Using HAL

julianspeith edited this page Aug 12, 2026 · 7 revisions

This page walks you through your first session with HAL: getting a netlist into HAL, finding your way around the GUI, and running your first Python commands on the netlist. It assumes you have built HAL and know how to start it.

If you want to skip ahead and just look at something interesting, import one of the example projects — they are ready-made HAL projects that need no setup beyond a few clicks.

HAL projects

HAL never works on a netlist file directly. Instead, it always operates on a project: a directory that holds the netlist together with everything you produce while analyzing it — your views, groupings, module colors, comments, Python scripts, and the log.

This matters because reverse engineering is incremental. The knowledge you build up about a design (this register is the key, these gates form a round function, this module is the controller) lives in the project, not in the original netlist file. Projects can be exported and shared, which is exactly how the example projects are distributed.

There are three ways to get started:

You have Do this
A netlist file (.v, .vhd, ...) Import Netlist — creates a new project
A zipped HAL project (.zip) Import Project — unpacks and opens it
A project directory you created earlier File > Open Project

Import netlist

Choose File > Import Netlist and select your netlist file. HAL currently ships parsers for structural Verilog and VHDL; the file dialog only offers the formats for which a netlist parser is available in your build.

HAL then shows the Netlist Import dialog, which asks for three things:

  1. Project directory. Where the new project should be created. HAL suggests a directory next to your netlist file, named after it.

  2. Gate library. This is the important one. A netlist is nothing but instances of cells (INV_X1, LUT6, FDRE, ...) — without a gate library, HAL has no idea what any of them do. The gate library defines each gate type, its pins, and its Boolean function, and it is what makes analysis possible in the first place. Pick the library matching the technology your netlist was synthesized for; HAL's built-in libraries are offered in the selection. If your netlist uses a library that HAL does not know yet, you will need to provide one — either a liberty file from your vendor or a hand-written HGL file.

  3. Two checkboxes. Move imported netlist into project directory and Copy gate library into project directory. Enabling both makes the project self-contained, which is what you want if you ever plan to move or share it.

Confirm with OK and HAL parses the netlist. Depending on its size this may take a moment; the Log Widget shows the progress and reports any parsing problems.

If parsing fails with errors about unknown gate types, you almost certainly picked the wrong gate library.

Import project

Example projects and projects shared by others come as zipped HAL projects. Choose File > Import Project and fill in:

  • Zipped HAL project file — the .zip archive, e.g. hal/examples/crypto_trojan.zip
  • Decompress in directory — where to unpack it
  • Decompressed HAL project name — the name of the resulting project directory

HAL extracts the archive and opens the project immediately. To share a project of your own the other way round, use File > Export Project.

What is in a project directory

Knowing the layout is useful once you start scripting or want to inspect things outside of HAL:

File / directory Content
.project.json The project manifest — which netlist and gate library belong to this project
<name>.hal The netlist itself, in HAL's own JSON-based serialization format
<name>.log The HAL log of this project
py/ (optional) Python scripts stored inside the project; these show up in the Python Editor
pythoneditor.json Which scripts are open in the Python Editor, and where each one lives
views.json Your saved views
groupings.json, groupingcolor.json Your groupings and their colors
modulecolor.json Colors assigned to modules
comments.json Comments you attached to netlist elements
simulator.json Simulation settings and results
<library>.hgl (optional) The gate library, if it was copied into the project

Files that may live elsewhere

Two things do not have to be stored inside the project directory, and the project simply records where they are instead:

  • The gate library. If you left the Copy gate library into project directory checkbox unticked on import, .project.json points at the library wherever it sits on your machine.
  • Python scripts. A script you open in the Python Editor from somewhere else on disk stays where it is; pythoneditor.json records its absolute path.

That is perfectly fine while you work locally, but it means the project directory on its own is not self-contained — copy it to another machine and the missing pieces will not come along.

Exporting handles this for you. An exported .zip always contains everything: HAL copies the gate library and every externally stored Python script into the archive and rewrites the paths to point at the copies. A project you receive from someone else — including the example projects — therefore always arrives complete.

The top module

Before looking at the GUI, one concept is worth knowing, because it shows up everywhere.

HAL groups gates into modules, which can be nested to form a hierarchy. Every netlist has exactly one module at the root of that hierarchy: the top module. It is created together with the netlist, it always has ID 1, and it contains every gate of the design — either directly or inside one of its submodules. It cannot be deleted, and its pins are the external inputs and outputs of the design.

Right after importing a netlist recovered from hardware, the top module is all there is: every gate sits directly in it and there are no submodules. Hierarchy is a design-time construct that lives in the HDL sources — it is not part of the fabricated chip or the FPGA configuration, so nothing of it comes back when a netlist is extracted by delayering an ASIC or by reverse engineering a bitstream. (A netlist you receive as an HDL file may still carry some hierarchy, depending on how it was synthesized.) Building a meaningful hierarchy underneath the top module — this group of flip-flops is a register, these gates are a round function — is a large part of what reverse engineering with HAL consists of.

First look around the GUI

When a project is open, you are looking at the following (see GUI for the full tour):

  • The Graph View in the center draws the part of the netlist you are currently looking at. Do not start by rendering the whole netlist of a large design — laying out tens of thousands of gates takes a long time and tells you very little. Start from the module hierarchy or from a single gate and expand outwards using the cone view.
  • The Modules Widget shows the module hierarchy described above, starting at the top module.
  • The Selection Details Widget shows everything HAL knows about whatever you currently have selected — pins, connected nets, Boolean functions, properties, data entries.
  • The Views Widget and Groupings Widget let you save the subsets of the netlist you are working on and mark elements you want to find again later.
  • The Python Console and Python Editor at the bottom operate on the very same netlist that the graph view displays. Anything you change there is reflected in the GUI immediately, and vice versa.
  • The Log Widget shows what HAL is doing.

Widgets can be toggled, rearranged, and detached — click and drag the buttons on the window borders.

A typical first pass through an unknown netlist looks like this: get an overview of the size and the gate types used, run dataflow analysis to recover register structures, look at what those registers connect to, isolate an interesting part into its own view, and start reasoning about its Boolean functions.

First steps in Python

The Python Console gives you the full Python API with two variables predefined:

  • netlist — the currently loaded netlist
  • gui — the GUI API, for interacting with the current selection

hal_py is imported for you as well, so you can start typing right away. Below are the questions you are most likely to ask of a netlist first, along with the code that answers them — try them out in the console as you read.

How do I refer to a specific element? Every gate, net, module, and grouping carries a numeric ID, and that is how you address them from Python.

gate   = netlist.get_gate_by_id(13)
net    = netlist.get_net_by_id(37)
module = netlist.get_module_by_id(2)

IDs are unique per element type rather than globally, so a gate with ID 5 and a net with ID 5 can coexist and have nothing to do with each other. They are stored in the .hal file and stay the same across saving and reloading, which makes it safe to hardcode one in a script — and IDs of deleted elements may be reused by newly created ones. Names, in contrast, are neither unique nor guaranteed to be meaningful; in a netlist recovered from hardware they are usually gone entirely, so prefer IDs whenever you need to refer to something unambiguously. The GUI shows the ID of every element in the Selection Details Widget, which is the usual way to get from "this gate looks interesting" to a line of Python that operates on it.

How big is this design? get_gates() and get_nets() return plain lists, so len() tells you how many there are.

gates = netlist.get_gates()
nets = netlist.get_nets()

print("gates:", len(gates))
print("nets:", len(nets))

What is a single gate? Every gate has an ID, a name, and a gate type. The gate type is what tells you what kind of cell it is.

gate = netlist.get_gate_by_id(1)

print("id:  ", gate.get_id())
print("name:", gate.get_name())
print("type:", gate.get_type().get_name())

What does it compute? get_boolean_functions() returns a dictionary that maps each output pin name to the Boolean function driving it.

functions = gate.get_boolean_functions()

for pin_name in functions:
    print(pin_name, "=", functions[pin_name])

Where does the hierarchy start? get_top_module() returns the top module described above.

top_module = netlist.get_top_module()

print(top_module.get_name())             # "top_module" by default
print(len(top_module.get_gates()))       # gates directly inside it
print(len(top_module.get_submodules()))  # 0 in a freshly imported flat netlist

Which gate types are used, and how often? Counting them is a good first look at an unknown design — a netlist dominated by flip-flops looks very different from one dominated by LUTs.

counts = {}

for gate in netlist.get_gates():
    type_name = gate.get_type().get_name()
    if type_name in counts:
        counts[type_name] = counts[type_name] + 1
    else:
        counts[type_name] = 1

for type_name in counts:
    print(type_name, counts[type_name])

What is this gate connected to? To move through the netlist, you go from a gate to the nets attached to it, and from those nets on to the next gates. A net does not just point at a gate, though — it points at a specific pin of that gate, and that pair is called an endpoint.

gate = netlist.get_gate_by_id(1)

for net in gate.get_fan_out_nets():
    print("net", net.get_name(), "leads to:")

    for endpoint in net.get_destinations():
        next_gate = endpoint.get_gate()
        print("   gate", next_gate.get_name(), "at pin", endpoint.get_pin().get_name())

get_fan_out_nets() gives you the nets leaving the gate, and get_destinations() gives you the endpoints those nets arrive at. The counterparts for the other direction are get_fan_in_nets() and get_sources().

What is selected in the GUI right now? The gui variable connects your script to what you see on screen. Select a few gates in the graph view, then run:

selected_gates = gui.getSelectedGates()

for gate in selected_gates:
    print(gate.get_id(), gate.get_name())

And the other way around? A script can just as well drive the selection in the graph view:

gate = netlist.get_gate_by_id(42)
gui.select(gate)

Scripts that you want to keep should go into the Python Editor — it saves them into the py/ folder of the project, so they travel with it.

Saving your work

File > Save HAL Project writes the netlist and all associated data back into the project directory. HAL will remind you about unsaved changes when you close a project or export it, but it is worth saving regularly — especially before running an expensive analysis.

To hand a project to someone else, use File > Export Project, which produces a single .zip archive that they can bring in via Import Project.

Where to go from here

Clone this wiki locally