Skip to main content

xmake 的配置参数

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

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

必要参数

必要参数为必须在 xmake.lua 中对应的 target 添加的,否则进行编译的时候会报错。

  1. add_rules("verilua")

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

  2. add_toolchains(<toolchain>)

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

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

    添加需要进行仿真的文件,可以在一个语句中同时添加多个文件,也可以分为多个语句来添加多个文件。

    • 对于 HVL 场景,可以是 Verilog/SystemVerilog 文件、Lua 文件。

      xmake.lua
      target("test", function()
      add_rules("verilua")
      add_toolchains("@verilator")
      add_files("src/main.sv", "src/main.lua")
      add_files("src/other.v")

      -- ...
      end)
    • 对于 WAL 场景,可以是波形文件、Lua文件。

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

      -- ...
      end)
      此时 add_files 只能添加一个波形文件
  4. set_values("cfg.top", <top module name>)

    设置顶层模块的名称,这是 Verilua 访问信号层次结构的根节点,对于 HVL/WAL 场景,这个参数必须设置。

    • HVL 场景:通常设置为实际的顶层 DUT 名称(如 DesignCounter) 或 testbench_gen 生成的 testbench 名称(tb_top
    • WAL 场景:根据波形文件的层次结构设置,详见下方说明

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

  5. set_values("cfg.lua_main", <lua main file>)

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

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

cfg.top 在不同场景下的设置指南

HVL 场景(使用 @verilator、@iverilog、@vcs、@xcelium)

通常情况下,cfg.top 应该指向实际的顶层模块名称:

set_values("cfg.top", "Design")  -- 直接指定 DUT 名称

如果使用 Verilua 的 testbench_gen 工具(Verilua 会自动生成 testbench), cfg.top 应该指向生成的 testbench 模块:

set_values("cfg.top", "tb_top")  -- 指向 testbench_gen 生成的模块

WAL 场景(使用 @wave_vpi)

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

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

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

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

这样可以访问:

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

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

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

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

可选参数

  1. set_values("cfg.user_cfg", <user cfg file>)

    设置用户自定义的配置文件,这个配置文件是一个 Lua 脚本,格式如下所示:

    my_cfg.lua
    local cfg = {}

    cfg.value1 = 123
    cfg.value2 = "hello"

    return cfg

    重点在于这个 Lua 脚本要返回一个 key-value 格式的 table。

    当用户在 xmake.lua 中设置了这个配置文件的时候(set_values("cfg.user_cfg", "my_cfg.lua")),那么在仿真进行的时候,可以通过全局变量 cfg 获取到这个 table 中的值,例如:

    main.lua
    fork {
    function ()
    print("cfg.value1 => ", cfg.value1)
    print("cfg.value2 => ", cfg.value2)

    assert(cfg.value1 == 123)
    assert(cfg.value2 == "hello")
    end
    }
  2. set_values("cfg.tb_gen_flags", <flags for testbench_gen>) / add_values("cfg.tb_gen_flags", "<flags for testbench_gen>")

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

    xmake 中 set_valuesadd_values 的区别
    • set_values(<key>, <value>)<key> 进行单次赋值,调用多次 set_values 时,会覆盖之前的值,一个 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 文档中此处的说明。
  3. set_values("<sim>.flags", <flags used in compilation>) / add_values("<sim>.flags", "<flags used in compilation>")

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

    注意
    • 对于 HVL 场景,目前 <sim> 可选值为 verilatoriverilogvcsxcelium
    • 对于 WAL 场景,这一设置不起作用。
  4. 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> 可选值为 verilatoriverilogvcsxcelium
    • 对于 WAL 场景,这一设置不起作用。
  5. 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> 可选值为 verilatoriverilogvcsxcelium
    • 对于 WAL 场景,这一设置不起作用。
    run_prefixrun_flags 的位置区别

    <run_prefix> <binary> <run_flags>

  6. set_values("cfg.build_dir_name", <build directory name>)

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

    构建目录生成的位置

    默认情况下为:./build/<simulator>/<top module name>,如果使用了 set_values("cfg.build_dir_name", "SomeName"),那么会使用用户自定义的名称:./build/<simulator>/SomeName。不过请注意,./build/<simulator> 是必须存在的,不支持更改。

  7. set_values("cfg.build_dir_path", <build directory path>)

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

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

    最终构建目录为 <build_dir_path>/<build_dir_name>,如未设置 build_dir_name,则默认为顶层模块名。

  8. set_values("cfg.version_required", "<version constraint>")

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

    set_values("cfg.version_required", ">=1.0.0")

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

  9. set_values("cfg.no_internal_clock", "1")

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

    示例:

    xmake.lua
    target("my_test", function()
    add_rules("verilua")
    add_toolchains("@verilator")
    set_values("cfg.top", "Top")
    set_values("cfg.lua_main", "main.lua")
    add_files("Top.v", "main.lua")
    set_values("cfg.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
    }