Show HN: SHDL – A minimal hardware description language built from logic gates
26 points
12 hours ago
| 7 comments
| github.com
| HN
Hi, everyone!

I built SHDL (Simple Hardware Description Language) as an experiment in stripping hardware description down to its absolute fundamentals.

In SHDL, there are no arithmetic operators, no implicit bit widths, and no high-level constructs. You build everything explicitly from logic gates and wires, and then compose larger components hierarchically. The goal is not synthesis or performance, but understanding: what digital systems actually look like when abstractions are removed.

SHDL is accompanied by PySHDL, a Python interface that lets you load circuits, poke inputs, step the simulation, and observe outputs. Under the hood, SHDL compiles circuits to C for fast execution, but the language itself remains intentionally small and transparent.

This is not meant to replace Verilog or VHDL. It’s aimed at: - learning digital logic from first principles - experimenting with HDL and language design - teaching or visualizing how complex hardware emerges from simple gates.

I would especially appreciate feedback on: - the language design choices - what feels unnecessarily restrictive vs. educationally valuable - whether this kind of “anti-abstraction” HDL is useful to you.

Repo: https://github.com/rafa-rrayes/SHDL

Python package: PySHDL on PyPI

To make this concrete, here are a few small working examples written in SHDL:

1. Full Adder

component FullAdder(A, B, Cin) -> (Sum, Cout) {

    x1: XOR; a1: AND;
    x2: XOR; a2: AND;
    o1: OR;

    connect {
        A -> x1.A; B -> x1.B;
        A -> a1.A; B -> a1.B;

        x1.O -> x2.A; Cin -> x2.B;
        x1.O -> a2.A; Cin -> a2.B;
        a1.O -> o1.A; a2.O -> o1.B;

        x2.O -> Sum; o1.O -> Cout;
    }
}

2. 16 bit register

# clk must be high for two cycles to store a value

component Register16(In[16], clk) -> (Out[16]) {

    >i[16]{
        a1{i}: AND;
        a2{i}: AND;
        not1{i}: NOT;
        nor1{i}: NOR;
        nor2{i}: NOR;
    }
    
    connect {
        >i[16]{
            # Capture on clk
            In[{i}] -> a1{i}.A;
            In[{i}] -> not1{i}.A;
            not1{i}.O -> a2{i}.A;
            
            clk -> a1{i}.B;
            clk -> a2{i}.B;
            
            a1{i}.O -> nor1{i}.A;
            a2{i}.O -> nor2{i}.A;
            nor1{i}.O -> nor2{i}.B;
            nor2{i}.O -> nor1{i}.B;
            nor2{i}.O -> Out[{i}];
        }
    }
}

3. 16-bit Ripple-Carry Adder

use fullAdder::{FullAdder};

component Adder16(A[16], B[16], Cin) -> (Sum[16], Cout) {

    >i[16]{ fa{i}: FullAdder; }

    connect {
        A[1] -> fa1.A;
        B[1] -> fa1.B;
        Cin -> fa1.Cin;
        fa1.Sum -> Sum[1];

        >i[2,16]{
            A[{i}] -> fa{i}.A;
            B[{i}] -> fa{i}.B;
            fa{i-1}.Cout -> fa{i}.Cin;
            fa{i}.Sum -> Sum[{i}];
        }

        fa16.Cout -> Cout;
    }
}
weebull
22 minutes ago
[-]
My biggest complaint is there's no way to name a signal because a wire isn't a thing. You instance gates and give those names, but wires are anonymous connections between gate pins.

I think this is backwards. Knowing that a signal is the clock, reset, data valid, adder result is far more important than the gate that drove it. The gates barely need names. Sadly, I think starting with that concept leads to a rather different language.

reply
vhantz
53 minutes ago
[-]
Real nice project!

If you removed the explicit declaration of every gate in a preamble and then their wiring as a separate step, you could reduce the boilerplate a lot. This example could look like this:

  component FullAdder(A, B, Cin) -> (Sum, Cout)
  {
    A XOR B -> AxB
    A AND B -> AB

    AxB XOR Cin -> S
    (AxB AND Cin) OR AB -> C

    Sum: S
    Cout: C
  }
reply
Lramseyer
4 hours ago
[-]
Kind of a wild idea, but have you considered using this as a markup language for logic diagrams? I'm thinking something like mermaid - https://mermaid.js.org/ While this might not be super useful for chip design, it is a fully functional HDL, and since it is gate level, it would map nicely to diagrams.
reply
rafa_rrayes
2 hours ago
[-]
That is a very interesting idea! Tbh, I have been thinking about something along those lines. I was messing around with gemini 3.0 back when it came out and made this program called Logic Lab (https://logiclab-227111532364.us-west1.run.app/). I was thinking of exporting/importing the components as SHDL, but as of rn they are just exported in some generic format gemini made.
reply
knowitnone3
1 hour ago
[-]
I thought the opposite. Use mermaid as the HDL language. Draw the diagram, then synthesis.
reply
bigbadfeline
2 hours ago
[-]
Looks cool and can be useful for its stated purpose. You mention simulation, is there a way to specify and simulate time delays?
reply
rafa_rrayes
2 hours ago
[-]
Not as a native functionality, not yet but it is something I have been wanting to do for a while. I want to make a complete simulation platform with useful tools such as that. For now you can make the python code call the step() function on your desired timing
reply
fspeech
3 hours ago
[-]
If you are just interested in a structural description (so-called netlist) the standard is EDIF.
reply
oleumbudget
1 hour ago
[-]
Looks really cool
reply
notherhack
3 hours ago
[-]
[flagged]
reply
dang
2 hours ago
[-]
I'm sure you didn't mean to, but this comes across as a shallow dismissal, which is against the site guidelines (https://news.ycombinator.com/newsguidelines.html): "Please don't post shallow dismissals, especially of other people's work. A good critical comment teaches us something.", as well as the Show HN guidelines (https://news.ycombinator.com/showhn.html).

A comment like this could turn from a bad one to a good one if it were written more in the key of curiosity: what are the similarities or differences? what are some pointers for further development? and so on. If you know more than someone else does, that's great, but then please share some of what you know so we can all learn.

Telling somebody that their project which they've been pouring their passion and creativity into is merely reinventing some well-known thing that's been around for years is going to come across as a putdown even when it isn't intended that way. The effect is to shut down creativity and exploration, which is the opposite of what this place is supposed to be for.

reply