#!/usr/bin/env perl ###################################################################### # # This program is free software; you can redistribute it and/or modify it # under the terms of either the GNU Lesser General Public License Version 3 # or the Perl Artistic License Version 2.0. # SPDX-FileCopyrightText: 2025-2026 Wilson Snyder # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 # ###################################################################### require 5.006_001; use warnings; use Getopt::Long; use FindBin qw($RealBin $RealScript); use IO::File; use Pod::Usage; use Cwd qw(realpath); use strict; use vars qw($Debug @Opt_Verilator_Sw); ####################################################################### ####################################################################### # main autoflush STDOUT 1; autoflush STDERR 1; $Debug = 0; my $opt_aslr; my $opt_gdb; my $opt_rr; my $opt_gdbbt; my $opt_quiet_exit; my $opt_unlimited_stack = 1; my $opt_valgrind; # No arguments can't do anything useful. Give help if ($#ARGV < 0) { pod2usage(-exitstatus => 2, -verbose => 0); } # Insert debugging options up front # (VERILATOR_TEST_FLAGS is not a documented nor official supported feature) push @ARGV, (split ' ', $ENV{VERILATOR_TEST_FLAGS} || ""); # We sneak a look at the flags so we can do some pre-environment checks # All flags will hit verilator... foreach my $sw (@ARGV) { push @Opt_Verilator_Sw, $sw; } Getopt::Long::config("no_auto_abbrev", "pass_through"); if (! GetOptions( # Major operating modes "help" => \&usage, "debug" => \&debug, # "version!" => \&version, # Also passthru'ed # Switches "aslr!" => \$opt_aslr, "gdb!" => \$opt_gdb, "gdbbt!" => \$opt_gdbbt, "quiet!" => \$opt_quiet_exit, # As -quiet implies -quiet-exit "quiet-exit!" => \$opt_quiet_exit, "rr!" => \$opt_rr, "unlimited-stack!" => \$opt_unlimited_stack, "valgrind!" => \$opt_valgrind, # Additional parameters "<>" => sub {}, # Ignored )) { pod2usage(-exitstatus => 2, -verbose => 0); } # WARNING: $verilator_pkgdatadir_relpath is substituted during Verilator 'make install' my $verilator_pkgdatadir_relpath = ".."; my $verilator_root = realpath("$RealBin/$verilator_pkgdatadir_relpath"); if (defined $ENV{VERILATOR_ROOT}) { if ((!-d $ENV{VERILATOR_ROOT}) || $verilator_root ne realpath($ENV{VERILATOR_ROOT})) { warn "%Error: verilator: VERILATOR_ROOT is set to inconsistent path. Suggest leaving it unset.\n"; warn "%Error: VERILATOR_ROOT=$ENV{VERILATOR_ROOT}\n"; exit 1; } } else { print "export VERILATOR_ROOT='$verilator_root'\n" if $Debug; $ENV{VERILATOR_ROOT} = $verilator_root; } if ($opt_gdbbt && !gdb_works()) { warn "-Info: --gdbbt ignored: gdb doesn't seem to be working\n" if $Debug; $opt_gdbbt = 0; } # Determine runtime flags and run # Opt_Verilator_Sw is what we want verilator to see on its argc/argv. # Starting with that, escape all special chars for the shell; # The shell will undo the escapes and the verilator binary should # then see exactly the contents of @Opt_Verilator_Sw. my @quoted_sw = map { sh_escape($_) } @Opt_Verilator_Sw; if ($opt_gdb) { # Generic GDB interactive run (ulimit_stack_unlimited() . aslr(0) . ($ENV{VERILATOR_GDB} || "gdb") . " " . verilator_bin() # Note, uncomment to set breakpoints before running: # ." -ex 'break main'" # Note, we must use double-quotes ("run ") # and not single ('run ') below. Bash swallows # escapes as you would expect in a double-quoted string. # That's not true for a single-quoted string, where \' # actually terminates the string -- not what we want! . " -ex \"run " . join(' ', @quoted_sw) . "\"" . " -ex 'set width 0'" . " -ex 'bt'"); } elsif ($opt_rr) { # Record with rr run (ulimit_stack_unlimited() . aslr(0) . "rr record " . verilator_bin() . " " . join(' ', @quoted_sw)); } elsif ($opt_gdbbt && $Debug) { # Run under GDB to get gdbbt run (ulimit_stack_unlimited() . aslr(0) . "gdb" . " " . verilator_bin() . " --batch --quiet --return-child-result" . " -ex \"run " . join(' ', @quoted_sw)."\"" . " -ex 'set width 0'" . " -ex 'bt' -ex 'quit'"); } elsif ($opt_valgrind) { # Run under valgrind my $valgrind_bin = ($ENV{VERILATOR_VALGRIND} || "valgrind --error-exitcode=1 --max-stackframe=2815880" # Magic number suggested by Valgrind, may need to be increased in future # if you get warnings. See: https://valgrind.org/docs/manual/manual-core.html#opt.max-stackframe ); run (ulimit_stack_unlimited() . aslr(0) . $valgrind_bin . " " . verilator_bin() . " " . join(' ', @quoted_sw)); } elsif ($Debug) { # Debug run(ulimit_stack_unlimited() . aslr(0) . verilator_bin() . " " . join(' ', @quoted_sw)); } else { # Normal, non-gdb run(ulimit_stack_unlimited() . aslr(1) . verilator_bin() . " " . join(' ', @quoted_sw)); } #---------------------------------------------------------------------- sub usage { pod2usage(-verbose => 2, -exitval => 0, -output => \*STDOUT); } sub debug { shift; my $level = shift; $Debug = $level || 3; } ####################################################################### ####################################################################### # Builds sub verilator_bin { my $basename = ($ENV{VERILATOR_BIN} || ($Debug ? "verilator_bin_dbg" : "verilator_bin")); if (-x "$RealBin/$basename" || -x "$RealBin/$basename.exe") { return "$RealBin/$basename"; } else { return $basename; # Find in PATH } } ####################################################################### ####################################################################### # Utilities sub gdb_works { $! = undef; # Cleanup -x system("gdb /bin/echo" . " --batch-silent --quiet --return-child-result" . " -ex 'run -n'" # `echo -n` . " -ex 'set width 0'" . " -ex 'bt'" . " -ex 'quit'"); my $status = $?; return $status == 0; } sub aslr { my $want_on = shift; $want_on = $opt_aslr if defined $opt_aslr; if (!$want_on) { my $ok = `setarch --addr-no-randomize echo ok 2>/dev/null` || ""; if ($ok =~ /ok/) { return "setarch --addr-no-randomize "; } } return ""; } sub ulimit_stack_unlimited { return "" if !$opt_unlimited_stack; my $limit = "unlimited"; # AddressSanitizer doesn't work with 'ulimit -s unlimted' if (`${\(verilator_bin())} --get-supported DEV_ASAN` eq "1\n") { # Use host 'physical memory / #cores / 8' instead open(my $fh, "<", "/proc/meminfo") || die "Can't read host memory for asan"; while (<$fh>) { if (m/MemTotal:\s+(\d+)\s+kB/) { $limit = int(int($1)/`nproc`/8); last; } } close($fh); } system("ulimit -s $limit 2>/dev/null"); my $status = $?; if ($status == 0) { return "ulimit -s $limit 2>/dev/null; exec "; } else { return ""; } } sub run { # Run command, check errors my $command = shift; $! = undef; # Cleanup -x print "\t$command\n" if $Debug >= 3; system($command); my $status = $?; if ($status) { if ($! =~ /no such file or directory/i) { warn "%Error: verilator: Misinstalled, or VERILATOR_ROOT might need to be in environment\n"; } if ($Debug) { # For easy rerunning warn "%Error: export VERILATOR_ROOT=" . ($ENV{VERILATOR_ROOT} || "") . "\n"; warn "%Error: $command\n"; } my $signal = ($status & 127); if ($signal) { if ($signal == 4 # SIGILL || $signal == 8 # SIGFPA || $signal == 11) { # SIGSEGV warn "%Error: Verilator internal fault, sorry. " . "Suggest trying --debug --gdbbt\n" if !$Debug; } elsif ($signal == 6) { # SIGABRT warn "%Error: Verilator aborted. " . "Suggest trying --debug --gdbbt\n" if !$Debug; } else { warn "%Error: Verilator threw signal $signal. " . "Suggest trying --debug --gdbbt\n" if !$Debug; } } if (!$opt_quiet_exit && ($status != 256 || $Debug)) { # i.e. not normal exit(1) warn "%Error: Command Failed $command\n"; } exit $! if $!; # errno exit $? >> 8 if $? >> 8; # pass along child exit code exit 128 + $signal; # last resort } } sub sh_escape { my ($arg) = @_; # This is similar to quotemeta() but less aggressive. # There's no need to escape hyphens, periods, or forward slashes # for the shell as these have no special meaning to the shell. $arg =~ s/([^0-9a-zA-Z_\-\+\=\.\/:])/\\$1/g; return $arg; } ####################################################################### ####################################################################### package main; __END__ =pod =head1 NAME Verilator - Lint, compile and simulate SystemVerilog code using C++/SystemC =head1 SYNOPSIS verilator --help verilator --version verilator --binary -j 0 [options] [source_files.v]... [opt_c_files.cpp/c/cc/a/o/so] verilator --cc [options] [source_files.v]... [opt_c_files.cpp/c/cc/a/o/so] verilator --sc [options] [source_files.v]... [opt_c_files.cpp/c/cc/a/o/so] verilator --lint-only -Wall [source_files.v]... =head1 DESCRIPTION The "Verilator" package converts all synthesizable, and many behavioral, Verilog and SystemVerilog designs into a C++ or SystemC model that after compiling can be executed. Verilator is not a traditional simulator, but a compiler. For documentation see L. =head1 ARGUMENT SUMMARY This is a short summary of the arguments to the "verilator" executable. See L for the detailed descriptions of these arguments. =for VL_SPHINX_EXTRACT "_build/gen/args_verilator.rst" Verilog package, module, and top module filenames Optional C++ files to compile in Optional C++ files to link in +1364-1995ext+ Use Verilog 1995 with file extension +1364-2001ext+ Use Verilog 2001 with file extension +1364-2005ext+ Use Verilog 2005 with file extension +1800-2005ext+ Use SystemVerilog 2005 with file extension +1800-2009ext+ Use SystemVerilog 2009 with file extension +1800-2012ext+ Use SystemVerilog 2012 with file extension +1800-2017ext+ Use SystemVerilog 2017 with file extension +1800-2023ext+ Use SystemVerilog 2023 with file extension --no-aslr Disable address space layout randomization --no-assert Disable all assertions --no-assert-case Disable unique/unique0/priority-case assertions --autoflush Flush streams after all $displays --bbox-sys Blackbox unknown $system calls --bbox-unsup Blackbox unsupported language features --binary Build model binary --build Build model executable/library after Verilation --build-dep-bin Override build dependency Verilator binary --build-jobs Parallelism for --build --cc Create C++ output -CFLAGS C++ compiler arguments for makefile --compiler Tune for specified C++ compiler --compiler-include Include additional header in the precompiled one --constraint-array-limit Maximum array size for constraint array reduction --converge-limit Tune convergence settle time --coverage Enable all coverage --coverage-expr Enable expression coverage --coverage-expr-max Maximum permutations allowed for an expression --coverage-line Enable line coverage --coverage-max-width Maximum array depth for coverage --coverage-toggle Enable toggle coverage --coverage-underscore Enable coverage of _signals --coverage-user Enable SVL user coverage -D[=] Set preprocessor define --debug Enable debugging --debug-check Enable debugging assertions --no-debug-leak Disable leaking memory in --debug mode --debugi Enable debugging at a specified level --debugi- Enable debugging a source file at a level --no-decoration Disable comments and lower spacing level --decorations Set output comment and spacing level --default-language Default language to parse +define+= Set preprocessor define --diagnostics-sarif Enable SARIF diagnostics output --diagnostics-sarif-output Set SARIF diagnostics output file --dpi-hdr-only Only produce the DPI header file --dump- Enable dumping everything in source file --dump-defines Show preprocessor defines with -E --dump-dfg Enable dumping DfgGraphs to .dot files --dump-graph Enable dumping V3Graphs to .dot files --dump-inputs Enable dumping preprocessed input files --dump-tree Enable dumping Ast .tree files --dump-tree-addrids Use short identifiers instead of addresses --dump-tree-dot Enable dumping Ast .tree.dot debug files --dump-tree-json Enable dumping Ast .tree.json files and .tree.meta.json file --dumpi- Enable dumping everything in source file at level --dumpi-dfg Enable dumping DfgGraphs to .dot files at level --dumpi-graph Enable dumping V3Graphs to .dot files at level --dumpi-tree Enable dumping Ast .tree files at level --dumpi-tree-json Enable dumping Ast .tree.json files at level -E Preprocess, but do not compile --emit-accessors Emit getter and setter methods for model top class --error-limit Abort after this number of errors --exe Link to create executable --expand-limit Set expand optimization limit -F Parse arguments from a file, relatively -f Parse arguments from a file -FI Force include of a file --flatten Force inlining of all modules, tasks and functions --func-recursion-depth Maximum recursive constant function depth --future0