summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author24bit-xjkp <[email protected]>2026-01-01 18:08:00 +0800
committer24bit-xjkp <[email protected]>2026-01-01 18:08:00 +0800
commit13bb0e6506af38aa303c9adc49125b4a18ebe388 (patch)
tree21825a0d5c2fe4a178cf1a5cb517a7829092948a
parent34a2d99adfd90c5dac77f0201528961712e92912 (diff)
refactor(rules/verilator): Switch from cmake to json format for Verilator build file parsing
1. The "-make cmake" option of Verilator is deprecated and will be removed in future. See [Deprecations](https://verilator.org/guide/latest/deprecations.html). Use "-make cmake" option in Verilator v5.042 will lead Verilator to return a non-zero value, thus the script reports an error. 2. Verilator can generate build options in json format which can be parsed easier, so we switch from cmake to json format. 3. Add new SystemVerilog language standard `v1800-2023` support. 4. Fix the issue with c++ language standard settings. BREAKING CHANGE: CMake build file parsing is deprecated.
-rw-r--r--xmake/rules/verilator/verilator.lua183
1 files changed, 78 insertions, 105 deletions
diff --git a/xmake/rules/verilator/verilator.lua b/xmake/rules/verilator/verilator.lua
index 2867d1e09..0fb56f306 100644
--- a/xmake/rules/verilator/verilator.lua
+++ b/xmake/rules/verilator/verilator.lua
@@ -22,55 +22,28 @@
import("utils.progress")
import("core.base.hashset")
import("core.project.depend")
-import("private.action.build.object", {alias = "build_objectfiles"})
+import("private.action.build.object", { alias = "build_objectfiles" })
+import("core.base.json")
--- parse sourcefiles from cmakefile
-function _get_sourcefiles_from_cmake(target, cmakefile)
- local global_classes = {}
- local classefiles_slow = {}
- local classefiles_fast = {}
- local supportfiles_slow = {}
- local supportfiles_fast = {}
- local targetname = target:name()
- local verilator_root = assert(target:data("verilator.root"), "no verilator_root!")
- io.gsub(cmakefile, "set%((%S-) (.-)%)", function (key, values)
- if key == targetname .. "_GLOBAL" then
- -- get global class source files
- -- set(hello_GLOBAL "${VERILATOR_ROOT}/include/verilated.cpp" "${VERILATOR_ROOT}/include/verilated_threads.cpp")
- for classfile in values:gmatch("\"(.-)\"") do
- classfile = classfile:gsub("%${VERILATOR_ROOT}", verilator_root)
- if os.isfile(classfile) then
- table.insert(global_classes, classfile)
- end
- end
- elseif key == targetname .. "_CLASSES_SLOW" then
- for classfile in values:gmatch("\"(.-)\"") do
- table.insert(classefiles_slow, classfile)
- end
- elseif key == targetname .. "_CLASSES_FAST" then
- for classfile in values:gmatch("\"(.-)\"") do
- table.insert(classefiles_fast, classfile)
- end
- elseif key == targetname .. "_SUPPORT_SLOW" then
- for classfile in values:gmatch("\"(.-)\"") do
- table.insert(supportfiles_slow, classfile)
- end
- elseif key == targetname .. "_SUPPORT_FAST" then
- for classfile in values:gmatch("\"(.-)\"") do
- table.insert(supportfiles_fast, classfile)
- end
- end
- end)
+-- parse sourcefiles from jsonfile
+function _get_sourcefiles_from_json(jsonfile)
+ local json = json.loadfile(jsonfile)
+ local global_classes = json["sources"]["global"]
+ local classefiles_slow = json["sources"]["classes_slow"]
+ local classefiles_fast = json["sources"]["classes_fast"]
+ local supportfiles_slow = json["sources"]["support_slow"]
+ local supportfiles_fast = json["sources"]["support_fast"]
-- get compiled source files
- local sourcefiles = table.join(global_classes, classefiles_slow, classefiles_fast, supportfiles_slow, supportfiles_fast)
+ local sourcefiles = table.join(global_classes, classefiles_slow, classefiles_fast, supportfiles_slow,
+ supportfiles_fast)
return sourcefiles
end
-- get languages
--
-- Select the Verilog language generation to support in the compiler.
--- This selects between v1364-1995, v1364-2001, v1364-2005, v1800-2005, v1800-2009, v1800-2012.
+-- This selects between v1364-1995, v1364-2001, v1364-2005, v1800-2005, v1800-2009, v1800-2012, v1800-2017, v1800-2023.
--
function _get_lanuage_flags(target)
local language_v
@@ -94,6 +67,7 @@ function _get_lanuage_flags(target)
["v1800-2009"] = "+1800-2009ext+v",
["v1800-2012"] = "+1800-2012ext+v",
["v1800-2017"] = "+1800-2017ext+v",
+ ["v1800-2023"] = "+1800-2023ext+v",
}
local flag = maps[language_v]
if flag then
@@ -105,15 +79,17 @@ function _get_lanuage_flags(target)
end
function config(target)
- local toolchain = assert(target:toolchain("verilator"), 'we need to set_toolchains("verilator") in target("%s")', target:name())
+ local toolchain = assert(target:toolchain("verilator"), 'we need to set_toolchains("verilator") in target("%s")',
+ target:name())
local verilator = assert(toolchain:config("verilator"), "verilator not found!")
local autogendir = path.join(target:autogendir(), "rules", "verilator")
local tmpdir = os.tmpfile() .. ".dir"
- local cmakefile = path.join(tmpdir, "test.cmake")
+ local jsonfile = path.join(tmpdir, "test.json")
local sourcefile = path.join(tmpdir, "main.v")
- local argv = {"--cc", "--make", "cmake", "--prefix", "test", "--Mdir", tmpdir, "main.v"}
+ local argv = { "--cc", "--make", "json", "--prefix", "test", "--Mdir", tmpdir, "main.v" }
local flags = target:values("verilator.flags")
- local switches_flags = hashset.of( "sc", "coverage", "timing", "trace", "trace-fst", "threads")
+ local switches_flags = hashset.of("sc", "coverage", "timing", "trace", "trace-vcd", "trace-fst", "trace-saif",
+ "threads")
if flags then
for idx, flag in ipairs(flags) do
if flag:startswith("--") and switches_flags:has(flag:sub(3)) then
@@ -134,39 +110,21 @@ endmodule]])
os.mkdir(tmpdir)
-- we just pass relative sourcefile path to solve this issue on windows.
-- @see https://github.com/verilator/verilator/issues/3873
- os.runv(verilator, argv, {curdir = tmpdir, envs = toolchain:runenvs()})
+ os.runv(verilator, argv, { curdir = tmpdir, envs = toolchain:runenvs() })
- -- parse some configurations from cmakefile
+ -- parse some configurations from jsonfile
local verilator_root
local switches = {}
- local targetname = target:name()
- io.gsub(cmakefile, "set%((%S-) (.-)%)", function (key, values)
- if key == "VERILATOR_ROOT" then
- verilator_root = values:match("\"(.-)\" CACHE PATH")
- if not verilator_root then
- verilator_root = values:match("(.-) CACHE PATH")
- end
- elseif key == "test_SC" then
- -- SystemC output mode? 0/1 (from --sc)
- switches.SC = values:trim()
- elseif key == "test_COVERAGE" then
- -- Coverage output mode? 0/1 (from --coverage)
- switches.COVERAGE = values:trim()
- elseif key == "test_TIMING" then
- -- Timing mode? 0/1 (from --timing)
- switches.TIMING = values:trim()
- elseif key == "test_THREADS" then
- -- Threaded output mode? 1/N threads (from --threads)
- switches.THREADS = values:trim()
- elseif key == "test_TRACE_VCD" then
- -- VCD Tracing output mode? 0/1 (from --trace)
- switches.TRACE_VCD = values:trim()
- elseif key == "test_TRACE_FST" then
- -- FST Tracing output mode? 0/1 (from --trace-fst)
- switches.TRACE_FST = values:trim()
- end
- end)
+ local json = json.loadfile(jsonfile)
+ verilator_root = json["system"]["verilator_root"]
+ switches.SC = json["options"]["system_c"]
+ switches.COVERAGE = json["options"]["coverage"]
+ switches.TIMING = json["options"]["use_timing"]
+ switches.THREADS = json["options"]["threads"]
+ switches.TRACE_VCD = json["options"]["trace_vcd"]
+ switches.TRACE_FST = json["options"]["trace_fst"]
+ switches.TRACE_SAIF = json["options"]["trace_saif"]
assert(verilator_root, "the verilator root directory not found!")
target:data_set("verilator.root", verilator_root)
@@ -174,49 +132,60 @@ endmodule]])
if not os.isfile(autogendir) then
os.mkdir(autogendir)
end
- target:add("includedirs", autogendir, {public = true})
- target:add("includedirs", path.join(verilator_root, "include"), {public = true})
- target:add("includedirs", path.join(verilator_root, "include", "vltstd"), {public = true})
+ target:add("includedirs", autogendir, { public = true })
+ target:add("includedirs", path.join(verilator_root, "include"), { public = true })
+ target:add("includedirs", path.join(verilator_root, "include", "vltstd"), { public = true })
-- set languages
local languages = target:get("languages")
local cxxlang = false
for _, lang in ipairs(languages) do
- if lang:startswith("xx") or lang:startswith("++") then
+ if lang:startswith("cxx") or lang:startswith("c++") then
cxxlang = true
break
end
end
if not cxxlang then
- target:add("languages", "c++20", {public = true})
+ target:add("languages", "c++20", { public = true })
end
-- add definitions for switches
for k, v in table.orderpairs(switches) do
- target:add("defines", "VM_" .. k .. "=" .. v, {public = true})
+ target:add("defines", "VM_" .. k .. "=" .. (v and "1" or "0"), { public = true })
+ end
+ local cflags = json["options"]["cflags"]
+ if cflags then
+ for _, flag in ipairs(cflags) do
+ if flag:startswith("-D") then
+ target:add("defines", flag:sub(3), { public = true })
+ end
+ end
end
-- add syslinks
- if target:is_plat("linux", "macosx") and switches.THREADS == "1" then
- target:add("syslinks", "pthread")
- end
- if target:is_plat("linux", "macosx") and switches.TRACE_FST == "1" then
- target:add("syslinks", "z")
+ local ldflags = json["options"]["ldflags"]
+ if ldflags then
+ for _, flag in ipairs(ldflags) do
+ if flag:startswith("-l") then
+ target:add("syslinks", flag:sub(3))
+ end
+ end
end
os.rm(tmpdir)
end
function build_cppfiles(target, jobgraph, sourcebatch, opt)
- local toolchain = assert(target:toolchain("verilator"), 'we need to set_toolchains("verilator") in target("%s")', target:name())
+ local toolchain = assert(target:toolchain("verilator"), 'we need to set_toolchains("verilator") in target("%s")',
+ target:name())
local verilator = assert(toolchain:config("verilator"), "verilator not found!")
local autogendir = path.join(target:autogendir(), "rules", "verilator")
local targetname = target:name()
- local cmakefile = path.join(autogendir, targetname .. ".cmake")
+ local jsonfile = path.join(autogendir, targetname .. ".json")
-- build verilog files
depend.on_changed(function()
- local argv = {"--cc", "--make", "cmake", "--prefix", targetname, "--Mdir", autogendir}
+ local argv = { "--cc", "--make", "json", "--prefix", targetname, "--Mdir", autogendir }
local flags = target:values("verilator.flags")
if flags then
table.join2(argv, flags)
@@ -237,15 +206,16 @@ function build_cppfiles(target, jobgraph, sourcebatch, opt)
end
-- generate c++ sourcefiles
- os.vrunv(verilator, argv, {envs = toolchain:runenvs()})
-
- end, {dependfile = cmakefile .. ".d",
- files = sourcebatch.sourcefiles,
- changed = target:is_rebuilt(),
- lastmtime = os.mtime(cmakefile)})
+ os.vrunv(verilator, argv, { envs = toolchain:runenvs() })
+ end, {
+ dependfile = jsonfile .. ".d",
+ files = sourcebatch.sourcefiles,
+ changed = target:is_rebuilt(),
+ lastmtime = os.mtime(jsonfile)
+ })
-- get compiled source files
- local sourcefiles = _get_sourcefiles_from_cmake(target, cmakefile)
+ local sourcefiles = _get_sourcefiles_from_json(jsonfile)
-- do build
local sourcebatch_cpp = {
@@ -253,7 +223,8 @@ function build_cppfiles(target, jobgraph, sourcebatch, opt)
sourcekind = "cxx",
sourcefiles = sourcefiles,
objectfiles = {},
- dependfiles = {}}
+ dependfiles = {}
+ }
for _, sourcefile in ipairs(sourcefiles) do
local objectfile = target:objectfile(sourcefile)
local dependfile = target:dependfile(objectfile)
@@ -265,14 +236,15 @@ function build_cppfiles(target, jobgraph, sourcebatch, opt)
end
function buildcmd_vfiles(target, batchcmds, sourcebatch, opt)
- local toolchain = assert(target:toolchain("verilator"), 'we need to set_toolchains("verilator") in target("%s")', target:name())
+ local toolchain = assert(target:toolchain("verilator"), 'we need to set_toolchains("verilator") in target("%s")',
+ target:name())
local verilator = assert(toolchain:config("verilator"), "verilator not found!")
local autogendir = path.join(target:autogendir(), "rules", "verilator")
local targetname = target:name()
- local cmakefile = path.join(autogendir, targetname .. ".cmake")
- local dependfile = cmakefile .. ".d"
+ local jsonfile = path.join(autogendir, targetname .. ".json")
+ local dependfile = jsonfile .. ".d"
- local argv = {"--cc", "--make", "cmake", "--prefix", targetname, "--Mdir", path(autogendir)}
+ local argv = { "--cc", "--make", "json", "--prefix", targetname, "--Mdir", path(autogendir) }
local flags = target:values("verilator.flags")
if flags then
table.join2(argv, flags)
@@ -284,7 +256,7 @@ function buildcmd_vfiles(target, batchcmds, sourcebatch, opt)
local sourcefiles = sourcebatch.sourcefiles
for _, sourcefile in ipairs(sourcefiles) do
batchcmds:show_progress(opt.progress, "${color.build.object}compiling.verilog %s", sourcefile)
- table.insert(argv, path(sourcefile, function (v)
+ table.insert(argv, path(sourcefile, function(v)
-- we need to use slashes to fix it on windows
-- @see https://github.com/verilator/verilator/issues/3873
if is_host("windows") then
@@ -295,22 +267,23 @@ function buildcmd_vfiles(target, batchcmds, sourcebatch, opt)
end
-- generate c++ sourcefiles
- batchcmds:vrunv(verilator, argv, {envs = toolchain:runenvs()})
+ batchcmds:vrunv(verilator, argv, { envs = toolchain:runenvs() })
batchcmds:add_depfiles(sourcefiles)
- batchcmds:set_depmtime(os.mtime(cmakefile))
+ batchcmds:set_depmtime(os.mtime(jsonfile))
batchcmds:set_depcache(dependfile)
end
function buildcmd_cppfiles(target, batchcmds, sourcebatch, opt)
- local toolchain = assert(target:toolchain("verilator"), 'we need set_toolchains("verilator") in target("%s")', target:name())
+ local toolchain = assert(target:toolchain("verilator"), 'we need set_toolchains("verilator") in target("%s")',
+ target:name())
local verilator = assert(toolchain:config("verilator"), "verilator not found!")
local autogendir = path.join(target:autogendir(), "rules", "verilator")
local targetname = target:name()
- local cmakefile = path.join(autogendir, targetname .. ".cmake")
+ local jsonfile = path.join(autogendir, targetname .. ".json")
local dependfile = path.join(autogendir, targetname .. ".build.d")
-- get compiled source files
- local sourcefiles = _get_sourcefiles_from_cmake(target, cmakefile)
+ local sourcefiles = _get_sourcefiles_from_json(jsonfile)
-- do build
for _, sourcefile in ipairs(sourcefiles) do