Skip to main content

xmake 的配置参数

Verilua 的 HVL/WAL 场景下的工程管理使用的是 xmake,因此在 xmake 中支持多种可配置的参数,下面将对其进行说明。

用户可以使用 xmake 来编写灵活多样的 xmake.lua 文件来构建工程,具体可以参考 xmake 官方文档

概览​

这一页介绍 Verilua 在 xmake.lua 中常用的配置项,以及它们分别影响什么。

必需配置​

这些配置必须在 xmake.lua 中对应的 target 里设置,否则构建或运行时会报错。

启用 Verilua​

对应配置:add_rules("verilua")

对于所有的 HVL/WAL 场景下的工程,都需要在 xmake 的 target 中添加这一句配置,否则将无法正常使用 Verilua。

选择仿真后端​

对应配置:add_toolchains(<toolchain>)

添加具体的仿真器(Verilua 中称为仿真后端(Backend))。

  • 对于 HVL 场景,目前 <toolchain> 的可选值为 @verilator、@iverilog、@vcs、 @xcelium,分别对应了开源的 Verilator、开源的 Icarus Verilog、商业的 Synopsys VCS、Cadence Xcelium 等仿真器。
  • 对于 WAL 场景,目前 <toolchain> 的可选值为 @wave_vpi,wave_vpi 是 Verilua 开发的一个用于仿真波形的仿真后端,目前支持的波形格式为: VCD、FST、FSDB。

添加输入文件​

对应配置:add_files(...)

添加需要进行仿真的文件,可以在一个语句中同时添加多个文件,也可以分为多个语句来添加多个文件。add_files 支持 xmake 的通配符(glob)写法,便于批量添加源文件。

对于 HVL 场景,可以是 Verilog/SystemVerilog 文件,以及需要参与工程管理的 Lua 文件。

xmake.lua
target("test", function()
add_rules("verilua")
add_toolchains("@verilator")
add_files("src/main.sv")
add_files("src/other.v")
add_files("rtl/**/*.sv") -- 通配符:递归添加 rtl 目录下所有 .sv 文件

-- ...
end)

对于 WAL 场景,可以是波形文件,以及需要复用的 Lua 文件。

xmake.lua
target("test", function()
add_rules("verilua")
add_toolchains("@wave_vpi")
add_files("./test.vcd")

-- ...
end)
此时 add_files 只能添加一个波形文件

set_values("verilua.lua_main", ...) 指向的 Lua 入口脚本不需要额外添加到 add_files(...) 中。

移除输入文件​

对应配置:remove_files(...)

从 add_files 已添加的文件列表中移除指定文件,支持与 add_files 相同的通配符(glob)写法。

add_files("src/*.sv")
remove_files("src/test.sv") -- 移除单个文件
remove_files("src/wip_*.sv") -- 通配符批量移除
remove_files("src/subdir/*.sv") -- 移除 subdir 下所有 .sv

指定顶层模块​

对应配置:set_values("verilua.top", <top module name>)

设置 DUT 顶层模块的名称。对于 HVL/WAL 场景,这个参数必须设置。

  • HVL 场景:设置为实际的顶层 DUT 名称(如 Design、Counter),Verilua 会据此生成 testbench 并自动将运行期 cfg.top 设为 testbench 顶层名。
  • WAL 场景:根据波形文件的层次结构设置,详见下方说明

例如在这个例子 中我们顶层 DUT 模块的名称是 Design,因此可以这么设置:set_values("verilua.top", "Design")。

指定 Lua 入口脚本​

对应配置:set_values("verilua.lua_main", <lua main file>)

设置仿真时候执行的 lua 主脚本文件,对于 HVL/WAL 场景,这个参数必须设置,例如在这个例子 中我们的 lua 主脚本文件是 LuaMain.lua,因此可以这么设置:set_values("verilua.lua_main", "LuaMain.lua")。

<lua main file> 是一个具体的文件,可以包含路径。

该入口脚本由 verilua.lua_main 单独指定,不需要再放进 add_files(...)。

顶层模块的设置指南​

HVL 场景:verilua.top 应始终填写 DUT 顶层模块名称:

set_values("verilua.top", "Design") -- 始终指定 DUT 名称

Verilua 会自动生成 testbench(默认名 tb_top)并例化该 DUT。运行期 Lua 侧的 cfg.top 会被自动映射为 tb_top(即信号层次的根节点),无需手动设置。

WAL 场景:verilua.top 应该设置为波形文件中的顶层模块名称。这取决于波形是如何生成的:

场景 1:波形由 Verilua 的 HVL 仿真生成

