From ac6ddfcf7d8a849753fb1a8948f3250a402ff933 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Jun 2026 20:11:17 +0000 Subject: [PATCH 1/6] Initial plan From 9fdc7af3c2e619b4e1d3682d7da504d2b2a0b135 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Jun 2026 20:23:59 +0000 Subject: [PATCH 2/6] Add --verilator-hier-blocks option to emit hier_block annotations --- compiler/cpp/options.h | 4 ++ compiler/cpp/verilog.cpp | 8 +++ compiler/hs/app/Options.hs | 1 + compiler/hs/app/Options/CmdArgs.hs | 1 + compiler/hs/app/Options/FFI.hsc | 1 + test/compiler/cli/CMakeLists.txt | 12 ++++ .../cli/check_verilator_hier_blocks.py | 66 +++++++++++++++++++ test/compiler/cli/verilator_hier_blocks.k | 14 ++++ 8 files changed, 107 insertions(+) create mode 100644 test/compiler/cli/check_verilator_hier_blocks.py create mode 100644 test/compiler/cli/verilator_hier_blocks.k diff --git a/compiler/cpp/options.h b/compiler/cpp/options.h index c2c6400..a13b705 100644 --- a/compiler/cpp/options.h +++ b/compiler/cpp/options.h @@ -261,6 +261,10 @@ extern "C" // Don't output the informational header on top of generated Verilog files BOOL _noVerilogHeader; + // Emit a /*verilator hier_block*/ metacomment in each generated module + // to enable hierarchical Verilation + BOOL _emitVerilatorHierBlocks; + // True to enable warnings about missing [[transaction_size]] BOOL _enableTransactionSizeWarning; diff --git a/compiler/cpp/verilog.cpp b/compiler/cpp/verilog.cpp index 8a22ecd..a4a7fdb 100644 --- a/compiler/cpp/verilog.cpp +++ b/compiler/cpp/verilog.cpp @@ -7118,6 +7118,14 @@ class VerilogCompiler coreModule.FinishPorts(); + // Optionally mark this module as a Verilator hierarchical block to enable + // hierarchical Verilation. The /*verilator hier_block*/ metacomment must + // appear inside the module body, after the port list. + if (GetCodeGenConfig()._emitVerilatorHierBlocks) + { + _writer.Str() << "/*verilator hier_block*/"; + } + DeclareDebugVariables(); DeclareStringTable(); diff --git a/compiler/hs/app/Options.hs b/compiler/hs/app/Options.hs index 70a59dd..616e2bc 100644 --- a/compiler/hs/app/Options.hs +++ b/compiler/hs/app/Options.hs @@ -122,6 +122,7 @@ data Options , template_iterations :: Int , template_passes :: Int , using :: [String] + , verilator_hier_blocks :: Bool , warnings_state :: [WarningState WarningKind] , warnings_as_errors :: Bool , work_list_size :: Int diff --git a/compiler/hs/app/Options/CmdArgs.hs b/compiler/hs/app/Options/CmdArgs.hs index ff92b77..b304629 100644 --- a/compiler/hs/app/Options/CmdArgs.hs +++ b/compiler/hs/app/Options/CmdArgs.hs @@ -81,6 +81,7 @@ compile = Compile , no_fifo_stutter = def &= groupname "Code generation" &= help "Disable fifos stutter" , no_debug_view = def &= groupname "Code generation" &= help "Disables debug views" , no_verilog_header = def &= groupname "Code generation" &= help "Don't output the informational header on top of generated Verilog files" + , verilator_hier_blocks = def &= groupname "Code generation" &= help "Emit a /*verilator hier_block*/ metacomment in each generated module to enable hierarchical Verilation" &= name "verilator-hier-blocks" &= explicit , code_coverage = def &= groupname "Code generation" &= help "Enable generation of code coverage using SystemVerilog coverpoints" , code_coverage_mux_threshold = 0 &= groupname "Code generation" &= help "Only generate code coverage code for muxes with this number of cases; the default value of 0 means to generate for all muxes" , optimize = 2 &= groupname "Code generation" &= help "Optimize generated code" &= typ "LEVEL" &= name "O" diff --git a/compiler/hs/app/Options/FFI.hsc b/compiler/hs/app/Options/FFI.hsc index fe4e28d..59ba398 100644 --- a/compiler/hs/app/Options/FFI.hsc +++ b/compiler/hs/app/Options/FFI.hsc @@ -98,6 +98,7 @@ instance Storable Options where #{poke CodeGenOptions, _fifoWriteDelay } ptrCodegen fifo_write_delay #{poke CodeGenOptions, _fifoMergeDistance } ptrCodegen fifo_merge_distance #{poke CodeGenOptions, _noVerilogHeader } ptrCodegen no_verilog_header + #{poke CodeGenOptions, _emitVerilatorHierBlocks } ptrCodegen verilator_hier_blocks #{poke CodeGenOptions, _optimize } ptrCodegen optimize #{poke CodeGenOptions, _logicRegisterRatio } ptrCodegen register_ratio #{poke CodeGenOptions, _maxLogicRegisterRatio } ptrCodegen max_register_ratio diff --git a/test/compiler/cli/CMakeLists.txt b/test/compiler/cli/CMakeLists.txt index 858c4fc..fddc076 100644 --- a/test/compiler/cli/CMakeLists.txt +++ b/test/compiler/cli/CMakeLists.txt @@ -104,3 +104,15 @@ add_cli_test(skip_circt_lowering TEST "python3 ${CMAKE_CURRENT_SOURCE_DIR}/check_skip_circt_lowering.py ${CMAKE_CURRENT_BINARY_DIR}/skip_circt_lowering" ) + +add_cli_test(verilator_hier_blocks + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/verilator_hier_blocks.k + OPTIONS + --backend=sv + --verilator-hier-blocks + --base-library=${CMAKE_SOURCE_DIR}/library/mini-base.k + --import-dir=${CMAKE_SOURCE_DIR}/library + --place-iterations=1 + TEST + "python3 ${CMAKE_CURRENT_SOURCE_DIR}/check_verilator_hier_blocks.py ${CMAKE_CURRENT_BINARY_DIR}/verilator_hier_blocks" +) diff --git a/test/compiler/cli/check_verilator_hier_blocks.py b/test/compiler/cli/check_verilator_hier_blocks.py new file mode 100644 index 0000000..6feac5b --- /dev/null +++ b/test/compiler/cli/check_verilator_hier_blocks.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +""" +Verify the output of a `--verilator-hier-blocks` compile. + +Contract of the flag: every generated module should carry a +`/*verilator hier_block*/` metacomment, which enables hierarchical +Verilation. Verilator requires this metacomment to appear inside the +module body (after the `module name(...);` port list), so we check both +that the metacomment is present and that it follows a `module` +declaration. + +Checks: + 1. At least one .sv file exists. + 2. The `/*verilator hier_block*/` metacomment appears in a generated + .sv file, and it occurs after a `module` declaration (i.e. inside a + module body, as Verilator requires). + +Exits non-zero on failure. +""" +import argparse +import sys +from pathlib import Path + +HIER_BLOCK = '/*verilator hier_block*/' + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('output_dir', help='Directory containing compiler outputs') + args = parser.parse_args() + + output_dir = Path(args.output_dir) + if not output_dir.is_dir(): + print(f"Output directory does not exist: {output_dir}") + return 1 + + sv_files = sorted(output_dir.glob('*.sv')) + if not sv_files: + print("--verilator-hier-blocks should produce a .sv file, but none was found.") + return 1 + + for sv in sv_files: + text = sv.read_text() + idx = text.find(HIER_BLOCK) + if idx == -1: + continue + # The metacomment must be inside a module body, so a `module` + # keyword must precede it in the same file. + if 'module' not in text[:idx]: + print( + f"{sv.name} contains {HIER_BLOCK!r} but not after a module declaration." + ) + return 1 + return 0 + + print( + f"--verilator-hier-blocks must emit {HIER_BLOCK!r} into a generated module, " + f"but none of {[s.name for s in sv_files]} contain it." + ) + return 1 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/test/compiler/cli/verilator_hier_blocks.k b/test/compiler/cli/verilator_hier_blocks.k new file mode 100644 index 0000000..b109fe4 --- /dev/null +++ b/test/compiler/cli/verilator_hier_blocks.k @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Minimal program used by the --verilator-hier-blocks CLI test. +class VerilatorHierBlock +{ +public: + uint32 TimesTwo(uint32 x) + { + return x + x; + } +} + +export VerilatorHierBlock; From 3d88f3e56084699b90b3392727be569b93637423 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Jun 2026 20:27:49 +0000 Subject: [PATCH 3/6] Make module-declaration check in CLI test more precise --- test/compiler/cli/check_verilator_hier_blocks.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/compiler/cli/check_verilator_hier_blocks.py b/test/compiler/cli/check_verilator_hier_blocks.py index 6feac5b..91e8f77 100644 --- a/test/compiler/cli/check_verilator_hier_blocks.py +++ b/test/compiler/cli/check_verilator_hier_blocks.py @@ -20,11 +20,15 @@ Exits non-zero on failure. """ import argparse +import re import sys from pathlib import Path HIER_BLOCK = '/*verilator hier_block*/' +# Matches a SystemVerilog module declaration, e.g. `module Foo (`. +MODULE_DECL = re.compile(r'(?:^|\s)module\s+\w+', re.MULTILINE) + def main(): parser = argparse.ArgumentParser(description=__doc__) @@ -47,8 +51,8 @@ def main(): if idx == -1: continue # The metacomment must be inside a module body, so a `module` - # keyword must precede it in the same file. - if 'module' not in text[:idx]: + # declaration must precede it in the same file. + if not MODULE_DECL.search(text[:idx]): print( f"{sv.name} contains {HIER_BLOCK!r} but not after a module declaration." ) From f20f8afe67d0ac3d04b6811e2f9bb251a55fc07a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Jun 2026 17:56:26 +0000 Subject: [PATCH 4/6] Assert non-exported modules omit verilator hier_block metacomment --- ...heck_verilator_hier_blocks.cpython-312.pyc | Bin 0 -> 4059 bytes .../cli/check_verilator_hier_blocks.py | 81 ++++++++++++------ 2 files changed, 53 insertions(+), 28 deletions(-) create mode 100644 test/compiler/cli/__pycache__/check_verilator_hier_blocks.cpython-312.pyc diff --git a/test/compiler/cli/__pycache__/check_verilator_hier_blocks.cpython-312.pyc b/test/compiler/cli/__pycache__/check_verilator_hier_blocks.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8cc739534edaff50ad3e52019f248ac21092d2a5 GIT binary patch literal 4059 zcma)9TWk~A89rl=9cO$e8*ZiS0kTPK5@&&ZA*{#-5-u%-J5>XVGoG2)W5zS)%s9c8 zQ+cII1uYWn_5mt{O0})Z3Z!PWNK4;VWgjZ_B_vt!&Qb}fs1k1>v=8vq|IEcnxTsjl zIcLuKFXz9U@Bj0UaF|2zTlc3#erFh=f6)*3$2yB=ld!mqL^O;Ihu=ENo#gHlKgobE)3 ztOR-9{A!naVTS$SP3Q9_V=ov~_LMz|X8ylkgt+4pkw?qe$Vpf$8O4%;wNcFDk?!s> zI8k^*Bi%V!BHbB96Hep4w^LIM!V4A$JvY`r7RcT9AvS$PrB!dTi1xYo!@OVxZa#&LN zj3Vh4Ax{L@;}y#YxT>tFDNGHru8oOwrX&-fHFC1PSQa)k%omFiPq3`&vMA9@bI$ED znpno2{HP%j%a##mU*!u@XDXFSY#YJUI;_aLkx1dAVELkZVp->sx}->gA&*JPUMw51 zg*8fOu;|Y4x-8gHb;WjJ$q-Tr8rqx$!S3ZS-ju@q zV5`LI^kNcD>0@{l;*X`XV85OMlFhag-Y$-g<8{~bU`InZ$bz41iRk8w9T7PtrLY?o z;IduOq2rNP17r&lB|+iACy*9hnAcyE8DJ{LTVAqI1D7rMvvCXCUfc7c27XRLtdj5? zRD+l8h*{TPlnY(BNVG9o&00?9Rba4gLlXk{Mr9R}0df%(f;*Qy8QTKKGF}xa3(bv; z!mFnxqZ@*$$Ts(qJaG~PLO6I{ymu3L+MU(-SOh0|f zs%WxQgXzl>tyE0-%mC=5Pg6IWoHQ^!`k2XDqI?D35OO;8s+FcM-UqBOdK@$-J%S?l z2=vvb8(^GX0AoE>ESph5Qz)*b9qD8l2 z$z$J~`0B*B@vl!!{bb<#(BM-qC7<(AsdE7oYN-u91BFPSgZrap+Df~BgBvd+qmgF$ zMoPJ)2pMkaMzWsQa21FdLppOITJ?jRWh|O#ns_@dW(ijSxSE#SKeV9fsz(ejxd{LX z(ECL{)em}`t^51o{*i0G#h$7LmdK30rIgqb-P}@{<+$KsEPsu|Xs!JJZt|M^pluP z>9nW`>9iT*MKKLz)}hH+)bv{?6z<4!7)-yc(~z6KA_4PFzixHkCYx2XjD^yK!lTLU z**kbRy<^{joj*@Bn|@0aF8+gzU1ubc%ph z8KDEAIAyX0XoE-+mYd*D{{#TIh8~7nAB5ZPh1+hgms|Q={v)SO6P3}q@%X`hu|_x!sc)H z+~2bQ&Y8*nZ+3mXYkJH6sm()w=cghEX9I_T;nA86_hY@6&it`5d1&&?S4XEiwtgO; ziuKm^!cc#={eDaTm36n0clz(}e;t@ke)M_&R7-zt9}G|ZDAWon>XG+vubzy|A*OFb zee>4)8+vaXy54`C|6*WzL+{l3ZFfGL^D^PR%zwPzW)A9EEdG>3p_RZn=V79oAFX}w zezg5c{1S6%-EZ0HX!}&8<9g+Ga&qmRGjl#qcn2`Dz{mmPqhRRy{1)`V5c7QAkK)^& zn=Sp%=R>G%+w=M5DAu9VaQtmk%iwD6ZcA+NUG{DpOUG1fu#LUj$HMsC%FtjU^4+%3 zV2U#X=`@XEI-Q7+HNZ+JE}I@AnO?mNZAB5GAK`cjml^U2Warf1fr|0{{R3 literal 0 HcmV?d00001 diff --git a/test/compiler/cli/check_verilator_hier_blocks.py b/test/compiler/cli/check_verilator_hier_blocks.py index 91e8f77..1037fd5 100644 --- a/test/compiler/cli/check_verilator_hier_blocks.py +++ b/test/compiler/cli/check_verilator_hier_blocks.py @@ -4,18 +4,22 @@ """ Verify the output of a `--verilator-hier-blocks` compile. -Contract of the flag: every generated module should carry a +Contract of the flag: the exported design (core) module should carry a `/*verilator hier_block*/` metacomment, which enables hierarchical Verilation. Verilator requires this metacomment to appear inside the -module body (after the `module name(...);` port list), so we check both -that the metacomment is present and that it follows a `module` -declaration. +module body (after the `module name(...);` port list). The metacomment is +*selective*: it is only emitted on the core design module, not on the +non-exported helper modules that the compiler generates alongside it (the +ESI wrapper, the per-basic-block modules, etc.). Checks: 1. At least one .sv file exists. - 2. The `/*verilator hier_block*/` metacomment appears in a generated - .sv file, and it occurs after a `module` declaration (i.e. inside a - module body, as Verilator requires). + 2. The `/*verilator hier_block*/` metacomment appears inside at least one + generated module body (i.e. after that module's `module name(...);` + declaration, as Verilator requires). + 3. At least one other generated module exists that does *not* contain the + metacomment, proving the annotation is confined to the exported design + module and is not blanket-applied to non-exported modules. Exits non-zero on failure. """ @@ -26,8 +30,20 @@ HIER_BLOCK = '/*verilator hier_block*/' -# Matches a SystemVerilog module declaration, e.g. `module Foo (`. -MODULE_DECL = re.compile(r'(?:^|\s)module\s+\w+', re.MULTILINE) +# Matches a SystemVerilog module body, capturing the module name. Modules do +# not nest, so a non-greedy match up to the first `endmodule` is sufficient. +MODULE_BODY = re.compile( + r'(?:^|\s)module\s+(\w+).*?\bendmodule\b', re.DOTALL) + + +def collect_modules(sv_files): + """Return a list of (sv_name, module_name, body) for every module.""" + modules = [] + for sv in sv_files: + text = sv.read_text() + for match in MODULE_BODY.finditer(text): + modules.append((sv.name, match.group(1), match.group(0))) + return modules def main(): @@ -45,25 +61,34 @@ def main(): print("--verilator-hier-blocks should produce a .sv file, but none was found.") return 1 - for sv in sv_files: - text = sv.read_text() - idx = text.find(HIER_BLOCK) - if idx == -1: - continue - # The metacomment must be inside a module body, so a `module` - # declaration must precede it in the same file. - if not MODULE_DECL.search(text[:idx]): - print( - f"{sv.name} contains {HIER_BLOCK!r} but not after a module declaration." - ) - return 1 - return 0 - - print( - f"--verilator-hier-blocks must emit {HIER_BLOCK!r} into a generated module, " - f"but none of {[s.name for s in sv_files]} contain it." - ) - return 1 + modules = collect_modules(sv_files) + if not modules: + print(f"No SystemVerilog modules found in {[s.name for s in sv_files]}.") + return 1 + + with_meta = [m for m in modules if HIER_BLOCK in m[2]] + without_meta = [m for m in modules if HIER_BLOCK not in m[2]] + + # Check 2: the metacomment must appear inside at least one module body. + if not with_meta: + print( + f"--verilator-hier-blocks must emit {HIER_BLOCK!r} into a generated " + f"module, but none of {[m[1] for m in modules]} contain it." + ) + return 1 + + # Check 3: the metacomment must be selective. The compiler emits several + # non-exported helper modules (ESI wrapper, per-basic-block modules); these + # must not carry the metacomment. + if not without_meta: + print( + f"--verilator-hier-blocks should only annotate the exported design " + f"module, but every generated module " + f"{[m[1] for m in modules]} contains {HIER_BLOCK!r}." + ) + return 1 + + return 0 if __name__ == '__main__': From d74f8b5330c9c4b324767f3841c207975d5caa72 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Jun 2026 17:57:46 +0000 Subject: [PATCH 5/6] Parse modules on declaration boundaries for robustness --- ...heck_verilator_hier_blocks.cpython-312.pyc | Bin 4059 -> 4961 bytes .../cli/check_verilator_hier_blocks.py | 32 ++++++++++++------ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/test/compiler/cli/__pycache__/check_verilator_hier_blocks.cpython-312.pyc b/test/compiler/cli/__pycache__/check_verilator_hier_blocks.cpython-312.pyc index 8cc739534edaff50ad3e52019f248ac21092d2a5..dc67d33e64fe0db018193efd716318f9543cefba 100644 GIT binary patch delta 2199 zcmZuyU2GIp6ux(NX8-@%?GODiT!bzx)Jj;1!4|O4O)YGT2x66>ygZN-Pce)ED;U;tE?wRj= z=ey_LbN1KOzsEv927^8Xqx5M!+ZMhOTI6uU`+P$zgPFB5yzq9yb9W4^r_nGP#|G*_ zN3NPFzO9~pv4_r8S6R1d@U2HLS4hS=ol)4s;Hp+2C?fQV1EFz#+-2}09s`8#uK>{l zWCD2l8MlOd|+iL7g6 zumV?vyfjEeDU%bZpv$U4iUm^ARohiRX z+-G^IB#3F2EsM*^nx3@${rh@eOeNDj$=xZ-GbAgbtV`7LN=h*=L82tfnUfTY*K~pE zmW!!UM2lnDwD@7F77KBY`MGO#3(JINVcFu?%5nls^FUNMUh`*HUy0qm7(CjSFioIx zEeh96^e%)NmJrYP<4MOtxaM8sr1AC}liZz1-3Nz%sgK{Pk6&CjU;pHMWb-6{r;(hm zpKn~hgdE;}e6n}4ds1K6xap#BsqNa@8R_cApEh>A*EWr(yFcPjwf|DP?pE!(+qJPD z)?OEH#3x_by%31LJ8*Jfde^z$k9yA^{Or)jhi34FBQrg-b>B6A)BJ7g^~~H;d*)j9 z{v1dx@+?N#&6Je`C=i_(xC^pThE3JshJ{_<*REc3@5h|z%{H-u*yMW)8O|PbxdOag zt!G}Zsrrh3gFl1BfZ6MP0td~acWXhGyzw7~^RtM7`=${Gn zQ&Zyn{^>R6VrOHwniBUk)^y)&ScT0&e|za6@$5)#@$9zV7Z077i5C$&rHWiX$i=o? z2j#&$a0%p60xJvWSL&sYgN-SDq|oQv;Oh#dt%>u(^#17+XAjBbh~HBSl)cczv}%!Dp0X%WX$o5`Ep<{e$2cOSkukqTU=I^ z70dTrU-E_YuGGHWd!aSB3If%j@;QMHYxFUIQP%V+yRsI~>RqGjVQu~wXi8Xt<=|=C zuCf0@sPoFOkI3TKZs|7o!X8aFJA-CyAyRkRd&&zZaB;)!ro?#ePMgw z?7+=6WhV~yZC`1Edd- zzxf0AmYzg4o%gJ0x5lp5jc6pfKEmBt$0cFzh$QQ|8#_6eEl)blwv|rDLv$k`=>`*r zTMlo5rR9e1T!23a%iI5A>R?~0Zy-ro1EehFb|RQNOISK>ankFuPT38ktXh|EwWn)2 yt2^i}u(7V84Vovyo0{jEw#@AMI&~#AAL^d)FS#N(x)f{2!SYdaHoTf+4F3cCQaEn_ delta 1407 zcma)6QA`{~7@pbNUH0~N?{+ysT1kNdheuPeP>lryx!ysW!XYXTO54qGx4>OExbAMT zT=qPCYaDI0V&crfNqN#q=AZxO z|L*%{=Kufw#q)EO^E*-G0UkA!7aifOL3>3D(;N_s{p~=t2CI4(ZGan0Ix0Cg;v?F^dIB^8abtxwd|T2 ziYSJ9!>}Cv1OB1DfZ`kQzh!Zw(aA{EP&JDUB@*}{EP65&S1o2to4TIxG8U&#E2Gf~ zRkup^-$=J8ecGZ6R7^Z%gvWJq|7tRxykMxh(Hx$NC!*+Y?&WkTjx^w@$FZ3OJ5Fh~ zciUN>12(1y-lVo&^1OM=eE;2>^y9MXpUS+C%Dl^U-uPNFd;#VmjbkCq&#p#wc~ zyqIEaJmRf`hU=~$gk+O$x9#AqbD z79GdJS|fJP;HkfdewR?qV@}LSEe|eiwf3)HTj{>vv(~fO+Mj6&ejCa-U;BX@M2qq( zXjgVu)^4|)+p29_9$f5R3@!OLYuhp>+t)j?HYi?1a_O__mYoyzTQ1LC`8K>=gXm3{ zC*y2bOn%k4a$@~jmZ3x+{L4n$`7944dB-8-bFJWP5ax3%klXW?yE~r~KwW!2R}Q2G zot*QVGw#4~e#0#Vs_2b6n%E{OP)Bcc(bzt$5CUH3!*(Ii#9N$_R>=Jn#p~26@qaZ^ zT^6OOmQA0*jhYA<;}g*lja0o>OJXI3mYh&6)<5uOcVC}IK1EvL;fXk=R7l$^ibbn8 zqQ*U-xe0*0)c Nvu~qLcNI-Y{sI2nTz3Ef diff --git a/test/compiler/cli/check_verilator_hier_blocks.py b/test/compiler/cli/check_verilator_hier_blocks.py index 1037fd5..6139950 100644 --- a/test/compiler/cli/check_verilator_hier_blocks.py +++ b/test/compiler/cli/check_verilator_hier_blocks.py @@ -30,19 +30,27 @@ HIER_BLOCK = '/*verilator hier_block*/' -# Matches a SystemVerilog module body, capturing the module name. Modules do -# not nest, so a non-greedy match up to the first `endmodule` is sufficient. -MODULE_BODY = re.compile( - r'(?:^|\s)module\s+(\w+).*?\bendmodule\b', re.DOTALL) +# Matches a SystemVerilog module declaration, e.g. `module Foo (`, capturing +# the module name. +MODULE_DECL = re.compile(r'(?:^|\s)module\s+(\w+)', re.MULTILINE) def collect_modules(sv_files): - """Return a list of (sv_name, module_name, body) for every module.""" + """Return a list of (sv_name, module_name, body) for every module. + + Modules do not nest in SystemVerilog, so each module body is the text + spanning from its `module name` declaration up to the next module + declaration (or end of file). Slicing on declaration boundaries avoids + relying on an `endmodule` token, which could otherwise appear inside a + comment or string and truncate the body prematurely. + """ modules = [] for sv in sv_files: text = sv.read_text() - for match in MODULE_BODY.finditer(text): - modules.append((sv.name, match.group(1), match.group(0))) + decls = list(MODULE_DECL.finditer(text)) + for i, decl in enumerate(decls): + end = decls[i + 1].start() if i + 1 < len(decls) else len(text) + modules.append((sv.name, decl.group(1), text[decl.start():end])) return modules @@ -63,17 +71,19 @@ def main(): modules = collect_modules(sv_files) if not modules: - print(f"No SystemVerilog modules found in {[s.name for s in sv_files]}.") + names = ', '.join(s.name for s in sv_files) + print(f"No SystemVerilog modules found in {names}.") return 1 with_meta = [m for m in modules if HIER_BLOCK in m[2]] without_meta = [m for m in modules if HIER_BLOCK not in m[2]] + module_names = ', '.join(m[1] for m in modules) # Check 2: the metacomment must appear inside at least one module body. if not with_meta: print( f"--verilator-hier-blocks must emit {HIER_BLOCK!r} into a generated " - f"module, but none of {[m[1] for m in modules]} contain it." + f"module, but none of these modules contain it: {module_names}." ) return 1 @@ -83,8 +93,8 @@ def main(): if not without_meta: print( f"--verilator-hier-blocks should only annotate the exported design " - f"module, but every generated module " - f"{[m[1] for m in modules]} contains {HIER_BLOCK!r}." + f"module, but every generated module contains {HIER_BLOCK!r}: " + f"{module_names}." ) return 1 From 0c833dd9dde160566fc027ce87eccf65cc64a2a3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Jun 2026 18:32:29 +0000 Subject: [PATCH 6/6] Fix review feedback on hier_block placement and docs --- compiler/cpp/options.h | 4 ++-- compiler/cpp/verilog.cpp | 5 ++++- compiler/hs/app/Options/CmdArgs.hs | 2 +- ...heck_verilator_hier_blocks.cpython-312.pyc | Bin 4961 -> 5701 bytes .../cli/check_verilator_hier_blocks.py | 17 +++++++++++++++++ 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/compiler/cpp/options.h b/compiler/cpp/options.h index a13b705..f3806f5 100644 --- a/compiler/cpp/options.h +++ b/compiler/cpp/options.h @@ -261,8 +261,8 @@ extern "C" // Don't output the informational header on top of generated Verilog files BOOL _noVerilogHeader; - // Emit a /*verilator hier_block*/ metacomment in each generated module - // to enable hierarchical Verilation + // Emit a /*verilator hier_block*/ metacomment in the exported core + // design module to enable hierarchical Verilation BOOL _emitVerilatorHierBlocks; // True to enable warnings about missing [[transaction_size]] diff --git a/compiler/cpp/verilog.cpp b/compiler/cpp/verilog.cpp index a4a7fdb..68ba5f6 100644 --- a/compiler/cpp/verilog.cpp +++ b/compiler/cpp/verilog.cpp @@ -7123,7 +7123,10 @@ class VerilogCompiler // appear inside the module body, after the port list. if (GetCodeGenConfig()._emitVerilatorHierBlocks) { - _writer.Str() << "/*verilator hier_block*/"; + coreModule.AddVerbatimOp(GetUnknownLocation(), [&](VerbatimWriter &writer) + { + writer << "/*verilator hier_block*/"; + }); } DeclareDebugVariables(); diff --git a/compiler/hs/app/Options/CmdArgs.hs b/compiler/hs/app/Options/CmdArgs.hs index b304629..e9633a7 100644 --- a/compiler/hs/app/Options/CmdArgs.hs +++ b/compiler/hs/app/Options/CmdArgs.hs @@ -81,7 +81,7 @@ compile = Compile , no_fifo_stutter = def &= groupname "Code generation" &= help "Disable fifos stutter" , no_debug_view = def &= groupname "Code generation" &= help "Disables debug views" , no_verilog_header = def &= groupname "Code generation" &= help "Don't output the informational header on top of generated Verilog files" - , verilator_hier_blocks = def &= groupname "Code generation" &= help "Emit a /*verilator hier_block*/ metacomment in each generated module to enable hierarchical Verilation" &= name "verilator-hier-blocks" &= explicit + , verilator_hier_blocks = def &= groupname "Code generation" &= help "Emit a /*verilator hier_block*/ metacomment in the exported core design module to enable hierarchical Verilation" &= name "verilator-hier-blocks" &= explicit , code_coverage = def &= groupname "Code generation" &= help "Enable generation of code coverage using SystemVerilog coverpoints" , code_coverage_mux_threshold = 0 &= groupname "Code generation" &= help "Only generate code coverage code for muxes with this number of cases; the default value of 0 means to generate for all muxes" , optimize = 2 &= groupname "Code generation" &= help "Optimize generated code" &= typ "LEVEL" &= name "O" diff --git a/test/compiler/cli/__pycache__/check_verilator_hier_blocks.cpython-312.pyc b/test/compiler/cli/__pycache__/check_verilator_hier_blocks.cpython-312.pyc index dc67d33e64fe0db018193efd716318f9543cefba..1b87a081b64cec2aabf376c85b636f7d964349bd 100644 GIT binary patch delta 1317 zcmZuxOKclO7~Wa0U%TtKLtaijDM{-s!KEz-r3of!A)?R%bpr%cX}k80>rL&onO!S! zWGg*z%q7|b6$Mdll_I2~B9sFMq?QvGn*xnim1xBQ^=9!ngbU29?X(DfX}tD zzx9Iy-%bU;3j}zE$Y-BR%U?$}gG1n}&4Vj1slE@G_e2y>{g+YTI2r_%H75^Cx>Y$KxjGBJ1}efe)Dmvka_pF*XYNnN83DD(jpG>aMPz zkFB##HUZ-0*2uoqvyj;58Ri@#xz|o)ky*n!T*Ng5wE}$Q)XQ1<#OXIqz6Ogs}*d*l4h9cHCCE=_&1S-hqS)L+FU`?RePO(RE!vfaz(9` zkesWibvr=QWtuJ{T{UPPgm{Q-_P(NG$VCldIajLWFUijF@?JdNPlBe&GL93t%-oMB z@5U$E@ri4TcjAXGpV{%oudv^HM|MIp@g3obyTWK&82$Lw>w#_1PEFqtj&JAM!d#1+ z!y_a=Pu8AziRScq%5^is{{qr6hG}}tv3@|qqXve_kAB+?un}!|Hrb5Dm`(mzIxn)GUp zTxHeR|7FzUc@{8vw&__R_+L#LcwGXvpdurWwJIH$%~xt>_2$pw8~|Ah22Zni%+iBz z9wj_wY*2oD2KW%MtqqnHO;68~At)sylb*eZbhKKKhc%eXQC!|0s>`wTg z@rWES)n(5GY37171#>kM>Xlv`EGuTdhzvq4jii*6JSrpIgc!YF(=gSo)ldV3tUp61 z!K5`Eerg>j$;BK7NP_LD5_TeNa|*s_;7RHUQ=pBs-MUgn22NAmzoMB%xr|K39@tYK z3@=2u+hZI- z+b7HPcCsvm@DY-P4->FijBJ-tH*9ZJF^eTFhbh-_()u*I{{{L{Ij^C~^xd*-b7)mF s@zc~p`RKg+FW+ppIT?J4*yz8MQLuKSbAlVpgWtl>fk3BfWnxeM1HcYn0RR91 delta 545 zcmX@A^H7cNG%qg~0}#|N)yz`mpU5Y{xM8Atxm_wx3P-jE14EGn6GJL*}4&uhrYIa!cT9!MJU zDOwAbz|Eb_lp<8aIh!GcXD%y}X>66k$xMt4$xO9u(EoK7J3JOIMK&nUyNK}dECT8a8+2rIWC*~B}>Di>G=A~8?6xjt# z{vgmZ`H5f!Bj4m$A!kO}$qR+F>u+&+c)A9~JNfuKduwvtVk<~2Do!oB#gbT*UR)## zGE@LW2m*;)ta*vKsl`R=AU0=tW=TeTZfZ&5EgldvzqAC(%gs+I%}I?1t1SivwgMc0 zU3rTI