Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • RTL Foundations36
  • Combinational Design25
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
  • Advanced RTL28
    • Parameterization and Generate Hub
    • Top-Level Integration Hub
    • Synthesis Intent Hub
    • Style and Static Checks Hub
    • Assertions in RTL Hub
    • Formal Verification Basics Hub
    • Reusable SystemVerilog for RTL
      • Packages and Compile Order
      • Packed Structs and Unions
      • Parameter Types and Guards
      • Functions and Tasks
      • Interfaces, Modports, and Portability
      • Compile-Order and Package Errors, Decoded
      • Mini Project: a Reusable FIFO IP
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Reusable SystemVerilog for RTL
  1. Topics
  2. RTL Design
  3. Advanced RTL
  4. Reusable SystemVerilog for RTL
  5. Compile-Order and Package Errors, Decoded

Part 8 · Advanced · Advanced

Compile-Order and Package Errors, Decoded

Six realistic ways to break a multi-file SystemVerilog build, the real messages two tools print, and a file-list check that catches order bugs first.

On this page

    Why this matters

    A missing package and a misspelt package name give the same two-line Icarus error, and a width change can build with warnings only. Reading the right word in each message, and checking the file list first, saves hours of guessing.

    After this lesson you can: read the order, import, ambiguity, typo and width errors two compilers print, name the cause and the one-line fix, and check a file list for package order before building.

    Same message, different bugs

    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.

    Dependency graph: 1 base_pkg feeds 2 pkt_pkg; pkt_pkg feeds 3 hdr_gen, 4 hdr_check and 5 top; hdr_gen and hdr_check also feed top.
    The tiny project: two packages and three modules, numbered in a legal compile order. An arrow means must be compiled before.

    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.

    The working project

    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.

    hdr_gen.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    // 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;
    endmodule

    Symptom, cause, fix

    Keep 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

    The six cases, read line by line

    1. A module before its package

    Diagram
    $ 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 declaration
    • Points 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.

    2. A missing import

    Diagram
    $ 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.

    3. One literal, two packages

    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.

    Diagram
    $ 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;.

    4. A package before the package it imports

    Diagram
    $ 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 declaration
    • Points 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.

    5. A typo in the package name

    Diagram
    $ 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.

    6. A width changed in the package

    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.

    Diagram
    $ 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.

    A file list and an order check

    Put the order in one file list, packages first, lowest level first. Both tools read it with -f:

    Diagram
    // 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.f

    Both 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.

    Diagram
    #!/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
    Diagram
    $ ./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.f

    Run 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.

    Common mistakes

    Common pitfall

    A wildcard import outside any module goes into the compilation-unit scope, $unit, and leaks into every file compiled after it. With import pkt_pkg::*; at the top of hdr_gen.sv and no import in hdr_check.sv, Icarus built the project with hdr_gen.sv first and failed with hdr_check.sv:2: syntax error when the two files swapped places. Verilator -Wall flagged the import itself: %Warning-IMPORTSTAR: hdr_gen.sv:1:8: 'import::*' in $unit scope may pollute global namespace.

    Put every import inside the module header. Each file then compiles on its own, in any order after its packages.

    Check yourself A build log shows only: hdr_check.sv:2: syntax error and hdr_check.sv:1: Errors in port declarations. Line 2 is input header_t hdr_i. What are the two likely causes, and how do you tell them apart?

    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.

    Check yourself Verilator prints Import package not found: 'pkt_pkt'. Will reordering the file list fix it?

    No. No file declares pkt_pkt; it is a typo for pkt_pkg in the import. Correct the name.

    Remember

    • Before declaration with a second location means file order; Can't find means a missing import; Import package not found means a typo.

    • Two wildcard imports that export the same name are ambiguous; one tool may silently pick by import order. Qualify the name.

    • Keep imports inside module headers and the order in one file list, packages first, checked by a script before the compiler runs.

    Rule of thumb: when a package error is unclear in one tool, run the second one: the message that names a location or a package is the cause.

    How this was checked

    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.

    Keep going

    • Code lab: Package functions

    • Interview: run a mock interview on this topic

    Related topics

    • Packages and compile order

    • Compilation and elaboration

    • Mini project: a reusable FIFO IP

    Previous

    272 / 350

    Next: Mini Project: a Reusable FIFO IP

    Up next

    Up nextMini Project: a Reusable FIFO IP

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Packages and Compile Order
    • Packed Structs and Unions
    • Parameter Types and Guards