如果波形文件是通过 Verilua 的 HVL 仿真生成的(如 WAL 示例中的 gen_wave), Verilua 会自动使用 testbench_gen 生成 tb_top 模块,波形文件的顶层是 tb_top:

set_values("verilua.top", "tb_top")

这样可以访问:

  • Testbench 信号(时钟、复位等)
  • 导出的 DUT 端口
  • 通过层次路径访问 DUT 内部信号(如 tb_top.uut.count_reg)

场景 2:波形直接来自 RTL(无 testbench 层)

如果波形文件是直接从 RTL 编译生成的(不通过 Verilua,没有 testbench), verilua.top 应该指向实际的 RTL 顶层模块:

set_values("verilua.top", "top") -- 或者你的实际顶层模块名
如何确定应该使用哪个值?
  1. 查看波形文件: 在波形查看器(如 GTKWave、Verdi)中打开波形文件,查看顶层模块名称
  2. 查看信号路径: 如果信号路径包含 tb_top. 前缀,则应使用 verilua.top = "tb_top"
  3. 参考生成方式:
    • 通过 Verilua 的 HVL 仿真生成 → 通常包含 tb_top 层次
    • 直接用仿真器编译 RTL(不经过 Verilua)→ 通常是实际的模块名

testbench_gen 配置​

传递额外的 testbench_gen 参数​

对应配置:set_values("verilua.tb_gen_flags", <flags for testbench_gen>) / add_values("verilua.tb_gen_flags", "<flags for testbench_gen>")

设置需要传递给 testbench_gen 的额外参数,具体支持的 flags 可以参考 这里 的介绍。

xmake 中 set_values 和 add_values 的区别
  • set_values(<key>, <value>) 对 <key> 进行单次赋值,调用多次 set_values 时,会覆盖之前的值。需要一次设置多个值时,也可以传入多个 <value>;
set_values("key", "value1") -- "key" = "value1"
set_values("key", "value2") -- "key" = "value2", the previous value "value1" is overwritten
  • add_values(<key>, <value> ...) 对 <key> 进行多次赋值,调用多次 add_values 时,会合并之前的值,一个 add_values 可以有多个 <value>。
add_values("key", "value1") -- "key" = "value1"
add_values("key", "value2") -- "key" = {"value1", "value2"}, the previous value "value1" is merged

-- equivalent to

set_values("key", "value1", "value2")
  • 也可以参考 xmake 文档中此处的说明。

控制内部时钟生成​

对应配置:set_values("verilua.no_internal_clock", "1")

禁用自动时钟生成,适用于需要自定义时钟的场景。此时需在主 Lua 文件中手动生成时钟信号。

示例:

xmake.lua
target("my_test", function()
add_rules("verilua")
add_toolchains("@verilator")
set_values("verilua.top", "Top")
set_values("verilua.lua_main", "main.lua")
add_files("Top.v")
set_values("verilua.no_internal_clock", "1") -- 禁用自动时钟生成
end)

对应的 main.lua 需手动生成时钟信号:

main.lua
fork {
clock_gen_task = function()
local clock = dut.clock:chdl()
while true do
clock:set(1)
await_time_ns(2)
clock:set(0)
await_time_ns(2)
end
end,

another_task = function()
-- ...
end
}

仿真运行配置​

添加编译参数​

对应配置:set_values("<sim>.flags", <flags used in compilation>) / add_values("<sim>.flags", "<flags used in compilation>")

用来添加需要传递给仿真器进行编译的额外参数,具体支持的 flags 可以与使用的仿真器相关。

注意
  • 对于 HVL 场景,目前 <sim> 可选值为 verilator、iverilog、vcs 、 xcelium。
  • 对于 WAL 场景,这一设置不起作用。

切换到 nosim 时复用其他仿真器的 flags​

对应配置:set_values("verilua.infer_nosim_flags", <simulators>)

nosim 后端底层是 slang,只能理解 slang 自己的参数。打开这个开关后,构建 nosim 时会扫描 verilator.flags、vcs.flags、iverilog.flags、xcelium.flags,把两边都支持的写法翻译成 slang 拼写后追加进 nosim.flags,切到 nosim 时无需重复维护这些参数。取值写 "1" 表示复用全部四个来源,也可以写逗号分隔的名单,只复用其中一部分。

xmake.lua
set_values("vcs.flags", "+incdir+/path/to/include", "+define+MY_MACRO=1", "-timescale=1ps/1ps")
set_values("verilator.flags", "-I/path/to/include", "-DMY_MACRO=1")

-- 切到 nosim(add_toolchains("@nosim"))时自动带上上面的 -I / -D / --timescale
set_values("verilua.infer_nosim_flags", "1")

-- 也可以只复用其中一个来源
-- set_values("verilua.infer_nosim_flags", "vcs")

