HDLs Are Software (and It’s Crazy We’re Still Arguing About It)
HDLs are formal descriptions of behavior, making them software by definition. Modernizing these outdated tools is key to making FPGA development more accessible and productive for all engineers.
I’ve been hearing people say that HDL languages are not software and should not be treated like software for decades now. This is fundamentally wrong.
A big part of the confusion comes from a narrow definition of “software.” When people hear the word, they tend to imagine imperative languages like C or Python. They’re right that languages like those do not map cleanly to FPGAs. But they’re wrong to assume that all software must look like those languages.

Are HDL languages software or something else? Chip image used courtesy of AMD
Software is the domain of computer science, and at its core, it encompasses any formal description of behavior. HDLs are unequivocally formal descriptions of behavior. They describe, unambiguously, how a system is supposed to operate.
Beyond Turing Completeness
When people mentally equate software with C or Python, what they’re really assuming is that software implies a Turing machine. While Turing machines are necessary to solve certain classes of problems, many real-world problems do not require them.
Take spreadsheets. Traditional spreadsheets solve problems that do not require Turing completeness. They define an acyclic dependency graph: A depends on B, B depends on C, so when C changes, B updates, and then A updates. While modern spreadsheets include features that technically make them Turing-complete, those features, which are rarely used, must always extend beyond the traditional pure table structure.
Spreadsheets are ubiquitous precisely because millions of problems can be represented as dependency graphs, and spreadsheets are an effective way to describe them. Computer science exists so we can understand how to create a description of a problem.
HTML (hypertext markup language) is another example. HTML is a domain-specific language that tells a browser how to render a page. It has transformed how people interact with technology. It is also not Turing-complete, but is still a software language. Engineers analyzed what information was required to describe a user interface and created a formal language to represent it.
GUIs can only go so far. If you want to tell a computer to do anything specific, you must type formal text that the computer understands. Regular expressions (regex) are a mini-language that describes how to match strings of characters. Ultimately, somewhere behind the scenes, the computer is almost always running a regex against any formal text. At its core, a regex represents a non-deterministic finite automaton (NFA). NFAs can always be converted into classical state machines.
That brings us to state machines themselves. State machines are not Turing-complete, yet they are the foundation of all computation. A state machine takes inputs, an internal state, and produces outputs while updating that internal state. State machines are the building blocks of all digital logic and are used to construct Turing machines, but they are not Turing machines themselves. Importantly, state machines are independent of implementation technology. Charles Babbage designed state machines using mechanical gears. Later, they were implemented with vacuum tubes, then transistors. The concept does not imply silicon.
Deterministic Logic vs. General Computation
This is where FPGAs come in. FPGAs are mechanisms for implementing state machines, often many state machines working together. Physically, an FPGA die is a fabric of many thousands of tiny state machines called combinatorial logic blocks. Sometimes those collections form a Turing machine, but often they do not. If I pulled up to your house with a truck full of gears and cogs, you could make a computer, but that probably would not be your first thought. An FPGA is just a truck filled with tiny state machines.

An FPGA’s programmable fabric allows designers to rapidly program (and re-program) the device to perform nearly any function. Image used courtesy of Lattice Semiconductor
There are deep, mathematically provable differences between state machines and Turing machines. One important difference: state machines produce deterministic outputs in known time. Turing machines do not. This is the halting problem. Computer science proves that it is impossible to know if or when an arbitrary program will terminate. Therefore, state machines solve a narrower class of problems but do so with guaranteed timing. Turing machines solve a far broader class, but with no guarantees on execution time.
General-purpose programming languages assume a Turing machine. That’s what most software developers are trained on. Enormous effort has gone into making HDLs resemble those languages, under the assumption that familiarity would make them more approachable. That assumption is wrong.
If you abstract away timing, you destroy the value of the FPGA. Countless niche HDL languages have tried to blur this line. None have succeeded because an FPGA is not a good way to execute general-purpose computation, but it is a good way to maintain precision timing.
That does not mean the existing languages are good.
The Need for Modern Domain-Specific Languages
A full critique of VHDL and Verilog is beyond the scope of this article, but one example illustrates the problem. In VHDL, there is a keyword rising_edge(). Under the hood, it instructs the compiler to attach a clock to a flip-flop and latch data on the rising edge of that signal.
But a “rising edge” exists for any changing signal. To use this keyword correctly, the developer must understand that it only works in an extremely specific hardware context. That is unacceptable. Further, it is good practice for all flip-flops to clock on the rising edge, so the language should assume rising-edge clocking. In addition, the programmer should be required to take extra actions to explicitly call out anything outside of that default.

