From 56c45e3ea8eef59040271a6f5aa504b93dc8f5ff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:56:02 +0000 Subject: [PATCH 1/6] Initial plan From e8cf90e8f11ccbf2b9c67636ba45c175d74c6d2e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 16:09:06 +0000 Subject: [PATCH 2/6] Fix duplicate SV struct typedefs when multiple APIs share same struct type Co-authored-by: mballance <1340805+mballance@users.noreply.github.com> --- src/hdl_if/impl/call/gen_sv_class.py | 15 ++++++--- tests/unit/test_api_gen_sv_filtering.py | 42 +++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/hdl_if/impl/call/gen_sv_class.py b/src/hdl_if/impl/call/gen_sv_class.py index cbcaa28..d36a7ba 100644 --- a/src/hdl_if/impl/call/gen_sv_class.py +++ b/src/hdl_if/impl/call/gen_sv_class.py @@ -37,6 +37,7 @@ def __init__(self, out, ind="", uvm=False, deprecated=False): self._deprecated = deprecated self._have_imp = False self._struct_types = set() # Track struct types used in API + self._emitted_struct_types = set() # Track struct types already emitted (across multiple gen() calls) pass def _collect_methods(self, api: ApiDef): @@ -93,16 +94,20 @@ def gen(self, api : ApiDef): # Collect struct types used in the API self._collect_struct_types(api) - # Generate struct typedefs - if self._struct_types: - for struct_type in sorted(self._struct_types, key=lambda t: t.__name__): + # Generate struct typedefs only for types not already emitted + new_struct_types = self._struct_types - self._emitted_struct_types + if new_struct_types: + for struct_type in sorted(new_struct_types, key=lambda t: t.__name__): self.gen_struct_typedef(struct_type) self.println() - # Generate conversion functions for each struct - for struct_type in sorted(self._struct_types, key=lambda t: t.__name__): + # Generate conversion functions for each new struct + for struct_type in sorted(new_struct_types, key=lambda t: t.__name__): self.gen_struct_conversion_functions(struct_type) self.println() + + self._emitted_struct_types.update(new_struct_types) + self._struct_types = set() # Existing class generation (unchanged) # self.gen_class_interface_exp(api) diff --git a/tests/unit/test_api_gen_sv_filtering.py b/tests/unit/test_api_gen_sv_filtering.py index 1a137d4..177e71f 100644 --- a/tests/unit/test_api_gen_sv_filtering.py +++ b/tests/unit/test_api_gen_sv_filtering.py @@ -450,3 +450,45 @@ def __init__(self): assert len(filtered) == 3 names = [a.name for a in filtered] assert names == ["First", "Second", "Third"] + + def test_no_duplicate_struct_typedefs_across_apis(self): + """Test that struct typedefs are not duplicated when multiple APIs share the same struct type.""" + + class Point(ct.Structure): + _fields_ = [ + ("x", ct.c_int32), + ("y", ct.c_int32), + ] + + @api + class FirstAPI(object): + @imp + async def func1(self, pt: Point): + pass + + @api + class SecondAPI(object): + @exp + def func2(self, pt: Point): + pass + + all_apis = ApiDefRgy.inst().getApis() + + out = io.StringIO() + gen = GenSVClass(out, ind="", uvm=False, deprecated=False) + for a in all_apis: + gen.gen(a) + sv_content = out.getvalue() + + # Count occurrences of the struct typedef — must appear exactly once + typedef_count = sv_content.count("typedef struct") + assert typedef_count == 1, ( + f"Expected 1 struct typedef for Point_t, but found {typedef_count}. " + f"Duplicate typedefs cause SV compilation errors." + ) + # Conversion function definitions must also appear exactly once + # (the name may also appear in calls within API method bodies) + assert sv_content.count("function Point_t pyhdl_if_py_to_struct_Point") == 1, \ + "pyhdl_if_py_to_struct_Point conversion function definition duplicated" + assert sv_content.count("function pyhdl_if::PyObject pyhdl_if_struct_to_py_Point") == 1, \ + "pyhdl_if_struct_to_py_Point conversion function definition duplicated" From 211d527f25f4231abfbef56baf47bc832f4d4fd6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 17:18:40 +0000 Subject: [PATCH 3/6] Fix CI build failure: explicitly install pcpp cxxheaderparser before setup.py build_ext Co-authored-by: mballance <1340805+mballance@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56cfe9c..f956e37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: python3 -m venv py ./py/bin/pip install -U ivpm ./py/bin/python3 -m ivpm update -a - ./packages/python/bin/pip install -U typing_extensions build + ./packages/python/bin/pip install -U typing_extensions build pcpp cxxheaderparser ./packages/python/bin/python3 setup.py build_ext --inplace ./packages/python/bin/python3 -m build -n ls src From 538bf1497dfce17f5176ac9c6bfa996c09a686aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 17:26:13 +0000 Subject: [PATCH 4/6] Fix CI: install pcpp cxxheaderparser without -U to avoid setuptools upgrade incompatibility Co-authored-by: mballance <1340805+mballance@users.noreply.github.com> --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f956e37..af875df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,8 @@ jobs: python3 -m venv py ./py/bin/pip install -U ivpm ./py/bin/python3 -m ivpm update -a - ./packages/python/bin/pip install -U typing_extensions build pcpp cxxheaderparser + ./packages/python/bin/pip install -U typing_extensions build + ./packages/python/bin/pip install pcpp cxxheaderparser ./packages/python/bin/python3 setup.py build_ext --inplace ./packages/python/bin/python3 -m build -n ls src From 90db34579a5fe82f44424952ae6733bb1924b391 Mon Sep 17 00:00:00 2001 From: Matthew Ballance Date: Mon, 2 Mar 2026 03:41:43 +0000 Subject: [PATCH 5/6] Correct incorect import of dv-flow-mgr branch Signed-off-by: Matthew Ballance --- ivpm.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ivpm.yaml b/ivpm.yaml index a113253..d5964a6 100644 --- a/ivpm.yaml +++ b/ivpm.yaml @@ -8,14 +8,6 @@ package: dep-sets: - - name: default - deps: - - name: pytest - src: pypi - # - name: pyvsc-dataclasses - # src: pypi - - name: fusesoc - src: pypi - name: default-dev deps: @@ -35,7 +27,6 @@ package: url: https://github.com/dv-flow/dv-flow-libhdlsim.git - name: dv-flow-mgr url: https://github.com/dv-flow/dv-flow-mgr.git - branch: mballance/taskdeps - name: verilator url: https://github.com/edapack/verilator-bin src: gh-rls @@ -107,6 +98,15 @@ package: - name: doxygen-filter-sv url: https://github.com/SeanOBoyle/DoxygenFilterSystemVerilog.git + - name: default + deps: + - name: pytest + src: pypi + # - name: pyvsc-dataclasses + # src: pypi + - name: fusesoc + src: pypi + env: - name: PATH path-prepend: From e6b94acb16453f54f8944cd77b57401a91894d08 Mon Sep 17 00:00:00 2001 From: Matthew Ballance Date: Sun, 8 Mar 2026 16:16:31 +0000 Subject: [PATCH 6/6] Fix xsim compatibility: guard $stacktrace with XILINX_SIMULATOR, use automatic in initial blocks - In pyhdl_if_macros.svh, conditionally define STACKTRACE macro to use a display placeholder when XILINX_SIMULATOR is defined, since Vivado xsim does not support $stacktrace - In pyhdl_if.sv, switch the inline $stacktrace call to use the STACKTRACE macro for consistency - In struct_bfm.sv and struct_comprehensive_bfm.sv, declare class variables in initial blocks as 'automatic' to satisfy xelab's requirement for explicit lifetime Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/hdl_if/share/dpi/pyhdl_if.sv | 2 +- src/hdl_if/share/dpi/pyhdl_if_macros.svh | 4 ++++ tests/unit/data/test_struct/struct_bfm.sv | 4 ++-- tests/unit/data/test_struct/struct_comprehensive_bfm.sv | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/hdl_if/share/dpi/pyhdl_if.sv b/src/hdl_if/share/dpi/pyhdl_if.sv index 7829538..417e6a9 100644 --- a/src/hdl_if/share/dpi/pyhdl_if.sv +++ b/src/hdl_if/share/dpi/pyhdl_if.sv @@ -207,7 +207,7 @@ package pyhdl_if; function automatic PyObject pyhdl_pi_if_HandleErr(PyObject obj); if (obj == null) begin $display("--> HandleErr"); - $stacktrace; + `STACKTRACE; PyErr_Print(); $display("<-- HandleErr"); end diff --git a/src/hdl_if/share/dpi/pyhdl_if_macros.svh b/src/hdl_if/share/dpi/pyhdl_if_macros.svh index 7e410ba..1501f17 100644 --- a/src/hdl_if/share/dpi/pyhdl_if_macros.svh +++ b/src/hdl_if/share/dpi/pyhdl_if_macros.svh @@ -29,7 +29,11 @@ $display x ; \ $finish ; +`ifdef XILINX_SIMULATOR +`define STACKTRACE $display("TODO: no stacktrace support in Xilinx simulator") +`else `define STACKTRACE $stacktrace +`endif `endif /* INCLUDED_PYHDL_IF_MACROS_SVH */ diff --git a/tests/unit/data/test_struct/struct_bfm.sv b/tests/unit/data/test_struct/struct_bfm.sv index c425b8a..5309de4 100644 --- a/tests/unit/data/test_struct/struct_bfm.sv +++ b/tests/unit/data/test_struct/struct_bfm.sv @@ -30,8 +30,8 @@ module struct_bfm Point_t stored_point; initial begin - StructBFM_Impl impl = new(); - StructTest_exp_impl test; + automatic StructBFM_Impl impl = new(); + automatic StructTest_exp_impl test; int fd; string line; diff --git a/tests/unit/data/test_struct/struct_comprehensive_bfm.sv b/tests/unit/data/test_struct/struct_comprehensive_bfm.sv index 98dcecf..7603a9b 100644 --- a/tests/unit/data/test_struct/struct_comprehensive_bfm.sv +++ b/tests/unit/data/test_struct/struct_comprehensive_bfm.sv @@ -90,8 +90,8 @@ module struct_comprehensive_bfm ComprehensiveBFM_imp_impl#(ComprehensiveBFM_Impl) bfm; initial begin - ComprehensiveBFM_Impl impl = new(); - ComprehensiveTest_exp_impl test; + automatic ComprehensiveBFM_Impl impl = new(); + automatic ComprehensiveTest_exp_impl test; int fd; string line;