翻译范围(其余参数一律丢弃,因为 slang 不认识这些厂商私有选项)。识别只看写法:同一个写法写在任何一个 *.flags 里都会被翻译,报错文案里的仿真器名用于指明来源:

nosim(slang)识别到的写法
-I <dir>-I <dir>、-I<dir>、+incdir+...、-incdir <dir>
-D <macro>-D <macro>、-D<macro>、+define+...、-define <macro>
-y <dir>-y <dir>
+libext+<ext>+libext+...
--timescale <v>--timescale <v>、--timescale-override <v>、--timescale=、--timescale-override=、-timescale=、+timescale+、-timescale <v>

常见对应关系:+incdir+ / +define+ / -timescale= 是 VCS 写法,-I<dir> / --timescale 是 Verilator 写法,-incdir / -define 是 Xcelium 写法,+timescale+ 是 Icarus 写法。

  • 不设置该开关时行为完全不变(不读取也不翻译任何 *.flags)。
  • +incdir+dir_a+dir_b 这种 + 分隔的多值会展开成多个 -I。+ 在这里就是分隔符,所以路径本身含 + 时请改用 -I <dir> 写法。
  • 参数按空白切分,值里不能带空格,否则只会取到第一个词。
  • 没有 nosim 等价写法的参数会被丢弃,并在构建时打印一行提示(按来源 *.flags 分组);需要照样传给 nosim 时写进 nosim.flags。
  • 合并以参数种类为单位:-I / -y 按规范化后的目录比较,+libext+ 比较扩展名,-D 比较宏名,--timescale 按单值处理。因此同一个目录的两种写法(例如 -I a/../b 和 -I b)只会进 nosim.flags 一次。
  • 宏和 timescale 是单值。两个来源给出不同的值时,构建会直接报错并列出两侧的来源与取值。宏名写法不同但取值相同(例如 -DNAME 和 -DNAME=)视为同一个定义,只保留一种写法。
  • 自己写在 nosim.flags 里的同类参数不重复追加;与推断结果冲突时,报错会指出 nosim.flags 里的取值。
  • 只指定部分来源(例如 "verilator,vcs")时,其余仿真器的 *.flags 不参与推断。同时维护多个仿真器时,可以让 nosim 只复用其中一部分。
  • 推断出的 -I 同时会传给 testbench_gen;宏定义不会,testbench_gen 需要用 verilua.tb_gen_flags 自行传 -D。
  • -f / -F 文件列表不在翻译范围内,-top / --top-module 等顶部模块参数也不翻译(由 verilua.top / tb_top 决定)。

内联 Verilator control file​

对应配置:set_values("verilua.verilator_config", <vlt content>) / add_values("verilua.verilator_config", <vlt content>)

