Getting Real With VHDL Simulation

Most people approach circuit design and simulation with Vhdl by watching YouTube tutorials that skip over the parts that actually matter. They write a module, slap a testbench on it, hit simulate, and everything "passes." Then they ship it to FPGA and wonder why their design glitches at 100MHz. The gap between simulated correctness and hardware correctness is where things break. I spent years learning that the hard way. Here is how I actually do it now. The process starts before you write a single line of code. You pick your toolchain. For quick iteration I use GHDL with GTKWave. For anything going onto real silicon I use Xilinx Vivado or Intel Quartus. Both work fine. GHDL is faster for unit-level tests because it skips the synthesis step. Vivado ties simulation and synthesis together, which matters once your design grows past a few modules.

Circuit Design And Simulation With Vhdl: The Workflow I Use

Write the entity declaration first. Always. Not the architecture. The interface. This forces you to think about what your module actually needs to talk to the outside world. I have seen engineers write entire architectures and then realize mid-simulation they forgot to expose a reset pin because they were too busy optimizing internal logic. For a synchronous counter example, your entity looks like this:

entity counter is port ( clk : in std_logic; rst : in std_logic; en : in std_logic; count : out std_logic_vector(7 downto 0); overflow : out std_logic ); end entity;

Then write the architecture. Keep it behavioral. Don't try to be clever with concurrent statements in your first pass. Descriptive code synthesizes fine. Clever code often doesn't, and debugging inference issues takes three times longer than just writing clear process blocks. The testbench is where most people waste time. Stop trying to simulate everything in one file. Write a single testbench that instantiates your design and drives stimulus through a simple clock generator process. Here is a pattern I use everywhere:

Get the Full Details

2160x1440px | free download | HD wallpaper: purple and green circuit ...
2160x1440px | free download | HD wallpaper: purple and green circuit ...
constant clk_period : time := 10 ns; clk_gen : process begin clk <= '0'; wait for clk_period / 2; clk = '1'; wait for clk_period / 2; end process;

This is boilerplate. Copy it. Don't rewrite it for every project. You lose about twenty minutes every time you do. Run the simulation. Check the waveforms in GTKWave or the built-in simulator. Look for actual timing violations, not just functional correctness. A common mistake beginners make is assuming that because the output value is correct at the end of a cycle, the design is correct. It isn't. Metastability, setup and hold violations, and race conditions don't show up in functional simulation. They show up after programming the chip.

What No One Tells You About VHDL Simulation

Functional simulation does not model gate delays by default. When you simulate in Vivado's testbench mode, everything is instantaneous unless you explicitly add delay annotations. This means your simulation will pass even if the real hardware has timing issues. To catch some of this, run a post-synthesis or post-implementation simulation. It takes longer. Vivado's post-implementation sim can take 10 to 20 minutes for a modest design where functional simulation takes 30 seconds. Worth it for anything beyond a homework assignment. Another thing: VHDL's sensitivity lists matter more than people admit. In VHDL-2008 you can sometimes get away with missing signals in a combinational process sensitivity list, but the synthesis tool may infer latches instead of the combinational logic you intended. I lost two days once because I had a process like this:

process(a, b) begin if a = '1' then y <= b; else y = '0'; end if; end process;

I forgot c in the sensitivity list. Simulation worked fine. Synthesis inferred a latch. The board failed in production at high temperature. Added c to the list. Problem gone. Never happened again. If you want to avoid this category of problem entirely, use VHDL-2008 and the "all" keyword in sensitivity lists for combinational processes. It is cleaner and prevents accidental latch inference. Not all tools support it equally, but Vivado and GHDL both do.

Types of electrical circuit connections - Basic tutorial on series and ...
Types of electrical circuit connections - Basic tutorial on series and ...

A Specific Problem I Ran Into

I was designing a simple SPI master for an FPGA project a few years back. The simulation passed perfectly. Every state transition fired at the right time. Everything looked correct in the waveform viewer. I synthesized it, routed it, and uploaded it. The device worked about 60 percent of the time. The rest of the time it would start transmitting and then freeze mid-frame. I spent three days debugging. Checked clocks. Checked resets. Checked my state machine. Nothing was obviously wrong. Eventually I enabled timing analysis in Vivado and found that my SPI clock divider was creating a timing violation on the boundary between two clock domains. The simulation never modeled this because the testbench ran everything in the same clock domain with zero delay. The workaround was straightforward: I added explicit SDRAM-style synchronization between the clock domains and inserted false path constraints for the divider logic. Timing analysis passed. The hardware worked on the first try after that. The lesson was not that my code was bad. It was that the simulation model was incomplete. I had not accounted for clock domain crossing delays.

Now I always simulate across clock domains when my design has more than one. I add realistic clock skew into my testbench. It takes a bit more setup but catches about 80 percent of the bugs that otherwise slip through.

When VHDL Simulation Is The Wrong Tool

Verilog or SystemVerilog might be faster for large designs. VHDL is verbose. Writing a 200-line testbench in VHDL takes roughly twice as long as in SystemVerilog because VHDL lacks some of the procedural convenience features. If you are working on a large SoC design with aggressive timelines, SystemVerilog gives you more tools for less code. Also, VHDL simulation of large designs can be slow. GHDL handles reasonable-sized designs fine, but once you push past a few thousand lines of well-structured code, simulation times grow non-linearly. I have seen designs where a functional sim that should take five minutes ran for forty. Switching to a commercial simulator like ModelSim or Vivado's simulator with compilation mode helps. Compiled simulation is significantly faster than interpreted. Turn it on. There is also the matter of simulation vs. emulation. If you need to validate a design at scale before tapeout, FPGA prototyping or hardware emulation is the right step. VHDL simulation alone will never give you confidence about physical layer issues, power integrity, or signal timing at speed. It is a design validation tool, not a hardware verification tool.

Electronic Circuit Board Free Stock Photo - Public Domain Pictures
Electronic Circuit Board Free Stock Photo - Public Domain Pictures

Practical Steps To Get Started Today

Install GHDL if you are on Linux or macOS. On Windows use the MSI installer from the official GHDL site. It is free and does not require a license. For a full flow with synthesis and implementation, install Vivado WebPACK, which is also free for most Xilinx parts. Create a new project. Add a single .vhdl file for your design and another for the testbench. Write the testbench with a clock generator and a stimulus process. Run the simulation. Look at the waveforms. Make one change. Run again. Repeat. This is the loop. It is not glamorous but it is how real hardware gets built. Don't try to simulate your entire system at once. Break it into blocks. Simulate each block independently before integrating them. I test every module separately. It saves hours of debugging later when something breaks in the integrated flow.

The files you need are straightforward to set up. A basic project structure looks like this on disk: project/ src/counter.vhdl tb/tb_counter.vhdl sim/gtkwave_settings.trs Keep it simple. Track your waveform settings in version control. I have lost simulation setups multiple times by not committing the .trs files. They are small. Commit them. It takes five seconds.

One final point that probably sounds obvious but isn't: read the error messages from your simulator. VHDL error messages are terrible, yes. But they are also specific. "Resolution function failed" means you have multiple drivers on a net. "Process never waits" means you have an infinite loop in your testbench. "Type mismatch" means exactly what it says. Most people skim these and move on. Reading them carefully saves more time than any technique I have mentioned.

Green Circuit Board · Free Stock Photo
Green Circuit Board · Free Stock Photo