Hardware Description Languages: Programming’s Strangest Corner
VHDL and Verilog look like ordinary programming languages, right up until you realize every line of a module runs at the same time, forever, and the order you wrote them in was never a promise about anything.
A software engineer opening a VHDL or Verilog file for the first time reads it the only way they know how: top to bottom, one statement handing off to the next. That habit is not just unhelpful here, it is actively wrong. An HDL description is not a sequence of steps for a processor to execute. It is a blueprint for physical circuitry that all exists and all operates simultaneously the instant power is applied, and every strange rule these languages have follows directly from that one inversion.
Two Languages Built to Describe Silicon, Not Steps
VHDL was developed starting in 1983 under the U.S. Department of Defense’s VHSIC program, originally meant simply to document the behavior of custom chips being delivered by contractors, and became the IEEE 1076 standard in 1987. Verilog has a scrappier, more commercial origin story: Phil Moorby designed it in about a month in 1983 and 1984 at Gateway Design Automation, initially as a proprietary simulation language sold alongside Gateway’s Verilog-XL simulator. Cadence acquired Gateway in 1989, opened Verilog to the public through Open Verilog International in 1990, and it became the IEEE 1364 standard in 1995. Both languages ended up solving the same underlying problem from different corporate starting points: describing digital circuits precisely enough that a simulator and eventually a synthesis tool could turn the description into working silicon.
The Inversion: Every Statement Runs at Once
In a normal programming language, statement order is the whole story. In VHDL, statements inside an architecture body that are not wrapped in a process execute concurrently by definition, meaning the order you typed them in the file has no effect on simulated behavior at all. Reordering two concurrent signal assignments changes nothing, because both descriptions correspond to physical wires that exist and drive their outputs continuously, independent of each other, exactly like two separate logic gates sitting side by side on a chip. Verilog’s always and initial blocks work the same way relative to each other: every block in a module starts running “at time zero” and keeps running in parallel with every other block for the entire simulation.
Even inside a single process or always block, where statements genuinely are evaluated in sequence during simulation, that sequence describes the behavior of a piece of hardware that will ultimately execute in a single clock edge, not a sequence of operations spread across time. The mental model has to flip from “what happens next” to “what is wired to what.”
Delta Cycles and the Blocking Assignment Trap
The mechanism that makes concurrent execution actually simulate deterministically is the delta cycle, an infinitesimally small step of simulated time with no real-world duration, used purely to sequence otherwise-simultaneous signal updates without creating ambiguity. When a signal is assigned a new value, that value does not appear until the next delta cycle, so anything else reading that signal in the current delta still sees its old value. This is precise and consistent, but it means the exact bug pattern software engineers fall into on day one: assuming a value read immediately after being assigned reflects the update.
Verilog makes this worse before it makes it better, because it offers two assignment operators inside procedural blocks that look almost identical but behave completely differently. Blocking assignment, written =, updates its target immediately, in program order, much like assignment in a normal language. Non-blocking assignment, written <=, evaluates its right-hand side immediately but defers the actual update until the end of the current time step, which is exactly how real flip-flops behave: they all sample their inputs and update their outputs on the same clock edge, simultaneously, not one after another. Using blocking assignment to describe clocked, sequential logic is a textbook mistake with a name in the industry, thanks in large part to Cliff Cummings’ widely cited SNUG paper on the subject, and it produces circuits that simulate one way and can synthesize to a different, broken circuit, or that only work correctly depending on the arbitrary order the simulator happens to evaluate blocks in.
The rule of thumb every HDL style guide converges on:
- Use non-blocking assignment (
<=) for anything inside a clocked, sequential always block, modeling flip-flops - Use blocking assignment (
=) for combinational logic, modeling gates whose output depends only on current inputs - Never mix both assignment types for the same signal inside the same always block
Loops That Don’t Loop
Nothing captures the inversion better than a for loop. In software, a loop describes repetition over time: the same instructions execute again and again as the loop counter advances. In synthesizable VHDL or Verilog, a for loop with a fixed, compile-time-known range usually describes something closer to the opposite: replication in space. The synthesis tool unrolls the loop entirely, generating one copy of the described hardware for every iteration, all of which exist simultaneously on the chip. A loop that a software engineer expects to produce one adder used eight times in sequence instead produces eight separate physical adders wired in parallel. The keyword is identical to the one in every language they already know, and the meaning is close to the opposite.
The Data Behind the Difficulty
This is not a difficulty that shows up only for beginners and then disappears. Industry-wide verification data suggests that getting concurrent hardware descriptions right, and proving they are right, consumes a genuinely enormous share of real chip projects. The 2020 Wilson Research Group functional verification study, one of the longest-running industry surveys in this field, found that design engineers spend close to half their time on verification rather than design, and that only a minority of chip projects work correctly on their first fabrication run.


| Metric | 2020 finding |
|---|---|
| IC/ASIC projects achieving first silicon success | 32% |
| IC/ASIC projects behind schedule | 68% |
| Design engineer time spent on verification | 47% |
| Ratio of verification to design engineers, processor projects | Up to 5-to-1 |
None of this is proof that concurrency alone causes chip project overruns; growing design complexity, tighter power and safety requirements, and larger teams all play a role. But it is consistent with what every engineer who has made the jump from software finds out the hard way: reasoning correctly about a system where everything happens at once, and where a handful of assignment operators quietly decide whether that simultaneity is modeled correctly, takes real, sustained practice that ordinary programming experience does not provide.
What We Have Learned
VHDL and Verilog read like programming languages because that was a deliberate, practical choice by their designers, familiar syntax lowers the barrier to describing something genuinely unfamiliar. But underneath that syntax is a completely different execution model: independent, always-running concurrent processes synchronized by delta cycles instead of a single instruction pointer moving through a program. Blocking versus non-blocking assignment, and loops that unroll into physical copies instead of repeating in time, are not arbitrary quirks bolted onto the language. They are the direct, necessary consequences of describing something that does not execute step by step, because real circuits never did.