The rising_edge feature in VHDL code only works properly in specific hardware contexts. Image used courtesy of EmLogic
Language developers realized this decades ago. If someone created a language now that required the programmers to understand the nuances of the program registers, that language would not only not be adopted, but people would assume it was a parody like Intercal. When a language requires that level of implicit hardware knowledge to avoid subtle errors, it is a bad language.
HDLs are not creating something capable of the complexity required by a general-purpose language. The complexity of the problem space is closer to HTML than it is to general-purpose languages. Therefore, the domain-specific language targeting FPGAs should be simpler than general-purpose languages, not more complicated.
Here’s a hypothetical example of something that would make far more sense:
clock clk1(50e6); // Tell the system there is a 50Mhz clock signal called clk1
clk1.uint[13] divisor=0; // Create a state variable named divisor, assumed integer with 13 bits and referenced to the clk1
clk1.uint[1] clkout=0; // Create a single bit state variable clkout
if(rising_edge(divisor[13]){
clkout= ~clkout;
}
divisor=divisor+1;
This is just an example of a subset of a hypothetical language that addresses problems in current HDLs. In this case, the variable declaration includes a data type, data size, clock domain, and rising-edge clocking is assumed. Now, a programmer doesn’t need any context about flip-flops to apply the notion of a rising_edge to a signal. Further, the compiler can leverage the declared types to throw a compile error if the clock domain of the divisor does not match the clock domain of clkout. Lastly, because the clock domain has been specified, divisor=divisor+1 also inherently makes sense to the compiler.
I’m not proposing this language. I’m saying the current ones are awful and that there are obvious, well-understood ways to improve them. We’ve had four decades of progress in language theory since the creation of VHDL and Verilog. When they were designed, COBOL was still a reasonable software choice.
FPGA programming is not hard. It cannot be hard because it cannot express the complexity reserved for general-purpose computing. It is tedious and unpleasant because the languages and tools are decades out of date.

FPGA programming could potentially be simplified with new, improved languages and tools. Image used courtesy of Adobe Stock
Software engineers look at HDLs and, correctly, say they don’t want to touch them. FPGA developers respond by insisting that HDLs aren’t software and software engineers shouldn’t be involved. Everyone looks the other way.
That stalemate is not productive. It limits the adoption of an extremely powerful tool for solving real problems. The real world happens in real time, but true software does not and provably cannot. Marrying the two is possible, but extremely difficult. It requires tying together interrupts, thread safety, and DMA. It takes a long time, is difficult, error-prone, and requires highly specialized knowledge to develop and debug. Using an FPGA, we can solve many of those problems and build systems faster and much more robustly.
Unfortunately, people are not going to adopt FPGAs as a standard part of development until the tools and languages are not decades out of date.
there is so much wrong with this !
all ff should be on rising edge ! wow.
reality
sw compilers find it hard to spread work out over 8 threads, in an fpga , everything is parallel,
how are you going to cope with asyncronous logic ?
btw. a thing that keeps its output stable on an edge, is a register, a thing that keeps its output stable on a level, and variable on the other is a latch.
the difference in fpgas is critical, in sw it seems its insignificant.
anyway,
in sw, you dont tend to specify delay time through a block of code , in fpgas its imperative . what woukd happen if you had three lumps of code , all going into an output block, all have same delay, outouts align. some one modifies one block, the delay changes , outout is now not alligned.
there have been many tries at writing a language that is simple enough for sw engineers to write fpgas, none have worked, the extra wrapper you have to add to give you control , makes it more complicated than rtl !
also remember how short on gates hw chips are , and how slow the routing is, large parallel systems have to be made.
anyway,
its not going to matter soon!
AI is getting good at taking “english” abd pumping out RTL,