Put a module on the command line before its package, and Icarus prints hdr_gen.sv:1: syntax error and I give up. Misspell the package name in the import and it prints exactly the same two lines. The message names a file and a line, not the cause, so you need to know which word in it to trust and which second tool to ask.
This lesson builds a five-file project, breaks it in six realistic ways, and reads what Icarus (iverilog -g2012) and Verilator (verilator --lint-only -Wall) print for each. The packages lesson explains why packages need an order; this one is about reading the errors when the order is wrong.
Read the numbers as the order of the file list. Any order that never puts a box above one of its parents is legal.
base_pkg has no parents, so it is always first.
pkt_pkg imports base_pkg, so it is second. A package can depend on a package; that is the edge case 4 breaks.
hdr_gen and hdr_check are independent of each other and can swap places; top uses pkt_pkg::header_t directly, so it depends on pkt_pkg too.
Each // name.sv comment starts a separate file. The line numbers in the error messages below refer to those files. The bench at the end runs the whole project against a model.
// base_pkg.sv
package base_pkg;
localparam int TAG_W = 8;
typedef logic [TAG_W-1:0] tag_t;
endpackage
// pkt_pkg.sv
package pkt_pkg;
import base_pkg::*;
typedef enum logic [1:0] {IDLE, HEADER, PAYLOAD, ERROR} state_t;
typedef struct packed {
tag_t tag;
logic [7:0] length;
} header_t;
endpackage
// hdr_gen.sv
module hdr_gen import pkt_pkg::*; (
input logic clk, rst_n,
input logic [7:0] len_i,
output header_t hdr_o
);
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) hdr_o <= '0;
else begin
hdr_o.tag <= hdr_o.tag + 1'b1;
hdr_o.length <= len_i;
end
endmodule
// hdr_check.sv
module hdr_check import pkt_pkg::*; (
input header_t hdr_i,
output state_t state_o
);
logic bad;
assign bad = (hdr_i.length == 8'd0) || (hdr_i.tag == '1);
always_comb begin
if (bad) state_o = ERROR;
else state_o = HEADER;
end
endmodule
// top.sv
module top (
input logic clk, rst_n,
input logic [7:0] len_i,
output logic [1:0] state_o
);
pkt_pkg::header_t hdr;
pkt_pkg::state_t st;
hdr_gen u_gen (.clk, .rst_n, .len_i, .hdr_o(hdr));
hdr_check u_chk (.hdr_i(hdr), .state_o(st));
assign state_o = st;
endmoduleKeep this table next to your build log. The key words column is the part of each message that points at the cause.
Case | Key words to look for | Cause | One-line fix |
|---|---|---|---|
1. Module before its package | Icarus: syntax error on the line with the type. Verilator: Reference to 'header_t' before declaration, plus Location of original declaration | File order | Move the package file above the module in the file list |
2. Missing import | Icarus: syntax error, Errors in port declarations. Verilator: Can't find typedef/interface | No import in this module | Add import pkt_pkg::*; to the module header, or write pkt_pkg::header_t |
3. Same enum literal from two packages | Icarus: Ambiguous use of 'ERROR'. Verilator: silent, or ENUMVALUE if the import order is swapped | Two wildcard imports export ERROR | Write pkt_pkg::ERROR, or import only the names you use |
4. Package before the package it imports | Verilator: Reference to 'tag_t' before declaration, in pkt_pkg.sv | Package-to-package order | Put base_pkg.sv first; with a cycle, move the shared item down |
5. Typo in the package name | Icarus: syntax error on line 1. Verilator: Import package not found: 'pkt_pkt' | Spelling | Correct the name; the file list is fine |
6. Width changed in the package | Icarus: expects 20 bit(s), given 16 (warning only). Verilator: WIDTHEXPAND on the port connection | A hard-coded width outside the package | Declare the wire with the package type |
$ iverilog -g2012 -o /dev/null base_pkg.sv hdr_gen.sv pkt_pkg.sv hdr_check.sv top.sv
hdr_gen.sv:1: syntax error
I give up.
$ verilator --lint-only -Wall --top-module top base_pkg.sv hdr_gen.sv pkt_pkg.sv hdr_check.sv top.sv
%Error: hdr_gen.sv:4:10: Reference to 'header_t' before declaration (IEEE 1800-2023 6.18)
...
pkt_pkg.sv:7:5: ... Location of original declarationPoints at: the words before declaration, and the second location. Verilator found header_t later in the same run, in pkt_pkg.sv, so the definition exists and only the order is wrong.
Fix: move pkt_pkg.sv above hdr_gen.sv in the file list.
$ iverilog -g2012 -o /dev/null base_pkg.sv pkt_pkg.sv hdr_gen.sv hdr_check.sv top.sv
hdr_check.sv:2: syntax error
hdr_check.sv:1: Errors in port declarations.
$ verilator --lint-only -Wall --top-module top base_pkg.sv pkt_pkg.sv hdr_gen.sv hdr_check.sv top.sv
%Error: hdr_check.sv:2:10: Can't find typedef/interface: 'header_t'
%Error: hdr_check.sv:3:10: Can't find typedef/interface: 'state_t'
%Error: hdr_check.sv:8:24: Can't find definition of variable: 'ERROR'
%Error: hdr_check.sv:9:24: Can't find definition of variable: 'HEADER'Points at: Can't find, with no second location. Compare case 1: here the name is not visible at all, because the order is correct and the import is gone.
Four errors, one cause. Every name from pkt_pkg fails in that file. When several errors in one file all name the same package's types, look for the import first.
Fix: restore import pkt_pkg::*; in the module header, before the port list.
A debug package adds typedef enum logic [1:0] {OK, WARN, ERROR} dbg_level_t; and hdr_check imports both packages with wildcards. Both export ERROR.
$ iverilog -g2012 -o /dev/null base_pkg.sv pkt_pkg.sv dbg_pkg.sv hdr_gen.sv hdr_check.sv top.sv
hdr_check.sv:8: error: Ambiguous use of 'ERROR'. It is exported by both 'pkt_pkg' and by 'dbg_pkg'.
$ verilator --lint-only -Wall --top-module top base_pkg.sv pkt_pkg.sv dbg_pkg.sv hdr_gen.sv hdr_check.sv top.sv
[exit 0]
# hdr_check.sv edited: import dbg_pkg::*, pkt_pkg::*;
$ verilator --lint-only -Wall --top-module top base_pkg.sv pkt_pkg.sv dbg_pkg.sv hdr_gen.sv hdr_check.sv top.sv
%Error-ENUMVALUE: hdr_check.sv:8:24: Implicit conversion to enum 'enum{}pkt_pkg::state_t' from 'enum{}dbg_pkg::dbg_level_t' (IEEE 1800-2023 6.19.3)Icarus reports the conflict and names both packages: that message is the cause, word for word.
Verilator accepted the first version with no message, and a simulation of it used pkt_pkg's ERROR (value 3). Swap the import order and it picks dbg_pkg's ERROR, which then fails the enum type check. The result depends on the order of an import list.
Fix: write pkt_pkg::ERROR, or import only the names you use: import pkt_pkg::ERROR, pkt_pkg::HEADER;.
$ iverilog -g2012 -o /dev/null pkt_pkg.sv base_pkg.sv hdr_gen.sv hdr_check.sv top.sv
pkt_pkg.sv:2: syntax error
I give up.
$ verilator --lint-only -Wall --top-module top pkt_pkg.sv base_pkg.sv hdr_gen.sv hdr_check.sv top.sv
%Error: pkt_pkg.sv:5:5: Reference to 'tag_t' before declaration (IEEE 1800-2023 6.18)
...
base_pkg.sv:3:29: ... Location of original declarationPoints at: the failing file is a package, not a module. Packages have an order among themselves, and it must be in the file list too.
Circular version. When base_pkg was edited to use pkt_pkg::state_t while pkt_pkg still imports base_pkg, Icarus rejected both file orders. Verilator rejected one and accepted the other with only an unused-parameter warning. A build that passes in one tool is not proof the graph has no cycle.
Fix: base_pkg.sv first. For a cycle, move the shared definition down into the lower package, as the dependency graph shows.
$ iverilog -g2012 -o /dev/null base_pkg.sv pkt_pkg.sv hdr_gen.sv hdr_check.sv top.sv
hdr_gen.sv:1: syntax error
I give up.
$ verilator --lint-only -Wall --top-module top base_pkg.sv pkt_pkg.sv hdr_gen.sv hdr_check.sv top.sv
%Error: hdr_gen.sv:1:23: Import package not found: 'pkt_pkt'Icarus prints the same two lines as case 1. On its own, that message cannot tell order from spelling.
Verilator quotes the name it could not find. Compare it with the package line: pkt_pkt against pkt_pkg.
Fix: correct the spelling in hdr_gen.sv. Reordering files will never help with this one.
TAG_W goes from 8 to 12, so header_t grows from 16 to 20 bits. Every file that uses header_t follows. top.sv does not, because someone wrote its wire as logic [15:0] hdr; when the tag was 8 bits.
$ iverilog -g2012 -o /dev/null base_pkg.sv pkt_pkg.sv hdr_gen.sv hdr_check.sv top.sv
top.sv:8: warning: Port 4 (hdr_o) of module hdr_gen expects 20 bit(s), given 16.
top.sv:8: : Padding 4 high bits of the port.
top.sv:9: warning: Port 1 (hdr_i) of module hdr_check expects 20 bit(s), given 16.
top.sv:9: : Padding 4 high bits of the port.
[exit 0]
$ verilator --lint-only -Wall --top-module top base_pkg.sv pkt_pkg.sv hdr_gen.sv hdr_check.sv top.sv
%Warning-WIDTHEXPAND: top.sv:8:43: Output port connection 'hdr_o' expects 20 bits on the pin connection, but pin connection's VARREF 'hdr' generates 16 bits.
...
%Warning-WIDTHEXPAND: top.sv:9:21: Input port connection 'hdr_i' expects 20 bits on the pin connection, but pin connection's VARREF 'hdr' generates 16 bits.
%Error: Exiting due to 2 warning(s)Icarus builds it. Exit status 0: only warnings, and the top 4 bits of the tag are lost between the two blocks. A script that checks only the exit status passes this build.
Verilator with -Wall stops on the warnings. The two numbers, 20 and 16, are the new and the old width.
Fix: declare the wire as pkt_pkg::header_t hdr;, as the working top.sv does. Never repeat a package width by hand.
Both tools here read every source file on every run, so a package change always reaches every file. Flows that compile packages into a library once and reuse it later can keep an old copy of header_t: the same 20-against-16 mismatch, with nothing in the source to explain it. After a package change, rebuild every file that imports it, or the whole library.
Put the order in one file list, packages first, lowest level first. Both tools read it with -f:
// files.f: packages first, lowest level first
base_pkg.sv
pkt_pkg.sv
// then modules, leaves before the top
hdr_gen.sv
hdr_check.sv
top.sv
$ iverilog -g2012 -o /dev/null -f files.f
$ verilator --lint-only -Wall --top-module top -f files.fBoth commands finish with exit status 0. The check below catches order bugs before either tool runs. It walks the list in order, remembers each package it has seen, and flags any name:: used before its package. It is a text scan, not a parser: it does not see a package declared inside an ifdef or by a macro.
#!/bin/sh
# check_order.sh <file list>: fail if a file uses pkg:: before the file that declares pkg
seen=" "; status=0
for f in $(sed -e 's://.*::' -e '/^ *$/d' "$1"); do
for p in $(sed 's://.*::' "$f" | grep -oE '[A-Za-z_][A-Za-z0-9_]*::' | sed 's/:://' | sort -u); do
case "$seen" in
*" $p "*) ;;
*) echo "ORDER: $f uses $p:: but $p is not declared earlier in $1"; status=1 ;;
esac
done
for p in $(sed -n 's/^ *package *\([A-Za-z0-9_]*\).*/\1/p' "$f"); do seen="$seen$p "; done
done
[ $status -eq 0 ] && echo "order OK:$seen"
exit $status$ ./check_order.sh files.f
order OK: base_pkg pkt_pkg
$ ./check_order.sh bad.f # hdr_gen, pkt_pkg, base_pkg, hdr_check, top
ORDER: hdr_gen.sv uses pkt_pkg:: but pkt_pkg is not declared earlier in bad.f
ORDER: pkt_pkg.sv uses base_pkg:: but base_pkg is not declared earlier in bad.fRun against the other cases, it reports the typo of case 5 as hdr_gen.sv uses pkt_pkt::, and the circular version of case 4 in both file orders. Case 3 and case 6 pass it, because their order is correct: those need the compiler.
Either the module has no import of pkt_pkg (case 2) or pkt_pkg.sv comes after hdr_check.sv in the file list (case 1). Run Verilator: Can't find typedef/interface means the import is missing; Reference to 'header_t' before declaration, with a location in pkt_pkg.sv, means the order is wrong.
No. No file declares pkt_pkt; it is a typo for pkt_pkg in the import. Correct the name.
Tools: Icarus Verilog 13.0 and Verilator 5.048, run on 2026-10-17. Project: base_pkg.sv, pkt_pkg.sv, hdr_gen.sv, hdr_check.sv, top.sv exactly as in the lesson block (the bench tb_top.sv kept out of the error runs). Each case was rebuilt from the working files by a script and run with iverilog -g2012 -o /dev/null <files> and verilator --lint-only -Wall --top-module top <files>, in the file orders shown.
Results: working project and files.f exit 0 in both tools. Case 1 and case 5: Icarus syntax error and I give up on the same line; Verilator before declaration (case 1) and Import package not found (case 5). Case 2: Can't find typedef/interface. Case 3: Icarus Ambiguous use of 'ERROR'; Verilator exit 0 with pkt_pkg imported first (a verilator --binary run gave state 3, pkt_pkg's ERROR) and ENUMVALUE with the import order swapped. Case 4: before declaration in pkt_pkg.sv; the circular variant failed both orders in Icarus and one order in Verilator (the other gave only UNUSEDPARAM). Case 6: Icarus warnings, exit 0; Verilator WIDTHEXPAND, exit 1. $unit pitfall: Icarus passes in one order and fails in the other; Verilator reports IMPORTSTAR.
Order check: check_order.sh as shown (POSIX sh, sed, grep) on files.f (order OK), bad.f (two ORDER lines), the typo case and both orders of the circular case (flagged). Logs are trimmed with ... lines; kept lines are unedited. The bench in the lesson passes in Icarus and Verilator (600 cycles against a model).
Scope and limits: two open-source tools; commercial simulators word these errors differently. Stale library outputs were not reproduced, because both tools re-read all sources on every run. The order check is a text scan and does not see packages declared through macros or ifdef branches.