diff options
| author | 24bit-xjkp <[email protected]> | 2026-01-01 18:08:00 +0800 |
|---|---|---|
| committer | 24bit-xjkp <[email protected]> | 2026-01-01 18:08:00 +0800 |
| commit | 13bb0e6506af38aa303c9adc49125b4a18ebe388 (patch) | |
| tree | 21825a0d5c2fe4a178cf1a5cb517a7829092948a | |
| parent | 34a2d99adfd90c5dac77f0201528961712e92912 (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.lua | 183 |
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 |
