Introduction
Welcome to the troubleshooting guide for open-source EDA (Electronic Design Automation) tools. If you've been working with Yosys, Icarus Verilog, Verilator, or OpenSTA, you've probably encountered cryptic error messages or unexpected behavior. Don't worry—you're not alone! This guide will help you understand common problems, develop systematic debugging approaches, and avoid the pitfalls that catch even experienced designers.
Think of this guide as your debugging companion. We'll explore real error messages you're likely to encounter, explain what they actually mean (not just what they say), and provide practical solutions. By the end, you'll have a toolkit of strategies to tackle problems methodically rather than through trial and error.
Understanding Your Toolchain
Before diving into specific errors, let's clarify what each tool does:
- Icarus Verilog (iverilog): A simulator that executes your RTL code to verify functional correctness
- Verilator: A fast simulator that converts Verilog to C++ for high-performance verification
- Yosys: A synthesis tool that transforms RTL into gate-level netlists
- OpenSTA: A static timing analyzer that verifies your design meets timing requirements
Each tool has different strengths, limitations, and quirks. Knowing which tool is generating an error immediately narrows down the problem space.
Common Icarus Verilog Issues
Undeclared Signals and Implicit Nets
Error Message:
error: Unable to bind wire/reg/memory 'signal_name' in 'module_name'
What It Means: You're using a signal that hasn't been declared. Unlike some commercial simulators, Icarus Verilog won't automatically create implicit nets in all contexts.
Solution: Declare all signals explicitly at the beginning of your module:
module counter(
input wire clk,
input wire reset,
output reg [7:0] count
);
wire rollover; // Explicitly declare intermediate signals
assign rollover = (count == 8'd255);
// rest of code...
endmodule
Pro Tip: Use the -Wall flag when compiling to catch implicit wire declarations: iverilog -Wall -o sim design.v testbench.v
Syntax Errors with SystemVerilog Features
Error Message:
syntax error
What It Means: You're using SystemVerilog syntax, but Icarus is defaulting to Verilog-2001 mode, or you're using a construct that isn't yet supported.
Solution: Specify the language standard explicitly:
- For SystemVerilog:
iverilog -g2012 design.sv - For Verilog-2005:
iverilog -g2005 design.v
Common Gotcha: Even with -g2012, Icarus Verilog doesn't support all SystemVerilog features. Always-comb and always-ff blocks work, but interfaces and classes have limited or no support. Check the documentation or test incrementally.
Time Scale Mismatches
Warning Message:
warning: Some designs have no timescale declared
What It Means: Different modules have different or missing timescale directives, which can cause simulation timing issues.
Solution: Add a consistent timescale directive at the top of each file:
`timescale 1ns/1ps // time_unit / time_precision
module my_design(...);
// design code
endmodule
Verilator: Speed with Constraints
Verilator is exceptionally fast but more restrictive than Icarus Verilog. Understanding its limitations will save you hours of frustration.
Unsupported Constructs
Error Message:
%Error: Unsupported: Verilator does not support this SystemVerilog construct
What It Means: Verilator focuses on synthesizable constructs and doesn't support everything in the SystemVerilog specification.
Common Unsupported Features:
- Delays (
#10) - Fork-join parallelism
- Some SystemVerilog assertions
- User-defined primitives (UDPs)
- Certain data types like real
Solution: For testbenches that need these features, use Icarus Verilog instead. For design code, refactor to use synthesizable constructs. Remember: if it can't synthesize, Verilator probably won't simulate it.
Timing Construct Errors
Error Message:
%Error: Unexpected 'posedge': Delay statements are unsupported
What It Means: You're trying to use delay-based timing in your RTL code.
Solution: Remove delay statements from synthesizable code:
// Bad - don't do this
always @(posedge clk) begin
#5 data <= new_data; // Verilator rejects this
end
// Good - use proper clocking
always @(posedge clk) begin
data <= new_data; // Happens on clock edge
end
Unoptimizable Constructs Warning
Warning Message:
%Warning-UNOPTFLAT: Signal unoptimizable: Feedback loop found
What It Means: Verilator detected combinational logic with feedback, which it can't optimize efficiently. This often indicates a real design problem.
Solution: Review your combinational logic for unintended latches or circular dependencies. Use sequential logic (registers) to break feedback loops intentionally:
// Problematic combinational loop
assign a = b & c;
assign b = a | d; // Circular!
// Fixed with registered logic
always @(posedge clk) begin
a <= b & c;
b <= a | d;
end
Yosys Synthesis Challenges
Inferring Memory vs. Registers
Warning Message:
Warning: Replacing memory 'mem' with an array of registers
What It Means: Yosys couldn't infer proper memory blocks (BRAM) and is instead creating individual flip-flops for each memory location. This is extremely inefficient for large arrays.
Solution: Use proper memory inference patterns:
// Good - Yosys can infer block RAM
reg [7:0] memory [0:255];
always @(posedge clk) begin
if (write_enable)
memory[write_addr] <= write_data;
read_data <= memory[read_addr];
end
Gotcha: Read and write in the same always block with separate ports. Mixed read-write on the same address may prevent memory inference depending on your target FPGA.
Latch Inference Problems
Warning Message:
Warning: Latch inferred for signal 'data_out'
What It Means: Your combinational always block doesn't assign a value to the output in all code paths, creating an unintended latch.
Solution: Always assign values to all outputs in all branches:
// Bad - creates a latch
always @(*) begin
if (select)
data_out = data_in;
// What happens when select is 0? LATCH!
end
// Good - no latch
always @(*) begin
if (select)
data_out = data_in;
else
data_out = 8'd0; // Default assignment
end
Pro Tip: Initialize signals at the beginning of always @(*) blocks to provide default values, then override them conditionally.
Synthesis Attribute Issues
Error Message:
ERROR: Attribute 'keep' not recognized
What It Means: You're using synthesis attributes that Yosys doesn't recognize or support in the same way as commercial tools.
Solution: Use Yosys-specific attribute syntax:
(* keep *) wire important_signal;
(* fsm_encoding = "one-hot" *) reg [2:0] state;
Check Yosys documentation for supported attributes. Some Xilinx or Intel-specific attributes won't work.
OpenSTA Timing Analysis Traps
Missing or Incorrect SDC Constraints
Error Message:
Warning: No clock definition found
What It Means: OpenSTA can't analyze timing without knowing your clock parameters.
Solution: Create a proper SDC (Synopsys Design Constraints) file:
# Define clocks
create_clock -name clk -period 10.0 [get_ports clk]
# Define input/output delays
set_input_delay -clock clk 2.0 [all_inputs]
set_output_delay -clock clk 2.0 [all_outputs]
# Define clock uncertainty (jitter, skew)
set_clock_uncertainty 0.5 [get_clocks clk]
Path Grouping Confusion
Issue: Timing reports show unexpected critical paths or miss important violations.
What's Happening: Without proper path grouping, OpenSTA might not report the paths you care about.
Solution: Use path groups to organize timing analysis:
group_path -name input_to_reg -from [all_inputs] -to [all_registers]
group_path -name reg_to_reg -from [all_registers] -to [all_registers]
group_path -name reg_to_output -from [all_registers] -to [all_outputs]
False Paths and Multicycle Paths
Problem: OpenSTA reports timing violations on paths that don't need to meet single-cycle timing.
Solution: Use false_path and multicycle_path constraints:
# Asynchronous reset path - doesn't need timing analysis
set_false_path -from [get_ports reset]
# This path has two cycles to complete
set_multicycle_path 2 -from [get_pins reg_a/*] -to [get_pins reg_b/*]
General Debugging Strategies
The Incremental Approach
When facing complex errors, simplify aggressively:
- Create a minimal failing example: Strip your design down to the smallest piece that shows the problem
- Add complexity gradually: Once the simple version works, add features back one at a time
- Test at each step: Don't wait until everything is implemented to test
Systematic Error Interpretation
When you see an error message:
- Read the entire message: Don't just skim the first line
- Note the file and line number: Go directly to the problematic code
- Check the context: Look at surrounding code, not just the reported line
- Search for the exact error: Many errors have been solved by others—use search engines!
Comparing Tool Outputs
Run your design through multiple tools when possible:
- If Icarus Verilog simulates correctly but Verilator fails, you might be using unsupported constructs
- If Yosys synthesis succeeds but OpenSTA shows timing violations, your constraints might be too aggressive
- If simulation works but synthesis creates unexpected logic, review your coding style for synthesis-unfriendly patterns
Using Waveform Viewers
Visual debugging is powerful. Generate VCD (Value Change Dump) files:
// In your testbench
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testbench);
end
View with GTKWave to see signal behavior over time. Often, watching signals transition makes bugs obvious.
Enabling Verbose Output
Most tools have verbose modes that provide additional debugging information:
- Icarus Verilog: Use
-vflag - Yosys: Use
debugcommand or-vflag - Verilator: Use
--debugflag
Tool-Specific Configuration Tips
Icarus Verilog Configuration
Create a .verilog file in your home directory to set default options:
-g2012
-Wall
Yosys Optimization Control
Sometimes Yosys optimizes too aggressively. Control optimization:
# In your synthesis script
read_verilog design.v
hierarchy -check
# Reduce optimization for debugging
opt -fast
Verilator Lint Mode
Use Verilator's lint mode to catch potential issues without full compilation:
verilator --lint-only design.v
This is faster than full compilation and catches many common problems.
Conclusion
Debugging open-source EDA tools requires patience and systematic thinking, but it's a learnable skill. Remember these key principles:
- Understand each tool's purpose and limitations before blaming the tool for errors
- Read error messages completely and search for solutions—you're rarely the first person to encounter a particular error
- Simplify and isolate problems to their smallest reproducible form
- Test incrementally rather than building everything before testing
- Use multiple tools to cross-validate your design and identify tool-specific issues
With experience, you'll develop intuition for which tool is likely causing which problem, and debugging will become much faster. The open-source community is also incredibly helpful—don't hesitate to ask questions on forums or GitHub issues when you're truly stuck.
Happy debugging, and remember: every error message is an opportunity to learn something new about your tools and your design!