把 Verilator control file 内容直接写在 xmake.lua 里,无需单独维护文件,也不用 add_files("*.vlt")。构建时会写入当前 target 构建目录下的 verilua_generated.vlt。语法与可用指令见 Verilator Control Files。

  • 仅 verilator 后端生效;其它仿真器忽略
  • 只叠加指令,不会隐式关掉默认 --public-flat-rw
  • 内容里若没有 verilator_config,会自动包一层 `verilator_config
  • 可与 add_files("*.vlt") 同时使用;两者都会传给 Verilator
  • 内容(或任一 .vlt)含 forceable 时,构建期要求 Verilator ≥ 5.050(VPI force/release)
xmake.lua
target("test", function()
add_rules("verilua")
add_toolchains("@verilator")
add_files("rtl/top.sv")
set_values("verilua.top", "top")
set_values("verilua.lua_main", "main.lua")

-- forceable only; default --public-flat-rw still applies
set_values("verilua.verilator_config", [[
forceable -module "top" -var "i_ready"
]])
end)

关闭默认 --public-flat-rw​

对应配置:set_values("verilua.verilator_no_public_flat_rw", "1")

默认始终注入 --public-flat-rw(Verilua VPI 需要)。若要用 .vlt / verilua.verilator_config 做精细 public_flat_* 以提升性能,显式关闭:

xmake.lua
set_values("verilua.verilator_no_public_flat_rw", "1")
set_values("verilua.verilator_config", [[
public_flat_rw -module "tb_top" -var "*"
public_flat_rw -module "top" -var "*"
]])
-- 或 add_files("config.vlt")

Verilator C++ 优化级别(OPT_FAST / OPT_SLOW)​

对应配置:

  • set_values("verilua.verilator_opt_fast", <flags>):快路径(每周期执行的 model 代码),默认 -O3 -march=native
  • set_values("verilua.verilator_opt_slow", <flags>):慢路径(初始化/收尾),默认 -O0

传给 Verilator 生成的 Makefile 的 OPT_FAST / OPT_SLOW,不是 verilator CLI 参数。日常开发想加快编译可把 fast 降为 -O0:

xmake.lua
set_values("verilua.verilator_opt_fast", "-O0")

添加运行参数​

对应配置:set_values("<sim>.run_flags", <flags used at runtime>) / add_values("<sim>.run_flags", "<flags used at runtime>")

用来添加需要传递给编译后的二进制文件运行时的额外参数。例如 Verilator 编译得到的二进制文件通常叫 Vtb_top,则可以使用 set_values("verilator.run_flags", "--help") 来添加一个运行时参数,这样在 xmake 执行 run 的时候就会加上这个参数。运行仿真的时候等价于 Vtb_top --help。

注意
  • 对于 HVL 场景,目前 <sim> 可选值为 verilator、iverilog、vcs、 xcelium。
  • 对于 WAL 场景,这一设置不起作用。

添加运行前缀​

对应配置:set_values("<sim>.run_prefix", <prefix flags used at runtime>) / add_values("<sim>.run_prefix", "<prefix flags used at runtime>")

用来添加需要传递给编译后的二进制文件运行时的额外前缀参数。例如 Verilator 编译得到的二进制文件通常叫 Vtb_top,则可以使用 set_values("verilator.run_prefix", "gdb --args") 来添加一个运行时前缀参数,这样在 xmake 执行 run 的时候就会加上这个参数。运行仿真的时候等价于 gdb --args Vtb_top。

注意
  • 对于 HVL 场景,目前 <sim> 可选值为 verilator、iverilog、vcs、 xcelium。
  • 对于 WAL 场景,这一设置不起作用。
run_prefix 和 run_flags 的位置区别

<run_prefix> <binary> <run_flags>

构建目录配置​

设置构建目录名称​

对应配置:set_values("verilua.build_dir_name", <build directory name>)

设置构建目录的名称,如果不设置,默认为 set_values("verilua.top", <top module name>) 的值。

构建目录生成的位置

默认情况下为:./build/<simulator>/<top module name>,如果使用了 set_values("verilua.build_dir_name", "SomeName"),那么会使用用户自定义的名称:./build/<simulator>/SomeName。这里的 ./ 默认表示当前工程中 xmake.lua 所在的目录;文档中的命令示例也默认在该目录下执行。

设置构建目录位置​

对应配置:set_values("verilua.build_dir_path", <build directory path>)

设置构建目录的父路径。例如:

set_values("verilua.build_dir_path", "/tmp/builds")

最终构建目录为 <build_dir_path>/<build_dir_name>,如未设置 build_dir_name,则默认为顶层模块名。如果 verilua.build_dir_path 使用相对路径,则同样默认相对于当前工程中 xmake.lua 所在的目录解析。

其他配置​

加载用户自定义配置​

对应配置:set_values("verilua.user_cfg", <user cfg file>, ...) 或 add_values("verilua.user_cfg", <user cfg file>)

用于指定一个或多个用户自定义 Lua 配置文件。

这些 Lua 文件都需要返回一个 table;在运行期,table 里的字段会被合并到全局变量 cfg 中。

多个文件按声明顺序依次加载合并,后加载的文件覆盖先加载的同名字段。srcs 和 deps 除外,这两个字段会追加:

set_values("verilua.user_cfg", "common/cfg.lua", "case/cfg.lua")
add_values("verilua.user_cfg", "extra/cfg.lua") -- 追加在最后,优先级最高

每个配置文件按完整路径加载,即使多个配置文件同名(都叫 cfg.lua)也不会互相覆盖。配置文件内可以 require 同目录下的模块。合并顺序与同名模块的限制见 global_configuration。

常见误解

这里的 verilua.user_cfg 只是 xmake 配置项名,不代表运行期存在 cfg.user_cfg 这个字段。

完整的运行期行为说明见 global_configuration。

限制最低 Verilua 版本​

对应配置:set_values("verilua.require_version", "<version constraint>")

指定最低 Verilua 版本要求。例如:

set_values("verilua.require_version", ">=1.0.0")

构建时会自动校验当前 Verilua 版本是否满足要求。

相关文档​

  • 仿真后端默认参数:了解 Verilua 为每个后端自动注入的编译/运行参数(寄存器初始化、timescale 等)。
  • 编写 xmake.lua:查看这些参数在完整工程中的组织方式。
  • HVL 示例:对照最小示例理解 verilua.top 和 verilua.lua_main 的基本用法。
  • Testbench 自动生成流程:查看 verilua.tb_gen_flags 等参数如何影响生成结果。
  • 全局配置信息:了解构建期 verilua.xxx 与运行期全局 cfg 的关系。